<commit_before>package chromedp

import (
	"context"
	"fmt"
	"log"
	"net"
	"os"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"github.com/chromedp/cdproto"
	"github.com/chromedp/cdproto/cdp"
	"github.com/chromedp/cdproto/runtime"
	"github.com/chromedp/cdproto/target"
	easyjson "github.com/mailru/easyjson"
	jlexer "github.com/mailru/easyjson/jlexer"
	jwriter "github.com/mailru/easyjson/jwriter"
)

// Browser is the high-level Chrome DevTools Protocol browser manager, handling
// the browser process runner, WebSocket clients, associated targets, and
// network, page, and DOM events.
type Browser struct {
	// LostConnection is closed when the websocket connection to Chrome is
	// dropped. This can be useful to make sure that Browser's context is
	// cancelled (and the handler stopped) once the connection has failed.
	LostConnection chan struct{}

	dialTimeout time.Duration

	listenersMu sync.Mutex
	listeners   []cancelableListener

	conn Transport

	// next is the next message id.
	next int64

	// newTabQueue is the queue used to create new target handlers, once a new
	// tab is created and attached to. The newly created Target is sent back
	// via newTabResult.
	newTabQueue chan *Target

	// delTabQueue is used to clean up target handlers after the sessions
	// are detached.
	delTabQueue chan target.SessionID

	// cmdQueue is the outgoing command queue.
	cmdQueue chan cmdJob

	// logging funcs
	logf func(string, ...interface{})
	errf func(string, ...interface{})
	dbgf func(string, ...interface{})

	// The optional fields below are helpful for some tests.

	// process can be initialized by the allocators which start a process
	// when allocating a browser.
	process *os.Process

	// userDataDir can be initialized by the allocators which set up user
	// data dirs directly.
	userDataDir string
}

// TODO: move Transport to the same file as its default implementation once we
// settle on one websocket library.

type cmdJob struct {
	// msg is the message being sent.
	msg *cdproto.Message

	// resp is the channel to send the response to; must be non-nil.
	resp chan *cdproto.Message

	// respID is the ID to receive a response in resp for. If zero, msg.ID
	// is used. If non-zero and different than msg.ID, msg.ID's response is
	// discarded.
	respID int64
}

// NewBrowser creates a new browser. Typically, this function wouldn't be called
// directly, as the Allocator interface takes care of it.
func NewBrowser(ctx context.Context, urlstr string, opts ...BrowserOption) (*Browser, error) {
	b := &Browser{
		LostConnection: make(chan struct{}),

		dialTimeout: 10 * time.Second,

		newTabQueue: make(chan *Target),
		delTabQueue: make(chan target.SessionID, 1),

		// Fit some jobs without blocking, to reduce blocking in
		// Execute.
		cmdQueue: make(chan cmdJob, 32),

		logf: log.Printf,
	}
	// apply options
	for _, o := range opts {
		o(b)
	}
	// ensure errf is set
	if b.errf == nil {
		b.errf = func(s string, v ...interface{}) { b.logf("ERROR: "+s, v...) }
	}

	dialCtx := ctx
	if b.dialTimeout > 0 {
		var cancel context.CancelFunc
		dialCtx, cancel = context.WithTimeout(ctx, b.dialTimeout)
		defer cancel()
	}

	var err error
	urlstr = forceIP(urlstr)
	b.conn, err = DialContext(dialCtx, urlstr, WithConnDebugf(b.dbgf))
	if err != nil {
		return nil, fmt.Errorf("could not dial %q: %v", urlstr, err)
	}

	go b.run(ctx)
	return b, nil
}

// forceIP forces the host component in urlstr to be an IP address.
//
// Since Chrome 66+, Chrome DevTools Protocol clients connecting to a browser
// must send the "Host:" header as either an IP address, or "localhost".
func forceIP(urlstr string) string {
	if i := strings.Index(urlstr, "://"); i != -1 {
		scheme := urlstr[:i+3]
		host, port, path := urlstr[len(scheme)+3:], "", ""
		if i := strings.Index(host, "/"); i != -1 {
			host, path = host[:i], host[i:]
		}
		if i := strings.Index(host, ":"); i != -1 {
			host, port = host[:i], host[i:]
		}
		if addr, err := net.ResolveIPAddr("ip", host); err == nil {
			urlstr = scheme + addr.IP.String() + port + path
		}
	}
	return urlstr
}

func (b *Browser) newExecutorForTarget(targetID target.ID, sessionID target.SessionID) *Target {
	if targetID == "" {
		panic("empty target ID")
	}
	if sessionID == "" {
		panic("empty session ID")
	}
	t := &Target{
		browser:   b,
		TargetID:  targetID,
		SessionID: sessionID,

		eventQueue: make(chan *cdproto.Message, 1024),
		waitQueue:  make(chan func() bool, 1024),
		frames:     make(map[cdp.FrameID]*cdp.Frame),

		logf: b.logf,
		errf: b.errf,

		tick: make(chan time.Time, 1),
	}
	// This send should be blocking, to ensure the tab is inserted into the
	// map before any more target events are routed.
	b.newTabQueue <- t
	return t
}

func rawMarshal(v easyjson.Marshaler) easyjson.RawMessage {
	if v == nil {
		return nil
	}
	buf, err := easyjson.Marshal(v)
	if err != nil {
		panic(err)
	}
	return buf
}

func (b *Browser) Execute(ctx context.Context, method string, params easyjson.Marshaler, res easyjson.Unmarshaler) error {
	id := atomic.AddInt64(&b.next, 1)
	ch := make(chan *cdproto.Message, 1)
	b.cmdQueue <- cmdJob{
		msg: &cdproto.Message{
			ID:     id,
			Method: cdproto.MethodType(method),
			Params: rawMarshal(params),
		},
		resp: ch,
	}
	select {
	case <-ctx.Done():
		return ctx.Err()
	case msg := <-ch:
		switch {
		case msg == nil:
			return ErrChannelClosed
		case msg.Error != nil:
			return msg.Error
		case res != nil:
			return easyjson.Unmarshal(msg.Result, res)
		}
	}
	return nil
}

type tabEvent struct {
	sessionID target.SessionID
	msg       *cdproto.Message
}

//go:generate easyjson browser.go

//easyjson:json
type eventReceivedMessageFromTarget struct {
	SessionID target.SessionID `json:"sessionId"`
	Message   decMessageString `json:"message"`
}

type decMessageString struct {
	lexer jlexer.Lexer // to avoid an alloc
	m     cdproto.Message
}

func (m *decMessageString) UnmarshalEasyJSON(l *jlexer.Lexer) {
	if l.IsNull() {
		l.Skip()
	} else {
		l.AddError(unmarshal(&m.lexer, l.UnsafeBytes(), &m.m))
	}
}

//easyjson:json
type sendMessageToTargetParams struct {
	Message   encMessageString `json:"message"`
	SessionID target.SessionID `json:"sessionId,omitempty"`
}

type encMessageString struct {
	Message cdproto.Message
}

func (m encMessageString) MarshalEasyJSON(w *jwriter.Writer) {
	var w2 jwriter.Writer
	m.Message.MarshalEasyJSON(&w2)
	w.RawText(w2.BuildBytes(nil))
}

func (b *Browser) run(ctx context.Context) {
	defer b.conn.Close()

	// tabEventQueue is the queue of incoming target events, to be routed by
	// their session ID.
	tabEventQueue := make(chan tabEvent, 1)

	// resQueue is the incoming command result queue.
	resQueue := make(chan *cdproto.Message, 1)

	// This goroutine continuously reads events from the websocket
	// connection. The separate goroutine is needed since a websocket read
	// is blocking, so it cannot be used in a select statement.
	go func() {
		// Reuse the space for the read message, since in some cases
		// like EventTargetReceivedMessageFromTarget we throw it away.
		lexer := new(jlexer.Lexer)
		readMsg := new(cdproto.Message)
		for {
			*readMsg = cdproto.Message{}
			if err := b.conn.Read(ctx, readMsg); err != nil {
				// If the websocket failed, most likely Chrome
				// was closed or crashed. Signal that so the
				// entire browser handler can be stopped.
				close(b.LostConnection)
				return
			}
			if readMsg.Method == cdproto.EventRuntimeExceptionThrown {
				ev := new(runtime.EventExceptionThrown)
				if err := unmarshal(lexer, readMsg.Params, ev); err != nil {
					b.errf("%s", err)
					continue
				}
				b.errf("%+v\n", ev.ExceptionDetails)
				continue
			}

			var msg *cdproto.Message
			var sessionID target.SessionID
			if readMsg.Method == cdproto.EventTargetReceivedMessageFromTarget {
				ev := new(eventReceivedMessageFromTarget)
				if err := unmarshal(lexer, readMsg.Params, ev); err != nil {
					b.errf("%s", err)
					continue
				}
				sessionID = ev.SessionID
				msg = &ev.Message.m
			} else {
				// We're passing along readMsg to another
				// goroutine, so we must make a copy of it.
				msg = new(cdproto.Message)
				*msg = *readMsg
			}
			switch {
			case msg.Method != "":
				if sessionID == "" {
					ev, err := cdproto.UnmarshalMessage(msg)
					if err != nil {
						b.errf("%s", err)
						continue
					}
					b.listenersMu.Lock()
					b.listeners = runListeners(b.listeners, ev)
					b.listenersMu.Unlock()
					switch ev := ev.(type) {
					case *target.EventDetachedFromTarget:
						b.delTabQueue <- ev.SessionID
					default:
						// TODO: are any other browser
						// events useful?
					}
					continue
				}
				tabEventQueue <- tabEvent{
					sessionID: sessionID,
					msg:       msg,
				}
			case msg.ID != 0:
				// We can't process the response here, as it's
				// another goroutine that maintans respByID.
				resQueue <- msg
			default:
				b.errf("ignoring malformed incoming message (missing id or method): %#v", msg)
			}
		}
	}()

	// This goroutine handles tabs, as well as routing events to each tab
	// via the pages map.
	go func() {
		ticker := time.NewTicker(2 * time.Millisecond)
		defer ticker.Stop()

		// This map is only safe for use within this goroutine, so don't
		// declare it as a Browser field.
		pages := make(map[target.SessionID]*Target, 32)
		for {
			select {
			case <-ctx.Done():
				return
			case t := <-b.newTabQueue:
				if _, ok := pages[t.SessionID]; ok {
					b.errf("executor for %q already exists", t.SessionID)
				}
				pages[t.SessionID] = t

			case event := <-tabEventQueue:
				page, ok := pages[event.sessionID]
				if !ok {
					// Most likely, this is a page we
					// recently closed, but is still sending
					// events. Ignore it.
					continue
				}
				page.eventQueue <- event.msg

			case sessionID := <-b.delTabQueue:
				if _, ok := pages[sessionID]; !ok {
					b.errf("executor for %q doesn't exist", sessionID)
				}
				delete(pages, sessionID)

			case t := <-ticker.C:
				// Roughly once every 2ms, give every target a
				// chance to run periodic work like checking if
				// a wait function is complete.
				//
				// If a target hasn't picked up the previous
				// tick, skip it.
				for _, target := range pages {
					select {
					case target.tick <- t:
					default:
					}
				}

			}
		}
	}()

	respByID := make(map[int64]chan *cdproto.Message)

	// This goroutine handles sending commands to the browser, and sending
	// responses back for each of these commands via respByID.
	for {
		select {
		case <-ctx.Done():
			return
		case res := <-resQueue:
			resp, ok := respByID[res.ID]
			if !ok {
				b.errf("id %d not present in response map", res.ID)
				continue
			}
			if resp != nil {
				// resp could be nil, if we're not interested in
				// this response; for CommandSendMessageToTarget.
				resp <- res
				close(resp)
			}
			delete(respByID, res.ID)

		case q := <-b.cmdQueue:
			if _, ok := respByID[q.msg.ID]; ok {
				b.errf("id %d already present in response map", q.msg.ID)
				continue
			}
			if q.respID > 0 {
				respByID[q.msg.ID] = nil // discard this response
				respByID[q.respID] = q.resp
			} else {
				respByID[q.msg.ID] = q.resp
			}

			if err := b.conn.Write(ctx, q.msg); err != nil {
				b.errf("%s", err)
				continue
			}

		case <-b.LostConnection:
			return // to avoid "write: broken pipe" errors
		}
	}
}

// BrowserOption is a browser option.
type BrowserOption func(*Browser)

// WithBrowserLogf is a browser option to specify a func to receive general logging.
func WithBrowserLogf(f func(string, ...interface{})) BrowserOption {
	return func(b *Browser) { b.logf = f }
}

// WithBrowserErrorf is a browser option to specify a func to receive error logging.
func WithBrowserErrorf(f func(string, ...interface{})) BrowserOption {
	return func(b *Browser) { b.errf = f }
}

// WithBrowserDebugf is a browser option to specify a func to log actual
// websocket messages.
func WithBrowserDebugf(f func(string, ...interface{})) BrowserOption {
	return func(b *Browser) { b.dbgf = f }
}

// WithConsolef is a browser option to specify a func to receive chrome log events.
//
// Note: NOT YET IMPLEMENTED.
func WithConsolef(f func(string, ...interface{})) BrowserOption {
	return func(b *Browser) {}
}

// WithDialTimeout is a browser option to specify the timeout when dialing a
// browser's websocket address. The default is ten seconds; use a zero duration
// to not use a timeout.
func WithDialTimeout(d time.Duration) BrowserOption {
	return func(b *Browser) { b.dialTimeout = d }
}
<commit_msg>remove a goroutine from Browser.run<commit_after>package chromedp

import (
	"context"
	"fmt"
	"log"
	"net"
	"os"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"github.com/chromedp/cdproto"
	"github.com/chromedp/cdproto/cdp"
	"github.com/chromedp/cdproto/runtime"
	"github.com/chromedp/cdproto/target"
	easyjson "github.com/mailru/easyjson"
	jlexer "github.com/mailru/easyjson/jlexer"
	jwriter "github.com/mailru/easyjson/jwriter"
)

