<commit_before>package dudu

import (
	"errors"
	"fmt"
	"io"
	"os"
	"path"
	"runtime"
	"sort"
	"strconv"
	"strings"
	"sync"
	"sync/atomic"
	"syscall"

	"github.com/gholt/brimtext"
)

var HELP_TEXT = errors.New(strings.TrimSpace(`
Estimate disk space usage with parallelism; tries to be GNU du compatible.

Currently supports the following options:

--apparent-size
-B --block-size=SIZE
-b --bytes
-h --human-readable
-k
-m
-s --summarize
--help

Also has the following options:

-v --verbose
--x-parallel-tasks=N
    Attempts will be made to concurrently examine files and directories up to
    the limit of N. Default for N is 100.
`))

func DUDU(args []string) error {
	cfg, items, err := parseArgs(args)
	if err != nil {
		return err
	}
	if cfg.verbosity > 1 {
		fmt.Printf("cfg is %#v\n", cfg)
		fmt.Printf("items are %#v\n", items)
	}

	fileCounts := make(map[string]int64)
	fileCountsLock := &sync.Mutex{}
	dirCounts := make(map[string]int64)
	dirCountsLock := &sync.Mutex{}

	msgs := make(chan string, cfg.messageBuffer)
	msgsDone := make(chan struct{})
	go func() {
		for {
			msg := <-msgs
			if msg == "" {
				break
			}
			fmt.Println(msg)
		}
		close(msgsDone)
	}()

	var errCount uint32
	errs := make(chan string, cfg.errBuffer)
	errsDone := make(chan struct{})
	go func() {
		for {
			err := <-errs
			if err == "" {
				break
			}
			atomic.AddUint32(&errCount, 1)
			fmt.Println(err)
		}
		close(errsDone)
	}()

	wg := &sync.WaitGroup{}

	statTasks := make(chan *statTask, cfg.parallelTasks)
	freeStatTasks := make(chan *statTask, cfg.parallelTasks)
	for i := 0; i < cfg.parallelTasks; i++ {
		freeStatTasks <- &statTask{}
		go statter(cfg, fileCounts, fileCountsLock, dirCounts, dirCountsLock, msgs, errs, wg, statTasks, freeStatTasks)
	}

	if len(items) == 0 {
		fi, err := os.Lstat(".")
		if err != nil {
			errs <- fmtErr(".", err)
		} else {
			ct := <-freeStatTasks
			ct.item = "."
			ct.fi = fi
			wg.Add(1)
			statTasks <- ct
		}
	} else {
		for _, item := range items {
			fi, err := os.Lstat(item)
			if err != nil {
				errs <- fmtErr(item, err)
				continue
			}
			ct := <-freeStatTasks
			ct.item = item
			ct.fi = fi
			wg.Add(1)
			statTasks <- ct
		}
	}

	wg.Wait()

	close(msgs)
	<-msgsDone
	close(errs)
	<-errsDone

	bsit := func(n int64) string {
		if cfg.humanReadable {
			return brimtext.HumanSize(n, "")
		}
		return fmt.Sprintf("%d", (n+cfg.blockSize-1)/cfg.blockSize)
	}

	if cfg.summarize && len(items) == 0 {
		items = []string{"."}
	}

	if len(items) == 0 {
		items := make([]string, len(dirCounts))
		i := 0
		for item, _ := range dirCounts {
			items[i] = item
			i++
		}
		sort.Sort(sort.Reverse(sort.StringSlice(items)))
		for _, item := range items {
			fmt.Printf("%s\t%s\n", bsit(dirCounts[item]), item)
		}
	} else {
		for _, item := range items {
			fi, err := os.Lstat(item)
			if err != nil {
				errs <- fmtErr(item, err)
				continue
			}
			if fi.IsDir() {
				if !cfg.summarize {
					prefix := item
					if item[len(item)-1] != '/' {
						prefix += "/"
					}
					subitems := make([]string, len(dirCounts))
					i := 0
					for subitem, _ := range dirCounts {
						if strings.HasPrefix(subitem, prefix) {
							subitems[i] = subitem
							i++
						}
					}
					subitems = subitems[:i]
					sort.Sort(sort.Reverse(sort.StringSlice(subitems)))
					for _, subitem := range subitems {
						fmt.Printf("%s\t%s\n", bsit(dirCounts[subitem]), subitem)
					}
				}
				fmt.Printf("%s\t%s\n", bsit(dirCounts[item]), item)
			} else {
				fmt.Printf("%s\t%s\n", bsit(fileCounts[item]), item)
			}
		}
	}

	finalErrCount := atomic.LoadUint32(&errCount)
	if finalErrCount > 0 {
		return fmt.Errorf("there were %d errors", finalErrCount)
	}
	return nil
}

type config struct {
	verbosity     int
	blockSize     int64
	apparentSize  bool
	summarize     bool
	humanReadable bool
	parallelTasks int
	readdirBuffer int
	messageBuffer int
	errBuffer     int
}

func parseArgs(args []string) (*config, []string, error) {
	cfg := &config{
		verbosity:     0,
		blockSize:     512,
		apparentSize:  false,
		summarize:     false,
		humanReadable: false,
		parallelTasks: 100,
		readdirBuffer: 1000,
		messageBuffer: 1000,
		errBuffer:     1000,
	}
	var items []string
	mapitems := make(map[string]bool)
	for i := 0; i < len(args); i++ {
		if args[i] == "" {
			continue
		}
		if args[i][0] != '-' {
			if !mapitems[args[i]] {
				items = append(items, args[i])
				mapitems[args[i]] = true
			}
			continue
		}
		if args[i] == "-" {
			for _, item := range args[i+1:] {
				if !mapitems[item] {
					items = append(items, item)
					mapitems[item] = true
				}
			}
			continue
		}
		var opts []string
		if args[i][1] == '-' {
			opt := args[i][2:]
			if opt == "bytes" {
				opts = append(opts, "apparent-size", "block-size=1")
			} else {
				if !strings.Contains(opt, "=") {
					if opt == "B" || opt == "block-size" {
						i++
						if len(args) <= i {
							return nil, nil, fmt.Errorf("--block-size requires a parameter")
						}
						opt += "=" + args[i]
					}
				}
				opts = append(opts, opt)
			}
		} else {
			for _, s := range args[i][1:] {
				switch s {
				case 'b':
					opts = append(opts, "apparent-size", "block-size=1")
				case 'h':
					opts = append(opts, "human-readable")
				case 'k':
					opts = append(opts, "block-size=1024")
				case 'm':
					opts = append(opts, "block-size=1048576")
				case 's':
					opts = append(opts, "summarize")
				case 'v':
					opts = append(opts, "verbose")
				}
			}
		}
		for _, opt := range opts {
			var arg string
			s := strings.SplitN(opt, "=", 2)
			if len(s) > 1 {
				opt = s[0]
				arg = s[1]
			}
			switch opt {
			case "apparent-size":
				cfg.apparentSize = true
			case "block-size":
				if arg == "" {
					return nil, nil, fmt.Errorf("--block-size requires a parameter")
				}
				n, err := strconv.Atoi(arg)
				if err != nil {
					return nil, nil, fmt.Errorf("could not parse number %q for --block-size", arg)
				}
				if n < 1 {
					n = 1
				}
				cfg.blockSize = int64(n)
			case "help":
				return nil, nil, HELP_TEXT
			case "human-readable":
				cfg.humanReadable = true
			case "summarize":
				cfg.summarize = true
			case "verbose":
				cfg.verbosity++
			case "x-parallel-tasks":
				if arg == "" {
					return nil, nil, fmt.Errorf("--x-parallel-tasks requires a parameter")
				}
				n, err := strconv.Atoi(arg)
				if err != nil {
					return nil, nil, fmt.Errorf("could not parse number %q for --x-parallel-tasks", arg)
				}
				if n < 1 {
					n = 1
				}
				cfg.parallelTasks = n
			default:
				return nil, nil, fmt.Errorf("unknown option %q", opt)
			}
		}
	}
	return cfg, items, nil
}

type statTask struct {
	item string
	fi   os.FileInfo
}

func fmtErr(pth string, err error) string {
	rv := err.Error()
	if rv == "" {
		rv = "unknown error"
	}
	if pth != "" {
		rv = pth + ": " + rv
	}
	_, filename, line, ok := runtime.Caller(1)
	if ok {
		rv = fmt.Sprintf("%s @%s:%d", rv, path.Base(filename), line)
	}
	return rv
}

func statter(cfg *config, fileCounts map[string]int64, fileCountsLock *sync.Mutex, dirCounts map[string]int64, dirCountsLock *sync.Mutex, msgs chan string, errs chan string, wg *sync.WaitGroup, statTasks chan *statTask, freeStatTasks chan *statTask) {
	var localTasks []*statTask
	for {
		var item string
		var fi os.FileInfo
		if i := len(localTasks); i > 0 {
			i--
			ct := localTasks[i]
			localTasks = localTasks[:i]
			select {
			case fct := <-freeStatTasks:
				fct.item = ct.item
				fct.fi = ct.fi
				statTasks <- fct
				continue
			default:
				item = ct.item
				fi = ct.fi
			}
		} else {
			ct := <-statTasks
			item = ct.item
			fi = ct.fi
			freeStatTasks <- ct
		}
		if cfg.verbosity > 0 {
			msgs <- fmt.Sprintf("Statting %s", item)
		}
		fiSize := fi.Size()
		if !cfg.apparentSize {
			if st, ok := fi.Sys().(*syscall.Stat_t); ok {
				fiSize = st.Blocks * 512
			}
		}
		if fi.IsDir() {
			dirCountsLock.Lock()
			dirCountItem := item
			for {
				dirCounts[dirCountItem] += fiSize
				if dirCountItem == "." || dirCountItem == "/" {
					break
				}
				dirCountItem = path.Dir(dirCountItem)
			}
			dirCountsLock.Unlock()
		} else {
			fileCountsLock.Lock()
			fileCounts[item] += fiSize
			fileCountsLock.Unlock()
			dirCountsLock.Lock()
			dirCountItem := path.Dir(item)
			for {
				dirCounts[dirCountItem] += fiSize
				if dirCountItem == "." || dirCountItem == "/" {
					break
				}
				dirCountItem = path.Dir(dirCountItem)
			}
			dirCountsLock.Unlock()
		}
		if fi.IsDir() {
			f, err := os.Open(item)
			if err != nil {
				errs <- fmtErr(item, err)
				wg.Done()
				continue
			}
			for {
				subfis, err := f.Readdir(cfg.readdirBuffer)
				for _, subfi := range subfis {
					subitem := path.Join(item, subfi.Name())
					wg.Add(1)
					select {
					case ct := <-freeStatTasks:
						ct.item = subitem
						ct.fi = subfi
						statTasks <- ct
					default:
						localTasks = append(localTasks, &statTask{
							item: subitem,
							fi:   subfi,
						})
					}
				}
				if err != nil {
					f.Close()
					if err != io.EOF {
						errs <- fmtErr(item, err)
					}
					break
				}
			}
		}
		wg.Done()
	}
}
<commit_msg>cfs du: Support for the block size related env vars<commit_after>package dudu

import (
	"errors"
	"fmt"
	"io"
	"os"
	"path"
	"runtime"
	"sort"
	"strconv"
	"strings"
	"sync"
	"sync/atomic"
	"syscall"

	"github.com/gholt/brimtext"
)

var HELP_TEXT = errors.New(strings.TrimSpace(`
Estimate disk space usage with parallelism; tries to be GNU du compatible.

Currently supports the following options:

--apparent-size
-B --block-size=SIZE
-b --bytes
-h --human-readable
-k
-m
-s --summarize
--help

Also has the following options:

-v --verbose
--x-parallel-tasks=N
    Attempts will be made to concurrently examine files and directories up to
    the limit of N. Default for N is 100.
`))