// Browser is the high-level Chrome DevTools Protocol browser manager, handling
// the browser process runner, WebSocket clients, associated targets, and
// network, page, and DOM events.
type Browser struct {
	// LostConnection is closed when the websocket connection to Chrome is
	// dropped. This can be useful to make sure that Browser's context is
	// cancelled (and the handler stopped) once the connection has failed.
	LostConnection chan struct{}

	dialTimeout time.Duration

	listenersMu sync.Mutex
	listeners   []cancelableListener

	conn Transport

	// next is the next message id.
	next int64

	// newTabQueue is the queue used to create new target handlers, once a new
	// tab is created and attached to. The newly created Target is sent back
	// via newTabResult.
	newTabQueue chan *Target

	// delTabQueue is used to clean up target handlers after the sessions
	// are detached.
	delTabQueue chan target.SessionID

	// cmdQueue is the outgoing command queue.
	cmdQueue chan cmdJob

	// logging funcs
	logf func(string, ...interface{})
	errf func(string, ...interface{})
	dbgf func(string, ...interface{})

	// The optional fields below are helpful for some tests.

	// process can be initialized by the allocators which start a process
	// when allocating a browser.
	process *os.Process

	// userDataDir can be initialized by the allocators which set up user
	// data dirs directly.
	userDataDir string
}

// TODO: move Transport to the same file as its default implementation once we
// settle on one websocket library.

type cmdJob struct {
	// msg is the message being sent.
	msg *cdproto.Message

	// resp is the channel to send the response to; must be non-nil.
	resp chan *cdproto.Message

	// respID is the ID to receive a response in resp for. If zero, msg.ID
	// is used. If non-zero and different than msg.ID, msg.ID's response is
	// discarded.
	respID int64
}

// NewBrowser creates a new browser. Typically, this function wouldn't be called
// directly, as the Allocator interface takes care of it.
func NewBrowser(ctx context.Context, urlstr string, opts ...BrowserOption) (*Browser, error) {
	b := &Browser{
		LostConnection: make(chan struct{}),

		dialTimeout: 10 * time.Second,

		newTabQueue: make(chan *Target),
		delTabQueue: make(chan target.SessionID, 1),

		// Fit some jobs without blocking, to reduce blocking in
		// Execute.
		cmdQueue: make(chan cmdJob, 32),

		logf: log.Printf,
	}
	// apply options
	for _, o := range opts {
		o(b)
	}
	// ensure errf is set
	if b.errf == nil {
		b.errf = func(s string, v ...interface{}) { b.logf("ERROR: "+s, v...) }
	}

	dialCtx := ctx
	if b.dialTimeout > 0 {
		var cancel context.CancelFunc
		dialCtx, cancel = context.WithTimeout(ctx, b.dialTimeout)
		defer cancel()
	}

	var err error
	urlstr = forceIP(urlstr)
	b.conn, err = DialContext(dialCtx, urlstr, WithConnDebugf(b.dbgf))
	if err != nil {
		return nil, fmt.Errorf("could not dial %q: %v", urlstr, err)
	}

	go b.run(ctx)
	return b, nil
}

// forceIP forces the host component in urlstr to be an IP address.
//
// Since Chrome 66+, Chrome DevTools Protocol clients connecting to a browser
// must send the "Host:" header as either an IP address, or "localhost".
func forceIP(urlstr string) string {
	if i := strings.Index(urlstr, "://"); i != -1 {
		scheme := urlstr[:i+3]
		host, port, path := urlstr[len(scheme)+3:], "", ""
		if i := strings.Index(host, "/"); i != -1 {
			host, path = host[:i], host[i:]
		}
		if i := strings.Index(host, ":"); i != -1 {
			host, port = host[:i], host[i:]
		}
		if addr, err := net.ResolveIPAddr("ip", host); err == nil {
			urlstr = scheme + addr.IP.String() + port + path
		}
	}
	return urlstr
}

func (b *Browser) newExecutorForTarget(targetID target.ID, sessionID target.SessionID) *Target {
	if targetID == "" {
		panic("empty target ID")
	}
	if sessionID == "" {
		panic("empty session ID")
	}
	t := &Target{
		browser:   b,
		TargetID:  targetID,
		SessionID: sessionID,

		eventQueue: make(chan *cdproto.Message, 1024),
		waitQueue:  make(chan func() bool, 1024),
		frames:     make(map[cdp.FrameID]*cdp.Frame),

		logf: b.logf,
		errf: b.errf,

		tick: make(chan time.Time, 1),
	}
	// This send should be blocking, to ensure the tab is inserted into the
	// map before any more target events are routed.
	b.newTabQueue <- t
	return t
}

func rawMarshal(v easyjson.Marshaler) easyjson.RawMessage {
	if v == nil {
		return nil
	}
	buf, err := easyjson.Marshal(v)
	if err != nil {
		panic(err)
	}
	return buf
}

func (b *Browser) Execute(ctx context.Context, method string, params easyjson.Marshaler, res easyjson.Unmarshaler) error {
	id := atomic.AddInt64(&b.next, 1)
	ch := make(chan *cdproto.Message, 1)
	b.cmdQueue <- cmdJob{
		msg: &cdproto.Message{
			ID:     id,
			Method: cdproto.MethodType(method),
			Params: rawMarshal(params),
		},
		resp: ch,
	}
	select {
	case <-ctx.Done():
		return ctx.Err()
	case msg := <-ch:
		switch {
		case msg == nil:
			return ErrChannelClosed
		case msg.Error != nil:
			return msg.Error
		case res != nil:
			return easyjson.Unmarshal(msg.Result, res)
		}
	}
	return nil
}

type tabEvent struct {
	sessionID target.SessionID
	msg       *cdproto.Message
}

//go:generate easyjson browser.go

//easyjson:json
type eventReceivedMessageFromTarget struct {
	SessionID target.SessionID `json:"sessionId"`
	Message   decMessageString `json:"message"`
}

type decMessageString struct {
	lexer jlexer.Lexer // to avoid an alloc
	m     cdproto.Message
}

func (m *decMessageString) UnmarshalEasyJSON(l *jlexer.Lexer) {
	if l.IsNull() {
		l.Skip()
	} else {
		l.AddError(unmarshal(&m.lexer, l.UnsafeBytes(), &m.m))
	}
}

//easyjson:json
type sendMessageToTargetParams struct {
	Message   encMessageString `json:"message"`
	SessionID target.SessionID `json:"sessionId,omitempty"`
}

type encMessageString struct {
	Message cdproto.Message
}

func (m encMessageString) MarshalEasyJSON(w *jwriter.Writer) {
	var w2 jwriter.Writer
	m.Message.MarshalEasyJSON(&w2)
	w.RawText(w2.BuildBytes(nil))
}

func (b *Browser) run(ctx context.Context) {
	defer b.conn.Close()

	// tabEventQueue is the queue of incoming target events, to be routed by
	// their session ID.
	tabEventQueue := make(chan tabEvent, 1)

	// resQueue is the incoming command result queue.
	resQueue := make(chan *cdproto.Message, 1)

	// This goroutine continuously reads events from the websocket
	// connection. The separate goroutine is needed since a websocket read
	// is blocking, so it cannot be used in a select statement.
	go func() {
		// Reuse the space for the read message, since in some cases
		// like EventTargetReceivedMessageFromTarget we throw it away.
		lexer := new(jlexer.Lexer)
		readMsg := new(cdproto.Message)
		for {
			*readMsg = cdproto.Message{}
			if err := b.conn.Read(ctx, readMsg); err != nil {
				// If the websocket failed, most likely Chrome
				// was closed or crashed. Signal that so the
				// entire browser handler can be stopped.
				close(b.LostConnection)
				return
			}
			if readMsg.Method == cdproto.EventRuntimeExceptionThrown {
				ev := new(runtime.EventExceptionThrown)
				if err := unmarshal(lexer, readMsg.Params, ev); err != nil {
					b.errf("%s", err)
					continue
				}
				b.errf("%+v\n", ev.ExceptionDetails)
				continue
			}

			var msg *cdproto.Message
			var sessionID target.SessionID
			if readMsg.Method == cdproto.EventTargetReceivedMessageFromTarget {
				ev := new(eventReceivedMessageFromTarget)
				if err := unmarshal(lexer, readMsg.Params, ev); err != nil {
					b.errf("%s", err)
					continue
				}
				sessionID = ev.SessionID
				msg = &ev.Message.m
			} else {
				// We're passing along readMsg to another
				// goroutine, so we must make a copy of it.
				msg = new(cdproto.Message)
				*msg = *readMsg
			}
			switch {
			case msg.Method != "":
				if sessionID == "" {
					ev, err := cdproto.UnmarshalMessage(msg)
					if err != nil {
						b.errf("%s", err)
						continue
					}
					b.listenersMu.Lock()
					b.listeners = runListeners(b.listeners, ev)
					b.listenersMu.Unlock()
					switch ev := ev.(type) {
					case *target.EventDetachedFromTarget:
						b.delTabQueue <- ev.SessionID
					default:
						// TODO: are any other browser
						// events useful?
					}
					continue
				}
				tabEventQueue <- tabEvent{
					sessionID: sessionID,
					msg:       msg,
				}
			case msg.ID != 0:
				// We can't process the response here, as it's
				// another goroutine that maintans respByID.
				resQueue <- msg
			default:
				b.errf("ignoring malformed incoming message (missing id or method): %#v", msg)
			}
		}
	}()

	pages := make(map[target.SessionID]*Target, 32)
	respByID := make(map[int64]chan *cdproto.Message)

	ticker := time.NewTicker(2 * time.Millisecond)
	defer ticker.Stop()
	for {
		select {
		case <-ctx.Done():
			return

		case res := <-resQueue:
			resp, ok := respByID[res.ID]
			if !ok {
				b.errf("id %d not present in response map", res.ID)
				continue
			}
			if resp != nil {
				// resp could be nil, if we're not interested in
				// this response; for CommandSendMessageToTarget.
				resp <- res
				close(resp)
			}
			delete(respByID, res.ID)

		case q := <-b.cmdQueue:
			if _, ok := respByID[q.msg.ID]; ok {
				b.errf("id %d already present in response map", q.msg.ID)
				continue
			}
			if q.respID > 0 {
				respByID[q.msg.ID] = nil // discard this response
				respByID[q.respID] = q.resp
			} else {
				respByID[q.msg.ID] = q.resp
			}

			if err := b.conn.Write(ctx, q.msg); err != nil {
				b.errf("%s", err)
				continue
			}

		case t := <-b.newTabQueue:
			if _, ok := pages[t.SessionID]; ok {
				b.errf("executor for %q already exists", t.SessionID)
			}
			pages[t.SessionID] = t

		case event := <-tabEventQueue:
			page, ok := pages[event.sessionID]
			if !ok {
				// Most likely, this is a page we
				// recently closed, but is still sending
				// events. Ignore it.
				continue
			}
			page.eventQueue <- event.msg

		case sessionID := <-b.delTabQueue:
			if _, ok := pages[sessionID]; !ok {
				b.errf("executor for %q doesn't exist", sessionID)
			}
			delete(pages, sessionID)

		case t := <-ticker.C:
			// Roughly once every 2ms, give every target a
			// chance to run periodic work like checking if
			// a wait function is complete.
			//
			// If a target hasn't picked up the previous
			// tick, skip it.
			for _, target := range pages {
				select {
				case target.tick <- t:
				default:
				}
			}

		case <-b.LostConnection:
			return // to avoid "write: broken pipe" errors
		}
	}
}

// BrowserOption is a browser option.
type BrowserOption func(*Browser)

// WithBrowserLogf is a browser option to specify a func to receive general logging.
func WithBrowserLogf(f func(string, ...interface{})) BrowserOption {
	return func(b *Browser) { b.logf = f }
}

// WithBrowserErrorf is a browser option to specify a func to receive error logging.
func WithBrowserErrorf(f func(string, ...interface{})) BrowserOption {
	return func(b *Browser) { b.errf = f }
}

// WithBrowserDebugf is a browser option to specify a func to log actual
// websocket messages.
func WithBrowserDebugf(f func(string, ...interface{})) BrowserOption {
	return func(b *Browser) { b.dbgf = f }
}

// WithConsolef is a browser option to specify a func to receive chrome log events.
//
// Note: NOT YET IMPLEMENTED.
func WithConsolef(f func(string, ...interface{})) BrowserOption {
	return func(b *Browser) {}
}

// WithDialTimeout is a browser option to specify the timeout when dialing a
// browser's websocket address. The default is ten seconds; use a zero duration
// to not use a timeout.
func WithDialTimeout(d time.Duration) BrowserOption {
	return func(b *Browser) { b.dialTimeout = d }
}
<|endoftext|>


<commit_before>package env

import (
	"os"
	"os/user"
	"testing"
)

//Ensure that when we try to add a variable that already exists
//we set it instead of adding another variable of the same name
func Test_AddEnvVar(t *testing.T) {
	env := InitEnv()
	env.AddEnvVar("home", "two")
	testVartwo := env.GetEnvVar("home")
	if testVartwo != "two" {
		t.Error("Failed to set existing environment variable in AddEnvVar")
	}
}

//Ensure that if we try to set a non-existant variable, we add it instead
func Test_SetEnvVar(t *testing.T) {
	env := InitEnv()
	env.SetEnvVar("asdf", "asdf")
	if env.CheckExists("asdf") != true {
		t.Error("Failed to add new variable when trying to set non-existing variable")
	}
}

//Ensure that we get "" if we try to env.GetEnvVar a variable that doesn't exist
func Test_GetEnvVar(t *testing.T) {
	env := InitEnv()
	nilVar := env.GetEnvVar("fdsa")
	if nilVar != "" {
		t.Error("Failed to return \"\" when variable doesn't exist")
	}
}

//Ensure that we can delete existing variables and get false when we try to delete non
//existant variables
func Test_DeleteEnvVar(t *testing.T) {
	env := InitEnv()
	env.AddEnvVar("test", "test")
	env.DeleteEnvVar("test")

	//Ensure that we can delete existing environment variables
	if env.CheckExists("test") == true {
		t.Error("Failed to delete environment variable")
	}

	//Ensure that we get false when trying to delete non-existant environment variables
	if env.DeleteEnvVar("test") != false {
		t.Error("Expecte false when trying to delete non-existant variable")
	}
}

//Ensure that we get a correct default variable when calling InitEnv()
func Test_InitEnv(t *testing.T) {
	env := InitEnv()

	usr, _ := user.Current()
	pwd, _ := os.Getwd()
	var strTests = map[string]string{
		"prompt": "$ ",
		"pwd":    pwd,
		"home":   usr.HomeDir,
		"editor": os.Getenv("EDITOR"),
		"term":   os.Getenv("TERM"),
		"pager":  os.Getenv("PAGER"),
		"user":   usr.Username,
	}

	//Check that our default environment variables exist
	for input, expect := range strTests {
		got := env.GetEnvVar(input)
		if expect != got {
			t.Error(input, ": Expected:", expect, "Got:", got)
		}
	}

	//Ensure the environment isn't dirty by default
	if env.dirty != false {
		t.Error("env.dirty != false")
	}

	//Ensure we have the right amount of variables
	if env.count != len(strTests) {
		t.Error("Invalid variable count:", env.count)
	}

	env.Print()
}
<commit_msg>Added comment to env_test.go for clarification<commit_after>package env

import (
	"os"
	"os/user"
	"testing"
)

//Ensure that when we try to add a variable that already exists
//we set it instead of adding another variable of the same name
func Test_AddEnvVar(t *testing.T) {
	env := InitEnv()
	env.AddEnvVar("home", "two")
	testVartwo := env.GetEnvVar("home")
	if testVartwo != "two" {
		t.Error("Failed to set existing environment variable in AddEnvVar")
	}
}

//Ensure that if we try to set a non-existant variable, we add it instead
func Test_SetEnvVar(t *testing.T) {
	env := InitEnv()
	env.SetEnvVar("asdf", "asdf")
	if env.CheckExists("asdf") != true {
		t.Error("Failed to add new variable when trying to set non-existing variable")
	}
}

//Ensure that we get "" if we try to env.GetEnvVar a variable that doesn't exist
func Test_GetEnvVar(t *testing.T) {
	env := InitEnv()
	nilVar := env.GetEnvVar("fdsa")
	if nilVar != "" {
		t.Error("Failed to return \"\" when variable doesn't exist")
	}
}

//Ensure that we can delete existing variables and get false when we try to delete non
//existant variables
func Test_DeleteEnvVar(t *testing.T) {
	env := InitEnv()
	env.AddEnvVar("test", "test")
	env.DeleteEnvVar("test")

	//Ensure that we can delete existing environment variables
	if env.CheckExists("test") == true {
		t.Error("Failed to delete environment variable")
	}

	//Ensure that we get false when trying to delete non-existant environment variables
	if env.DeleteEnvVar("test") != false {
		t.Error("Expecte false when trying to delete non-existant variable")
	}
}

//Ensure that we get a correct default variable when calling InitEnv()
func Test_InitEnv(t *testing.T) {
	env := InitEnv()

	usr, _ := user.Current()
	pwd, _ := os.Getwd()

	//These are the default environment variables that come
	//pre loaded and hardcoded. The user can still set them
	//with the 'set-var' builtin command.
	var strTests = map[string]string{
		"prompt": "$ ",
		"pwd":    pwd,
		"home":   usr.HomeDir,
		"editor": os.Getenv("EDITOR"),
		"term":   os.Getenv("TERM"),
		"pager":  os.Getenv("PAGER"),
		"user":   usr.Username,
	}

	//Check that our default environment variables exist
	for input, expect := range strTests {
		got := env.GetEnvVar(input)
		if expect != got {
			t.Error(input, ": Expected:", expect, "Got:", got)
		}
	}

	//Ensure the environment isn't dirty by default
	if env.dirty != false {
		t.Error("env.dirty != false")
	}

	//Ensure we have the right amount of variables
	if env.count != len(strTests) {
		t.Error("Invalid variable count:", env.count)
	}

	env.Print()
}
<|endoftext|>


<commit_before>package goredisbench

import (
	"fmt"
	"github.com/fzzy/radix/redis"
	"log"
	"math/rand"
	"time"
)

type (
	GENFUNC func() string
)

const (
	appendname = "foobar"
)

//Goredisbench creates
type Goredisbench struct {
	// Create client
	client   *redis.Client
	// Commands which contain current test
	commands []string
	//Function to generate data for tests
	genfunc  GENFUNC
	//Errors contains every test
	errors []float64
}

type Options struct {
	//Show average time of running command after avgtimes times
	Avgtimes int
}

//Init creates and returns object of Goredisbench structure
func Init() *Goredisbench {
	grb := new(Goredisbench)
	clinet, err := redis.DialTimeout("tcp", "127.0.0.1:6379", time.Duration(10)*time.Second)
	if err != nil {
		panic(err)
	}
	grb.client = clinet
	return grb
}

//AddCommands is append command(for example hmset) to benchmarking
func (grb *Goredisbench) AddCommands(commands []string) {
	if len(commands) > 0 {
		grb.commands = commands
	} else {
		log.Fatal("Number of commands must be greather then zero")
	}
}

//AddGeneration provides user generation of data for inserting to redis
func (grb *Goredisbench) AddGeneration(fun GENFUNC) {
	grb.genfunc = fun
}

func (grb *Goredisbench) Start(iters []int, opt ...Options) {
	if len(opt) > 0 && opt[0].Avgtimes > 0 {
		grb.runWithAvg(iters, opt[0].Avgtimes)
	} else {
		grb.run(iters)
	}
}

func (grb *Goredisbench) run(iters []int) {
	for _, command := range grb.commands {
		comm := fmt.Sprintf("Command: %s", command)
		fmt.Println(comm)
		globalstatus:= 0.0
		for _, it := range iters {
			comm := fmt.Sprintf("Number of iterations: %d", it)
			fmt.Println(comm)
			result,status := grb.loop(it, command, true)
			fmt.Println("Time to complete: ", result)
			//fmt.Println("Statusff: ", status)
			globalstatus = status
			grb.errors = append(grb.errors, status)
		}
		res := fmt.Sprintf("%f percents of operations is complete", globalstatus*100)
		fmt.Println(res)
		fmt.Println("\n")
	}
}

func (grb* Goredisbench) Status() []float64{
	return grb.errors
}
func (grb *Goredisbench) loop(it int, command string, showitmessage bool) (float64, float64) {
	start := time.Now()
	/*if showitmessage {
		itnumber := fmt.Sprintf("Number of iterations: %d", it)
		fmt.Println(itnumber)
	}*/
	allstatus := 0
	for i := 0; i < it; i++ {
		elem := command
		if grb.genfunc != nil {
			elem = grb.genfunc()
		}
		status := 0
		switch command {
		case "set":
			status = redis_set(grb.client, it, i)
		case "hset":
			status = redis_hset(grb.client, it, i)
		case "hget":
			status = redis_hsets_generic(grb.client, elem, it, i)
		case "hdel":
			status = redis_hsets_generic(grb.client, elem, it, i)
		case "hlen":
			status = redis_hlen(grb.client, it, i)
		case "lpush":
			status = redis_list_generic(grb.client, elem, it, i)
		case "rpush":
			status = redis_list_generic(grb.client, elem, it, i)
		case "zadd":
			status = redis_sset(grb.client, command, it, i)
		case "zrem":
			status = redis_sset_generic(grb.client, command, it, i)
		case "zrank":
			status = redis_sset_generic(grb.client, command, it, i)
		case "zincrby":
			status = redis_sset(grb.client, command, it, i)
		default:
			log.Fatal(fmt.Sprintf("Test for command %s not implemented yet", command))
		}
		if status > 0 {
			allstatus += 1
		}
	}
	end := time.Since(start)
	return end.Seconds(), float64(allstatus/it)
}

func (grb *Goredisbench) runWithAvg(iters []int, avgtimes int) {
	for _, command := range grb.commands {
		comm := fmt.Sprintf("Command: %s", command)
		fmt.Println(comm)
		globalstatus := 0.0
		for _, it := range iters {
			preresult := fmt.Sprintf("Average result after %d times of %d iterations", avgtimes, it)
			fmt.Println(preresult)
			avgvalue := 0.0
			for i := 0; i < avgtimes; i++ {
				result, status := grb.loop(it, command, false)
				globalstatus = status
				avgvalue += result
			}
			fmt.Println("Average time to complete: ", avgvalue/float64(avgtimes))
		}
		res := fmt.Sprintf("%f percents of operations is complete", globalstatus*100)
		fmt.Println(res)
		fmt.Println("\n")

	}
}

//Commands area

func redis_set(client *redis.Client, num1, num2 int) int {
	item := fmt.Sprintf("%s%d%d", appendname, num1, num2)
	result, _ := client.Cmd("set", item, "fun").Int()
	return result
}

/* Hashes */

func redis_hset(client *redis.Client, num1, num2 int) int {
	hashname := fmt.Sprintf("%s%d%d", appendname, num1, num2)
	field := fmt.Sprintf("%s%s%d%d", appendname, appendname, num1, num2)
	item := fmt.Sprintf("%d%s", num1*num2, appendname)
	result, _ := client.Cmd("hset", hashname, field, item).Int()
	return result
}

func redis_hlen(client *redis.Client, num1, num2 int) int {
	hashname := fmt.Sprintf("%s%d%d", appendname, num1, num2)
	result, _ := client.Cmd("hlen", hashname).Int()
	return result
}

func redis_hsets_generic(client *redis.Client, command string, num1, num2 int) int{
	hashname := fmt.Sprintf("%s%d%d", appendname, num1, num2)
	field := fmt.Sprintf("%s%s%d%d", appendname, appendname, num1, num2)
	result , _ := client.Cmd(command, hashname, field).Int()
	return result
}

/* Lists */

func redis_list_generic(client *redis.Client, command string, num1, num2 int) int{
	hashname := fmt.Sprintf("%s", appendname)
	field := fmt.Sprintf("%s%s%d%d", appendname, appendname, num1, num2)
	result, _ := client.Cmd(command, hashname, field).Int()
	return result
}

func redis_list_pop(client *redis.Client) int {
	hashname := fmt.Sprintf("%s", appendname)
	result, _ := client.Cmd("lpop", hashname).Int()
	return result
}

/* Sorted sets*/

//Additional overhead is random generation of rank
func redis_sset(client *redis.Client, command string, num1, num2 int) int{
	setname := fmt.Sprintf("%s%d%d", appendname, num1, num2)
	rand.Seed(time.Now().UnixNano())
	rank := rand.Intn(20)
	result , _:= client.Cmd(command, setname, rank, "fun").Int()
	return result
}

func redis_sset_generic(client *redis.Client, command string, num1, num2 int) int {
	setname := fmt.Sprintf("%s%d%d", appendname, num1, num2)
	result , _:= client.Cmd(command, setname, "fun").Int()
	return result
}

func redis_sset_interstore(client *redis.Client, command string, num1, num2 int) {

}
<commit_msg>Append show errors<commit_after>package goredisbench

import (
	"fmt"
	"github.com/fzzy/radix/redis"
	"log"
	"math/rand"
	"time"
)

type (
	GENFUNC func() string
)

const (
	appendname = "foobar"
)

//Goredisbench creates
type Goredisbench struct {
	// Create client
	client   *redis.Client
	// Commands which contain current test
	commands []string
	//Function to generate data for tests
	genfunc  GENFUNC
	//Errors contains every test
	errors []float64

	showerrormessages bool
}

type Options struct {
	//Show average time of running command after avgtimes times
	Avgtimes int

	//This option allows to show error messages during tests
	Showerrors bool
}

//Init creates and returns object of Goredisbench structure
func Init() *Goredisbench {
	grb := new(Goredisbench)
	clinet, err := redis.DialTimeout("tcp", "127.0.0.1:6379", time.Duration(10)*time.Second)
	if err != nil {
		panic(err)
	}
	grb.client = clinet
	return grb
}

//AddCommands is append command(for example hmset) to benchmarking
func (grb *Goredisbench) AddCommands(commands []string) {
	if len(commands) > 0 {
		grb.commands = commands
	} else {
		log.Fatal("Number of commands must be greather then zero")
	}
}

//AddGeneration provides user generation of data for inserting to redis
func (grb *Goredisbench) AddGeneration(fun GENFUNC) {
	grb.genfunc = fun
}

func (grb *Goredisbench) Start(iters []int, opt ...Options) {
	if len(opt) > 0 && opt[0].Showerrors {
		grb.showerrormessages = opt[0].Showerrors
	}
	if len(opt) > 0 && opt[0].Avgtimes > 0 {
		grb.runWithAvg(iters, opt[0].Avgtimes)
	} else {
		grb.run(iters)
	}
}

func (grb *Goredisbench) run(iters []int) {
	for _, command := range grb.commands {
		comm := fmt.Sprintf("Command: %s", command)
		fmt.Println(comm)
		globalstatus:= 0.0
		for _, it := range iters {
			comm := fmt.Sprintf("Number of iterations: %d", it)
			fmt.Println(comm)
			result,status := grb.loop(it, command, grb.showerrormessages)
			fmt.Println("Time to complete: ", result)
			//fmt.Println("Statusff: ", status)
			globalstatus = status
			grb.errors = append(grb.errors, status)
		}
		res := fmt.Sprintf("%f percents of operations is complete", globalstatus*100)
		fmt.Println(res)
		fmt.Println("\n")
	}
}

func (grb* Goredisbench) Status() []float64{
	return grb.errors
}
func (grb *Goredisbench) loop(it int, command string, showerrormessages bool) (float64, float64) {
	start := time.Now()
	/*if showitmessage {
		itnumber := fmt.Sprintf("Number of iterations: %d", it)
		fmt.Println(itnumber)
	}*/
	allstatus := 0
	for i := 0; i < it; i++ {
		elem := command
		if grb.genfunc != nil {
			elem = grb.genfunc()
		}
		status := 0
		switch command {
		case "set":
			status = redis_set(grb.client, it, i, showerrormessages)
		case "hset":
			status = redis_hset(grb.client, it, i, showerrormessages)
		case "hget":
			status = redis_hsets_generic(grb.client, elem, it, i, showerrormessages)
		case "hdel":
			status = redis_hsets_generic(grb.client, elem, it, i, showerrormessages)
		case "hlen":
			status = redis_hlen(grb.client, it, i, showerrormessages)
		case "lpush":
			status = redis_list_generic(grb.client, elem, it, i, showerrormessages)
		case "rpush":
			status = redis_list_generic(grb.client, elem, it, i, showerrormessages)
		case "zadd":
			status = redis_sset(grb.client, command, it, i, showerrormessages)
		case "zrem":
			status = redis_sset_generic(grb.client, command, it, i, showerrormessages)
		case "zrank":
			status = redis_sset_generic(grb.client, command, it, i, showerrormessages)
		case "zincrby":
			status = redis_sset(grb.client, command, it, i, showerrormessages)
		default:
			log.Fatal(fmt.Sprintf("Test for command %s not implemented yet", command))
		}
		if status > 0 {
			allstatus += 1
		}
	}
	end := time.Since(start)
	return end.Seconds(), float64(allstatus/it)
}