func DUDU(args []string) error {
	cfg, items, err := parseArgs(args)
	if err != nil {
		return err
	}
	if cfg.verbosity > 1 {
		fmt.Printf("cfg is %#v\n", cfg)
		fmt.Printf("items are %#v\n", items)
	}

	fileCounts := make(map[string]int64)
	fileCountsLock := &sync.Mutex{}
	dirCounts := make(map[string]int64)
	dirCountsLock := &sync.Mutex{}

	msgs := make(chan string, cfg.messageBuffer)
	msgsDone := make(chan struct{})
	go func() {
		for {
			msg := <-msgs
			if msg == "" {
				break
			}
			fmt.Println(msg)
		}
		close(msgsDone)
	}()

	var errCount uint32
	errs := make(chan string, cfg.errBuffer)
	errsDone := make(chan struct{})
	go func() {
		for {
			err := <-errs
			if err == "" {
				break
			}
			atomic.AddUint32(&errCount, 1)
			fmt.Println(err)
		}
		close(errsDone)
	}()

	wg := &sync.WaitGroup{}

	statTasks := make(chan *statTask, cfg.parallelTasks)
	freeStatTasks := make(chan *statTask, cfg.parallelTasks)
	for i := 0; i < cfg.parallelTasks; i++ {
		freeStatTasks <- &statTask{}
		go statter(cfg, fileCounts, fileCountsLock, dirCounts, dirCountsLock, msgs, errs, wg, statTasks, freeStatTasks)
	}

	if len(items) == 0 {
		fi, err := os.Lstat(".")
		if err != nil {
			errs <- fmtErr(".", err)
		} else {
			ct := <-freeStatTasks
			ct.item = "."
			ct.fi = fi
			wg.Add(1)
			statTasks <- ct
		}
	} else {
		for _, item := range items {
			fi, err := os.Lstat(item)
			if err != nil {
				errs <- fmtErr(item, err)
				continue
			}
			ct := <-freeStatTasks
			ct.item = item
			ct.fi = fi
			wg.Add(1)
			statTasks <- ct
		}
	}

	wg.Wait()

	close(msgs)
	<-msgsDone
	close(errs)
	<-errsDone

	bsit := func(n int64) string {
		if cfg.humanReadable {
			return brimtext.HumanSize(n, "")
		}
		return fmt.Sprintf("%d", (n+cfg.blockSize-1)/cfg.blockSize)
	}

	if cfg.summarize && len(items) == 0 {
		items = []string{"."}
	}

	if len(items) == 0 {
		items := make([]string, len(dirCounts))
		i := 0
		for item, _ := range dirCounts {
			items[i] = item
			i++
		}
		sort.Sort(sort.Reverse(sort.StringSlice(items)))
		for _, item := range items {
			fmt.Printf("%s\t%s\n", bsit(dirCounts[item]), item)
		}
	} else {
		for _, item := range items {
			fi, err := os.Lstat(item)
			if err != nil {
				errs <- fmtErr(item, err)
				continue
			}
			if fi.IsDir() {
				if !cfg.summarize {
					prefix := item
					if item[len(item)-1] != '/' {
						prefix += "/"
					}
					subitems := make([]string, len(dirCounts))
					i := 0
					for subitem, _ := range dirCounts {
						if strings.HasPrefix(subitem, prefix) {
							subitems[i] = subitem
							i++
						}
					}
					subitems = subitems[:i]
					sort.Sort(sort.Reverse(sort.StringSlice(subitems)))
					for _, subitem := range subitems {
						fmt.Printf("%s\t%s\n", bsit(dirCounts[subitem]), subitem)
					}
				}
				fmt.Printf("%s\t%s\n", bsit(dirCounts[item]), item)
			} else {
				fmt.Printf("%s\t%s\n", bsit(fileCounts[item]), item)
			}
		}
	}

	finalErrCount := atomic.LoadUint32(&errCount)
	if finalErrCount > 0 {
		return fmt.Errorf("there were %d errors", finalErrCount)
	}
	return nil
}

type config struct {
	verbosity     int
	blockSize     int64
	apparentSize  bool
	summarize     bool
	humanReadable bool
	parallelTasks int
	readdirBuffer int
	messageBuffer int
	errBuffer     int
}

func parseArgs(args []string) (*config, []string, error) {
	cfg := &config{
		verbosity:     0,
		blockSize:     1024,
		apparentSize:  false,
		summarize:     false,
		humanReadable: false,
		parallelTasks: 100,
		readdirBuffer: 1000,
		messageBuffer: 1000,
		errBuffer:     1000,
	}
	if os.Getenv("POSIXLY_CORRECT") != "" {
		cfg.blockSize = 512
	}
	if bs, err := strconv.Atoi(os.Getenv("BLOCKSIZE")); err == nil && bs > 0 {
		cfg.blockSize = int64(bs)
	}
	if bs, err := strconv.Atoi(os.Getenv("BLOCK_SIZE")); err == nil && bs > 0 {
		cfg.blockSize = int64(bs)
	}
	if bs, err := strconv.Atoi(os.Getenv("DU_BLOCK_SIZE")); err == nil && bs > 0 {
		cfg.blockSize = int64(bs)
	}
	var items []string
	mapitems := make(map[string]bool)
	for i := 0; i < len(args); i++ {
		if args[i] == "" {
			continue
		}
		if args[i][0] != '-' {
			if !mapitems[args[i]] {
				items = append(items, args[i])
				mapitems[args[i]] = true
			}
			continue
		}
		if args[i] == "-" {
			for _, item := range args[i+1:] {
				if !mapitems[item] {
					items = append(items, item)
					mapitems[item] = true
				}
			}
			continue
		}
		var opts []string
		if args[i][1] == '-' {
			opt := args[i][2:]
			if opt == "bytes" {
				opts = append(opts, "apparent-size", "block-size=1")
			} else {
				if !strings.Contains(opt, "=") {
					if opt == "B" || opt == "block-size" {
						i++
						if len(args) <= i {
							return nil, nil, fmt.Errorf("--block-size requires a parameter")
						}
						opt += "=" + args[i]
					}
				}
				opts = append(opts, opt)
			}
		} else {
			for _, s := range args[i][1:] {
				switch s {
				case 'b':
					opts = append(opts, "apparent-size", "block-size=1")
				case 'h':
					opts = append(opts, "human-readable")
				case 'k':
					opts = append(opts, "block-size=1024")
				case 'm':
					opts = append(opts, "block-size=1048576")
				case 's':
					opts = append(opts, "summarize")
				case 'v':
					opts = append(opts, "verbose")
				}
			}
		}
		for _, opt := range opts {
			var arg string
			s := strings.SplitN(opt, "=", 2)
			if len(s) > 1 {
				opt = s[0]
				arg = s[1]
			}
			switch opt {
			case "apparent-size":
				cfg.apparentSize = true
			case "block-size":
				if arg == "" {
					return nil, nil, fmt.Errorf("--block-size requires a parameter")
				}
				n, err := strconv.Atoi(arg)
				if err != nil {
					return nil, nil, fmt.Errorf("could not parse number %q for --block-size", arg)
				}
				if n < 1 {
					n = 1
				}
				cfg.blockSize = int64(n)
			case "help":
				return nil, nil, HELP_TEXT
			case "human-readable":
				cfg.humanReadable = true
			case "summarize":
				cfg.summarize = true
			case "verbose":
				cfg.verbosity++
			case "x-parallel-tasks":
				if arg == "" {
					return nil, nil, fmt.Errorf("--x-parallel-tasks requires a parameter")
				}
				n, err := strconv.Atoi(arg)
				if err != nil {
					return nil, nil, fmt.Errorf("could not parse number %q for --x-parallel-tasks", arg)
				}
				if n < 1 {
					n = 1
				}
				cfg.parallelTasks = n
			default:
				return nil, nil, fmt.Errorf("unknown option %q", opt)
			}
		}
	}
	return cfg, items, nil
}

type statTask struct {
	item string
	fi   os.FileInfo
}

func fmtErr(pth string, err error) string {
	rv := err.Error()
	if rv == "" {
		rv = "unknown error"
	}
	if pth != "" {
		rv = pth + ": " + rv
	}
	_, filename, line, ok := runtime.Caller(1)
	if ok {
		rv = fmt.Sprintf("%s @%s:%d", rv, path.Base(filename), line)
	}
	return rv
}

func statter(cfg *config, fileCounts map[string]int64, fileCountsLock *sync.Mutex, dirCounts map[string]int64, dirCountsLock *sync.Mutex, msgs chan string, errs chan string, wg *sync.WaitGroup, statTasks chan *statTask, freeStatTasks chan *statTask) {
	var localTasks []*statTask
	for {
		var item string
		var fi os.FileInfo
		if i := len(localTasks); i > 0 {
			i--
			ct := localTasks[i]
			localTasks = localTasks[:i]
			select {
			case fct := <-freeStatTasks:
				fct.item = ct.item
				fct.fi = ct.fi
				statTasks <- fct
				continue
			default:
				item = ct.item
				fi = ct.fi
			}
		} else {
			ct := <-statTasks
			item = ct.item
			fi = ct.fi
			freeStatTasks <- ct
		}
		if cfg.verbosity > 0 {
			msgs <- fmt.Sprintf("Statting %s", item)
		}
		fiSize := fi.Size()
		if !cfg.apparentSize {
			if st, ok := fi.Sys().(*syscall.Stat_t); ok {
				fiSize = st.Blocks * 512
			}
		}
		if fi.IsDir() {
			dirCountsLock.Lock()
			dirCountItem := item
			for {
				dirCounts[dirCountItem] += fiSize
				if dirCountItem == "." || dirCountItem == "/" {
					break
				}
				dirCountItem = path.Dir(dirCountItem)
			}
			dirCountsLock.Unlock()
		} else {
			fileCountsLock.Lock()
			fileCounts[item] += fiSize
			fileCountsLock.Unlock()
			dirCountsLock.Lock()
			dirCountItem := path.Dir(item)
			for {
				dirCounts[dirCountItem] += fiSize
				if dirCountItem == "." || dirCountItem == "/" {
					break
				}
				dirCountItem = path.Dir(dirCountItem)
			}
			dirCountsLock.Unlock()
		}
		if fi.IsDir() {
			f, err := os.Open(item)
			if err != nil {
				errs <- fmtErr(item, err)
				wg.Done()
				continue
			}
			for {
				subfis, err := f.Readdir(cfg.readdirBuffer)
				for _, subfi := range subfis {
					subitem := path.Join(item, subfi.Name())
					wg.Add(1)
					select {
					case ct := <-freeStatTasks:
						ct.item = subitem
						ct.fi = subfi
						statTasks <- ct
					default:
						localTasks = append(localTasks, &statTask{
							item: subitem,
							fi:   subfi,
						})
					}
				}
				if err != nil {
					f.Close()
					if err != io.EOF {
						errs <- fmtErr(item, err)
					}
					break
				}
			}
		}
		wg.Done()
	}
}
<|endoftext|>


<commit_before>package handler

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"reflect"
	"strings"
	"unicode"
	"unicode/utf8"

	"github.com/rcrowley/go-tigertonic"
)

type Securer struct {
	v              reflect.Value
	securer        reflect.Value
	permissionName string
}

func Secure(i interface{}, securer interface{}, permissionName string) *Securer {
	t := reflect.TypeOf(i)
	if reflect.Func != t.Kind() {
		panic(NewSecurerError("kind was %v, not Func", t.Kind()))
	}
	if 2 != t.NumIn() && 3 != t.NumIn() && 4 != t.NumIn() {
		panic(NewSecurerError(
			"input arity was %v, not 2, 3, or 4",
			t.NumIn(),
		))
	}
	if "*url.URL" != t.In(0).String() {
		panic(NewSecurerError(
			"type of first argument was %v, not *url.URL",
			t.In(0),
		))
	}
	if "http.Header" != t.In(1).String() {
		panic(NewSecurerError(
			"type of second argument was %v, not http.Header",
			t.In(1),
		))
	}
	if 4 != t.NumOut() {
		panic(NewSecurerError("output arity was %v, not 4", t.NumOut()))
	}
	if reflect.Int != t.Out(0).Kind() {
		panic(NewSecurerError(
			"type of first return value was %v, not int",
			t.Out(0),
		))
	}
	if "http.Header" != t.Out(1).String() {
		panic(NewSecurerError(
			"type of second return value was %v, not http.Header",
			t.Out(1),
		))
	}
	if !t.Out(2).Implements(reflect.TypeOf((*interface{})(nil)).Elem()) {
		panic(NewSecurerError(
			"type of third return value was %v, not a pointer to a response struct",
			t.Out(2),
		))
	}
	if "error" != t.Out(3).String() {
		panic(NewSecurerError(
			"type of fourth return value was %v, not error",
			t.Out(3),
		))
	}
	return &Securer{
		v:              reflect.ValueOf(i),
		securer:        createSecurerSignature(securer),
		permissionName: permissionName,
	}
}