func (grb *Goredisbench) runWithAvg(iters []int, avgtimes int) {
	for _, command := range grb.commands {
		comm := fmt.Sprintf("Command: %s", command)
		fmt.Println(comm)
		globalstatus := 0.0
		for _, it := range iters {
			preresult := fmt.Sprintf("Average result after %d times of %d iterations", avgtimes, it)
			fmt.Println(preresult)
			avgvalue := 0.0
			for i := 0; i < avgtimes; i++ {
				result, status := grb.loop(it, command, false)
				globalstatus = status
				avgvalue += result
			}
			fmt.Println("Average time to complete: ", avgvalue/float64(avgtimes))
		}
		res := fmt.Sprintf("%f percents of operations is complete", globalstatus*100)
		fmt.Println(res)
		fmt.Println("\n")

	}
}

//Commands area

func checker(err error, isshow bool){
	if err != nil && isshow {
		log.Fatal(err)
	}
}

func redis_set(client *redis.Client, num1, num2 int, msg bool) int {
	item := fmt.Sprintf("%s%d%d", appendname, num1, num2)
	result,err := client.Cmd("set", item, "fun").Int()
	checker(err, msg)
	return result
}

/* Hashes */

func redis_hset(client *redis.Client, num1, num2 int, msg bool) int {
	hashname := fmt.Sprintf("%s%d%d", appendname, num1, num2)
	field := fmt.Sprintf("%s%s%d%d", appendname, appendname, num1, num2)
	item := fmt.Sprintf("%d%s", num1*num2, appendname)
	result,err := client.Cmd("hset", hashname, field, item).Int()
	if err != nil && msg{
		fmt.Println(err)
	}
	return result
}

func redis_hlen(client *redis.Client, num1, num2 int, msg bool) int {
	hashname := fmt.Sprintf("%s%d%d", appendname, num1, num2)
	result,_ := client.Cmd("hlen", hashname).Int()
	return result
}

func redis_hsets_generic(client *redis.Client, command string, num1, num2 int, msg bool) int{
	hashname := fmt.Sprintf("%s%d%d", appendname, num1, num2)
	field := fmt.Sprintf("%s%s%d%d", appendname, appendname, num1, num2)
	result ,_ := client.Cmd(command, hashname, field).Int()
	return result
}

/* Lists */

func redis_list_generic(client *redis.Client, command string, num1, num2 int, msg bool) int{
	hashname := fmt.Sprintf("%s", appendname)
	field := fmt.Sprintf("%s%s%d%d", appendname, appendname, num1, num2)
	result,_ := client.Cmd(command, hashname, field).Int()
	return result
}

func redis_list_pop(client *redis.Client, msg bool) int {
	hashname := fmt.Sprintf("%s", appendname)
	result, err := client.Cmd("lpop", hashname).Int()
	checker(err, msg)
	return result
}

/* Sorted sets*/

//Additional overhead is random generation of rank
func redis_sset(client *redis.Client, command string, num1, num2 int, msg bool) int{
	setname := fmt.Sprintf("%s%d%d", appendname, num1, num2)
	rand.Seed(time.Now().UnixNano())
	rank := rand.Intn(20)
	result, err := client.Cmd(command, setname, rank, "fun").Int()
	checker(err, msg)
	return result
}

func redis_sset_generic(client *redis.Client, command string, num1, num2 int, msg bool) int {
	setname := fmt.Sprintf("%s%d%d", appendname, num1, num2)
	result , err:= client.Cmd(command, setname, "fun").Int()
	checker(err, msg)
	return result
}

func redis_sset_interstore(client *redis.Client, command string, num1, num2 int, msg bool) {

}
<|endoftext|>


<commit_before>package gosfdoc

import (
	"bytes"
	"fmt"
	"sort"
	"strings"
	"testing"
)

func TestParseMarkdown(t *testing.T) {
	count := 3

	docs := make([]Document, count, count)
	pres := make([]Preview, count, count)
	blocks := make([]CodeBlock, count, count)

	for i := 1; i <= count; i++ {
		doc := Document{}
		doc.SortTag = i
		doc.Title = fmt.Sprintf("Document_title_%d", i)
		doc.Content = fmt.Sprintf("\ndocument markdown syntax content %d\n", i)
		docs[i-1] = doc

		pre := Preview{}
		//	TODO
		pres[i-1] = pre
	}
}

/**
 *
 */
func TestSortSet(t *testing.T) {
	pres := make([]Preview, 5, 5)

	pres[0] = Preview{SortTag: "4"}
	pres[1] = Preview{SortTag: "2"}
	pres[2] = Preview{SortTag: "5"}
	pres[3] = Preview{SortTag: "3"}
	pres[4] = Preview{SortTag: "1"}

	sort.Sort(SortSet{previews: pres})

	if "1" != pres[0].SortTag {
		t.Fail()
	}
}

/**
 *
 */
func TestParseDocument(t *testing.T) {
	strTest := `
/***1-title1
 *  content_1
 */

/***2-title2
 *  content_2
 */

func test2(){
}

///3-title3
//  content_3
//End

func test2(){
}

`

	documents := ParseDocument(NewFileBuf([]byte(strTest), "", nil, nil))

	if 3 != len(documents) {
		t.Fatalf("3 != len(documents)")
		return
	}

	if documents[0].SortTag != 1 || documents[0].Title != "title1" || -1 == strings.Index(documents[0].Content, "content_1") {
		t.Fatalf("ErrorParse: %v %v \n%v", documents[0].SortTag, documents[0].Title, documents[0].Content)
	}

	if documents[1].SortTag != 2 || documents[1].Title != "title2" || -1 == strings.Index(documents[1].Content, "content_2") {
		t.Fatalf("ErrorParse: %v %v \n%v", documents[1].SortTag, documents[1].Title, documents[1].Content)
	}

	if documents[2].SortTag != 3 || documents[2].Title != "title3" || -1 == strings.Index(documents[2].Content, "content_3") {
		t.Fatalf("ErrorParse: %v %v \n%v", documents[2].SortTag, documents[2].Title, documents[2].Content)
	}

}

/**
 *
 */
func TestREXDocument(t *testing.T) {
	str := `
/***1-title1
 *  content_1
 */

 /***2-
  *  content_2
  */

////3-title3
// content_3
//End

///4-
// content_4
//End

`
	results := REXDocument.FindAllString(str, -1)

	if 4 != len(results) {
		t.Fatal("find result num fatal.")
	}

	str2 := `///1234-title`
	subResult := REXDocIndexTitle.FindStringSubmatch(str2)
	if subResult[2] != "1234-" {
		t.Fatal("substring index fatal.")
	}

}

/**
 *
 */
func TestREXPrivateBlock(t *testing.T) {
	str := `
func test1(){
}
//#private
func test2(){
}
//#private-end
func test3(){
}
//#private
func test4(){
}
//#private-end
func test5(){
}
    `
	strResult := `
func test1(){
}
func test3(){
}
func test5(){
}
    `
	bf := NewFileBuf([]byte(str), "", nil, REXPrivateBlock)

	if bf.String() != strResult {
		t.Fatalf("private block replace failed.")
	}
}

/**
 *
 */
func TestREXParseAboutAndIntro(t *testing.T) {
	strTest := `

func func_name() {

}

//About
//  ## About
//  ------
//
//  gosfdoc document generator
//
//  More references: [https://github.com/slowfei/gosfdoc][0]

//  The MIT license (MIT) - [http://opensource.org/licenses/MIT][1]
temp
//  Copyright (c) 2014 slowfei

//  Email: slowfei#foxmail.com
//
//  [0]:https://github.com/slowfei/gosfdoc
//  [1]:http://opensource.org/licenses/MIT
//  [2]:http://opensource.org/licenses/MIT3
//End

/**About
 *  ## About
 *  ------
 *
 *  gosfdoc document generator
 *
 *  More references: [https://github.com/slowfei/gosfdoc][0]

 *  The MIT license (MIT) - [http://opensource.org/licenses/MIT][1]
temp
 *  Copyright (c) 2014 slowfei

 *  Email: slowfei#foxmail.com
 *
 *  [0]:https://github.com/slowfei/gosfdoc
 *  [1]:http://opensource.org/licenses/MIT
 *  [2]:http://opensource.org/licenses/MIT2
 */

/**Intro
 *  ## Intro
 *  ------
 *
 *  Intro content
 */

 func func_name() {

 }
`

	newBuf := ParseAbout(NewFileBuf([]byte(strTest), "", nil, nil))
	lineNumber := len(bytes.Split(newBuf.Content, []byte("\n")))

	if 15 != lineNumber {
		t.Log(string(newBuf.Content))
		t.Fatal("About: Target Line 14, parse Line error:", lineNumber)
	}

	newBuf2 := ParseIntro(NewFileBuf([]byte(strTest), "", nil, nil))
	lineNumber = len(bytes.Split(newBuf2.Content, []byte("\n")))
	if 5 != lineNumber {
		t.Log(string(newBuf2.Content))
		t.Fatal("Intro: Target Line 5, parse Line error:", lineNumber)
	}

}
<commit_msg>完成TestParseMarkdown的测试<commit_after>package gosfdoc

import (
	"bytes"
	"fmt"
	"sort"
	"strings"
	"testing"
)

func TestParseMarkdown(t *testing.T) {
	count := 3

	relPath := ""
	filesName := []string{"main.go"}
	docs := make([]Document, 0, count)
	pres := make([]Preview, 0, count)
	blocks := make([]CodeBlock, 0, count)

	for i := 1; i <= count; i++ {
		doc := Document{}
		doc.SortTag = i
		doc.Title = fmt.Sprintf("Document_title_%d", i)
		doc.Content = fmt.Sprintf("\ndocument markdown syntax content %d\n", i)
		docs = append(docs, doc)

		pre := Preview{}
		pre.Level = 0
		pre.ShowText = fmt.Sprintf("type TestStruct%d struct", i)
		pre.Anchor = fmt.Sprintf("temp.TestStruct%d", i)
		pre.DescText = "implements: [Test](javascript:;)"
		pres = append(pres, pre)

		pre2 := Preview{}
		pre2.Level = 1
		pre2.ShowText = fmt.Sprintf("func (* TestStruct) Hello%d(str string) string", i)
		pre2.Anchor = fmt.Sprintf("temp.TestStruct.Hello%d", i)
		pres = append(pres, pre2)

		pre3 := Preview{}
		pre3.Level = 1
		pre3.ShowText = fmt.Sprintf("func (* TestStruct) Hello2_%d(str string) string", i)
		pre3.Anchor = fmt.Sprintf("temp.TestStruct.Hello2_%d", i)
		pres = append(pres, pre3)

		block := CodeBlock{}
		block.Title = fmt.Sprintf("type TestStruct%d struct", i)
		block.Anchor = fmt.Sprintf("temp.TestStruct%d", i)
		block.Desc = `
函数介绍描述

@param 'v1' 字符串传递
@param 'v2' 字符串传递
@return
		`
		block.Code = `
type TestStruct struct{
	temp string
}
`
		block.CodeLang = "go"
		block.MenuTitle = "Func Details"
		block.SourceFileName = "main.go"
		block.FileLines = []int{10, 20}
		blocks = append(blocks, block)
	}

	body := ParseMarkdown(docs, pres, blocks, filesName, relPath)
	t.Log(string(body))
}

/**
 *
 */
func TestSortSet(t *testing.T) {
	pres := make([]Preview, 5, 5)

	pres[0] = Preview{SortTag: "4"}
	pres[1] = Preview{SortTag: "2"}
	pres[2] = Preview{SortTag: "5"}
	pres[3] = Preview{SortTag: "3"}
	pres[4] = Preview{SortTag: "1"}

	sort.Sort(SortSet{previews: pres})

	if "1" != pres[0].SortTag {
		t.Fail()
	}
}

/**
 *
 */
func TestParseDocument(t *testing.T) {
	strTest := `
/***1-title1
 *  content_1
 */

/***2-title2
 *  content_2
 */

func test2(){
}

///3-title3
//  content_3
//End

func test2(){
}

`

	documents := ParseDocument(NewFileBuf([]byte(strTest), "", nil, nil))

	if 3 != len(documents) {
		t.Fatalf("3 != len(documents)")
		return
	}

	if documents[0].SortTag != 1 || documents[0].Title != "title1" || -1 == strings.Index(documents[0].Content, "content_1") {
		t.Fatalf("ErrorParse: %v %v \n%v", documents[0].SortTag, documents[0].Title, documents[0].Content)
	}

	if documents[1].SortTag != 2 || documents[1].Title != "title2" || -1 == strings.Index(documents[1].Content, "content_2") {
		t.Fatalf("ErrorParse: %v %v \n%v", documents[1].SortTag, documents[1].Title, documents[1].Content)
	}

	if documents[2].SortTag != 3 || documents[2].Title != "title3" || -1 == strings.Index(documents[2].Content, "content_3") {
		t.Fatalf("ErrorParse: %v %v \n%v", documents[2].SortTag, documents[2].Title, documents[2].Content)
	}

}

/**
 *
 */
func TestREXDocument(t *testing.T) {
	str := `
/***1-title1
 *  content_1
 */

 /***2-
  *  content_2
  */

////3-title3
// content_3
//End

///4-
// content_4
//End

`
	results := REXDocument.FindAllString(str, -1)

	if 4 != len(results) {
		t.Fatal("find result num fatal.")
	}

	str2 := `///1234-title`
	subResult := REXDocIndexTitle.FindStringSubmatch(str2)
	if subResult[2] != "1234-" {
		t.Fatal("substring index fatal.")
	}

}

/**
 *
 */
func TestREXPrivateBlock(t *testing.T) {
	str := `
func test1(){
}
//#private
func test2(){
}
//#private-end
func test3(){
}
//#private
func test4(){
}
//#private-end
func test5(){
}
    `
	strResult := `
func test1(){
}
func test3(){
}
func test5(){
}
    `
	bf := NewFileBuf([]byte(str), "", nil, REXPrivateBlock)

	if bf.String() != strResult {
		t.Fatalf("private block replace failed.")
	}
}