func createSecurerSignature(securer interface{}) reflect.Value {
	t := reflect.TypeOf(securer)
	if reflect.Func != t.Kind() {
		panic(NewSecurerError("kind was %v, not Func", t.Kind()))
	}

	if t.NumIn() != 3 {
		panic(NewSecurerError(
			"input arity was %v, not 3", t.NumIn(),
		))
	}

	if "*models.Context" != t.In(2).String() {
		panic(NewSecurerError(
			"type of first argument was %v, not *models.Context",
			t.In(2),
		))
	}

	if t.NumOut() != 1 {
		panic(NewSecurerError("output arity was %v, not 1", t.NumOut()))
	}

	if "error" != t.Out(0).String() {
		panic(NewSecurerError(
			"type of first return value was %v, not error",
			t.Out(0),
		))
	}

	return reflect.ValueOf(securer)
}

// ServeHTTP unmarshals JSON input, handles the request via the function, and
// marshals JSON output.
func (m *Securer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	wHeader := w.Header()
	if !acceptJSON(r) {
		wHeader.Set("Content-Type", "text/plain")
		w.WriteHeader(http.StatusNotAcceptable)
		fmt.Fprintf(
			w,
			"\"%s\" does not contain \"application/json\"",
			r.Header.Get("Accept"),
		)
		return
	}
	wHeader.Set("Content-Type", "application/json")
	var rq reflect.Value
	if 2 < m.v.Type().NumIn() {
		in2 := m.v.Type().In(2)
		if reflect.Interface == in2.Kind() && 0 == in2.NumMethod() {
			rq = nilRequest
		} else if reflect.Slice == in2.Kind() || reflect.Map == in2.Kind() {
			// non-pointer maps/slices require special treatment because
			// json.Unmarshal won't work on a non-pointer destination. We
			// add a level indirection here, then deref it before .Call()
			rq = reflect.New(in2)
		} else {
			rq = reflect.New(in2.Elem())
		}
	} else {
		rq = nilRequest
	}
	if "PATCH" == r.Method || "POST" == r.Method || "PUT" == r.Method {
		if rq == nilRequest {
			writeJSONError(w, NewSecurerError(
				"empty interface is not suitable for %s request bodies",
				r.Method,
			))
			return
		}
		if !strings.HasPrefix(
			r.Header.Get("Content-Type"),
			"application/json",
		) {
			writeJSONError(w, tigertonic.NewHTTPEquivError(NewSecurerError(
				"Content-Type header is %s, not application/json",
				r.Header.Get("Content-Type"),
			), http.StatusUnsupportedMediaType))
			return
		}
		decoder := reflect.ValueOf(json.NewDecoder(r.Body))
		out := decoder.MethodByName("Decode").Call([]reflect.Value{rq})
		if !out[0].IsNil() {
			writeJSONError(w, tigertonic.NewHTTPEquivError(
				out[0].Interface().(error),
				http.StatusBadRequest,
			))
			return
		}
		r.Body.Close()
	} else if nilRequest != rq {
		log.Printf(
			"%s request body isn't an empty interface; this is weird and is being ignored\n",
			r.Method,
		)
	}
	if reflect.Slice == rq.Elem().Kind() || reflect.Map == rq.Elem().Kind() {
		rq = rq.Elem()
	}

	contextValue := reflect.ValueOf(tigertonic.Context(r))

	var permissionReq reflect.Value
	if rq == nilRequest {
		in := m.v.Type().In(1)
		permissionReq = reflect.New(in.Elem())
	} else {
		permissionReq = rq
	}

	secureRes := m.securer.Call([]reflect.Value{
		reflect.ValueOf(m.permissionName),
		permissionReq,
		contextValue,
	})

	if !secureRes[0].IsNil() {
		err := secureRes[0].Interface().(error)
		writeJSONError(w, tigertonic.NewHTTPEquivError(err, 403 /*forbidden*/))
		return
	}

	var out []reflect.Value
	switch m.v.Type().NumIn() {
	case 2:
		out = m.v.Call([]reflect.Value{
			reflect.ValueOf(r.URL),
			reflect.ValueOf(r.Header),
		})
	case 3:
		out = m.v.Call([]reflect.Value{
			reflect.ValueOf(r.URL),
			reflect.ValueOf(r.Header),
			rq,
		})
	case 4:
		out = m.v.Call([]reflect.Value{
			reflect.ValueOf(r.URL),
			reflect.ValueOf(r.Header),
			rq,
			contextValue,
		})
	default:
		panic(m.v.Type())
	}
	code := int(out[0].Int())
	header := out[1].Interface().(http.Header)
	rs := out[2].Interface()
	if !out[3].IsNil() {
		err := out[3].Interface().(error)
		if _, ok := err.(tigertonic.HTTPEquivError); ok {
			writeJSONError(w, err)
		} else {
			writeJSONError(w, tigertonic.NewHTTPEquivError(err, code))
		}
		return
	}
	if nil != header {
		for key, values := range header {
			wHeader.Del(key)
			for _, value := range values {
				wHeader.Add(key, value)
			}
		}
	}
	w.WriteHeader(code)
	if nil != rs && http.StatusNoContent != code && (out[2].Kind() != reflect.Ptr || !out[2].IsNil()) {
		if err := json.NewEncoder(w).Encode(rs); nil != err {
			log.Println(err)
		}
	}
}

// SecurerError is the response body for some 500 responses and panics
// when a handler function is not suitable.
type SecurerError string

func NewSecurerError(format string, args ...interface{}) SecurerError {
	return SecurerError(fmt.Sprintf(format, args...))
}

func (e SecurerError) Error() string { return string(e) }

var nilRequest = reflect.ValueOf((*interface{})(nil))

func errorStatusCode(err error) int {
	if httpEquivError, ok := err.(tigertonic.HTTPEquivError); ok {
		return httpEquivError.StatusCode()
	}
	return http.StatusInternalServerError
}

func writeJSONError(w http.ResponseWriter, err error) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(errorStatusCode(err))
	if jsonErr := json.NewEncoder(w).Encode(map[string]string{
		"description": err.Error(),
		"error":       errorName(err, "error"),
	}); nil != jsonErr {
		log.Printf("Error marshalling error response into JSON output: %s", jsonErr)
	}
}

func acceptJSON(r *http.Request) bool {
	accept := r.Header.Get("Accept")
	if "" == accept {
		return true
	}
	return strings.Contains(accept, "*/*") || strings.Contains(accept, "application/json")
}

func errorName(err error, fallback string) string {
	if namedError, ok := err.(tigertonic.NamedError); ok {
		if name := namedError.Name(); "" != name {
			return name
		}
	}
	if httpEquivError, ok := err.(tigertonic.HTTPEquivError); ok && tigertonic.SnakeCaseHTTPEquivErrors {
		return strings.Replace(
			strings.ToLower(http.StatusText(httpEquivError.StatusCode())),
			" ",
			"_",
			-1,
		)
	}
	t := reflect.TypeOf(err)
	if reflect.Ptr == t.Kind() {
		t = t.Elem()
	}
	if r, _ := utf8.DecodeRuneInString(t.Name()); unicode.IsLower(r) {
		return fallback
	}
	return t.String()
}
<commit_msg>Social: added better docs<commit_after>package handler

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"reflect"
	"strings"
	"unicode"
	"unicode/utf8"

	"github.com/rcrowley/go-tigertonic"
)

type Securer struct {
	v              reflect.Value
	securer        reflect.Value // this holds the securer handler, customized
	permissionName string        // this holds the permision name for securer function
}

// this function is copied from https://github.com/rcrowley/go-
// tigertonic/blob/master/marshaler.go#L25 while it is working with json data,
// it is also providing secure request mechanism i tried to keep the changeset
// as small as possible.
//
// Changes:
// 		function signature, added "securer interface{}, permissionName string"
//  	struct initialization, "added two new fields"
func Secure(i interface{}, securer interface{}, permissionName string) *Securer {
	t := reflect.TypeOf(i)
	if reflect.Func != t.Kind() {
		panic(NewSecurerError("kind was %v, not Func", t.Kind()))
	}
	if 2 != t.NumIn() && 3 != t.NumIn() && 4 != t.NumIn() {
		panic(NewSecurerError(
			"input arity was %v, not 2, 3, or 4",
			t.NumIn(),
		))
	}
	if "*url.URL" != t.In(0).String() {
		panic(NewSecurerError(
			"type of first argument was %v, not *url.URL",
			t.In(0),
		))
	}
	if "http.Header" != t.In(1).String() {
		panic(NewSecurerError(
			"type of second argument was %v, not http.Header",
			t.In(1),
		))
	}
	if 4 != t.NumOut() {
		panic(NewSecurerError("output arity was %v, not 4", t.NumOut()))
	}
	if reflect.Int != t.Out(0).Kind() {
		panic(NewSecurerError(
			"type of first return value was %v, not int",
			t.Out(0),
		))
	}
	if "http.Header" != t.Out(1).String() {
		panic(NewSecurerError(
			"type of second return value was %v, not http.Header",
			t.Out(1),
		))
	}
	if !t.Out(2).Implements(reflect.TypeOf((*interface{})(nil)).Elem()) {
		panic(NewSecurerError(
			"type of third return value was %v, not a pointer to a response struct",
			t.Out(2),
		))
	}
	if "error" != t.Out(3).String() {
		panic(NewSecurerError(
			"type of fourth return value was %v, not error",
			t.Out(3),
		))
	}
	return &Securer{
		v:              reflect.ValueOf(i),
		securer:        createSecurerSignature(securer),
		permissionName: permissionName,
	}
}

// createSecurerSignature checks and creates securer for processing
// panics if signature is not correct
func createSecurerSignature(securer interface{}) reflect.Value {
	t := reflect.TypeOf(securer)
	if reflect.Func != t.Kind() {
		panic(NewSecurerError("kind was %v, not Func", t.Kind()))
	}

	if t.NumIn() != 3 {
		panic(NewSecurerError(
			"input arity was %v, not 3", t.NumIn(),
		))
	}

	if "*models.Context" != t.In(2).String() {
		panic(NewSecurerError(
			"type of first argument was %v, not *models.Context",
			t.In(2),
		))
	}

	if t.NumOut() != 1 {
		panic(NewSecurerError("output arity was %v, not 1", t.NumOut()))
	}

	if "error" != t.Out(0).String() {
		panic(NewSecurerError(
			"type of first return value was %v, not error",
			t.Out(0),
		))
	}

	return reflect.ValueOf(securer)
}

// ServeHTTP unmarshals JSON input, handles the request via the function, and
// marshals JSON output. Before processing the request it checks if the context
// is allowed to operate
//
// This function is also shamelessly copied fromhttps://github.com/rcrowley/go-
// tigertonic/blob/master/marshaler.go#L25 Only addition to that function is
// "securer.Call"
func (m *Securer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	wHeader := w.Header()
	if !acceptJSON(r) {
		wHeader.Set("Content-Type", "text/plain")
		w.WriteHeader(http.StatusNotAcceptable)
		fmt.Fprintf(
			w,
			"\"%s\" does not contain \"application/json\"",
			r.Header.Get("Accept"),
		)
		return
	}
	wHeader.Set("Content-Type", "application/json")
	var rq reflect.Value
	if 2 < m.v.Type().NumIn() {
		in2 := m.v.Type().In(2)
		if reflect.Interface == in2.Kind() && 0 == in2.NumMethod() {
			rq = nilRequest
		} else if reflect.Slice == in2.Kind() || reflect.Map == in2.Kind() {
			// non-pointer maps/slices require special treatment because
			// json.Unmarshal won't work on a non-pointer destination. We
			// add a level indirection here, then deref it before .Call()
			rq = reflect.New(in2)
		} else {
			rq = reflect.New(in2.Elem())
		}
	} else {
		rq = nilRequest
	}
	if "PATCH" == r.Method || "POST" == r.Method || "PUT" == r.Method {
		if rq == nilRequest {
			writeJSONError(w, NewSecurerError(
				"empty interface is not suitable for %s request bodies",
				r.Method,
			))
			return
		}
		if !strings.HasPrefix(
			r.Header.Get("Content-Type"),
			"application/json",
		) {
			writeJSONError(w, tigertonic.NewHTTPEquivError(NewSecurerError(
				"Content-Type header is %s, not application/json",
				r.Header.Get("Content-Type"),
			), http.StatusUnsupportedMediaType))
			return
		}
		decoder := reflect.ValueOf(json.NewDecoder(r.Body))
		out := decoder.MethodByName("Decode").Call([]reflect.Value{rq})
		if !out[0].IsNil() {
			writeJSONError(w, tigertonic.NewHTTPEquivError(
				out[0].Interface().(error),
				http.StatusBadRequest,
			))
			return
		}
		r.Body.Close()
	} else if nilRequest != rq {
		log.Printf(
			"%s request body isn't an empty interface; this is weird and is being ignored\n",
			r.Method,
		)
	}
	if reflect.Slice == rq.Elem().Kind() || reflect.Map == rq.Elem().Kind() {
		rq = rq.Elem()
	}

	contextValue := reflect.ValueOf(tigertonic.Context(r))

	var permissionReq reflect.Value
	if rq == nilRequest {
		in := m.v.Type().In(1)
		permissionReq = reflect.New(in.Elem())
	} else {
		permissionReq = rq
	}

	secureRes := m.securer.Call([]reflect.Value{
		reflect.ValueOf(m.permissionName),
		permissionReq,
		contextValue,
	})

	if !secureRes[0].IsNil() {
		err := secureRes[0].Interface().(error)
		writeJSONError(w, tigertonic.NewHTTPEquivError(err, 403 /*forbidden*/))
		return
	}

	var out []reflect.Value
	switch m.v.Type().NumIn() {
	case 2:
		out = m.v.Call([]reflect.Value{
			reflect.ValueOf(r.URL),
			reflect.ValueOf(r.Header),
		})
	case 3:
		out = m.v.Call([]reflect.Value{
			reflect.ValueOf(r.URL),
			reflect.ValueOf(r.Header),
			rq,
		})
	case 4:
		out = m.v.Call([]reflect.Value{
			reflect.ValueOf(r.URL),
			reflect.ValueOf(r.Header),
			rq,
			contextValue,
		})
	default:
		panic(m.v.Type())
	}
	code := int(out[0].Int())
	header := out[1].Interface().(http.Header)
	rs := out[2].Interface()
	if !out[3].IsNil() {
		err := out[3].Interface().(error)
		if _, ok := err.(tigertonic.HTTPEquivError); ok {
			writeJSONError(w, err)
		} else {
			writeJSONError(w, tigertonic.NewHTTPEquivError(err, code))
		}
		return
	}
	if nil != header {
		for key, values := range header {
			wHeader.Del(key)
			for _, value := range values {
				wHeader.Add(key, value)
			}
		}
	}
	w.WriteHeader(code)
	if nil != rs && http.StatusNoContent != code && (out[2].Kind() != reflect.Ptr || !out[2].IsNil()) {
		if err := json.NewEncoder(w).Encode(rs); nil != err {
			log.Println(err)
		}
	}
}

// Below this line is from tigertonic package, Error name is changed

// SecurerError is the response body for some 500 responses and panics
// when a handler function is not suitable.
type SecurerError string

func NewSecurerError(format string, args ...interface{}) SecurerError {
	return SecurerError(fmt.Sprintf(format, args...))
}

func (e SecurerError) Error() string { return string(e) }

var nilRequest = reflect.ValueOf((*interface{})(nil))

func errorStatusCode(err error) int {
	if httpEquivError, ok := err.(tigertonic.HTTPEquivError); ok {
		return httpEquivError.StatusCode()
	}
	return http.StatusInternalServerError
}

func writeJSONError(w http.ResponseWriter, err error) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(errorStatusCode(err))
	if jsonErr := json.NewEncoder(w).Encode(map[string]string{
		"description": err.Error(),
		"error":       errorName(err, "error"),
	}); nil != jsonErr {
		log.Printf("Error marshalling error response into JSON output: %s", jsonErr)
	}
}

func acceptJSON(r *http.Request) bool {
	accept := r.Header.Get("Accept")
	if "" == accept {
		return true
	}
	return strings.Contains(accept, "*/*") || strings.Contains(accept, "application/json")
}

func errorName(err error, fallback string) string {
	if namedError, ok := err.(tigertonic.NamedError); ok {
		if name := namedError.Name(); "" != name {
			return name
		}
	}
	if httpEquivError, ok := err.(tigertonic.HTTPEquivError); ok && tigertonic.SnakeCaseHTTPEquivErrors {
		return strings.Replace(
			strings.ToLower(http.StatusText(httpEquivError.StatusCode())),
			" ",
			"_",
			-1,
		)
	}
	t := reflect.TypeOf(err)
	if reflect.Ptr == t.Kind() {
		t = t.Elem()
	}
	if r, _ := utf8.DecodeRuneInString(t.Name()); unicode.IsLower(r) {
		return fallback
	}
	return t.String()
}
<|endoftext|>


<commit_before>package CoreModule

import (
	"fmt"
	"github.com/bwmarrin/discordgo"
	"github.com/gendonl/genbot/Bot"
	"time"
)

func initPingCommand() (cc CoreCommand) {
	cc = CoreCommand{
		name:        "ping",
		description: "Returns pong.",
		usage:       "`%sping`",
		aliases:	 []string{},
		permission:  discordgo.PermissionSendMessages,
		execute:     (*CoreModule).pingCommand,
	}
	return
}

func (c *CoreModule) pingCommand(cmd CoreCommand, s *discordgo.Session, m *discordgo.MessageCreate, data *Bot.ServerData) {

	ping := s.HeartbeatLatency() / time.Millisecond

	response := Bot.NewEmbed().
		SetAuthorFromUser(m.Author).
		SetColorFromUser(s, m.ChannelID, m.Author).
		SetDescription(fmt.Sprintf("❤ %dms", ping))

	_, err := s.ChannelMessageSendEmbed(m.ChannelID, response.MessageEmbed)

	if err != nil {
		c.Bot.Log.Error(err)
		return
	}
}<commit_msg>Add bot-latency to ping command<commit_after>package CoreModule

import (
	"fmt"
	"github.com/bwmarrin/discordgo"
	"github.com/gendonl/genbot/Bot"
	"time"
)

func initPingCommand() (cc CoreCommand) {
	cc = CoreCommand{
		name:        "ping",
		description: "Returns pong.",
		usage:       "`%sping`",
		aliases:	 []string{},
		permission:  discordgo.PermissionSendMessages,
		execute:     (*CoreModule).pingCommand,
	}
	return
}

func (c *CoreModule) pingCommand(cmd CoreCommand, s *discordgo.Session, m *discordgo.MessageCreate, data *Bot.ServerData) {

	ping := s.HeartbeatLatency() / time.Millisecond

	response := Bot.NewEmbed().
		SetColorFromUser(s, m.ChannelID, m.Author).
		SetTitle("🏓 Pong").
		SetDescription("Pinging...")

	// Benchmark round-trip time of sent message
	start := time.Now()
	msg, err := s.ChannelMessageSendEmbed(m.ChannelID, response.MessageEmbed)
	elapsed := time.Since(start) / time.Millisecond

	if err != nil {
		c.Bot.Log.Error(err)
		return
	}

	// Add the new data of the round-trip
	response.SetDescription("").
		AddInlineField("Bot", fmt.Sprintf("%dms", elapsed), true).
		AddInlineField("API", fmt.Sprintf("%dms", ping), true)

	_, err = s.ChannelMessageEditEmbed(msg.ChannelID, msg.ID, response.MessageEmbed)
	if err != nil {
		c.Bot.Log.Error(err)
		return
	}
}<|endoftext|>


<commit_before>package isolated

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"

	"code.cloudfoundry.org/cli/integration/helpers"
)

var _ = Describe("set-org-role command", func() {
	When("the org and user both exist", func() {
		var (
			username string
			orgName  string
		)

		BeforeEach(func() {
			helpers.LoginCF()
			orgName = helpers.NewOrgName()
			helpers.CreateOrg(orgName)
			username, _ = helpers.CreateUser()
		})

		It("sets the org role for the user", func() {
			session := helpers.CF("set-org-role", username, orgName, "OrgAuditor")
			Eventually(session).Should(Say("Assigning role OrgAuditor to user %s in org %s as admin...", username, orgName))
			Eventually(session).Should(Say("OK"))
			Eventually(session).Should(Exit(0))
		})

		When("the logged in user has insufficient permissions", func() {
			BeforeEach(func() {
				helpers.SwitchToOrgRole(orgName, "OrgAuditor")
			})

			It("prints out the error message from CC API and exits 1", func() {
				session := helpers.CF("set-org-role", username, orgName, "OrgAuditor")
				Eventually(session).Should(Say("FAILED"))
				Eventually(session).Should(Say("Server error, status code: 403, error code: 10003, message: You are not authorized to perform the requested action"))
				Eventually(session).Should(Exit(1))
			})
		})

		When("the user already has the desired role", func() {
			BeforeEach(func() {
				session := helpers.CF("set-org-role", username, orgName, "OrgManager")
				Eventually(session).Should(Say("Assigning role OrgManager to user %s in org %s as admin...", username, orgName))
				Eventually(session).Should(Exit(0))
			})

			It("is idempotent", func() {
				session := helpers.CF("set-org-role", username, orgName, "OrgManager")
				Eventually(session).Should(Say("Assigning role OrgManager to user %s in org %s as admin...", username, orgName))
				Eventually(session).Should(Exit(0))
			})
		})
	})
})
<commit_msg>Test behavior of set-org-role when user isn't found<commit_after>package isolated

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"

	"code.cloudfoundry.org/cli/integration/helpers"
)

var _ = Describe("set-org-role command", func() {
	var orgName string

	BeforeEach(func() {
		helpers.LoginCF()
		orgName = helpers.NewOrgName()
		helpers.CreateOrg(orgName)
	})

	When("the org and user both exist", func() {
		var username string

		BeforeEach(func() {
			username, _ = helpers.CreateUser()
		})

		It("sets the org role for the user", func() {
			session := helpers.CF("set-org-role", username, orgName, "OrgAuditor")
			Eventually(session).Should(Say("Assigning role OrgAuditor to user %s in org %s as admin...", username, orgName))
			Eventually(session).Should(Say("OK"))
			Eventually(session).Should(Exit(0))
		})

		When("the logged in user has insufficient permissions", func() {
			BeforeEach(func() {
				helpers.SwitchToOrgRole(orgName, "OrgAuditor")
			})

			It("prints out the error message from CC API and exits 1", func() {
				session := helpers.CF("set-org-role", username, orgName, "OrgAuditor")
				Eventually(session).Should(Say("FAILED"))
				Eventually(session).Should(Say("Server error, status code: 403, error code: 10003, message: You are not authorized to perform the requested action"))
				Eventually(session).Should(Exit(1))
			})
		})

		When("the user already has the desired role", func() {
			BeforeEach(func() {
				session := helpers.CF("set-org-role", username, orgName, "OrgManager")
				Eventually(session).Should(Say("Assigning role OrgManager to user %s in org %s as admin...", username, orgName))
				Eventually(session).Should(Exit(0))
			})

			It("is idempotent", func() {
				session := helpers.CF("set-org-role", username, orgName, "OrgManager")
				Eventually(session).Should(Say("Assigning role OrgManager to user %s in org %s as admin...", username, orgName))
				Eventually(session).Should(Exit(0))
			})
		})
	})

	When("the user does not exist", func() {
		It("prints an appropriate error and exits 1", func() {
			session := helpers.CF("set-org-role", "not-exists", orgName, "OrgAuditor")
			Eventually(session).Should(Say("Assigning role OrgAuditor to user not-exists in org %s as admin...", orgName))
			Eventually(session).Should(Say("FAILED"))
			Eventually(session).Should(Say("Server error, status code: 404, error code: 20003, message: The user could not be found: not-exists"))
			Eventually(session).Should(Exit(1))
		})
	})
})
<|endoftext|>