/**
 *
 */
func TestREXParseAboutAndIntro(t *testing.T) {
	strTest := `

func func_name() {

}

//About
//  ## About
//  ------
//
//  gosfdoc document generator
//
//  More references: [https://github.com/slowfei/gosfdoc][0]

//  The MIT license (MIT) - [http://opensource.org/licenses/MIT][1]
temp
//  Copyright (c) 2014 slowfei

//  Email: slowfei#foxmail.com
//
//  [0]:https://github.com/slowfei/gosfdoc
//  [1]:http://opensource.org/licenses/MIT
//  [2]:http://opensource.org/licenses/MIT3
//End

/**About
 *  ## About
 *  ------
 *
 *  gosfdoc document generator
 *
 *  More references: [https://github.com/slowfei/gosfdoc][0]

 *  The MIT license (MIT) - [http://opensource.org/licenses/MIT][1]
temp
 *  Copyright (c) 2014 slowfei

 *  Email: slowfei#foxmail.com
 *
 *  [0]:https://github.com/slowfei/gosfdoc
 *  [1]:http://opensource.org/licenses/MIT
 *  [2]:http://opensource.org/licenses/MIT2
 */

/**Intro
 *  ## Intro
 *  ------
 *
 *  Intro content
 */

 func func_name() {

 }
`

	newBuf := ParseAbout(NewFileBuf([]byte(strTest), "", nil, nil))
	lineNumber := len(bytes.Split(newBuf.Content, []byte("\n")))

	if 15 != lineNumber {
		t.Log(string(newBuf.Content))
		t.Fatal("About: Target Line 14, parse Line error:", lineNumber)
	}

	newBuf2 := ParseIntro(NewFileBuf([]byte(strTest), "", nil, nil))
	lineNumber = len(bytes.Split(newBuf2.Content, []byte("\n")))
	if 5 != lineNumber {
		t.Log(string(newBuf2.Content))
		t.Fatal("Intro: Target Line 5, parse Line error:", lineNumber)
	}

}
<|endoftext|>


<commit_before>package gpg

import (
	"bytes"
	"io"
	"io/ioutil"
	"testing"

	"github.com/TNG/gpg-validation-server/test/utils"
	"golang.org/x/crypto/openpgp"
	"golang.org/x/crypto/openpgp/errors"
)

func newGPGtest(t *testing.T, path string) {
	t.Log("Testing NewGPG for", path)

	file, cleanup := utils.Open(t, path)
	defer cleanup()

	gpg, err := NewGPG(file, passphrase)
	if err != nil {
		t.Fatal("Failed to create GPG object for", path, ":", err)
	}

	if gpg.serverEntity == nil {
		t.Error("Failed to initialize serverEntity for path:", path)
	}

	if _, ok := gpg.serverEntity.Identities[expectedIdentity]; !ok {
		t.Error("Could not find identity in serverEntity")
	}
}

func TestNewGPG(t *testing.T) {
	for _, path := range [2]string{asciiKeyFileSecret, binaryKeyFileSecret} {
		newGPGtest(t, path)
	}

	file, cleanup := utils.Open(t, asciiKeyFileSecret)
	defer cleanup()
	_, err := NewGPG(file, "invalidpassphrase")
	if _, ok := err.(errors.StructuralError); !ok {
		t.Error("GPG object created with wrong passphrase")
	}

	file, cleanup = utils.Open(t, asciiKeyFilePublic)
	defer cleanup()
	_, err = NewGPG(file, passphrase)
	if err != ErrNoPrivateKey {
		t.Error("Unexpected error for GPG object creation without private key:", err)
	}

	invalidKeyFile := new(bytes.Buffer)
	_, err = NewGPG(invalidKeyFile, "")
	if err != io.EOF {
		t.Error("Unexpected error for GPG object creation from empty file:", err)
	}
}

func setupGPG(t *testing.T) *GPG {
	file, cleanup := utils.Open(t, asciiKeyFileSecret)
	defer cleanup()

	gpg, err := NewGPG(file, passphrase)
	if err != nil {
		t.Fatal("Failed to create GPG object for", asciiKeyFileSecret, ":", err)
	}
	return gpg
}

func TestGPGSignUserIDWithCorrectEmail(t *testing.T) {
	gpg := setupGPG(t)

	clientPublicKeyFile, cleanup := utils.Open(t, asciiKeyFileClient)
	defer cleanup()

	buffer := new(bytes.Buffer)
	err := gpg.SignUserID("test-gpg-validation@client.local", clientPublicKeyFile, buffer)
	if err != nil {
		t.Fatal("Failed to sign user id:", err)
	}

	signedClientEntity, _ := readEntity(buffer, true)
	verifySignatureTest(t, expectedClientIdentity, signedClientEntity)
}

func TestGPGSignUserIDWithIncorrectEmail(t *testing.T) {
	gpg := setupGPG(t)

	clientPublicKeyFile, cleanup := utils.Open(t, asciiKeyFileClient)
	defer cleanup()

	buffer := new(bytes.Buffer)
	err := gpg.SignUserID("impostor@faux.fake", clientPublicKeyFile, buffer)
	if err != ErrUnknownIdentity {
		t.Fatal("Unexpected error for signing user id with fake email:", err)
	}
}

func TestGPGSignUserIDWithInvalidKeyFile(t *testing.T) {
	gpg := setupGPG(t)

	buffer := new(bytes.Buffer)
	invalidKeyFile := new(bytes.Buffer)

	err := gpg.SignUserID("test-gpg-validation@client.local", invalidKeyFile, buffer)
	if err != io.EOF {
		t.Fatal("Unexpected error for signing invalid key file:", err)
	}
}

func TestGPGSignMessage(t *testing.T) {
	gpg := setupGPG(t)
	messageBytes := []byte("Hello World!")

	message := bytes.NewReader(messageBytes)
	signature := new(bytes.Buffer)
	err := gpg.SignMessage(message, signature)
	if err != nil {
		t.Fatal("Signing message failed:", err)
	}

	keyFile, cleanup := utils.Open(t, binaryKeyFilePublic)
	defer cleanup()

	keyRing, err := openpgp.ReadKeyRing(keyFile)
	if err != nil {
		t.Fatal("Failed to read key ring:", err)
	}

	signer, err := openpgp.CheckArmoredDetachedSignature(keyRing, bytes.NewReader(messageBytes), signature)
	if err != nil {
		t.Error("Failed to verify signature:", err)
	}

	_, ok := signer.Identities[expectedIdentity]
	if !ok {
		t.Error("Signature not signed by", expectedIdentity)
	}
}

func checkMessageSignatureTest(t *testing.T, gpg *GPG, message, signature []byte, checkedSignerKeyFilePath string, expectedError error) {
	signerKeyFile, cleanup := utils.Open(t, checkedSignerKeyFilePath)
	defer cleanup()

	messageReader := bytes.NewReader(message)
	signatureReader := bytes.NewReader(signature)
	err := gpg.CheckMessageSignature(messageReader, signatureReader, signerKeyFile)
	if err != expectedError {
		t.Error("Failed to correctly verify signature against key:", checkedSignerKeyFilePath)
		t.Error("Expected error:", expectedError)
		t.Error("Got error:", err)
	}
}

func TestGPGCheckMessageSignature(t *testing.T) {
	gpg := setupGPG(t)
	messageBytes := []byte("Hello World!")

	message := bytes.NewReader(messageBytes)
	signatureBuffer := new(bytes.Buffer)
	err := gpg.SignMessage(message, signatureBuffer)
	if err != nil {
		t.Fatal("Signing message failed:", err)
	}
	signatureBytes := signatureBuffer.Bytes()
	t.Log("Signature:", string(signatureBytes))

	checkMessageSignatureTest(t, gpg, messageBytes, signatureBytes, asciiKeyFilePublic, nil)
	checkMessageSignatureTest(t, gpg, messageBytes, signatureBytes, binaryKeyFilePublic, nil)

	// *KeyFileSecret contains both public and private key, so they can also be used to check the signature
	checkMessageSignatureTest(t, gpg, messageBytes, signatureBytes, asciiKeyFileSecret, nil)
	checkMessageSignatureTest(t, gpg, messageBytes, signatureBytes, binaryKeyFileSecret, nil)

	checkMessageSignatureTest(t, gpg, messageBytes, signatureBytes, asciiKeyFileClient, ErrUnknownIssuer)
	checkMessageSignatureTest(t, gpg, messageBytes, signatureBytes, binaryKeyFileClient, ErrUnknownIssuer)
	checkMessageSignatureTest(t, gpg, messageBytes, signatureBytes, asciiKeyFileOther, ErrUnknownIssuer)
}

func TestGPGEncryptMessage(t *testing.T) {
	gpg := setupGPG(t)
	messageBytes := []byte("Hello World!")

	message := bytes.NewReader(messageBytes)
	cipherTextBuffer := new(bytes.Buffer)
	recipientKeyFile, cleanup := utils.Open(t, asciiKeyFileClient)
	defer cleanup()

	err := gpg.EncryptMessage(message, cipherTextBuffer, recipientKeyFile)
	if err != nil {
		t.Fatal("Encryption failed:", err)
	}

	clientEntity := readEntityFromFile(asciiKeyFileClientSecret, true)
	serverPublicEntity := readEntityFromFile(asciiKeyFilePublic, true)
	decryptPrivateKeys(clientEntity, []byte(passphrase))
	keyRing := openpgp.EntityList([]*openpgp.Entity{clientEntity, serverPublicEntity})

	md, err := openpgp.ReadMessage(bytes.NewBuffer(cipherTextBuffer.Bytes()), keyRing, nil, nil)
	if err != nil {
		t.Fatal("Decryption failed:", err)
	}
	if !md.IsEncrypted {
		t.Error("Encrypted message has not actually been encrypted")
	}
	if !md.IsSigned {
		t.Error("Encrypted message has not been signed")
	}

	decryptedMessageBytes, err := ioutil.ReadAll(md.UnverifiedBody)
	if err != nil {
		t.Fatal("Reading decrypted text failed:", err)
	}

	if string(decryptedMessageBytes) != string(messageBytes) {
		t.Error("Decrypted text mismatch")
		t.Error("Expected:", string(messageBytes))
		t.Error("Got:", string(decryptedMessageBytes))
	}

	if md.SignatureError != nil {
		t.Error("Validating signature failed:", md.SignatureError)
	}

	if md.SignedByKeyId != gpg.serverEntity.PrimaryKey.KeyId {
		t.Error("Message signed by wrong key")
		t.Error("Expected:", gpg.serverEntity.PrimaryKey.KeyId)
		t.Error("Got:", md.SignedByKeyId)
	}

	if md.SignedBy == nil {
		t.Error("Signer key not found")
	}

	if _, ok := md.SignedBy.Entity.Identities[expectedIdentity]; !ok {
		t.Error("Invalid signer key:", md.SignedBy)
	}
}

func TestGPGEncryptMessageWithInvalidRecipient(t *testing.T) {
	gpg := setupGPG(t)
	messageBytes := []byte("Hello World!")

	message := bytes.NewReader(messageBytes)
	cipherTextBuffer := new(bytes.Buffer)
	invalidRecipient := new(bytes.Buffer)

	err := gpg.EncryptMessage(message, cipherTextBuffer, invalidRecipient)
	if err != io.EOF {
		t.Fatal("Unexpected error for encrypting message to empty recipient key file:", err)
	}
}

func makeEncryptedMessage(t *testing.T, messageBytes []byte, signed bool) *bytes.Buffer {
	var senderEntity *openpgp.Entity

	recipientEntity := readEntityFromFile(asciiKeyFilePublic, true)
	if signed {
		senderEntity = readEntityFromFile(asciiKeyFileClientSecret, true)
		decryptPrivateKeys(senderEntity, []byte(passphrase))
	}

	cipherTextBuffer := new(bytes.Buffer)

	w, err := openpgp.Encrypt(cipherTextBuffer, []*openpgp.Entity{recipientEntity}, senderEntity, nil, nil)
	if err != nil {
		t.Fatal(err)
	}
	w.Write(messageBytes)
	err = w.Close()
	if err != nil {
		t.Fatal(err)
	}

	return cipherTextBuffer
}

func TestGPGDecryptSignedMessage(t *testing.T) {
	gpg := setupGPG(t)
	messageBytes := []byte("Hello World!")

	cipherTextBuffer := makeEncryptedMessage(t, messageBytes, true)

	decryptedText := new(bytes.Buffer)
	senderKeyFile, cleanup := utils.Open(t, asciiKeyFileClient)
	defer cleanup()

	err := gpg.DecryptSignedMessage(bytes.NewBuffer(cipherTextBuffer.Bytes()), decryptedText, senderKeyFile)
	if err != nil {
		t.Fatal("Decryption failed:", err)
	}

	if decryptedText.String() != string(messageBytes) {
		t.Error("Decrypted text mismatch")
		t.Error("Expected:", string(messageBytes))
		t.Error("Got:", decryptedText.String())
	}
}

func TestGPGDecryptSignedMessageWithInvalidInput(t *testing.T) {
	gpg := setupGPG(t)
	messageBytes := []byte("Hello World!")

	cipherTextBuffer := makeEncryptedMessage(t, messageBytes, false)
	decryptedText := new(bytes.Buffer)
	senderKeyFile, cleanup := utils.Open(t, asciiKeyFileClient)
	defer cleanup()
	err := gpg.DecryptSignedMessage(bytes.NewBuffer(cipherTextBuffer.Bytes()), decryptedText, senderKeyFile)
	if err != ErrMessageNotSigned {
		t.Error("Unexpected error for decrypting unsigned message:", err)
	}

	cipherTextBuffer = makeEncryptedMessage(t, messageBytes, true)
	decryptedText = new(bytes.Buffer)
	senderKeyFile, cleanup = utils.Open(t, asciiKeyFileOther)
	defer cleanup()
	err = gpg.DecryptSignedMessage(bytes.NewBuffer(cipherTextBuffer.Bytes()), decryptedText, senderKeyFile)
	if err != ErrUnknownIssuer {
		t.Error("Unexpected error for decrypting message from wrong signer:", err)
	}

	senderKeyFile, cleanup = utils.Open(t, asciiKeyFileClient)
	defer cleanup()
	err = gpg.DecryptSignedMessage(new(bytes.Buffer), decryptedText, senderKeyFile)
	if err != io.EOF {
		t.Error("Unexpected error for decrypting empty message:", err)
	}

	err = gpg.DecryptSignedMessage(bytes.NewBuffer(cipherTextBuffer.Bytes()), decryptedText, new(bytes.Buffer))
	if err != io.EOF {
		t.Error("Unexpected error for decrypting message with empty sender key:", err)
	}
}
<commit_msg>Check more error return values<commit_after>package gpg