<commit_before>package isolated

import (
	"os"
	"regexp"

	. "code.cloudfoundry.org/cli/cf/util/testhelpers/matchers"

	"code.cloudfoundry.org/cli/integration/helpers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
)

var _ = Describe("download-droplet command", func() {
	var (
		helpText func(*Session)
		appName  string
	)

	BeforeEach(func() {
		appName = helpers.NewAppName()

		helpText = func(session *Session) {
			Eventually(session).Should(Say("NAME:"))
			Eventually(session).Should(Say("download-droplet - Download an application droplet"))
			Eventually(session).Should(Say("USAGE:"))
			Eventually(session).Should(Say("cf download-droplet APP_NAME"))
			Eventually(session).Should(Say("SEE ALSO:"))
			Eventually(session).Should(Say("apps, droplets, push, set-droplet"))
		}
	})

	Describe("help", func() {
		When("--help flag is set", func() {
			It("appears in cf help -a", func() {
				session := helpers.CF("help", "-a")
				Eventually(session).Should(Exit(0))
				Expect(session).To(HaveCommandInCategoryWithDescription("download-droplet", "APPS", "Download an application droplet"))
			})

			It("Displays command usage to output", func() {
				session := helpers.CF("download-droplet", "--help")
				helpText(session)
				Eventually(session).Should(Exit(0))
			})
		})
	})

	When("the app name is not provided", func() {
		It("tells the user that the app name is required, prints help text, and exits 1", func() {
			session := helpers.CF("download-droplet")

			Eventually(session.Err).Should(Say("Incorrect Usage: the required argument `APP_NAME` was not provided"))
			helpText(session)
			Eventually(session).Should(Exit(1))
		})
	})

	When("the environment is not setup correctly", func() {
		It("fails with the appropriate errors", func() {
			helpers.CheckEnvironmentTargetedCorrectly(true, true, ReadOnlyOrg, "download-droplet", appName)
		})
	})

	When("the environment is setup correctly", func() {
		var (
			spaceName string
			orgName   string
			userName  string
		)

		BeforeEach(func() {
			spaceName = helpers.NewSpaceName()
			orgName = helpers.NewOrgName()

			helpers.SetupCF(orgName, spaceName)
			userName, _ = helpers.GetCredentials()
		})

		AfterEach(func() {
			helpers.QuickDeleteOrg(orgName)
		})

		When("the app has a current droplet", func() {
			var dropletPath string

			BeforeEach(func() {
				helpers.CreateApp(appName)

				helpers.WithHelloWorldApp(func(appDir string) {
					Eventually(helpers.CustomCF(helpers.CFEnv{WorkingDirectory: appDir}, "push", appName)).Should(Exit(0))
				})
				dropletSession := helpers.CF("droplets", appName)
				Eventually(dropletSession).Should(Exit(0))
				regex := regexp.MustCompile(`(.+)\s+\(current\)`)
				matches := regex.FindStringSubmatch(string(dropletSession.Out.Contents()))
				Expect(matches).To(HaveLen(2))
				dropletGUID := matches[1]

				dir, err := os.Getwd()
				Expect(err).ToNot(HaveOccurred())
				dropletPath = dir + "/droplet_" + dropletGUID + ".tgz"
			})

			AfterEach(func() {
				os.RemoveAll(dropletPath)
			})

			It("downloads the droplet successfully", func() {
				session := helpers.CF("download-droplet", appName)
				Eventually(session).Should(Say(`Downloading current droplet for app %s in org %s / space %s as %s\.\.\.`, appName, orgName, spaceName, userName))
				Eventually(session).Should(helpers.SayPath(`Droplet downloaded successfully at %s`, dropletPath))
				Eventually(session).Should(Say("OK"))

				_, err := os.Stat(dropletPath)
				Expect(err).ToNot(HaveOccurred())
			})
		})

		When("the app does not exist", func() {
			It("displays app not found and exits 1", func() {
				session := helpers.CF("download-droplet", appName)

				Eventually(session).Should(Say(`Downloading current droplet for app %s in org %s / space %s as %s\.\.\.`, appName, orgName, spaceName, userName))
				Eventually(session.Err).Should(Say("App '%s' not found", appName))
				Eventually(session).Should(Say("FAILED"))

				Eventually(session).Should(Exit(1))
			})
		})

		When("the app does not have a current droplet", func() {
			BeforeEach(func() {
				helpers.CreateApp(appName)
			})

			It("displays that there is no current droplet and exits 1", func() {
				session := helpers.CF("download-droplet", appName)

				Eventually(session).Should(Say(`Downloading current droplet for app %s in org %s / space %s as %s\.\.\.`, appName, orgName, spaceName, userName))
				Eventually(session.Err).Should(Say("App '%s' does not have a current droplet.", appName))
				Eventually(session).Should(Say("FAILED"))

				Eventually(session).Should(Exit(1))
			})
		})
	})
})
<commit_msg>Use path.Join in integration test to account for Windows<commit_after>package isolated

import (
	"os"
	"path"
	"regexp"

	. "code.cloudfoundry.org/cli/cf/util/testhelpers/matchers"

	"code.cloudfoundry.org/cli/integration/helpers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
)

var _ = Describe("download-droplet command", func() {
	var (
		helpText func(*Session)
		appName  string
	)

	BeforeEach(func() {
		appName = helpers.NewAppName()

		helpText = func(session *Session) {
			Eventually(session).Should(Say("NAME:"))
			Eventually(session).Should(Say("download-droplet - Download an application droplet"))
			Eventually(session).Should(Say("USAGE:"))
			Eventually(session).Should(Say("cf download-droplet APP_NAME"))
			Eventually(session).Should(Say("SEE ALSO:"))
			Eventually(session).Should(Say("apps, droplets, push, set-droplet"))
		}
	})

	Describe("help", func() {
		When("--help flag is set", func() {
			It("appears in cf help -a", func() {
				session := helpers.CF("help", "-a")
				Eventually(session).Should(Exit(0))
				Expect(session).To(HaveCommandInCategoryWithDescription("download-droplet", "APPS", "Download an application droplet"))
			})

			It("Displays command usage to output", func() {
				session := helpers.CF("download-droplet", "--help")
				helpText(session)
				Eventually(session).Should(Exit(0))
			})
		})
	})

	When("the app name is not provided", func() {
		It("tells the user that the app name is required, prints help text, and exits 1", func() {
			session := helpers.CF("download-droplet")

			Eventually(session.Err).Should(Say("Incorrect Usage: the required argument `APP_NAME` was not provided"))
			helpText(session)
			Eventually(session).Should(Exit(1))
		})
	})

	When("the environment is not setup correctly", func() {
		It("fails with the appropriate errors", func() {
			helpers.CheckEnvironmentTargetedCorrectly(true, true, ReadOnlyOrg, "download-droplet", appName)
		})
	})

	When("the environment is setup correctly", func() {
		var (
			spaceName string
			orgName   string
			userName  string
		)

		BeforeEach(func() {
			spaceName = helpers.NewSpaceName()
			orgName = helpers.NewOrgName()

			helpers.SetupCF(orgName, spaceName)
			userName, _ = helpers.GetCredentials()
		})

		AfterEach(func() {
			helpers.QuickDeleteOrg(orgName)
		})

		When("the app has a current droplet", func() {
			var dropletPath string

			BeforeEach(func() {
				helpers.CreateApp(appName)

				helpers.WithHelloWorldApp(func(appDir string) {
					Eventually(helpers.CustomCF(helpers.CFEnv{WorkingDirectory: appDir}, "push", appName)).Should(Exit(0))
				})
				dropletSession := helpers.CF("droplets", appName)
				Eventually(dropletSession).Should(Exit(0))
				regex := regexp.MustCompile(`(.+)\s+\(current\)`)
				matches := regex.FindStringSubmatch(string(dropletSession.Out.Contents()))
				Expect(matches).To(HaveLen(2))
				dropletGUID := matches[1]

				dir, err := os.Getwd()
				Expect(err).ToNot(HaveOccurred())
				dropletPath = path.Join(dir, "droplet_"+dropletGUID+".tgz")
			})

			AfterEach(func() {
				os.RemoveAll(dropletPath)
			})

			It("downloads the droplet successfully", func() {
				session := helpers.CF("download-droplet", appName)
				Eventually(session).Should(Say(`Downloading current droplet for app %s in org %s / space %s as %s\.\.\.`, appName, orgName, spaceName, userName))
				Eventually(session).Should(helpers.SayPath(`Droplet downloaded successfully at %s`, dropletPath))
				Eventually(session).Should(Say("OK"))

				_, err := os.Stat(dropletPath)
				Expect(err).ToNot(HaveOccurred())
			})
		})

		When("the app does not exist", func() {
			It("displays app not found and exits 1", func() {
				session := helpers.CF("download-droplet", appName)

				Eventually(session).Should(Say(`Downloading current droplet for app %s in org %s / space %s as %s\.\.\.`, appName, orgName, spaceName, userName))
				Eventually(session.Err).Should(Say("App '%s' not found", appName))
				Eventually(session).Should(Say("FAILED"))

				Eventually(session).Should(Exit(1))
			})
		})

		When("the app does not have a current droplet", func() {
			BeforeEach(func() {
				helpers.CreateApp(appName)
			})

			It("displays that there is no current droplet and exits 1", func() {
				session := helpers.CF("download-droplet", appName)

				Eventually(session).Should(Say(`Downloading current droplet for app %s in org %s / space %s as %s\.\.\.`, appName, orgName, spaceName, userName))
				Eventually(session.Err).Should(Say("App '%s' does not have a current droplet.", appName))
				Eventually(session).Should(Say("FAILED"))

				Eventually(session).Should(Exit(1))
			})
		})
	})
})
<|endoftext|>


<commit_before>package isolated

import (
	"regexp"

	"code.cloudfoundry.org/cli/integration/helpers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
)

var _ = Describe("network-policies command", func() {
	Describe("help", func() {
		When("--help flag is set", func() {
			It("Displays command usage to output", func() {
				session := helpers.CF("network-policies", "--help")
				Eventually(session).Should(Say("NAME:"))
				Eventually(session).Should(Say("network-policies - List direct network traffic policies"))
				Eventually(session).Should(Say("USAGE:"))
				Eventually(session).Should(Say(regexp.QuoteMeta("cf network-policies [--source SOURCE_APP]")))
				Eventually(session).Should(Say("OPTIONS:"))
				Eventually(session).Should(Say("   --source      Source app to filter results by"))
				Eventually(session).Should(Say("SEE ALSO:"))
				Eventually(session).Should(Say("   add-network-policy, apps, remove-network-policy"))
				Eventually(session).Should(Exit(0))
			})
		})
	})

	When("the environment is not setup correctly", func() {
		It("fails with the appropriate errors", func() {
			helpers.CheckEnvironmentTargetedCorrectly(true, true, ReadOnlyOrg, "network-policies")
		})
	})

	When("the org and space are properly targeted", func() {
		var (
			orgName   string
			spaceName string
			appName   string
		)

		BeforeEach(func() {
			orgName = helpers.NewOrgName()
			spaceName = helpers.NewSpaceName()
			appName = helpers.PrefixedRandomName("app")

			helpers.SetupCF(orgName, spaceName)

			helpers.WithHelloWorldApp(func(appDir string) {
				Eventually(helpers.CF("push", appName, "-p", appDir, "-b", "staticfile_buildpack", "--no-start")).Should(Exit(0))
			})

			session := helpers.CF("add-network-policy", appName, "--destination-app", appName)
			Eventually(session).Should(Exit(0))
		})

		AfterEach(func() {
			helpers.QuickDeleteOrg(orgName)
		})

		When("policies exists", func() {
			It("lists all the policies", func() {
				session := helpers.CF("network-policies")

				username, _ := helpers.GetCredentials()
				Eventually(session).Should(Say(`Listing network policies in org %s / space %s as %s\.\.\.`, orgName, spaceName, username))
				Consistently(session).ShouldNot(Say("OK"))
				Eventually(session).Should(Say(`source\s+destination\s+protocol\s+ports\s+destination space\s+destination org`))
				Eventually(session).Should(Say(`%s\s+%s\s+tcp\s+8080\s+%s\s+%s`, appName, appName, spaceName, orgName))
				Eventually(session).Should(Exit(0))
			})
		})

		When("policy has a destination in another org and space", func() {
			var (
				destOrg   string
				destSpace string
				destApp   string
			)

			BeforeEach(func() {
				destOrg = helpers.NewOrgName()
				destSpace = helpers.NewSpaceName()
				destApp = helpers.PrefixedRandomName("destapp")

				helpers.SetupCF(destOrg, destSpace)

				helpers.WithHelloWorldApp(func(appDir string) {
					Eventually(helpers.CF("push", destApp, "-p", appDir, "-b", "staticfile_buildpack", "--no-start")).Should(Exit(0))
				})

				helpers.SetupCF(orgName, spaceName)

				session := helpers.CF("add-network-policy", appName, "--destination-app", destApp, "-o", destOrg, "-s", destSpace)
				username, _ := helpers.GetCredentials()
				Eventually(session).Should(Say(`Adding network policy from app %s in org %s / space %s to app %s in org %s / space %s as %s\.\.\.`, appName, orgName, spaceName, destApp, destOrg, destSpace, username))
				Eventually(session).Should(Say("OK"))
				Eventually(session).Should(Exit(0))
			})

			It("lists the policy", func() {
				session := helpers.CF("network-policies")

				username, _ := helpers.GetCredentials()
				Eventually(session).Should(Say(`Listing network policies in org %s / space %s as %s\.\.\.`, orgName, spaceName, username))
				Eventually(session).Should(Say(`source\s+destination\s+protocol\s+ports\s+destination space\s+destination org`))
				Eventually(session).Should(Say(`%s\s+%s\s+tcp\s+8080\s+%s\s+%s`, appName, destApp, destSpace, destOrg))
				Eventually(session).Should(Exit(0))
			})
		})

		When("policies are filtered by a source app", func() {
			var srcAppName string
			BeforeEach(func() {
				srcAppName = helpers.PrefixedRandomName("app")
				helpers.WithHelloWorldApp(func(appDir string) {
					Eventually(helpers.CF("push", srcAppName, "-p", appDir, "-b", "staticfile_buildpack", "--no-start")).Should(Exit(0))
				})

				session := helpers.CF("add-network-policy", srcAppName, "--destination-app", appName)
				Eventually(session).Should(Exit(0))
			})

			It("lists only policies for which the app is a source", func() {
				session := helpers.CF("network-policies", "--source", srcAppName)

				username, _ := helpers.GetCredentials()
				Eventually(session).Should(Say(`Listing network policies of app %s in org %s / space %s as %s\.\.\.`, srcAppName, orgName, spaceName, username))
				Eventually(session).Should(Say(`source\s+destination\s+protocol\s+ports\s+destination space\s+destination org`))
				Eventually(session).ShouldNot(Say(`%s\s+%s\s+tcp\s+8080\s+%s\s+%s`, appName, appName, spaceName, orgName))
				Eventually(session).Should(Say(`%s\s+%s\s+tcp\s+8080\s+%s\s+%s`, srcAppName, appName, spaceName, orgName))
				Eventually(session).Should(Exit(0))
			})

			When("policy has a destination in another space", func() {
				var (
					destOrg   string
					destSpace string
					destApp   string
				)

				BeforeEach(func() {
					destOrg = helpers.NewOrgName()
					destSpace = helpers.NewSpaceName()
					destApp = helpers.PrefixedRandomName("destapp")

					helpers.SetupCF(destOrg, destSpace)

					helpers.WithHelloWorldApp(func(appDir string) {
						Eventually(helpers.CF("push", destApp, "-p", appDir, "-b", "staticfile_buildpack", "--no-start")).Should(Exit(0))
					})

					helpers.SetupCF(orgName, spaceName)

					session := helpers.CF("add-network-policy", appName, "--destination-app", destApp, "-o", destOrg, "-s", destSpace)
					username, _ := helpers.GetCredentials()
					Eventually(session).Should(Say(`Adding network policy from app %s in org %s / space %s to app %s in org %s / space %s as %s\.\.\.`, appName, orgName, spaceName, destApp, destOrg, destSpace, username))
					Eventually(session).Should(Say("OK"))
					Eventually(session).Should(Exit(0))
				})

				It("lists only policies for which the app is a source", func() {
					session := helpers.CF("network-policies", "--source", appName)

					username, _ := helpers.GetCredentials()
					Eventually(session).Should(Say(`Listing network policies of app %s in org %s / space %s as %s\.\.\.`, appName, orgName, spaceName, username))
					Eventually(session).Should(Say(`source\s+destination\s+protocol\s+ports\s+destination space\s+destination org`))
					Eventually(session).Should(Say(`%s\s+%s\s+tcp\s+8080\s+%s\s+%s`, appName, appName, spaceName, orgName))
					Eventually(session).Should(Say(`%s\s+%s\s+tcp\s+8080\s+%s\s+%s`, appName, destApp, destSpace, destOrg))
					Eventually(session).ShouldNot(Say(`%s\s+%s\s+tcp\s+8080\s+%s\s+%s`, srcAppName, appName, spaceName, orgName))
					Eventually(session).Should(Exit(0))
				})
			})
		})

		When("policies are filtered by a non-existent source app", func() {
			It("returns an error", func() {
				session := helpers.CF("network-policies", "--source", "pineapple")

				username, _ := helpers.GetCredentials()
				Eventually(session).Should(Say(`Listing network policies of app pineapple in org %s / space %s as %s\.\.\.`, orgName, spaceName, username))
				Eventually(session.Err).Should(Say("App 'pineapple' not found"))
				Eventually(session).Should(Say("FAILED"))
				Eventually(session).Should(Exit(1))
			})
		})
	})
})
<commit_msg>🐞 V7: Integration uses new `*-network-policy` syntax<commit_after>package isolated

import (
	"regexp"

	"code.cloudfoundry.org/cli/integration/helpers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
)

var _ = Describe("network-policies command", func() {
	Describe("help", func() {
		When("--help flag is set", func() {
			It("Displays command usage to output", func() {
				session := helpers.CF("network-policies", "--help")
				Eventually(session).Should(Say("NAME:"))
				Eventually(session).Should(Say("network-policies - List direct network traffic policies"))
				Eventually(session).Should(Say("USAGE:"))
				Eventually(session).Should(Say(regexp.QuoteMeta("cf network-policies [--source SOURCE_APP]")))
				Eventually(session).Should(Say("OPTIONS:"))
				Eventually(session).Should(Say("   --source      Source app to filter results by"))
				Eventually(session).Should(Say("SEE ALSO:"))
				Eventually(session).Should(Say("   add-network-policy, apps, remove-network-policy"))
				Eventually(session).Should(Exit(0))
			})
		})
	})

	When("the environment is not setup correctly", func() {
		It("fails with the appropriate errors", func() {
			helpers.CheckEnvironmentTargetedCorrectly(true, true, ReadOnlyOrg, "network-policies")
		})
	})

	When("the org and space are properly targeted", func() {
		var (
			orgName   string
			spaceName string
			appName   string
		)

		BeforeEach(func() {
			orgName = helpers.NewOrgName()
			spaceName = helpers.NewSpaceName()
			appName = helpers.PrefixedRandomName("app")

			helpers.SetupCF(orgName, spaceName)

			helpers.WithHelloWorldApp(func(appDir string) {
				Eventually(helpers.CF("push", appName, "-p", appDir, "-b", "staticfile_buildpack", "--no-start")).Should(Exit(0))
			})

			session := helpers.CF("add-network-policy", appName, appName)
			Eventually(session).Should(Exit(0))
		})

		AfterEach(func() {
			helpers.QuickDeleteOrg(orgName)
		})

		When("policies exists", func() {
			It("lists all the policies", func() {
				session := helpers.CF("network-policies")

				username, _ := helpers.GetCredentials()
				Eventually(session).Should(Say(`Listing network policies in org %s / space %s as %s\.\.\.`, orgName, spaceName, username))
				Consistently(session).ShouldNot(Say("OK"))
				Eventually(session).Should(Say(`source\s+destination\s+protocol\s+ports\s+destination space\s+destination org`))
				Eventually(session).Should(Say(`%s\s+%s\s+tcp\s+8080\s+%s\s+%s`, appName, appName, spaceName, orgName))
				Eventually(session).Should(Exit(0))
			})
		})

		When("policy has a destination in another org and space", func() {
			var (
				destOrg   string
				destSpace string
				destApp   string
			)

			BeforeEach(func() {
				destOrg = helpers.NewOrgName()
				destSpace = helpers.NewSpaceName()
				destApp = helpers.PrefixedRandomName("destapp")

				helpers.SetupCF(destOrg, destSpace)

				helpers.WithHelloWorldApp(func(appDir string) {
					Eventually(helpers.CF("push", destApp, "-p", appDir, "-b", "staticfile_buildpack", "--no-start")).Should(Exit(0))
				})

				helpers.SetupCF(orgName, spaceName)

				session := helpers.CF("add-network-policy", appName, destApp, "-o", destOrg, "-s", destSpace)
				username, _ := helpers.GetCredentials()
				Eventually(session).Should(Say(`Adding network policy from app %s in org %s / space %s to app %s in org %s / space %s as %s\.\.\.`, appName, orgName, spaceName, destApp, destOrg, destSpace, username))
				Eventually(session).Should(Say("OK"))
				Eventually(session).Should(Exit(0))
			})

			It("lists the policy", func() {
				session := helpers.CF("network-policies")

				username, _ := helpers.GetCredentials()
				Eventually(session).Should(Say(`Listing network policies in org %s / space %s as %s\.\.\.`, orgName, spaceName, username))
				Eventually(session).Should(Say(`source\s+destination\s+protocol\s+ports\s+destination space\s+destination org`))
				Eventually(session).Should(Say(`%s\s+%s\s+tcp\s+8080\s+%s\s+%s`, appName, destApp, destSpace, destOrg))
				Eventually(session).Should(Exit(0))
			})
		})

		When("policies are filtered by a source app", func() {
			var srcAppName string
			BeforeEach(func() {
				srcAppName = helpers.PrefixedRandomName("app")
				helpers.WithHelloWorldApp(func(appDir string) {
					Eventually(helpers.CF("push", srcAppName, "-p", appDir, "-b", "staticfile_buildpack", "--no-start")).Should(Exit(0))
				})

				session := helpers.CF("add-network-policy", srcAppName, appName)
				Eventually(session).Should(Exit(0))
			})

			It("lists only policies for which the app is a source", func() {
				session := helpers.CF("network-policies", "--source", srcAppName)

				username, _ := helpers.GetCredentials()
				Eventually(session).Should(Say(`Listing network policies of app %s in org %s / space %s as %s\.\.\.`, srcAppName, orgName, spaceName, username))
				Eventually(session).Should(Say(`source\s+destination\s+protocol\s+ports\s+destination space\s+destination org`))
				Eventually(session).ShouldNot(Say(`%s\s+%s\s+tcp\s+8080\s+%s\s+%s`, appName, appName, spaceName, orgName))
				Eventually(session).Should(Say(`%s\s+%s\s+tcp\s+8080\s+%s\s+%s`, srcAppName, appName, spaceName, orgName))
				Eventually(session).Should(Exit(0))
			})

			When("policy has a destination in another space", func() {
				var (
					destOrg   string
					destSpace string
					destApp   string
				)

				BeforeEach(func() {
					destOrg = helpers.NewOrgName()
					destSpace = helpers.NewSpaceName()
					destApp = helpers.PrefixedRandomName("destapp")

					helpers.SetupCF(destOrg, destSpace)

					helpers.WithHelloWorldApp(func(appDir string) {
						Eventually(helpers.CF("push", destApp, "-p", appDir, "-b", "staticfile_buildpack", "--no-start")).Should(Exit(0))
					})

					helpers.SetupCF(orgName, spaceName)

					session := helpers.CF("add-network-policy", appName, destApp, "-o", destOrg, "-s", destSpace)
					username, _ := helpers.GetCredentials()
					Eventually(session).Should(Say(`Adding network policy from app %s in org %s / space %s to app %s in org %s / space %s as %s\.\.\.`, appName, orgName, spaceName, destApp, destOrg, destSpace, username))
					Eventually(session).Should(Say("OK"))
					Eventually(session).Should(Exit(0))
				})

				It("lists only policies for which the app is a source", func() {
					session := helpers.CF("network-policies", "--source", appName)

					username, _ := helpers.GetCredentials()
					Eventually(session).Should(Say(`Listing network policies of app %s in org %s / space %s as %s\.\.\.`, appName, orgName, spaceName, username))
					Eventually(session).Should(Say(`source\s+destination\s+protocol\s+ports\s+destination space\s+destination org`))
					Eventually(session).Should(Say(`%s\s+%s\s+tcp\s+8080\s+%s\s+%s`, appName, appName, spaceName, orgName))
					Eventually(session).Should(Say(`%s\s+%s\s+tcp\s+8080\s+%s\s+%s`, appName, destApp, destSpace, destOrg))
					Eventually(session).ShouldNot(Say(`%s\s+%s\s+tcp\s+8080\s+%s\s+%s`, srcAppName, appName, spaceName, orgName))
					Eventually(session).Should(Exit(0))
				})
			})
		})

		When("policies are filtered by a non-existent source app", func() {
			It("returns an error", func() {
				session := helpers.CF("network-policies", "--source", "pineapple")

				username, _ := helpers.GetCredentials()
				Eventually(session).Should(Say(`Listing network policies of app pineapple in org %s / space %s as %s\.\.\.`, orgName, spaceName, username))
				Eventually(session.Err).Should(Say("App 'pineapple' not found"))
				Eventually(session).Should(Say("FAILED"))
				Eventually(session).Should(Exit(1))
			})
		})
	})
})
<|endoftext|>