import (
	"bytes"
	"io"
	"io/ioutil"
	"testing"

	"github.com/TNG/gpg-validation-server/test/utils"
	"golang.org/x/crypto/openpgp"
	"golang.org/x/crypto/openpgp/errors"
)

func newGPGtest(t *testing.T, path string) {
	t.Log("Testing NewGPG for", path)

	file, cleanup := utils.Open(t, path)
	defer cleanup()

	gpg, err := NewGPG(file, passphrase)
	if err != nil {
		t.Fatal("Failed to create GPG object for", path, ":", err)
	}

	if gpg.serverEntity == nil {
		t.Error("Failed to initialize serverEntity for path:", path)
	}

	if _, ok := gpg.serverEntity.Identities[expectedIdentity]; !ok {
		t.Error("Could not find identity in serverEntity")
	}
}

func TestNewGPG(t *testing.T) {
	for _, path := range [2]string{asciiKeyFileSecret, binaryKeyFileSecret} {
		newGPGtest(t, path)
	}

	file, cleanup := utils.Open(t, asciiKeyFileSecret)
	defer cleanup()
	_, err := NewGPG(file, "invalidpassphrase")
	if _, ok := err.(errors.StructuralError); !ok {
		t.Error("GPG object created with wrong passphrase")
	}

	file, cleanup = utils.Open(t, asciiKeyFilePublic)
	defer cleanup()
	_, err = NewGPG(file, passphrase)
	if err != ErrNoPrivateKey {
		t.Error("Unexpected error for GPG object creation without private key:", err)
	}

	invalidKeyFile := new(bytes.Buffer)
	_, err = NewGPG(invalidKeyFile, "")
	if err != io.EOF {
		t.Error("Unexpected error for GPG object creation from empty file:", err)
	}
}

func setupGPG(t *testing.T) *GPG {
	file, cleanup := utils.Open(t, asciiKeyFileSecret)
	defer cleanup()

	gpg, err := NewGPG(file, passphrase)
	if err != nil {
		t.Fatal("Failed to create GPG object for", asciiKeyFileSecret, ":", err)
	}
	return gpg
}

func TestGPGSignUserIDWithCorrectEmail(t *testing.T) {
	gpg := setupGPG(t)

	clientPublicKeyFile, cleanup := utils.Open(t, asciiKeyFileClient)
	defer cleanup()

	buffer := new(bytes.Buffer)
	err := gpg.SignUserID("test-gpg-validation@client.local", clientPublicKeyFile, buffer)
	if err != nil {
		t.Fatal("Failed to sign user id:", err)
	}

	signedClientEntity, _ := readEntity(buffer, true)
	verifySignatureTest(t, expectedClientIdentity, signedClientEntity)
}

func TestGPGSignUserIDWithIncorrectEmail(t *testing.T) {
	gpg := setupGPG(t)

	clientPublicKeyFile, cleanup := utils.Open(t, asciiKeyFileClient)
	defer cleanup()

	buffer := new(bytes.Buffer)
	err := gpg.SignUserID("impostor@faux.fake", clientPublicKeyFile, buffer)
	if err != ErrUnknownIdentity {
		t.Fatal("Unexpected error for signing user id with fake email:", err)
	}
}

func TestGPGSignUserIDWithInvalidKeyFile(t *testing.T) {
	gpg := setupGPG(t)

	buffer := new(bytes.Buffer)
	invalidKeyFile := new(bytes.Buffer)

	err := gpg.SignUserID("test-gpg-validation@client.local", invalidKeyFile, buffer)
	if err != io.EOF {
		t.Fatal("Unexpected error for signing invalid key file:", err)
	}
}

func TestGPGSignMessage(t *testing.T) {
	gpg := setupGPG(t)
	messageBytes := []byte("Hello World!")

	message := bytes.NewReader(messageBytes)
	signature := new(bytes.Buffer)
	err := gpg.SignMessage(message, signature)
	if err != nil {
		t.Fatal("Signing message failed:", err)
	}

	keyFile, cleanup := utils.Open(t, binaryKeyFilePublic)
	defer cleanup()

	keyRing, err := openpgp.ReadKeyRing(keyFile)
	if err != nil {
		t.Fatal("Failed to read key ring:", err)
	}

	signer, err := openpgp.CheckArmoredDetachedSignature(keyRing, bytes.NewReader(messageBytes), signature)
	if err != nil {
		t.Error("Failed to verify signature:", err)
	}

	_, ok := signer.Identities[expectedIdentity]
	if !ok {
		t.Error("Signature not signed by", expectedIdentity)
	}
}

func checkMessageSignatureTest(t *testing.T, gpg *GPG, message, signature []byte, checkedSignerKeyFilePath string, expectedError error) {
	signerKeyFile, cleanup := utils.Open(t, checkedSignerKeyFilePath)
	defer cleanup()

	messageReader := bytes.NewReader(message)
	signatureReader := bytes.NewReader(signature)
	err := gpg.CheckMessageSignature(messageReader, signatureReader, signerKeyFile)
	if err != expectedError {
		t.Error("Failed to correctly verify signature against key:", checkedSignerKeyFilePath)
		t.Error("Expected error:", expectedError)
		t.Error("Got error:", err)
	}
}

func TestGPGCheckMessageSignature(t *testing.T) {
	gpg := setupGPG(t)
	messageBytes := []byte("Hello World!")

	message := bytes.NewReader(messageBytes)
	signatureBuffer := new(bytes.Buffer)
	err := gpg.SignMessage(message, signatureBuffer)
	if err != nil {
		t.Fatal("Signing message failed:", err)
	}
	signatureBytes := signatureBuffer.Bytes()
	t.Log("Signature:", string(signatureBytes))

	checkMessageSignatureTest(t, gpg, messageBytes, signatureBytes, asciiKeyFilePublic, nil)
	checkMessageSignatureTest(t, gpg, messageBytes, signatureBytes, binaryKeyFilePublic, nil)

	// *KeyFileSecret contains both public and private key, so they can also be used to check the signature
	checkMessageSignatureTest(t, gpg, messageBytes, signatureBytes, asciiKeyFileSecret, nil)
	checkMessageSignatureTest(t, gpg, messageBytes, signatureBytes, binaryKeyFileSecret, nil)

	checkMessageSignatureTest(t, gpg, messageBytes, signatureBytes, asciiKeyFileClient, ErrUnknownIssuer)
	checkMessageSignatureTest(t, gpg, messageBytes, signatureBytes, binaryKeyFileClient, ErrUnknownIssuer)
	checkMessageSignatureTest(t, gpg, messageBytes, signatureBytes, asciiKeyFileOther, ErrUnknownIssuer)
}

func TestGPGEncryptMessage(t *testing.T) {
	gpg := setupGPG(t)
	messageBytes := []byte("Hello World!")

	message := bytes.NewReader(messageBytes)
	cipherTextBuffer := new(bytes.Buffer)
	recipientKeyFile, cleanup := utils.Open(t, asciiKeyFileClient)
	defer cleanup()

	err := gpg.EncryptMessage(message, cipherTextBuffer, recipientKeyFile)
	if err != nil {
		t.Fatal("Encryption failed:", err)
	}

	clientEntity := readEntityFromFile(asciiKeyFileClientSecret, true)
	serverPublicEntity := readEntityFromFile(asciiKeyFilePublic, true)
	err = decryptPrivateKeys(clientEntity, []byte(passphrase))
	if err != nil {
		t.Fatal("Failed to decrypt private keys")
	}
	keyRing := openpgp.EntityList([]*openpgp.Entity{clientEntity, serverPublicEntity})

	md, err := openpgp.ReadMessage(bytes.NewBuffer(cipherTextBuffer.Bytes()), keyRing, nil, nil)
	if err != nil {
		t.Fatal("Decryption failed:", err)
	}
	if !md.IsEncrypted {
		t.Error("Encrypted message has not actually been encrypted")
	}
	if !md.IsSigned {
		t.Error("Encrypted message has not been signed")
	}

	decryptedMessageBytes, err := ioutil.ReadAll(md.UnverifiedBody)
	if err != nil {
		t.Fatal("Reading decrypted text failed:", err)
	}

	if string(decryptedMessageBytes) != string(messageBytes) {
		t.Error("Decrypted text mismatch")
		t.Error("Expected:", string(messageBytes))
		t.Error("Got:", string(decryptedMessageBytes))
	}

	if md.SignatureError != nil {
		t.Error("Validating signature failed:", md.SignatureError)
	}

	if md.SignedByKeyId != gpg.serverEntity.PrimaryKey.KeyId {
		t.Error("Message signed by wrong key")
		t.Error("Expected:", gpg.serverEntity.PrimaryKey.KeyId)
		t.Error("Got:", md.SignedByKeyId)
	}

	if md.SignedBy == nil {
		t.Error("Signer key not found")
	}

	if _, ok := md.SignedBy.Entity.Identities[expectedIdentity]; !ok {
		t.Error("Invalid signer key:", md.SignedBy)
	}
}

func TestGPGEncryptMessageWithInvalidRecipient(t *testing.T) {
	gpg := setupGPG(t)
	messageBytes := []byte("Hello World!")

	message := bytes.NewReader(messageBytes)
	cipherTextBuffer := new(bytes.Buffer)
	invalidRecipient := new(bytes.Buffer)

	err := gpg.EncryptMessage(message, cipherTextBuffer, invalidRecipient)
	if err != io.EOF {
		t.Fatal("Unexpected error for encrypting message to empty recipient key file:", err)
	}
}

func makeEncryptedMessage(t *testing.T, messageBytes []byte, signed bool) *bytes.Buffer {
	var senderEntity *openpgp.Entity

	recipientEntity := readEntityFromFile(asciiKeyFilePublic, true)
	if signed {
		senderEntity = readEntityFromFile(asciiKeyFileClientSecret, true)
		err := decryptPrivateKeys(senderEntity, []byte(passphrase))
		if err != nil {
			t.Fatal("Failed to decrypt private keys")
		}
	}

	cipherTextBuffer := new(bytes.Buffer)

	w, err := openpgp.Encrypt(cipherTextBuffer, []*openpgp.Entity{recipientEntity}, senderEntity, nil, nil)
	if err != nil {
		t.Fatal(err)
	}
	_, err = w.Write(messageBytes)
	if err != nil {
		t.Fatal(err)
	}
	err = w.Close()
	if err != nil {
		t.Fatal(err)
	}

	return cipherTextBuffer
}

func TestGPGDecryptSignedMessage(t *testing.T) {
	gpg := setupGPG(t)
	messageBytes := []byte("Hello World!")

	cipherTextBuffer := makeEncryptedMessage(t, messageBytes, true)

	decryptedText := new(bytes.Buffer)
	senderKeyFile, cleanup := utils.Open(t, asciiKeyFileClient)
	defer cleanup()

	err := gpg.DecryptSignedMessage(bytes.NewBuffer(cipherTextBuffer.Bytes()), decryptedText, senderKeyFile)
	if err != nil {
		t.Fatal("Decryption failed:", err)
	}

	if decryptedText.String() != string(messageBytes) {
		t.Error("Decrypted text mismatch")
		t.Error("Expected:", string(messageBytes))
		t.Error("Got:", decryptedText.String())
	}
}

func TestGPGDecryptSignedMessageWithInvalidInput(t *testing.T) {
	gpg := setupGPG(t)
	messageBytes := []byte("Hello World!")

	cipherTextBuffer := makeEncryptedMessage(t, messageBytes, false)
	decryptedText := new(bytes.Buffer)
	senderKeyFile, cleanup := utils.Open(t, asciiKeyFileClient)
	defer cleanup()
	err := gpg.DecryptSignedMessage(bytes.NewBuffer(cipherTextBuffer.Bytes()), decryptedText, senderKeyFile)
	if err != ErrMessageNotSigned {
		t.Error("Unexpected error for decrypting unsigned message:", err)
	}

	cipherTextBuffer = makeEncryptedMessage(t, messageBytes, true)
	decryptedText = new(bytes.Buffer)
	senderKeyFile, cleanup = utils.Open(t, asciiKeyFileOther)
	defer cleanup()
	err = gpg.DecryptSignedMessage(bytes.NewBuffer(cipherTextBuffer.Bytes()), decryptedText, senderKeyFile)
	if err != ErrUnknownIssuer {
		t.Error("Unexpected error for decrypting message from wrong signer:", err)
	}

	senderKeyFile, cleanup = utils.Open(t, asciiKeyFileClient)
	defer cleanup()
	err = gpg.DecryptSignedMessage(new(bytes.Buffer), decryptedText, senderKeyFile)
	if err != io.EOF {
		t.Error("Unexpected error for decrypting empty message:", err)
	}

	err = gpg.DecryptSignedMessage(bytes.NewBuffer(cipherTextBuffer.Bytes()), decryptedText, new(bytes.Buffer))
	if err != io.EOF {
		t.Error("Unexpected error for decrypting message with empty sender key:", err)
	}
}
<|endoftext|>


<commit_before>// 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.

// Binary btbolt injects the btbolt driver into the bw command line tool.
package main

import (
	"flag"
	"os"
	"time"

	"github.com/boltdb/bolt"
	"github.com/google/badwolf/storage"
	"github.com/google/badwolf/storage/memory"
	"github.com/google/badwolf/tools/vcli/bw/common"
	"github.com/google/badwolf/triple/literal"
	"github.com/xllora/bwdrivers/bwbolt"
)