<commit_before>package action

import (
	bosherr "github.com/cloudfoundry/bosh-agent/errors"

	bslcstem "github.com/maximilien/bosh-softlayer-cpi/softlayer/stemcell"
)

type CreateStemcell struct {
	stemcellFinder bslcstem.Finder
}

type CreateStemcellCloudProps struct {
	Uuid string `json:"uuid"`
}

func NewCreateStemcell(stemcellFinder bslcstem.Finder) CreateStemcell {
	return CreateStemcell{stemcellFinder: stemcellFinder}
}

func (a CreateStemcell) Run(stemcellCloudProps CreateStemcellCloudProps) (StemcellCID, error) {
	stemcell, found, err := a.stemcellFinder.Find(stemcellCloudProps.Uuid)
	if err != nil {
		return 0, bosherr.WrapError(err, "Finding stemcell with UUID '%s'", stemcellCloudProps.Uuid)
	}

	if !found {
		return 0, bosherr.WrapError(err, "Did not find stemcell with UUID '%s'", stemcellCloudProps.Uuid)
	}

	return StemcellCID(stemcell.ID()), nil
}
<commit_msg>added correct JSON names for SL light stemcells image ID and UUID<commit_after>package action

import (
	bosherr "github.com/cloudfoundry/bosh-agent/errors"

	bslcstem "github.com/maximilien/bosh-softlayer-cpi/softlayer/stemcell"
)

type CreateStemcell struct {
	stemcellFinder bslcstem.Finder
}

type CreateStemcellCloudProps struct {
	Id   string `json:"virtual-disk-image-id"`
	Uuid string `json:"virtual-disk-image-uuid"`
}

func NewCreateStemcell(stemcellFinder bslcstem.Finder) CreateStemcell {
	return CreateStemcell{stemcellFinder: stemcellFinder}
}

func (a CreateStemcell) Run(stemcellCloudProps CreateStemcellCloudProps) (StemcellCID, error) {
	stemcell, found, err := a.stemcellFinder.Find(stemcellCloudProps.Uuid)
	if err != nil {
		return 0, bosherr.WrapError(err, "Finding stemcell with UUID '%s'", stemcellCloudProps.Uuid)
	}

	if !found {
		return 0, bosherr.WrapError(err, "Did not find stemcell with UUID '%s'", stemcellCloudProps.Uuid)
	}

	return StemcellCID(stemcell.ID()), nil
}
<|endoftext|>


<commit_before>package csv

import (
	"bytes"
	"fmt"
	"path/filepath"
	"reflect"
	"runtime"
	"strings"
	"testing"

	"github.com/ginabythebay/ledger-tools/csv/citi"
	"github.com/ginabythebay/ledger-tools/csv/ops"
)

//
// BEGIN HELPERS FROM https://github.com/benbjohnson/testing
//

// assert fails the test if the condition is false.
func assert(tb testing.TB, condition bool, msg string, v ...interface{}) {
	if !condition {
		_, file, line, _ := runtime.Caller(1)
		fmt.Printf("\033[31m%s:%d: "+msg+"\033[39m\n\n", append([]interface{}{filepath.Base(file), line}, v...)...)
		tb.FailNow()
	}
}

// ok fails the test if an err is not nil.
func ok(tb testing.TB, err error) {
	if err != nil {
		_, file, line, _ := runtime.Caller(1)
		fmt.Printf("\033[31m%s:%d: unexpected error: %s\033[39m\n\n", filepath.Base(file), line, err.Error())
		tb.FailNow()
	}
}

// equals fails the test if exp is not equal to act.
func equals(tb testing.TB, exp, act interface{}) {
	if !reflect.DeepEqual(exp, act) {
		_, file, line, _ := runtime.Caller(1)
		fmt.Printf("\033[31m%s:%d:\n\n\texp: %#v\n\n\tgot: %#v\033[39m\n\n", filepath.Base(file), line, exp, act)
		tb.FailNow()
	}
}

//
// END HELPERS FROM https://github.com/benbjohnson/testing
//

var citiInput = strings.TrimSpace(`
"Status","Date","Description","Debit","Credit"
"Cleared","07/27/2016","GITHUB.COM  2IK4B        415-448-6673 CA
","1.01",""
"Cleared","08/09/2016","NORDSTROM #0427          SAN FRANCISCOCA
","","2.02"
"Cleared","08/25/2016","INTEREST CHARGED TO STANDARD PURCH
","3.03",""
`)

const citiExpected = `cleared,date,payee,amount,credit
Cleared,07/27/2016,GITHUB.COM  2IK4B        415-448-6673 CA,$-1.01,
Cleared,08/09/2016,NORDSTROM #0427          SAN FRANCISCOCA,$2.02,
Cleared,08/25/2016,INTEREST CHARGED TO STANDARD PURCH      ,$-3.03,
`

type testCase struct {
	name     string
	mutators []ops.Mutator
	input    string
	expected string
}

func (c testCase) testFunc(t *testing.T) {
	var buf bytes.Buffer
	actLineCnt, err := Process(c.mutators, strings.NewReader(c.input), &buf)
	if err != nil {
		t.Error(err)
	}
	actual := buf.String()
	equals(t, c.expected, actual)
	equals(t, strings.Count(c.expected, "\n"), actLineCnt)
}

var cases = []testCase{
	testCase{"citi", citi.Mutators(), citiInput, citiExpected},
}

func TestProcess(t *testing.T) {
	for _, c := range cases {
		t.Run(c.name, c.testFunc)
	}
}
<commit_msg>use ok func<commit_after>package csv

import (
	"bytes"
	"fmt"
	"path/filepath"
	"reflect"
	"runtime"
	"strings"
	"testing"

	"github.com/ginabythebay/ledger-tools/csv/citi"
	"github.com/ginabythebay/ledger-tools/csv/ops"
)

//
// BEGIN HELPERS FROM https://github.com/benbjohnson/testing
//

// assert fails the test if the condition is false.
func assert(tb testing.TB, condition bool, msg string, v ...interface{}) {
	if !condition {
		_, file, line, _ := runtime.Caller(1)
		fmt.Printf("\033[31m%s:%d: "+msg+"\033[39m\n\n", append([]interface{}{filepath.Base(file), line}, v...)...)
		tb.FailNow()
	}
}

// ok fails the test if an err is not nil.
func ok(tb testing.TB, err error) {
	if err != nil {
		_, file, line, _ := runtime.Caller(1)
		fmt.Printf("\033[31m%s:%d: unexpected error: %s\033[39m\n\n", filepath.Base(file), line, err.Error())
		tb.FailNow()
	}
}

// equals fails the test if exp is not equal to act.
func equals(tb testing.TB, exp, act interface{}) {
	if !reflect.DeepEqual(exp, act) {
		_, file, line, _ := runtime.Caller(1)
		fmt.Printf("\033[31m%s:%d:\n\n\texp: %#v\n\n\tgot: %#v\033[39m\n\n", filepath.Base(file), line, exp, act)
		tb.FailNow()
	}
}

//
// END HELPERS FROM https://github.com/benbjohnson/testing
//

var citiInput = strings.TrimSpace(`
"Status","Date","Description","Debit","Credit"
"Cleared","07/27/2016","GITHUB.COM  2IK4B        415-448-6673 CA
","1.01",""
"Cleared","08/09/2016","NORDSTROM #0427          SAN FRANCISCOCA
","","2.02"
"Cleared","08/25/2016","INTEREST CHARGED TO STANDARD PURCH
","3.03",""
`)

const citiExpected = `cleared,date,payee,amount,credit
Cleared,07/27/2016,GITHUB.COM  2IK4B        415-448-6673 CA,$-1.01,
Cleared,08/09/2016,NORDSTROM #0427          SAN FRANCISCOCA,$2.02,
Cleared,08/25/2016,INTEREST CHARGED TO STANDARD PURCH      ,$-3.03,
`

type testCase struct {
	name     string
	mutators []ops.Mutator
	input    string
	expected string
}

func (c testCase) testFunc(t *testing.T) {
	var buf bytes.Buffer
	actLineCnt, err := Process(c.mutators, strings.NewReader(c.input), &buf)
	ok(t, err)
	actual := buf.String()
	equals(t, c.expected, actual)
	equals(t, strings.Count(c.expected, "\n"), actLineCnt)
}

var cases = []testCase{
	testCase{"citi", citi.Mutators(), citiInput, citiExpected},
}

func TestProcess(t *testing.T) {
	for _, c := range cases {
		t.Run(c.name, c.testFunc)
	}
}
<|endoftext|>


<commit_before>package kite

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/koding/kite/dnode"
	"github.com/koding/kite/protocol"
)

type kontrolFunc func(*Client) error

// kontrolFunc setups and prepares a kontrol instance. It connects to
// kontrol and providers a way to call the given function in that connected
// kontrol environment. This method is called internally whenever a kontrol
// client specific action is taking (getKites, getToken, register). The main
// reason for having this is doing the call and close the connection
// immediately, so there will be no persistent connection.
func (k *Kite) kontrolFunc(fn kontrolFunc) error {
	if k.Config.KontrolURL == "" {
		return errors.New("no kontrol URL given in config")
	}

	client := k.NewClient(k.Config.KontrolURL)

	client.Kite = protocol.Kite{Name: "kontrol"} // for logging purposes
	client.Auth = &Auth{
		Type: "kiteKey",
		Key:  k.Config.KiteKey,
	}

	if err := client.Dial(); err != nil {
		return err
	}
	defer client.Close()

	return fn(client)
}

// RegisterHTTPForever is just lika RegisterHTTP however it first tries to
// register forever until a response from kontrol is received. It's useful to
// use it durint app initializations. After the registiration a reconnect is
// automatically handled inside the RegisterHTTP method.
func (k *Kite) RegisterHTTPForever(kiteURL *url.URL) {
	interval := time.NewTicker(kontrolRetryDuration)
	defer interval.Stop()

	_, err := k.RegisterHTTP(kiteURL)
	if err == nil {
		return
	}

	for _ = range interval.C {
		_, err := k.RegisterHTTP(kiteURL)
		if err == nil {
			return
		}

		k.Log.Error("Cannot register to Kontrol: %s Will retry after %d seconds",
			err, kontrolRetryDuration/time.Second)

	}
}