var (
	// drivers contains the registed drivers available for this command line tool.
	registeredDrivers map[string]common.StoreGenerator

	// Available flags.
	driverName = flag.String("driver", "VOLATILE", "The storage driver to use {VOLATILE|BWBOLT}.")

	bqlChannelSize       = flag.Int("bql_channel_size", 0, "Internal channel size to use on BQL queries.")
	bulkTripleOpSize     = flag.Int("bulk_triple_op_size", 1000, "Number of triples to use in bulk load operations.")
	bulkTriplBuildersize = flag.Int("bulk_triple_builder_size_in_bytes", 1000, "Maximum size of literals when parsing a triple.")

	// Add your driver flags below.

	// BwBolt driver.
	boltDBPath   = flag.String("bolt_db_path", "", "The path to the Bolt database to use.")
	boldTimeout  = flag.Duration("bold_timeout", 3*time.Second, "The duration of the timeout while opening the Bolt database.")
	boltReadOnly = flag.Bool("bolt_db_read_only", false, "Use te Bolt DB only in read only mode.")

	// Driver specific variables.
	db *bolt.DB
)

// Registers the available drivers.
func registerDrivers() {
	registeredDrivers = map[string]common.StoreGenerator{
		// Memory only storage driver.
		"VOLATILE": func() (storage.Store, error) {
			return memory.NewStore(), nil
		},
		"BWBOLT": func() (storage.Store, error) {
			s, bdb, err := bwbolt.New(*boltDBPath, literal.DefaultBuilder(), *boldTimeout, *boltReadOnly)
			db = bdb
			return s, err
		},
	}
}

func main() {
	flag.Parse()
	registerDrivers()
	ret := common.Run(*driverName, registeredDrivers, *bqlChannelSize, *bulkTripleOpSize, *bulkTriplBuildersize)
	// Clean up.
	if db != nil {
		db.Close()
	}
	os.Exit(ret)
}
<commit_msg>Fix run API call change<commit_after>// 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.

// Binary btbolt injects the btbolt driver into the bw command line tool.
package main

import (
	"flag"
	"os"
	"time"

	"github.com/boltdb/bolt"
	"github.com/google/badwolf/storage"
	"github.com/google/badwolf/storage/memory"
	"github.com/google/badwolf/tools/vcli/bw/common"
	"github.com/google/badwolf/triple/literal"
	"github.com/xllora/bwdrivers/bwbolt"
)

var (
	// drivers contains the registed drivers available for this command line tool.
	registeredDrivers map[string]common.StoreGenerator

	// Available flags.
<<<<<<< HEAD
	driverName = flag.String("driver", "VOLATILE", "The storage driver to use {VOLATILE|BWBOLT}.")

	bqlChannelSize       = flag.Int("bql_channel_size", 0, "Internal channel size to use on BQL queries.")
	bulkTripleOpSize     = flag.Int("bulk_triple_op_size", 1000, "Number of triples to use in bulk load operations.")
	bulkTriplBuildersize = flag.Int("bulk_triple_builder_size_in_bytes", 1000, "Maximum size of literals when parsing a triple.")

=======
	driverName           = flag.String("driver", "VOLATILE", "The storage driver to use {VOLATILE|BWBOLT}.")
	bqlChannelSize       = flag.Int("bql_channel_size", 0, "Internal channel size to use on BQL queries.")
	bulkTripleOpSize     = flag.Int("bulk_triple_op_size", 1000, "Number of triples to use in bulk load operations.")
	bulkTriplBuildersize = flag.Int("bulk_triple_builder_size_in_bytes", 1000, "Maximum size of literals when parsing a triple.")
>>>>>>> 46f45036c6745a0ef584dfeb30c1c293dadbf4fa
	// Add your driver flags below.

	// BwBolt driver.
	boltDBPath   = flag.String("bolt_db_path", "", "The path to the Bolt database to use.")
	boldTimeout  = flag.Duration("bold_timeout", 3*time.Second, "The duration of the timeout while opening the Bolt database.")
	boltReadOnly = flag.Bool("bolt_db_read_only", false, "Use te Bolt DB only in read only mode.")

	// Driver specific variables.
	db *bolt.DB
)

// Registers the available drivers.
func registerDrivers() {
	registeredDrivers = map[string]common.StoreGenerator{
		// Memory only storage driver.
		"VOLATILE": func() (storage.Store, error) {
			return memory.NewStore(), nil
		},
		"BWBOLT": func() (storage.Store, error) {
			s, bdb, err := bwbolt.New(*boltDBPath, literal.DefaultBuilder(), *boldTimeout, *boltReadOnly)
			db = bdb
			return s, err
		},
	}
}

func main() {
	flag.Parse()
	registerDrivers()
	ret := common.Run(*driverName, registeredDrivers, *bqlChannelSize, *bulkTripleOpSize, *bulkTriplBuildersize)
	// Clean up.
	if db != nil {
		db.Close()
	}
	os.Exit(ret)
}
<|endoftext|>


<commit_before>// Copyright 2015 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 oglematchers_test

import (
	"testing"

	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
)

func TestHasSameTypeAs(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

type HasSameTypeAsTest struct {
}

func init() { RegisterTestSuite(&HasSameTypeAsTest{}) }

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *HasSameTypeAsTest) CandidateIsLiteralNil() {
	matcher := HasSameTypeAs(nil)
	var err error

	// Description
	ExpectEq("has type <nil>", matcher.Description())

	// Literal nil
	err = matcher.Matches(nil)
	ExpectEq(nil, err)

	// int
	err = matcher.Matches(17)
	AssertNe(nil, err)
	ExpectThat(err, Error(Equals("which has type int")))

	// string
	err = matcher.Matches("")
	AssertNe(nil, err)
	ExpectThat(err, Error(Equals("which has type string")))

	// nil map
	var m map[string]string
	err = matcher.Matches(m)

	AssertNe(nil, err)
	ExpectThat(err, Error(Equals("which has type map[string]string")))

	// Non-nil map
	m = make(map[string]string)
	err = matcher.Matches(m)

	AssertNe(nil, err)
	ExpectThat(err, Error(Equals("which has type map[string]string")))
}

func (t *HasSameTypeAsTest) CandidateIsNilMap() {
	AssertTrue(false, "TODO")
}

func (t *HasSameTypeAsTest) CandidateIsNilInterface() {
	AssertTrue(false, "TODO")
}

func (t *HasSameTypeAsTest) CandidateIsString() {
	AssertTrue(false, "TODO")
}

func (t *HasSameTypeAsTest) CandidateIsStringAlias() {
	AssertTrue(false, "TODO")
}
<commit_msg>HasSameTypeAsTest.CandidateIsNilMap<commit_after>// Copyright 2015 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 oglematchers_test

import (
	"testing"

	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
)

func TestHasSameTypeAs(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

type HasSameTypeAsTest struct {
}

func init() { RegisterTestSuite(&HasSameTypeAsTest{}) }

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *HasSameTypeAsTest) CandidateIsLiteralNil() {
	matcher := HasSameTypeAs(nil)
	var err error

	// Description
	ExpectEq("has type <nil>", matcher.Description())

	// Literal nil
	err = matcher.Matches(nil)
	ExpectEq(nil, err)

	// int
	err = matcher.Matches(17)
	AssertNe(nil, err)
	ExpectThat(err, Error(Equals("which has type int")))

	// string
	err = matcher.Matches("")
	AssertNe(nil, err)
	ExpectThat(err, Error(Equals("which has type string")))

	// nil map
	var m map[string]string
	err = matcher.Matches(m)

	AssertNe(nil, err)
	ExpectThat(err, Error(Equals("which has type map[string]string")))

	// Non-nil map
	m = make(map[string]string)
	err = matcher.Matches(m)

	AssertNe(nil, err)
	ExpectThat(err, Error(Equals("which has type map[string]string")))
}

func (t *HasSameTypeAsTest) CandidateIsNilMap() {
	var m map[string]string
	matcher := HasSameTypeAs(m)
	var err error

	// Description
	ExpectEq("has type map[string]string", matcher.Description())

	// nil map
	m = nil
	err = matcher.Matches(m)
	ExpectEq(nil, err)

	// Non-nil map
	m = make(map[string]string)
	err = matcher.Matches(m)
	ExpectEq(nil, err)

	// Literal nil
	err = matcher.Matches(nil)
	AssertNe(nil, err)
	ExpectThat(err, Error(Equals("which has type <nil>")))

	// int
	err = matcher.Matches(17)
	AssertNe(nil, err)
	ExpectThat(err, Error(Equals("which has type int")))

	// string
	err = matcher.Matches("")
	AssertNe(nil, err)
	ExpectThat(err, Error(Equals("which has type string")))
}

func (t *HasSameTypeAsTest) CandidateIsNilInterface() {
	AssertTrue(false, "TODO")
}

func (t *HasSameTypeAsTest) CandidateIsString() {
	AssertTrue(false, "TODO")
}

func (t *HasSameTypeAsTest) CandidateIsStringAlias() {
	AssertTrue(false, "TODO")
}
<|endoftext|>


<commit_before>package v3_helpers

import (
	"encoding/json"
	"fmt"
	"strings"

	"github.com/cloudfoundry/cf-acceptance-tests/Godeps/_workspace/src/github.com/cloudfoundry-incubator/cf-test-helpers/cf"
	"github.com/cloudfoundry/cf-acceptance-tests/Godeps/_workspace/src/github.com/cloudfoundry-incubator/cf-test-helpers/helpers"
	"github.com/cloudfoundry/cf-acceptance-tests/Godeps/_workspace/src/github.com/cloudfoundry-incubator/cf-test-helpers/runner"

	. "github.com/cloudfoundry/cf-acceptance-tests/Godeps/_workspace/src/github.com/onsi/gomega"
	. "github.com/cloudfoundry/cf-acceptance-tests/Godeps/_workspace/src/github.com/onsi/gomega/gbytes"
	. "github.com/cloudfoundry/cf-acceptance-tests/Godeps/_workspace/src/github.com/onsi/gomega/gexec"
)

func StartApp(appGuid string) {
	startURL := fmt.Sprintf("/v3/apps/%s/start", appGuid)
	Expect(cf.Cf("curl", startURL, "-X", "PUT").Wait(DEFAULT_TIMEOUT)).To(Exit(0))
}

func StopApp(appGuid string) {
	stopURL := fmt.Sprintf("/v3/apps/%s/stop", appGuid)
	Expect(cf.Cf("curl", stopURL, "-X", "PUT").Wait(DEFAULT_TIMEOUT)).To(Exit(0))
}

func CreateApp(appName, spaceGuid, environmentVariables string) string {
	session := cf.Cf("curl", "/v3/apps", "-X", "POST", "-d", fmt.Sprintf(`{"name":"%s", "relationships": {"space": {"guid": "%s"}}, "environment_variables":%s}`, appName, spaceGuid, environmentVariables))
	bytes := session.Wait(DEFAULT_TIMEOUT).Out.Contents()
	var app struct {
		Guid string `json:"guid"`
	}
	json.Unmarshal(bytes, &app)
	return app.Guid
}

func CreateDockerApp(appName, spaceGuid, environmentVariables string) string {
	session := cf.Cf("curl", "/v3/apps", "-X", "POST", "-d", fmt.Sprintf(`{"name":"%s", "relationships": {"space": {"guid": "%s"}}, "environment_variables":%s, "lifecycle": {"type": "docker", "data": {} } }`, appName, spaceGuid, environmentVariables))
	bytes := session.Wait(DEFAULT_TIMEOUT).Out.Contents()
	var app struct {
		Guid string `json:"guid"`
	}
	json.Unmarshal(bytes, &app)
	return app.Guid
}

func DeleteApp(appGuid string) {
	session := cf.Cf("curl", fmt.Sprintf("/v3/apps/%s", appGuid), "-X", "DELETE", "-v")
	bytes := session.Wait(DEFAULT_TIMEOUT).Out.Contents()
	Expect(bytes).To(ContainSubstring("204 No Content"))
}

func WaitForPackageToBeReady(packageGuid string) {
	pkgUrl := fmt.Sprintf("/v3/packages/%s", packageGuid)
	Eventually(func() *Session {
		session := cf.Cf("curl", pkgUrl)
		Expect(session.Wait(DEFAULT_TIMEOUT)).To(Exit(0))
		return session
	}, LONG_CURL_TIMEOUT).Should(Say("READY"))
}

func WaitForDropletToStage(dropletGuid string) {
	dropletPath := fmt.Sprintf("/v3/droplets/%s", dropletGuid)
	Eventually(func() *Session {
		return cf.Cf("curl", dropletPath).Wait(DEFAULT_TIMEOUT)
	}, CF_PUSH_TIMEOUT).Should(Say("STAGED"))
}

func CreatePackage(appGuid string) string {
	packageCreateUrl := fmt.Sprintf("/v3/apps/%s/packages", appGuid)
	session := cf.Cf("curl", packageCreateUrl, "-X", "POST", "-d", fmt.Sprintf(`{"type":"bits"}`))
	bytes := session.Wait(DEFAULT_TIMEOUT).Out.Contents()
	var pac struct {
		Guid string `json:"guid"`
	}
	json.Unmarshal(bytes, &pac)
	return pac.Guid
}

func CreateDockerPackage(appGuid, imagePath string) string {
	packageCreateUrl := fmt.Sprintf("/v3/apps/%s/packages", appGuid)
	session := cf.Cf("curl", packageCreateUrl, "-X", "POST", "-d", fmt.Sprintf(`{"type":"docker", "data": {"image": "%s"}}`, imagePath))
	bytes := session.Wait(DEFAULT_TIMEOUT).Out.Contents()
	var pac struct {
		Guid string `json:"guid"`
	}
	json.Unmarshal(bytes, &pac)
	return pac.Guid
}

func GetSpaceGuidFromName(spaceName string) string {
	session := cf.Cf("space", spaceName, "--guid")
	bytes := session.Wait(DEFAULT_TIMEOUT).Out.Contents()
	return strings.TrimSpace(string(bytes))
}

func GetAuthToken() string {
	bytes := runner.Run("bash", "-c", "cf oauth-token | grep bearer").Wait(DEFAULT_TIMEOUT).Out.Contents()
	return strings.TrimSpace(string(bytes))
}

func UploadPackage(uploadUrl, packageZipPath, token string) {
	bits := fmt.Sprintf(`bits=@%s`, packageZipPath)
	curl := runner.Curl("-v", "-s", uploadUrl, "-F", bits, "-H", fmt.Sprintf("Authorization: %s", token)).Wait(DEFAULT_TIMEOUT)
	Expect(curl).To(Exit(0))
}

func StageBuildpackPackage(packageGuid, buildpack string) string {
	stageBody := fmt.Sprintf(`{"lifecycle":{ "type": "buildpack", "data": { "buildpack": "%s" } }}`, buildpack)
	stageUrl := fmt.Sprintf("/v3/packages/%s/droplets", packageGuid)
	session := cf.Cf("curl", stageUrl, "-X", "POST", "-d", stageBody)
	bytes := session.Wait(DEFAULT_TIMEOUT).Out.Contents()
	var droplet struct {
		Guid string `json:"guid"`
	}
	json.Unmarshal(bytes, &droplet)
	return droplet.Guid
}

func StageDockerPackage(packageGuid string) string {
	stageUrl := fmt.Sprintf("/v3/packages/%s/droplets", packageGuid)
	session := cf.Cf("curl", stageUrl, "-X", "POST", "-d", "")
	bytes := session.Wait(DEFAULT_TIMEOUT).Out.Contents()
	var droplet struct {
		Guid string `json:"guid"`
	}
	json.Unmarshal(bytes, &droplet)
	return droplet.Guid
}

func CreateAndMapRoute(appGuid, space, domain, host string) {
	Expect(cf.Cf("create-route", space, domain, "-n", host).Wait(DEFAULT_TIMEOUT)).To(Exit(0))
	getRoutePath := fmt.Sprintf("/v2/routes?q=host:%s", host)
	routeBody := cf.Cf("curl", getRoutePath).Wait(DEFAULT_TIMEOUT).Out.Contents()
	routeJSON := struct {
		Resources []struct {
			Metadata struct {
				Guid string `json:"guid"`
			} `json:"metadata"`
		} `json:"resources"`
	}{}
	json.Unmarshal([]byte(routeBody), &routeJSON)
	routeGuid := routeJSON.Resources[0].Metadata.Guid
	addRouteBody := fmt.Sprintf(`
	{
		"relationships": {
			"app":   {"guid": "%s"},
			"route": {"guid": "%s"}
		}
	}`, appGuid, routeGuid)
	Expect(cf.Cf("curl", "/v3/route_mappings", "-X", "POST", "-d", addRouteBody).Wait(DEFAULT_TIMEOUT)).To(Exit(0))
}

func AssignDropletToApp(appGuid, dropletGuid string) {
	appUpdatePath := fmt.Sprintf("/v3/apps/%s/current_droplet", appGuid)
	appUpdateBody := fmt.Sprintf(`{"droplet_guid":"%s"}`, dropletGuid)
	Expect(cf.Cf("curl", appUpdatePath, "-X", "PUT", "-d", appUpdateBody).Wait(DEFAULT_TIMEOUT)).To(Exit(0))

	for _, process := range GetProcesses(appGuid, "") {
		ScaleProcess(appGuid, process.Type, DEFAULT_MEMORY_LIMIT)
	}
}

func FetchRecentLogs(appGuid, oauthToken string, config helpers.Config) *Session {
	loggregatorEndpoint := strings.Replace(config.ApiEndpoint, "api", "loggregator", -1)
	logUrl := fmt.Sprintf("%s/recent?app=%s", loggregatorEndpoint, appGuid)
	session := runner.Curl(logUrl, "-H", fmt.Sprintf("Authorization: %s", oauthToken))
	Expect(session.Wait(DEFAULT_TIMEOUT)).To(Exit(0))
	return session
}

func ScaleProcess(appGuid, processType, memoryInMb string) {
	scalePath := fmt.Sprintf("/v3/apps/%s/processes/%s/scale", appGuid, processType)
	scaleBody := fmt.Sprintf(`{"memory_in_mb":"%s"}`, memoryInMb)
	Expect(cf.Cf("curl", scalePath, "-X", "PUT", "-d", scaleBody).Wait(DEFAULT_TIMEOUT)).To(Exit(0))
}
<commit_msg>Update current droplet endpoint<commit_after>package v3_helpers

import (
	"encoding/json"
	"fmt"
	"strings"

	"github.com/cloudfoundry/cf-acceptance-tests/Godeps/_workspace/src/github.com/cloudfoundry-incubator/cf-test-helpers/cf"
	"github.com/cloudfoundry/cf-acceptance-tests/Godeps/_workspace/src/github.com/cloudfoundry-incubator/cf-test-helpers/helpers"
	"github.com/cloudfoundry/cf-acceptance-tests/Godeps/_workspace/src/github.com/cloudfoundry-incubator/cf-test-helpers/runner"

	. "github.com/cloudfoundry/cf-acceptance-tests/Godeps/_workspace/src/github.com/onsi/gomega"
	. "github.com/cloudfoundry/cf-acceptance-tests/Godeps/_workspace/src/github.com/onsi/gomega/gbytes"
	. "github.com/cloudfoundry/cf-acceptance-tests/Godeps/_workspace/src/github.com/onsi/gomega/gexec"
)

func StartApp(appGuid string) {
	startURL := fmt.Sprintf("/v3/apps/%s/start", appGuid)
	Expect(cf.Cf("curl", startURL, "-X", "PUT").Wait(DEFAULT_TIMEOUT)).To(Exit(0))
}

func StopApp(appGuid string) {
	stopURL := fmt.Sprintf("/v3/apps/%s/stop", appGuid)
	Expect(cf.Cf("curl", stopURL, "-X", "PUT").Wait(DEFAULT_TIMEOUT)).To(Exit(0))
}

func CreateApp(appName, spaceGuid, environmentVariables string) string {
	session := cf.Cf("curl", "/v3/apps", "-X", "POST", "-d", fmt.Sprintf(`{"name":"%s", "relationships": {"space": {"guid": "%s"}}, "environment_variables":%s}`, appName, spaceGuid, environmentVariables))
	bytes := session.Wait(DEFAULT_TIMEOUT).Out.Contents()
	var app struct {
		Guid string `json:"guid"`
	}
	json.Unmarshal(bytes, &app)
	return app.Guid
}

func CreateDockerApp(appName, spaceGuid, environmentVariables string) string {
	session := cf.Cf("curl", "/v3/apps", "-X", "POST", "-d", fmt.Sprintf(`{"name":"%s", "relationships": {"space": {"guid": "%s"}}, "environment_variables":%s, "lifecycle": {"type": "docker", "data": {} } }`, appName, spaceGuid, environmentVariables))
	bytes := session.Wait(DEFAULT_TIMEOUT).Out.Contents()
	var app struct {
		Guid string `json:"guid"`
	}
	json.Unmarshal(bytes, &app)
	return app.Guid
}

func DeleteApp(appGuid string) {
	session := cf.Cf("curl", fmt.Sprintf("/v3/apps/%s", appGuid), "-X", "DELETE", "-v")
	bytes := session.Wait(DEFAULT_TIMEOUT).Out.Contents()
	Expect(bytes).To(ContainSubstring("204 No Content"))
}

func WaitForPackageToBeReady(packageGuid string) {
	pkgUrl := fmt.Sprintf("/v3/packages/%s", packageGuid)
	Eventually(func() *Session {
		session := cf.Cf("curl", pkgUrl)
		Expect(session.Wait(DEFAULT_TIMEOUT)).To(Exit(0))
		return session
	}, LONG_CURL_TIMEOUT).Should(Say("READY"))
}

func WaitForDropletToStage(dropletGuid string) {
	dropletPath := fmt.Sprintf("/v3/droplets/%s", dropletGuid)
	Eventually(func() *Session {
		return cf.Cf("curl", dropletPath).Wait(DEFAULT_TIMEOUT)
	}, CF_PUSH_TIMEOUT).Should(Say("STAGED"))
}

func CreatePackage(appGuid string) string {
	packageCreateUrl := fmt.Sprintf("/v3/apps/%s/packages", appGuid)
	session := cf.Cf("curl", packageCreateUrl, "-X", "POST", "-d", fmt.Sprintf(`{"type":"bits"}`))
	bytes := session.Wait(DEFAULT_TIMEOUT).Out.Contents()
	var pac struct {
		Guid string `json:"guid"`
	}
	json.Unmarshal(bytes, &pac)
	return pac.Guid
}

func CreateDockerPackage(appGuid, imagePath string) string {
	packageCreateUrl := fmt.Sprintf("/v3/apps/%s/packages", appGuid)
	session := cf.Cf("curl", packageCreateUrl, "-X", "POST", "-d", fmt.Sprintf(`{"type":"docker", "data": {"image": "%s"}}`, imagePath))
	bytes := session.Wait(DEFAULT_TIMEOUT).Out.Contents()
	var pac struct {
		Guid string `json:"guid"`
	}
	json.Unmarshal(bytes, &pac)
	return pac.Guid
}

func GetSpaceGuidFromName(spaceName string) string {
	session := cf.Cf("space", spaceName, "--guid")
	bytes := session.Wait(DEFAULT_TIMEOUT).Out.Contents()
	return strings.TrimSpace(string(bytes))
}

func GetAuthToken() string {
	bytes := runner.Run("bash", "-c", "cf oauth-token | grep bearer").Wait(DEFAULT_TIMEOUT).Out.Contents()
	return strings.TrimSpace(string(bytes))
}

func UploadPackage(uploadUrl, packageZipPath, token string) {
	bits := fmt.Sprintf(`bits=@%s`, packageZipPath)
	curl := runner.Curl("-v", "-s", uploadUrl, "-F", bits, "-H", fmt.Sprintf("Authorization: %s", token)).Wait(DEFAULT_TIMEOUT)
	Expect(curl).To(Exit(0))
}

func StageBuildpackPackage(packageGuid, buildpack string) string {
	stageBody := fmt.Sprintf(`{"lifecycle":{ "type": "buildpack", "data": { "buildpack": "%s" } }}`, buildpack)
	stageUrl := fmt.Sprintf("/v3/packages/%s/droplets", packageGuid)
	session := cf.Cf("curl", stageUrl, "-X", "POST", "-d", stageBody)
	bytes := session.Wait(DEFAULT_TIMEOUT).Out.Contents()
	var droplet struct {
		Guid string `json:"guid"`
	}
	json.Unmarshal(bytes, &droplet)
	return droplet.Guid
}

func StageDockerPackage(packageGuid string) string {
	stageUrl := fmt.Sprintf("/v3/packages/%s/droplets", packageGuid)
	session := cf.Cf("curl", stageUrl, "-X", "POST", "-d", "")
	bytes := session.Wait(DEFAULT_TIMEOUT).Out.Contents()
	var droplet struct {
		Guid string `json:"guid"`
	}
	json.Unmarshal(bytes, &droplet)
	return droplet.Guid
}

func CreateAndMapRoute(appGuid, space, domain, host string) {
	Expect(cf.Cf("create-route", space, domain, "-n", host).Wait(DEFAULT_TIMEOUT)).To(Exit(0))
	getRoutePath := fmt.Sprintf("/v2/routes?q=host:%s", host)
	routeBody := cf.Cf("curl", getRoutePath).Wait(DEFAULT_TIMEOUT).Out.Contents()
	routeJSON := struct {
		Resources []struct {
			Metadata struct {
				Guid string `json:"guid"`
			} `json:"metadata"`
		} `json:"resources"`
	}{}
	json.Unmarshal([]byte(routeBody), &routeJSON)
	routeGuid := routeJSON.Resources[0].Metadata.Guid
	addRouteBody := fmt.Sprintf(`
	{
		"relationships": {
			"app":   {"guid": "%s"},
			"route": {"guid": "%s"}
		}
	}`, appGuid, routeGuid)
	Expect(cf.Cf("curl", "/v3/route_mappings", "-X", "POST", "-d", addRouteBody).Wait(DEFAULT_TIMEOUT)).To(Exit(0))
}

func AssignDropletToApp(appGuid, dropletGuid string) {
	appUpdatePath := fmt.Sprintf("/v3/apps/%s/droplets/current", appGuid)
	appUpdateBody := fmt.Sprintf(`{"droplet_guid":"%s"}`, dropletGuid)
	Expect(cf.Cf("curl", appUpdatePath, "-X", "PUT", "-d", appUpdateBody).Wait(DEFAULT_TIMEOUT)).To(Exit(0))

	for _, process := range GetProcesses(appGuid, "") {
		ScaleProcess(appGuid, process.Type, DEFAULT_MEMORY_LIMIT)
	}
}

func FetchRecentLogs(appGuid, oauthToken string, config helpers.Config) *Session {
	loggregatorEndpoint := strings.Replace(config.ApiEndpoint, "api", "loggregator", -1)
	logUrl := fmt.Sprintf("%s/recent?app=%s", loggregatorEndpoint, appGuid)
	session := runner.Curl(logUrl, "-H", fmt.Sprintf("Authorization: %s", oauthToken))
	Expect(session.Wait(DEFAULT_TIMEOUT)).To(Exit(0))
	return session
}

func ScaleProcess(appGuid, processType, memoryInMb string) {
	scalePath := fmt.Sprintf("/v3/apps/%s/processes/%s/scale", appGuid, processType)
	scaleBody := fmt.Sprintf(`{"memory_in_mb":"%s"}`, memoryInMb)
	Expect(cf.Cf("curl", scalePath, "-X", "PUT", "-d", scaleBody).Wait(DEFAULT_TIMEOUT)).To(Exit(0))
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"os/exec"
)

type sendNotification struct {
	HipchatClient

	Message string   `cli:"arg required"`
	Command []string `cli:"arg required"`
}

func (act *sendNotification) Run() (e error) {
	cmd := exec.Command(act.Command[0], act.Command[1:]...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	e = cmd.Run()
	switch e {
	case nil:
		e = act.Send(&HipchatNotification{Message: "[Success] " + act.Message, Color: "green"})
	default:
		e = act.Send(&HipchatNotification{Message: "[Failed] " + act.Message + "\n" + e.Error(), Color: "red"})
	}

	return e
}
<commit_msg>also forward environment<commit_after>package main

import (
	"os"
	"os/exec"
)

type sendNotification struct {
	HipchatClient

	Message string   `cli:"arg required"`
	Command []string `cli:"arg required"`
}

func (act *sendNotification) Run() (e error) {
	cmd := exec.Command(act.Command[0], act.Command[1:]...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.Env = os.Environ()
	e = cmd.Run()
	switch e {
	case nil:
		e = act.Send(&HipchatNotification{Message: "[Success] " + act.Message, Color: "green"})
	default:
		e = act.Send(&HipchatNotification{Message: "[Failed] " + act.Message + "\n" + e.Error(), Color: "red"})
	}

	return e
}
<|endoftext|>