// RegisterHTTP registers current Kite to Kontrol. After registration other Kites
// can find it via GetKites() or WatchKites() method. It registers again if
// connection to kontrol is lost.
func (k *Kite) RegisterHTTP(kiteURL *url.URL) (*registerResult, error) {
	var response *dnode.Partial

	registerFunc := func(kontrol *Client) error {
		args := protocol.RegisterArgs{
			URL: kiteURL.String(),
		}

		k.Log.Info("Registering to kontrol with URL (via HTTP): %s", kiteURL.String())
		var err error
		response, err = kontrol.TellWithTimeout("registerHTTP", 4*time.Second, args)
		return err
	}

	if err := k.kontrolFunc(registerFunc); err != nil {
		return nil, err
	}

	var rr protocol.RegisterResult
	if err := response.Unmarshal(&rr); err != nil {
		return nil, err
	}

	parsed, err := url.Parse(rr.URL)
	if err != nil {
		k.Log.Error("Cannot parse registered URL: %s", err.Error())
	}

	heartbeat := time.Duration(rr.HeartbeatInterval) * time.Second

	k.Log.Info("Registered (via HTTP) with URL: '%s' and HeartBeat interval: '%s'",
		rr.URL, heartbeat)

	go k.sendHeartbeats(heartbeat, kiteURL)

	return &registerResult{parsed}, nil
}

func (k *Kite) sendHeartbeats(interval time.Duration, kiteURL *url.URL) {
	tick := time.NewTicker(interval)

	var heartbeatURL string
	if strings.HasSuffix(k.Config.KontrolURL, "/kite") {
		heartbeatURL = strings.TrimSuffix(k.Config.KontrolURL, "/kite") + "/heartbeat"
	} else {
		heartbeatURL = k.Config.KontrolURL + "/heartbeat"
	}

	u, err := url.Parse(heartbeatURL)
	if err != nil {
		k.Log.Fatal("HeartbeatURL is malformed: %s", err)
	}

	q := u.Query()
	q.Set("id", k.Id)
	u.RawQuery = q.Encode()

	errRegisterAgain := errors.New("register again")

	heartbeatFunc := func() error {
		k.Log.Info("Sending heartbeat to %s", u.String())

		resp, err := http.Get(u.String())
		if err != nil {
			return err
		}
		defer resp.Body.Close()

		// we are just receving small size strings such as "pong",
		// "registeragain" so it's totally normal to consume the whole response
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return err
		}

		k.Log.Info("Heartbeat response received '%s'", string(body))

		switch string(body) {
		case "pong":
			return nil
		case "registeragain":
			tick.Stop()
			k.RegisterHTTP(kiteURL)
			return errRegisterAgain
		}

		return fmt.Errorf("malformed heartbeat response %v", string(body))
	}

	for _ = range tick.C {
		err := heartbeatFunc()
		if err == errRegisterAgain {
			return // return so we don't run forever
		}

		if err != nil {
			k.Log.Error("couldn't sent hearbeat: %s", err)
		}
	}
}
<commit_msg>heartbeat: fix typos<commit_after>package kite

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/koding/kite/dnode"
	"github.com/koding/kite/protocol"
)

type kontrolFunc func(*Client) error

// kontrolFunc setups and prepares a kontrol instance. It connects to
// kontrol and providers a way to call the given function in that connected
// kontrol environment. This method is called internally whenever a kontrol
// client specific action is taking (getKites, getToken, register). The main
// reason for having this is doing the call and close the connection
// immediately, so there will be no persistent connection.
func (k *Kite) kontrolFunc(fn kontrolFunc) error {
	if k.Config.KontrolURL == "" {
		return errors.New("no kontrol URL given in config")
	}

	client := k.NewClient(k.Config.KontrolURL)

	client.Kite = protocol.Kite{Name: "kontrol"} // for logging purposes
	client.Auth = &Auth{
		Type: "kiteKey",
		Key:  k.Config.KiteKey,
	}

	if err := client.Dial(); err != nil {
		return err
	}
	defer client.Close()

	return fn(client)
}

// RegisterHTTPForever is just like RegisterHTTP however it first tries to
// register forever until a response from kontrol is received. It's useful to
// use it during app initializations. After the registration a reconnect is
// automatically handled inside the RegisterHTTP method.
func (k *Kite) RegisterHTTPForever(kiteURL *url.URL) {
	interval := time.NewTicker(kontrolRetryDuration)
	defer interval.Stop()

	_, err := k.RegisterHTTP(kiteURL)
	if err == nil {
		return
	}

	for _ = range interval.C {
		_, err := k.RegisterHTTP(kiteURL)
		if err == nil {
			return
		}

		k.Log.Error("Cannot register to Kontrol: %s Will retry after %d seconds",
			err, kontrolRetryDuration/time.Second)

	}
}

// RegisterHTTP registers current Kite to Kontrol. After registration other Kites
// can find it via GetKites() or WatchKites() method. It registers again if
// connection to kontrol is lost.
func (k *Kite) RegisterHTTP(kiteURL *url.URL) (*registerResult, error) {
	var response *dnode.Partial

	registerFunc := func(kontrol *Client) error {
		args := protocol.RegisterArgs{
			URL: kiteURL.String(),
		}

		k.Log.Info("Registering to kontrol with URL (via HTTP): %s", kiteURL.String())
		var err error
		response, err = kontrol.TellWithTimeout("registerHTTP", 4*time.Second, args)
		return err
	}

	if err := k.kontrolFunc(registerFunc); err != nil {
		return nil, err
	}

	var rr protocol.RegisterResult
	if err := response.Unmarshal(&rr); err != nil {
		return nil, err
	}

	parsed, err := url.Parse(rr.URL)
	if err != nil {
		k.Log.Error("Cannot parse registered URL: %s", err.Error())
	}

	heartbeat := time.Duration(rr.HeartbeatInterval) * time.Second

	k.Log.Info("Registered (via HTTP) with URL: '%s' and HeartBeat interval: '%s'",
		rr.URL, heartbeat)

	go k.sendHeartbeats(heartbeat, kiteURL)

	return &registerResult{parsed}, nil
}

func (k *Kite) sendHeartbeats(interval time.Duration, kiteURL *url.URL) {
	tick := time.NewTicker(interval)

	var heartbeatURL string
	if strings.HasSuffix(k.Config.KontrolURL, "/kite") {
		heartbeatURL = strings.TrimSuffix(k.Config.KontrolURL, "/kite") + "/heartbeat"
	} else {
		heartbeatURL = k.Config.KontrolURL + "/heartbeat"
	}

	u, err := url.Parse(heartbeatURL)
	if err != nil {
		k.Log.Fatal("HeartbeatURL is malformed: %s", err)
	}

	q := u.Query()
	q.Set("id", k.Id)
	u.RawQuery = q.Encode()

	errRegisterAgain := errors.New("register again")

	heartbeatFunc := func() error {
		k.Log.Info("Sending heartbeat to %s", u.String())

		resp, err := http.Get(u.String())
		if err != nil {
			return err
		}
		defer resp.Body.Close()

		// we are just receving small size strings such as "pong",
		// "registeragain" so it's totally normal to consume the whole response
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return err
		}

		k.Log.Info("Heartbeat response received '%s'", string(body))

		switch string(body) {
		case "pong":
			return nil
		case "registeragain":
			tick.Stop()
			k.RegisterHTTP(kiteURL)
			return errRegisterAgain
		}

		return fmt.Errorf("malformed heartbeat response %v", string(body))
	}

	for _ = range tick.C {
		err := heartbeatFunc()
		if err == errRegisterAgain {
			return // return so we don't run forever
		}

		if err != nil {
			k.Log.Error("couldn't sent hearbeat: %s", err)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright © 2017 Sascha Andres <sascha.andres@outlook.com>
// 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 helper

import (
	"os"
	"os/exec"
	"strings"
	"syscall"

	"github.com/pkg/errors"
)

// Environ is a type alias for environment variables
type Environ []string

// Unset removes an environment key for a new process
func (e *Environ) Unset(key string) {
	for i := range *e {
		if strings.HasPrefix((*e)[i], key+"=") {
			(*e)[i] = (*e)[len(*e)-1]
			*e = (*e)[:len(*e)-1]
			break
		}
	}
}

// StartAndWait calls the command and returns the result
func StartAndWait(command *exec.Cmd) (int, error) {
	if err := command.Start(); err != nil {
		return -1, errors.Wrap(err, "could not start command")
	}
	if err := command.Wait(); err != nil {
		if exitError, ok := err.(*exec.ExitError); ok {
			if status, ok := exitError.Sys().(syscall.WaitStatus); ok {
				if err.(*exec.ExitError).Stderr == nil {
					return 0, nil
				}
				return status.ExitStatus(), errors.Wrap(err, "Error waiting for command")
			}
		} else {
			return -1, errors.Wrap(err, "Error waiting for command")
		}
	}
	return 0, nil
}

// Exists returns whether the given file or directory exists or not
func Exists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return true, err
}

// GetEnvironmentVariables returns environment variables as map
func GetEnvironmentVariables() map[string]string {
	var (
		env = os.Environ()
		m   = make(map[string]string, len(env))
	)

	for _, e := range env {
		keyVal := strings.SplitN(e, "=", 2)
		key, val := keyVal[0], keyVal[1]
		m[key] = val
	}
	return m
}

// GetCommand creates a command structure
func GetCommand(commandName string, env Environ, path string, arguments ...string) (*exec.Cmd, error) {
	command := exec.Command(commandName, arguments...)
	command.Dir = path
	command.Env = env
	command.Stdout = os.Stdout
	command.Stdin = os.Stdin
	command.Stderr = os.Stderr
	return command, nil
}
<commit_msg>Refactored StartAndWait<commit_after>// Copyright © 2017 Sascha Andres <sascha.andres@outlook.com>
// 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 helper

import (
	"os"
	"os/exec"
	"strings"
	"syscall"

	"github.com/pkg/errors"
)

// Environ is a type alias for environment variables
type Environ []string

// Unset removes an environment key for a new process
func (e *Environ) Unset(key string) {
	for i := range *e {
		if strings.HasPrefix((*e)[i], key+"=") {
			(*e)[i] = (*e)[len(*e)-1]
			*e = (*e)[:len(*e)-1]
			break
		}
	}
}

// StartAndWait calls the command and returns the result
func StartAndWait(command *exec.Cmd) (int, error) {
	var err error
	if err = command.Start(); err != nil {
		return -1, errors.Wrap(err, "could not start command")
	}
	err = command.Wait()
	if err == nil {
		return 0, nil
	}
	if exitError, ok := err.(*exec.ExitError); ok {
		if err.(*exec.ExitError).Stderr == nil {
			return 0, nil
		}
		if status, ok := exitError.Sys().(syscall.WaitStatus); ok {
			return status.ExitStatus(), errors.Wrap(err, "Error waiting for command")
		}
	} else {
		return -1, errors.Wrap(err, "Error waiting for command")
	}
	return 0, nil
}

// Exists returns whether the given file or directory exists or not
func Exists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return true, err
}

// GetEnvironmentVariables returns environment variables as map
func GetEnvironmentVariables() map[string]string {
	var (
		env = os.Environ()
		m   = make(map[string]string, len(env))
	)

	for _, e := range env {
		keyVal := strings.SplitN(e, "=", 2)
		key, val := keyVal[0], keyVal[1]
		m[key] = val
	}
	return m
}

// GetCommand creates a command structure
func GetCommand(commandName string, env Environ, path string, arguments ...string) (*exec.Cmd, error) {
	command := exec.Command(commandName, arguments...)
	command.Dir = path
	command.Env = env
	command.Stdout = os.Stdout
	command.Stdin = os.Stdin
	command.Stderr = os.Stderr
	return command, nil
}
<|endoftext|>