<commit_before>package timequeue

import (
	"sync"
	"time"
)

const (
	//The default capacity used for Messages() channels.
	DefaultCapacity = 1
)

//Type TimeQueue is a queue of Messages that releases its Messages when their
//Time fields pass.
//
//When Messages are pushed to a TimeQueue, the earliest Message is used to
//determine when the TimeQueue should wake. Upon waking, that earliest Message
//is "released" from the TimeQueue by being sent on the channel returned by
//Messages().
//
//Messages may be pushed and popped from a TimeQueue whether or not the TimeQueue
//is running or not. Start() and Stop() may be called as many times as desired,
//but Messsages will be released only between calls to Start() and Stop(), i.e.
//while the TimeQueue is running and IsRunning() returns true.
//
//Calls to Pop(), PopAll(), and PopAllUntil() may be called to remove Messages
//from a TimeQueue, but this is required for normal use.
//
//One of the New*() functions should be used to create a TimeQueue. A zero-value
//TimeQueue is not in a valid or working state.
type TimeQueue struct {
	//the goal is to have only one go-routine "inside" a TimeQueue at once.
	//this is acheived by locking on lock in all exported methods and
	//requiring the TimeQueue be locked in all unexported methods and
	//before all use of unexported fields.

	//protects all other members of a TimeQueue.
	lock *sync.Mutex

	//the heap of Messages in the TimeQueue.
	messages *messageHeap

	//flag determining if the TimeQueue is running.
	//should be true between calls to Start() and Stop() and false otherwise.
	running bool
	//signal that sends to stopChan or wakeChan to wake or stop the running go-routine.
	wakeSignal *wakeSignal

	//the channel to send released Messages on. should be receive only in client code.
	messageChan chan *Message
	//send to this channel to wake the running go-routine and release Messages.
	wakeChan chan time.Time
	//send to this channel to stop the running go-routine.
	stopChan chan struct{}
}

//New creates a new *TimeQueue with a call to New(DefaultCapacity).
func New() *TimeQueue {
	return NewCapacity(DefaultCapacity)
}

//NewCapacity creates a new *TimeQueue where the channel returned from Messages()
//has the capacity given by capacity.
//The new TimeQueue is in the stopped state and has no Messages in it.
func NewCapacity(capacity int) *TimeQueue {
	return &TimeQueue{
		lock:        &sync.Mutex{},
		messages:    newMessageHeap(),
		running:     false,
		wakeSignal:  nil,
		messageChan: make(chan *Message, capacity),
		wakeChan:    make(chan time.Time),
		stopChan:    make(chan struct{}),
	}
}

//Push creates and adds a Message to q with t and data. The created Message is returned.
func (q *TimeQueue) Push(t time.Time, data interface{}) *Message {
	q.lock.Lock()
	defer q.lock.Unlock()
	return q.messages.pushMessageValues(t, data)
}

//Peek returns (without removing) the Time and Data fields from the earliest
//Message in q.
//If q is empty, then the zero Time and nil are returned.
func (q *TimeQueue) Peek() (time.Time, interface{}) {
	message := q.PeekMessage()
	if message == nil {
		return time.Time{}, nil
	}
	return message.Time, message.Data
}

//PeekMessage returns (without removing) the earliest Message in q or nil if q
//is empty.
func (q *TimeQueue) PeekMessage() *Message {
	q.lock.Lock()
	defer q.lock.Unlock()
	return q.peekMessage()
}

//peekMessage is the unexported version of PeekMessage().
//It should only be called when q is locked.
func (q *TimeQueue) peekMessage() *Message {
	return q.messages.peekMessage()
}

//Pop removes and returns the earliest Message in q or nil if q is empty.
//If release is true, then the Message (if not nil) will also be sent on the
//channel returned from Messages().
func (q *TimeQueue) Pop(release bool) *Message {
	q.lock.Lock()
	defer q.lock.Unlock()
	message := q.messages.popMessage()
	if message == nil {
		return nil
	}
	if release {
		q.releaseMessage(message)
	}
	q.afterHeapUpdate()
	return message
}

//PopAll removes and returns a slice of all Messages in q.
//The returned slice will be non-nil but empty if q is itseld empty.
//If release is true, then all returned Messages will also be sent on the channel
//returned from Messages().
func (q *TimeQueue) PopAll(release bool) []*Message {
	q.lock.Lock()
	defer q.lock.Unlock()
	result := make([]*Message, 0, q.messages.Len())
	for message := q.messages.popMessage(); message != nil; message = q.messages.popMessage() {
		result = append(result, message)
	}
	if release {
		q.releaseCopyToChan(result)
	}
	q.afterHeapUpdate()
	return result
}

//PopAllUntil removes and returns a slice of Messages in q with Time fields before,
//but not equal to, until.
//If release is true, then all returned Messages will also be sent on the channel
//returned from Messages().
func (q *TimeQueue) PopAllUntil(until time.Time, release bool) []*Message {
	q.lock.Lock()
	defer q.lock.Unlock()
	return q.popAllUntil(until, release)
}

//popAllUntil is the unexported verson of PopAllUntil.
//It should only be called when q is locked.
func (q *TimeQueue) popAllUntil(until time.Time, release bool) []*Message {
	result := make([]*Message, 0, q.messages.Len())
	for message := q.messages.peekMessage(); message != nil && message.Before(until); message = q.messages.peekMessage() {
		result = append(result, q.messages.popMessage())
	}
	if release {
		q.releaseCopyToChan(result)
	}
	q.afterHeapUpdate()
	return result
}

//Remove removes message from q.
//If q is empty, message is nil, or message is not in q, then Remove is a nop
//and returns false.
//Returns true or false indicating whether or not message was actually removed from q.
func (q *TimeQueue) Remove(message *Message) bool {
	q.lock.Lock()
	defer q.lock.Unlock()
	result := q.messages.removeMessage(message)
	q.afterHeapUpdate()
	return result
}

//afterHeapUpdate ensures the earliest time is in the next wake signal, if q is running.
//It should only be called when q is locked.
func (q *TimeQueue) afterHeapUpdate() {
	if q.isRunning() {
		q.updateAndSpawnWakeSignal()
	}
}

//Messages returns the receive only channel that all Messages are released on.
//The returned channel will be the same instance on every call, and this value
//will never be closed.
//
//In order to receive Messages when they are earliest available a go-routine should
//be spawned to drain the channel of all Messages.
//	q := timequeue.New()
//	q.Start()
//	go func() {
//		message := <-q.Messages()
//	}()
//	//push Messages to q.
func (q *TimeQueue) Messages() <-chan *Message {
	return q.messageChan
}

//Size returns the number of Messages in q. This is the number of Messages that
//have yet to be released (or waiting to be sent on Messages()) in q.
//Therefore, there could still be Messages that q has reference to that are waiting
//to be released or in the Messages() channel buffer.
//
//To obtain the number of total Messages that q still has refernce to add this value
//and the length of Messages():
//	q.Size() + len(q.Messages())
func (q *TimeQueue) Size() int {
	q.lock.Lock()
	defer q.lock.Unlock()
	return q.messages.Len()
}

//Start spawns a new go-routine to listen for wake times of Messages and sets the
//state to running.
//If q is already running, then Start is a nop.
func (q *TimeQueue) Start() {
	q.lock.Lock()
	defer q.lock.Unlock()
	if q.isRunning() {
		return
	}
	q.setRunning(true)
	go q.run()
	q.updateAndSpawnWakeSignal()
}

//IsRunning returns whether or not q is running. E.g. in between calls to Start()
//and Stop().
//If IsRunning returns true, then it is possible that Messages are being released.
func (q *TimeQueue) IsRunning() bool {
	q.lock.Lock()
	defer q.lock.Unlock()
	return q.isRunning()
}

//isRunning is the unexported version of IsRunning.
//It should only be called when q is locked.
func (q *TimeQueue) isRunning() bool {
	return q.running
}

//run is the run loop of a TimeQueue.
//It is an infinite loop that selects between q.wakeChan and q.stopChan.
//If q.wakeChan is selected, then q.onWake() is called.
//If q.wakeStop is selected, then this method returns.
//Note that this method does not spawn a new go-routine.
//That should be done outside of run.
//run does not have the precondition that q must be locked.
//This is a function that should execute in its own go-routine and thus cannot
//lock any other parts of q.
func (q *TimeQueue) run() {
	for {
		select {
		case wakeTime := <-q.wakeChan:
			q.onWake(wakeTime)
		case <-q.stopChan:
			return
		}
	}
}

//onWake should be called when q receives a value on q.wakeChan.
//Because onWake will be called from a go-routine that we spawned, we lock and
//defer unlock on q since this acts like an exported method of sorts in that
//it starts execution of unexported code from an outside go-routine.
func (q *TimeQueue) onWake(wakeTime time.Time) {
	q.lock.Lock()
	defer q.lock.Unlock()
	q.popAllUntil(wakeTime, true)
	q.updateAndSpawnWakeSignal()
}

//releaseMessage is a utility method that spawns a go-routine to send message on
//q.messageChan so that that calling go-routine does not have to wait.
func (q *TimeQueue) releaseMessage(message *Message) {
	go func() {
		q.messageChan <- message
	}()
}

//releaseCopyToChan is a utility method that copies messages to a new, buffered
//channel, and empties that new channel by sending every messsage on q.messageChan.
func (q *TimeQueue) releaseCopyToChan(messages []*Message) {
	copyChan := make(chan *Message, len(messages))
	for _, message := range messages {
		copyChan <- message
	}
	q.releaseChan(copyChan)
	close(copyChan)
}

//releaseChan is a utility method that spawns a go-routine to send every message
//in messages on q.messageChan.
//Note that releaseChan reads from messages until it is closed, thus messages must
//be closed by the calling function.
func (q *TimeQueue) releaseChan(messages <-chan *Message) {
	go func() {
		for message := range messages {
			q.messageChan <- message
		}
	}()
}

//updateAndSpawnSignal kills the current wake signal if it exists
//and creates and spawns the next wake signal if there are any messages left in q.
//Returns true if a new wakeSignal was spawned, false otherwise.
//It should only be called when q is locked.
func (q *TimeQueue) updateAndSpawnWakeSignal() bool {
	q.killWakeSignal()
	message := q.peekMessage()
	if message == nil {
		return false
	}
	q.setWakeSignal(newWakeSignal(q.wakeChan, message.Time))
	return q.spawnWakeSignal()
}

//setWakeSignal sets q.wakeSignal to wakeSignal.
//It should only be called when q is locked.
func (q *TimeQueue) setWakeSignal(wakeSignal *wakeSignal) {
	q.wakeSignal = wakeSignal
}

//spawnWakeSignal calls spawn() on q.wakeSignal if it is not nil.
//Returns true if spawn was called, false otherwise.
//It should only be called when q is locked.
func (q *TimeQueue) spawnWakeSignal() bool {
	if q.wakeSignal != nil {
		q.wakeSignal.spawn()
		return true
	}
	return false
}

//killWakeSignal call kill() and sets q.wakeSignal to nil if it is not nil.
//Returns true if the old wakeSignal is not nil, false otherwise.
//It should only be called when q is locked.
func (q *TimeQueue) killWakeSignal() bool {
	if q.wakeSignal != nil {
		q.wakeSignal.kill()
		q.wakeSignal = nil
		return true
	}
	return false
}

//Stop tells the running go-routine to stop running.
//This results in no more Messages being released (until a subsequent call to Start())
//and the state to be set to not running.
//If q is already stopped, then Stop is a nop.
func (q *TimeQueue) Stop() {
	q.lock.Lock()
	defer q.lock.Unlock()
	if !q.isRunning() {
		return
	}
	q.killWakeSignal()
	q.setRunning(false)
	go func() {
		q.stopChan <- struct{}{}
	}()
}

//setRunning is the unexported version of SetRunning. Sets q.running to running.
//It should only be called when q is locked.
func (q *TimeQueue) setRunning(running bool) {
	q.running = running
}

//wakeSignal represents a signal that sends a time.Time value after that time has passed.
//wakeSignals can be killed, which will prevent the signal from sending its value.
type wakeSignal struct {
	dst  chan time.Time
	src  <-chan time.Time
	stop chan struct{}
}

//newWakeSignal create a wakeSignal that sends wakeTime on dst when wakeTime passes.
//this function should be used to create wakeSignals.
//the zero value wakeSignal is not valid.
func newWakeSignal(dst chan time.Time, wakeTime time.Time) *wakeSignal {
	return &wakeSignal{
		dst:  dst,
		src:  time.After(wakeTime.Sub(time.Now())),
		stop: make(chan struct{}),
	}
}

//spawn starts a new go-routine that selects on w.src and w.stop.
//If w.src is selected, the received value is sent on w.dst.
//If w.stop is selected, then the function stops selecting.
//In both cases, w.src is set to nil and the function returns.
func (w *wakeSignal) spawn() {
	go func() {
		select {
		case wakeTime := <-w.src:
			w.dst <- wakeTime
		case <-w.stop:
		}
		w.src = nil
	}()
}

//kill closes the w.stop channel.
//This is NOT idempotent. I.e. kill should only be called once a single wakeSignal.
func (w *wakeSignal) kill() {
	close(w.stop)
}
<commit_msg>Updates Remove implementation.<commit_after>package timequeue

import (
	"sync"
	"time"
)

const (
	//The default capacity used for Messages() channels.
	DefaultCapacity = 1
)

//Type TimeQueue is a queue of Messages that releases its Messages when their
//Time fields pass.
//
//When Messages are pushed to a TimeQueue, the earliest Message is used to
//determine when the TimeQueue should wake. Upon waking, that earliest Message
//is "released" from the TimeQueue by being sent on the channel returned by
//Messages().
//
//Messages may be pushed and popped from a TimeQueue whether or not the TimeQueue
//is running or not. Start() and Stop() may be called as many times as desired,
//but Messsages will be released only between calls to Start() and Stop(), i.e.
//while the TimeQueue is running and IsRunning() returns true.
//
//Calls to Pop(), PopAll(), and PopAllUntil() may be called to remove Messages
//from a TimeQueue, but this is required for normal use.
//
//One of the New*() functions should be used to create a TimeQueue. A zero-value
//TimeQueue is not in a valid or working state.
type TimeQueue struct {
	//the goal is to have only one go-routine "inside" a TimeQueue at once.
	//this is acheived by locking on lock in all exported methods and
	//requiring the TimeQueue be locked in all unexported methods and
	//before all use of unexported fields.

	//protects all other members of a TimeQueue.
	lock *sync.Mutex

	//the heap of Messages in the TimeQueue.
	messages *messageHeap

	//flag determining if the TimeQueue is running.
	//should be true between calls to Start() and Stop() and false otherwise.
	running bool
	//signal that sends to stopChan or wakeChan to wake or stop the running go-routine.
	wakeSignal *wakeSignal

	//the channel to send released Messages on. should be receive only in client code.
	messageChan chan *Message
	//send to this channel to wake the running go-routine and release Messages.
	wakeChan chan time.Time
	//send to this channel to stop the running go-routine.
	stopChan chan struct{}
}

//New creates a new *TimeQueue with a call to New(DefaultCapacity).
func New() *TimeQueue {
	return NewCapacity(DefaultCapacity)
}

//NewCapacity creates a new *TimeQueue where the channel returned from Messages()
//has the capacity given by capacity.
//The new TimeQueue is in the stopped state and has no Messages in it.
func NewCapacity(capacity int) *TimeQueue {
	return &TimeQueue{
		lock:        &sync.Mutex{},
		messages:    newMessageHeap(),
		running:     false,
		wakeSignal:  nil,
		messageChan: make(chan *Message, capacity),
		wakeChan:    make(chan time.Time),
		stopChan:    make(chan struct{}),
	}
}

//Push creates and adds a Message to q with t and data. The created Message is returned.
func (q *TimeQueue) Push(t time.Time, data interface{}) *Message {
	q.lock.Lock()
	defer q.lock.Unlock()
	return q.messages.pushMessageValues(t, data)
}

//Peek returns (without removing) the Time and Data fields from the earliest
//Message in q.
//If q is empty, then the zero Time and nil are returned.
func (q *TimeQueue) Peek() (time.Time, interface{}) {
	message := q.PeekMessage()
	if message == nil {
		return time.Time{}, nil
	}
	return message.Time, message.Data
}

//PeekMessage returns (without removing) the earliest Message in q or nil if q
//is empty.
func (q *TimeQueue) PeekMessage() *Message {
	q.lock.Lock()
	defer q.lock.Unlock()
	return q.peekMessage()
}

//peekMessage is the unexported version of PeekMessage().
//It should only be called when q is locked.
func (q *TimeQueue) peekMessage() *Message {
	return q.messages.peekMessage()
}

//Pop removes and returns the earliest Message in q or nil if q is empty.
//If release is true, then the Message (if not nil) will also be sent on the
//channel returned from Messages().
func (q *TimeQueue) Pop(release bool) *Message {
	q.lock.Lock()
	defer q.lock.Unlock()
	message := q.messages.popMessage()
	if message == nil {
		return nil
	}
	if release {
		q.releaseMessage(message)
	}
	q.afterHeapUpdate()
	return message
}

//PopAll removes and returns a slice of all Messages in q.
//The returned slice will be non-nil but empty if q is itseld empty.
//If release is true, then all returned Messages will also be sent on the channel
//returned from Messages().
func (q *TimeQueue) PopAll(release bool) []*Message {
	q.lock.Lock()
	defer q.lock.Unlock()
	result := make([]*Message, 0, q.messages.Len())
	for message := q.messages.popMessage(); message != nil; message = q.messages.popMessage() {
		result = append(result, message)
	}
	if release {
		q.releaseCopyToChan(result)
	}
	q.afterHeapUpdate()
	return result
}

//PopAllUntil removes and returns a slice of Messages in q with Time fields before,
//but not equal to, until.
//If release is true, then all returned Messages will also be sent on the channel
//returned from Messages().
func (q *TimeQueue) PopAllUntil(until time.Time, release bool) []*Message {
	q.lock.Lock()
	defer q.lock.Unlock()
	return q.popAllUntil(until, release)
}

//popAllUntil is the unexported verson of PopAllUntil.
//It should only be called when q is locked.
func (q *TimeQueue) popAllUntil(until time.Time, release bool) []*Message {
	result := make([]*Message, 0, q.messages.Len())
	for message := q.messages.peekMessage(); message != nil && message.Before(until); message = q.messages.peekMessage() {
		result = append(result, q.messages.popMessage())
	}
	if release {
		q.releaseCopyToChan(result)
	}
	q.afterHeapUpdate()
	return result
}

//Remove removes message from q.
//If q is empty, message is nil, or message is not in q, then Remove is a nop
//and returns false.
//Returns true or false indicating whether or not message was actually removed from q.
//If release is true and message was actually removed, then message will also be
//sent on the channel returned by Messages().
func (q *TimeQueue) Remove(message *Message, release bool) bool {
	q.lock.Lock()
	defer q.lock.Unlock()
	removed := q.messages.removeMessage(message)
	if removed && release {
		q.releaseMessage(message)
	}
	q.afterHeapUpdate()
	return removed
}

//afterHeapUpdate ensures the earliest time is in the next wake signal, if q is running.
//It should only be called when q is locked.
func (q *TimeQueue) afterHeapUpdate() {
	if q.isRunning() {
		q.updateAndSpawnWakeSignal()
	}
}

//Messages returns the receive only channel that all Messages are released on.
//The returned channel will be the same instance on every call, and this value
//will never be closed.
//
//In order to receive Messages when they are earliest available a go-routine should
//be spawned to drain the channel of all Messages.
//	q := timequeue.New()
//	q.Start()
//	go func() {
//		message := <-q.Messages()
//	}()
//	//push Messages to q.
func (q *TimeQueue) Messages() <-chan *Message {
	return q.messageChan
}

//Size returns the number of Messages in q. This is the number of Messages that
//have yet to be released (or waiting to be sent on Messages()) in q.
//Therefore, there could still be Messages that q has reference to that are waiting
//to be released or in the Messages() channel buffer.
//
//To obtain the number of total Messages that q still has refernce to add this value
//and the length of Messages():
//	q.Size() + len(q.Messages())
func (q *TimeQueue) Size() int {
	q.lock.Lock()
	defer q.lock.Unlock()
	return q.messages.Len()
}

//Start spawns a new go-routine to listen for wake times of Messages and sets the
//state to running.
//If q is already running, then Start is a nop.
func (q *TimeQueue) Start() {
	q.lock.Lock()
	defer q.lock.Unlock()
	if q.isRunning() {
		return
	}
	q.setRunning(true)
	go q.run()
	q.updateAndSpawnWakeSignal()
}

//IsRunning returns whether or not q is running. E.g. in between calls to Start()
//and Stop().
//If IsRunning returns true, then it is possible that Messages are being released.
func (q *TimeQueue) IsRunning() bool {
	q.lock.Lock()
	defer q.lock.Unlock()
	return q.isRunning()
}

//isRunning is the unexported version of IsRunning.
//It should only be called when q is locked.
func (q *TimeQueue) isRunning() bool {
	return q.running
}

//run is the run loop of a TimeQueue.
//It is an infinite loop that selects between q.wakeChan and q.stopChan.
//If q.wakeChan is selected, then q.onWake() is called.
//If q.wakeStop is selected, then this method returns.
//Note that this method does not spawn a new go-routine.
//That should be done outside of run.
//run does not have the precondition that q must be locked.
//This is a function that should execute in its own go-routine and thus cannot
//lock any other parts of q.
func (q *TimeQueue) run() {
	for {
		select {
		case wakeTime := <-q.wakeChan:
			q.onWake(wakeTime)
		case <-q.stopChan:
			return
		}
	}
}

//onWake should be called when q receives a value on q.wakeChan.
//Because onWake will be called from a go-routine that we spawned, we lock and
//defer unlock on q since this acts like an exported method of sorts in that
//it starts execution of unexported code from an outside go-routine.
func (q *TimeQueue) onWake(wakeTime time.Time) {
	q.lock.Lock()
	defer q.lock.Unlock()
	q.popAllUntil(wakeTime, true)
	q.updateAndSpawnWakeSignal()
}

//releaseMessage is a utility method that spawns a go-routine to send message on
//q.messageChan so that that calling go-routine does not have to wait.
func (q *TimeQueue) releaseMessage(message *Message) {
	go func() {
		q.messageChan <- message
	}()
}

//releaseCopyToChan is a utility method that copies messages to a new, buffered
//channel, and empties that new channel by sending every messsage on q.messageChan.
func (q *TimeQueue) releaseCopyToChan(messages []*Message) {
	copyChan := make(chan *Message, len(messages))
	for _, message := range messages {
		copyChan <- message
	}
	q.releaseChan(copyChan)
	close(copyChan)
}

//releaseChan is a utility method that spawns a go-routine to send every message
//in messages on q.messageChan.
//Note that releaseChan reads from messages until it is closed, thus messages must
//be closed by the calling function.
func (q *TimeQueue) releaseChan(messages <-chan *Message) {
	go func() {
		for message := range messages {
			q.messageChan <- message
		}
	}()
}

//updateAndSpawnSignal kills the current wake signal if it exists
//and creates and spawns the next wake signal if there are any messages left in q.
//Returns true if a new wakeSignal was spawned, false otherwise.
//It should only be called when q is locked.
func (q *TimeQueue) updateAndSpawnWakeSignal() bool {
	q.killWakeSignal()
	message := q.peekMessage()
	if message == nil {
		return false
	}
	q.setWakeSignal(newWakeSignal(q.wakeChan, message.Time))
	return q.spawnWakeSignal()
}

//setWakeSignal sets q.wakeSignal to wakeSignal.
//It should only be called when q is locked.
func (q *TimeQueue) setWakeSignal(wakeSignal *wakeSignal) {
	q.wakeSignal = wakeSignal
}

//spawnWakeSignal calls spawn() on q.wakeSignal if it is not nil.
//Returns true if spawn was called, false otherwise.
//It should only be called when q is locked.
func (q *TimeQueue) spawnWakeSignal() bool {
	if q.wakeSignal != nil {
		q.wakeSignal.spawn()
		return true
	}
	return false
}

//killWakeSignal call kill() and sets q.wakeSignal to nil if it is not nil.
//Returns true if the old wakeSignal is not nil, false otherwise.
//It should only be called when q is locked.
func (q *TimeQueue) killWakeSignal() bool {
	if q.wakeSignal != nil {
		q.wakeSignal.kill()
		q.wakeSignal = nil
		return true
	}
	return false
}

//Stop tells the running go-routine to stop running.
//This results in no more Messages being released (until a subsequent call to Start())
//and the state to be set to not running.
//If q is already stopped, then Stop is a nop.
func (q *TimeQueue) Stop() {
	q.lock.Lock()
	defer q.lock.Unlock()
	if !q.isRunning() {
		return
	}
	q.killWakeSignal()
	q.setRunning(false)
	go func() {
		q.stopChan <- struct{}{}
	}()
}

//setRunning is the unexported version of SetRunning. Sets q.running to running.
//It should only be called when q is locked.
func (q *TimeQueue) setRunning(running bool) {
	q.running = running
}

//wakeSignal represents a signal that sends a time.Time value after that time has passed.
//wakeSignals can be killed, which will prevent the signal from sending its value.
type wakeSignal struct {
	dst  chan time.Time
	src  <-chan time.Time
	stop chan struct{}
}

//newWakeSignal create a wakeSignal that sends wakeTime on dst when wakeTime passes.
//this function should be used to create wakeSignals.
//the zero value wakeSignal is not valid.
func newWakeSignal(dst chan time.Time, wakeTime time.Time) *wakeSignal {
	return &wakeSignal{
		dst:  dst,
		src:  time.After(wakeTime.Sub(time.Now())),
		stop: make(chan struct{}),
	}
}

//spawn starts a new go-routine that selects on w.src and w.stop.
//If w.src is selected, the received value is sent on w.dst.
//If w.stop is selected, then the function stops selecting.
//In both cases, w.src is set to nil and the function returns.
func (w *wakeSignal) spawn() {
	go func() {
		select {
		case wakeTime := <-w.src:
			w.dst <- wakeTime
		case <-w.stop:
		}
		w.src = nil
	}()
}

//kill closes the w.stop channel.
//This is NOT idempotent. I.e. kill should only be called once a single wakeSignal.
func (w *wakeSignal) kill() {
	close(w.stop)
}
<|endoftext|>


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

package times

import (
	"os"
	"syscall"
	"time"
)

// HasChangeTime and HasBirthTime are true if and only if
// the target OS supports them.
const (
	HasChangeTime = true
	HasBirthTime  = false
)

type timespec struct {
	atime
	mtime
	ctime
	nobtime
}

func timespecToTime(ts syscall.StTimespec_t) time.Time {
	return time.Unix(int64(ts.Sec), int64(ts.Nsec))
}

func getTimespec(fi os.FileInfo) (t timespec) {
	stat := fi.Sys().(*syscall.Stat_t)
	t.atime.v = timespecToTime(stat.Atim)
	t.mtime.v = timespecToTime(stat.Mtim)
	t.ctime.v = timespecToTime(stat.Ctim)
	return t
}
<commit_msg>Update times_aix.go<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// https://golang.org/src/os/stat_aix.go

package times

import (
	"os"
	"syscall"
	"time"
)

// HasChangeTime and HasBirthTime are true if and only if
// the target OS supports them.
const (
	HasChangeTime = true
	HasBirthTime  = false
)

type timespec struct {
	atime
	mtime
	ctime
	nobtime
}

func timespecToTime(ts syscall.StTimespec_t) time.Time {
	return time.Unix(int64(ts.Sec), int64(ts.Nsec))
}

func getTimespec(fi os.FileInfo) (t timespec) {
	stat := fi.Sys().(*syscall.Stat_t)
	t.atime.v = timespecToTime(stat.Atim)
	t.mtime.v = timespecToTime(stat.Mtim)
	t.ctime.v = timespecToTime(stat.Ctim)
	return t
}
<|endoftext|>


<commit_before>// Copyright 2014-2015 The project AUTHORS. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package src

import (
	"bytes"
	"errors"
	"testing"

	"github.com/DevMine/srcanlzr/src/ast"
	"github.com/DevMine/srcanlzr/src/token"
)

func TestDecodeStringsList(t *testing.T) {
	expected := []string{"foo", "bar"}
	buf := bytes.NewBufferString(`["foo","bar"]`)
	dec := newDecoder(buf)
	sl := dec.decodeStrings()
	if dec.err != nil {
		t.Fatal(dec.err)
	}
	if !stringsSlicesEquals(sl, expected) {
		t.Errorf("decodeStringsList: found %v, expected %v", sl, expected)
	}
}

func TestDecodeLanguages(t *testing.T) {
	expected := []*Language{
		&Language{
			Lang:      Go,
			Paradigms: []string{Compiled, Concurrent, Imperative, Structured},
		},
		&Language{
			Lang:      Java,
			Paradigms: []string{ObjectOriented, Structured, Imperative, Generic, Reflective, Concurrent},
		},
	}
	buf := bytes.NewBufferString(`[
		{
			"language": "go",
			"paradigms": [
				"compiled",
				"concurrent",
				"imperative",
				"structured"
			]
		},
		{
			"language": "java",
			"paradigms": [
				"object oriented",
				"structured",
				"imperative",
				"generic",
				"reflective",
				"concurrent"
			]
		}
	]`)
	dec := newDecoder(buf)
	langs := dec.decodeLanguages()
	if dec.err != nil {
		t.Fatal(dec.err)
	}
	if l := len(langs); l != 2 {
		t.Fatalf("decodeLanguages: found %d languages, expected 2", l)
	}
	compareLanguages(t, langs[0], expected[0])
	compareLanguages(t, langs[1], expected[1])
}

func TestDecodeLanguage(t *testing.T) {
	expected := &Language{
		Lang:      Go,
		Paradigms: []string{Compiled, Concurrent, Imperative, Structured},
	}
	buf := bytes.NewBufferString(`{"language": "go", "paradigms": ["compiled", "concurrent", "imperative", "structured"]}`)
	dec := newDecoder(buf)
	lang := dec.decodeLanguage()
	if dec.err != nil {
		t.Fatal(dec.err)
	}
	compareLanguages(t, lang, expected)
}

func TestDecodeIdent(t *testing.T) {
	expected := &ast.Ident{
		ExprName: token.IdentName,
		Name:     "foo",
	}
	buf := bytes.NewBufferString(`{"expression_name": "IDENT", "name": "foo"}`)
	dec := newDecoder(buf)
	ident := dec.decodeIdent()
	if dec.err != nil {
		t.Fatal(dec.err)
	}
	if ident.ExprName != expected.ExprName {
		t.Errorf("decodeIdent: found '%s', found '%s'", ident.ExprName, expected.ExprName)
	}
	if ident.Name != expected.Name {
		t.Errorf("decodeIdent: found '%s', found '%s'", ident.Name, expected.Name)
	}
}

func TestExtractFirstKey(t *testing.T) {
	// test success
	buf := bytes.NewBufferString(`"expression_name": "IDENT"`)
	dec := newDecoder(buf)
	if val := dec.extractFirstKey("expression_name"); val != "IDENT" {
		t.Errorf("extractFirstKey 'expression_name': found '%s', expected 'IDENT'", val)
	}
	if dec.err != nil {
		t.Error(dec.err)
	}

	// test failure

	buf = bytes.NewBufferString(``)
	dec = newDecoder(buf)
	expectedErr := errors.New("unexpected EOF")
	_ = dec.extractFirstKey("expression_name")
	if dec.err.Error() != expectedErr.Error() {
		t.Errorf("extractFirstKey 'expression_name': found error \"%v\", expected error \"%v\"",
			dec.err, expectedErr)
	}

	buf = bytes.NewBufferString(`"foo": "bar"`)
	dec = newDecoder(buf)
	expectedErr = errors.New("expected key to be 'expression_name', found 'foo'")
	_ = dec.extractFirstKey("expression_name")
	if dec.err.Error() != expectedErr.Error() {
		t.Errorf("extractFirstKey 'expression_name': found error \"%v\", expected error \"%v\"",
			dec.err, expectedErr)
	}

	buf = bytes.NewBufferString(`"expression_name": 42}`)
	dec = newDecoder(buf)
	expectedErr = errors.New("expected 'string literal', found 'integer literal'")
	_ = dec.extractFirstKey("expression_name")
	if dec.err.Error() != expectedErr.Error() {
		t.Errorf("extractFirstKey 'expression_name': found error \"%v\", expected error \"%v\"",
			dec.err, expectedErr)
	}
}

func TestUnmarshalString(t *testing.T) {
	dec := newDecoder(new(bytes.Buffer))
	if str, err := dec.unmarshalString([]byte("foo")); err != nil {
		t.Error(err)
	} else if str != "foo" {
		t.Errorf("unmarshalString 'foo': found '%s', expected 'foo'", str)
	}

	expectedErr := errors.New("unable to unmarshal string: data is nil")
	if _, err := dec.unmarshalString(nil); err == nil {
		t.Errorf("unmarshalString nil: found no error, expected \"%v\"", expectedErr)
	} else if err.Error() != expectedErr.Error() {
		t.Errorf("unmarshalString nil: found error \"%v\", expected \"%v\"", err, expectedErr)
	}
}

func TestUnmarshalInt64(t *testing.T) {
	dec := newDecoder(new(bytes.Buffer))
	if num, err := dec.unmarshalInt64([]byte("42")); err != nil {
		t.Error(err)
	} else if num != 42 {
		t.Errorf("unmarshalInt64 '42': found %d, expected 42", num)
	}
}

func TestUnmarshalFloat64(t *testing.T) {
	dec := newDecoder(new(bytes.Buffer))
	if num, err := dec.unmarshalFloat64([]byte("42.42")); err != nil {
		t.Error(err)
	} else if num-42.42 > 0.0001 {
		t.Errorf("unmarshalFloat64 '42.42': found %f, expected 42.42", num)
	}
}

func TestUnmarshalBool(t *testing.T) {
	dec := newDecoder(new(bytes.Buffer))
	if num, err := dec.unmarshalBool([]byte("true")); err != nil {
		t.Error(err)
	} else if !num {
		t.Error("unmarshalBool 'true': found 'false', expected 'true'")
	}

	dec = newDecoder(new(bytes.Buffer))
	if num, err := dec.unmarshalBool([]byte("false")); err != nil {
		t.Error(err)
	} else if num {
		t.Error("unmarshalBool 'false': found 'true', expected 'false'")
	}

	expectedErr := errors.New("unable to unmarshal boolean: value 'none' is not a boolean")
	dec = newDecoder(new(bytes.Buffer))
	if num, err := dec.unmarshalBool([]byte("none")); err == nil {
		t.Errorf("unmarshalBool 'none': found no error, expected \"%v\"", expectedErr)
	} else if err.Error() != expectedErr.Error() {
		t.Errorf("unmarshalBool 'none': found \"%v\", expected \"%v\"", err, expectedErr)
	} else if num {
		t.Error("unmarshalBool 'none': found 'true', expected 'false'")
	}
}

func TestAssertNewObject(t *testing.T) {
	type returnStatus struct {
		status bool
		err    error
	}
	input := map[string]returnStatus{
		"{": returnStatus{true, nil},
		"":  returnStatus{false, errors.New("expected value, found EOF")},
		"[": returnStatus{false, errors.New("expected object, found '['")},
	}

	for in, ret := range input {
		buf := bytes.NewBufferString(in)
		dec := newDecoder(buf)
		if status := dec.assertNewObject(); status != ret.status {
			t.Errorf("assertNewObject '%s': found %v, expected %v", in, status, ret.status)
		}
		if err := dec.err; err != nil && err.Error() != ret.err.Error() {
			t.Errorf("assertNewObject '%s': found error \"%v\", expected error \"%v\"", in, dec.err, ret.err)
		}
	}
}

func TestAssertNewArray(t *testing.T) {
	type returnStatus struct {
		status bool
		err    error
	}
	input := map[string]returnStatus{
		"[": returnStatus{true, nil},
		"":  returnStatus{false, errors.New("expected value, found EOF")},
		"{": returnStatus{false, errors.New("expected array, found '{'")},
	}

	for in, ret := range input {
		buf := bytes.NewBufferString(in)
		dec := newDecoder(buf)
		if status := dec.assertNewArray(); status != ret.status {
			t.Errorf("assertNewArray '%s': found %v, expected %v", in, status, ret.status)
		}
		if err := dec.err; err != nil && err.Error() != ret.err.Error() {
			t.Errorf("assertNewArray '%s': found error \"%v\", expected error \"%v\"", in, dec.err, ret.err)
		}
	}
}

func TestIsEndObject(t *testing.T) {
	type returnStatus struct {
		status bool
		err    error
	}
	input := map[string]returnStatus{
		"}":   returnStatus{true, nil},
		",":   returnStatus{false, nil},
		"42}": returnStatus{false, errors.New("expected 'comma', found 'integer literal'")},
	}

	for in, ret := range input {
		buf := bytes.NewBufferString(in)
		dec := newDecoder(buf)
		if status := dec.isEndObject(); status != ret.status {
			t.Errorf("isEndObject '%s': found %v, expected %v", in, status, ret.status)
		}
		if err := dec.err; err != nil && err.Error() != ret.err.Error() {
			t.Errorf("isEndObject '%s': found error \"%v\", expected error \"%v\"", in, dec.err, ret.err)
		}
	}
}

func TestIsEndArray(t *testing.T) {
	type returnStatus struct {
		status bool
		err    error
	}
	input := map[string]returnStatus{
		"]":   returnStatus{true, nil},
		",":   returnStatus{false, nil},
		"42}": returnStatus{false, errors.New("expected 'comma', found 'integer literal'")},
	}

	for in, ret := range input {
		buf := bytes.NewBufferString(in)
		dec := newDecoder(buf)
		if status := dec.isEndArray(); status != ret.status {
			t.Errorf("isEndArray '%s': found %v, expected %v", in, status, ret.status)
		}
		if err := dec.err; err != nil && err.Error() != ret.err.Error() {
			t.Errorf("isEndArray '%s': found error \"%v\", expected error \"%v\"", in, dec.err, ret.err)
		}
	}
}

func TestIsEmptyObject(t *testing.T) {
	type returnStatus struct {
		status bool
		err    error
	}
	input := map[string]returnStatus{
		"}":        returnStatus{true, nil},
		"":         returnStatus{false, errors.New("unexpected EOF")},
		"\"foo\":": returnStatus{false, nil},
	}

	for in, ret := range input {
		buf := bytes.NewBufferString(in)
		dec := newDecoder(buf)
		if status := dec.isEmptyObject(); status != ret.status {
			t.Errorf("isEmptyObject '%s': found %v, expected %v", in, status, ret.status)
		}
		if err := dec.err; err != nil && err.Error() != ret.err.Error() {
			t.Errorf("isEmptyObject '%s': found error \"%v\", expected error \"%v\"", in, dec.err, ret.err)
		}
	}
}

func TestIsEmptyArray(t *testing.T) {
	type returnStatus struct {
		status bool
		err    error
	}
	input := map[string]returnStatus{
		"]":  returnStatus{true, nil},
		"":   returnStatus{false, errors.New("unexpected EOF")},
		"42": returnStatus{false, nil},
	}

	for in, ret := range input {
		buf := bytes.NewBufferString(in)
		dec := newDecoder(buf)
		if status := dec.isEmptyArray(); status != ret.status {
			t.Errorf("isEmptyArray '%s': found %v, expected %v", in, status, ret.status)
		}
		if err := dec.err; err != nil && err.Error() != ret.err.Error() {
			t.Errorf("isEmptyArray '%s': found error \"%v\", expected error \"%v\"", in, dec.err, ret.err)
		}
	}
}

func TestIsNull(t *testing.T) {
	input := map[string]bool{
		"null":  true,
		"nan":   false,
		`"foo"`: false,
	}

	for in, expected := range input {
		buf := bytes.NewBufferString(in)
		dec := newDecoder(buf)
		if b := dec.isNull(); b != expected {
			t.Errorf("isNull '%s': found '%v', expected '%v'", in, b, expected)
		}
	}
}

func compareLanguages(t *testing.T, found, expected *Language) {
	if found == nil {
		t.Fatal("decodeLanguage: should not be nil")
	}

	if expected.Lang != found.Lang {
		t.Errorf("decodeLanguage.Lang: found '%s', expected '%s'", found.Lang, expected.Lang)
	}
	if !stringsSlicesEquals(expected.Paradigms, found.Paradigms) {
		t.Errorf("decodeLanguage.Paradigms: found '%v', expected '%v'", found.Paradigms, expected.Paradigms)
	}
}

func stringsSlicesEquals(sl1, sl2 []string) bool {
	if len(sl1) != len(sl2) {
		return false
	}
	for i := 0; i < len(sl1); i++ {
		if sl1[i] != sl2[i] {
			return false
		}
	}
	return true
}
<commit_msg>src/decoder: fix typo in tests<commit_after>// Copyright 2014-2015 The project AUTHORS. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package src

import (
	"bytes"
	"errors"
	"testing"

	"github.com/DevMine/srcanlzr/src/ast"
	"github.com/DevMine/srcanlzr/src/token"
)

func TestDecodeStringsList(t *testing.T) {
	expected := []string{"foo", "bar"}
	buf := bytes.NewBufferString(`["foo","bar"]`)
	dec := newDecoder(buf)
	sl := dec.decodeStrings()
	if dec.err != nil {
		t.Fatal(dec.err)
	}
	if !stringsSlicesEquals(sl, expected) {
		t.Errorf("decodeStringsList: found %v, expected %v", sl, expected)
	}
}

func TestDecodeLanguages(t *testing.T) {
	expected := []*Language{
		&Language{
			Lang:      Go,
			Paradigms: []string{Compiled, Concurrent, Imperative, Structured},
		},
		&Language{
			Lang:      Java,
			Paradigms: []string{ObjectOriented, Structured, Imperative, Generic, Reflective, Concurrent},
		},
	}
	buf := bytes.NewBufferString(`[
		{
			"language": "go",
			"paradigms": [
				"compiled",
				"concurrent",
				"imperative",
				"structured"
			]
		},
		{
			"language": "java",
			"paradigms": [
				"object oriented",
				"structured",
				"imperative",
				"generic",
				"reflective",
				"concurrent"
			]
		}
	]`)
	dec := newDecoder(buf)
	langs := dec.decodeLanguages()
	if dec.err != nil {
		t.Fatal(dec.err)
	}
	if l := len(langs); l != 2 {
		t.Fatalf("decodeLanguages: found %d languages, expected 2", l)
	}
	compareLanguages(t, langs[0], expected[0])
	compareLanguages(t, langs[1], expected[1])
}

func TestDecodeLanguage(t *testing.T) {
	expected := &Language{
		Lang:      Go,
		Paradigms: []string{Compiled, Concurrent, Imperative, Structured},
	}
	buf := bytes.NewBufferString(`{"language": "go", "paradigms": ["compiled", "concurrent", "imperative", "structured"]}`)
	dec := newDecoder(buf)
	lang := dec.decodeLanguage()
	if dec.err != nil {
		t.Fatal(dec.err)
	}
	compareLanguages(t, lang, expected)
}

func TestDecodeIdent(t *testing.T) {
	expected := &ast.Ident{
		ExprName: token.IdentName,
		Name:     "foo",
	}
	buf := bytes.NewBufferString(`{"expression_name": "IDENT", "name": "foo"}`)
	dec := newDecoder(buf)
	ident := dec.decodeIdent()
	if dec.err != nil {
		t.Fatal(dec.err)
	}
	if ident.ExprName != expected.ExprName {
		t.Errorf("decodeIdent: found '%s', expected '%s'", ident.ExprName, expected.ExprName)
	}
	if ident.Name != expected.Name {
		t.Errorf("decodeIdent: found '%s', expected '%s'", ident.Name, expected.Name)
	}
}

func TestExtractFirstKey(t *testing.T) {
	// test success
	buf := bytes.NewBufferString(`"expression_name": "IDENT"`)
	dec := newDecoder(buf)
	if val := dec.extractFirstKey("expression_name"); val != "IDENT" {
		t.Errorf("extractFirstKey 'expression_name': found '%s', expected 'IDENT'", val)
	}
	if dec.err != nil {
		t.Error(dec.err)
	}

	// test failure

	buf = bytes.NewBufferString(``)
	dec = newDecoder(buf)
	expectedErr := errors.New("unexpected EOF")
	_ = dec.extractFirstKey("expression_name")
	if dec.err.Error() != expectedErr.Error() {
		t.Errorf("extractFirstKey 'expression_name': found error \"%v\", expected error \"%v\"",
			dec.err, expectedErr)
	}

	buf = bytes.NewBufferString(`"foo": "bar"`)
	dec = newDecoder(buf)
	expectedErr = errors.New("expected key to be 'expression_name', found 'foo'")
	_ = dec.extractFirstKey("expression_name")
	if dec.err.Error() != expectedErr.Error() {
		t.Errorf("extractFirstKey 'expression_name': found error \"%v\", expected error \"%v\"",
			dec.err, expectedErr)
	}

	buf = bytes.NewBufferString(`"expression_name": 42}`)
	dec = newDecoder(buf)
	expectedErr = errors.New("expected 'string literal', found 'integer literal'")
	_ = dec.extractFirstKey("expression_name")
	if dec.err.Error() != expectedErr.Error() {
		t.Errorf("extractFirstKey 'expression_name': found error \"%v\", expected error \"%v\"",
			dec.err, expectedErr)
	}
}

func TestUnmarshalString(t *testing.T) {
	dec := newDecoder(new(bytes.Buffer))
	if str, err := dec.unmarshalString([]byte("foo")); err != nil {
		t.Error(err)
	} else if str != "foo" {
		t.Errorf("unmarshalString 'foo': found '%s', expected 'foo'", str)
	}

	expectedErr := errors.New("unable to unmarshal string: data is nil")
	if _, err := dec.unmarshalString(nil); err == nil {
		t.Errorf("unmarshalString nil: found no error, expected \"%v\"", expectedErr)
	} else if err.Error() != expectedErr.Error() {
		t.Errorf("unmarshalString nil: found error \"%v\", expected \"%v\"", err, expectedErr)
	}
}

func TestUnmarshalInt64(t *testing.T) {
	dec := newDecoder(new(bytes.Buffer))
	if num, err := dec.unmarshalInt64([]byte("42")); err != nil {
		t.Error(err)
	} else if num != 42 {
		t.Errorf("unmarshalInt64 '42': found %d, expected 42", num)
	}
}

func TestUnmarshalFloat64(t *testing.T) {
	dec := newDecoder(new(bytes.Buffer))
	if num, err := dec.unmarshalFloat64([]byte("42.42")); err != nil {
		t.Error(err)
	} else if num-42.42 > 0.0001 {
		t.Errorf("unmarshalFloat64 '42.42': found %f, expected 42.42", num)
	}
}

func TestUnmarshalBool(t *testing.T) {
	dec := newDecoder(new(bytes.Buffer))
	if num, err := dec.unmarshalBool([]byte("true")); err != nil {
		t.Error(err)
	} else if !num {
		t.Error("unmarshalBool 'true': found 'false', expected 'true'")
	}

	dec = newDecoder(new(bytes.Buffer))
	if num, err := dec.unmarshalBool([]byte("false")); err != nil {
		t.Error(err)
	} else if num {
		t.Error("unmarshalBool 'false': found 'true', expected 'false'")
	}

	expectedErr := errors.New("unable to unmarshal boolean: value 'none' is not a boolean")
	dec = newDecoder(new(bytes.Buffer))
	if num, err := dec.unmarshalBool([]byte("none")); err == nil {
		t.Errorf("unmarshalBool 'none': found no error, expected \"%v\"", expectedErr)
	} else if err.Error() != expectedErr.Error() {
		t.Errorf("unmarshalBool 'none': found \"%v\", expected \"%v\"", err, expectedErr)
	} else if num {
		t.Error("unmarshalBool 'none': found 'true', expected 'false'")
	}
}

func TestAssertNewObject(t *testing.T) {
	type returnStatus struct {
		status bool
		err    error
	}
	input := map[string]returnStatus{
		"{": returnStatus{true, nil},
		"":  returnStatus{false, errors.New("expected value, found EOF")},
		"[": returnStatus{false, errors.New("expected object, found '['")},
	}

	for in, ret := range input {
		buf := bytes.NewBufferString(in)
		dec := newDecoder(buf)
		if status := dec.assertNewObject(); status != ret.status {
			t.Errorf("assertNewObject '%s': found %v, expected %v", in, status, ret.status)
		}
		if err := dec.err; err != nil && err.Error() != ret.err.Error() {
			t.Errorf("assertNewObject '%s': found error \"%v\", expected error \"%v\"", in, dec.err, ret.err)
		}
	}
}

func TestAssertNewArray(t *testing.T) {
	type returnStatus struct {
		status bool
		err    error
	}
	input := map[string]returnStatus{
		"[": returnStatus{true, nil},
		"":  returnStatus{false, errors.New("expected value, found EOF")},
		"{": returnStatus{false, errors.New("expected array, found '{'")},
	}

	for in, ret := range input {
		buf := bytes.NewBufferString(in)
		dec := newDecoder(buf)
		if status := dec.assertNewArray(); status != ret.status {
			t.Errorf("assertNewArray '%s': found %v, expected %v", in, status, ret.status)
		}
		if err := dec.err; err != nil && err.Error() != ret.err.Error() {
			t.Errorf("assertNewArray '%s': found error \"%v\", expected error \"%v\"", in, dec.err, ret.err)
		}
	}
}

func TestIsEndObject(t *testing.T) {
	type returnStatus struct {
		status bool
		err    error
	}
	input := map[string]returnStatus{
		"}":   returnStatus{true, nil},
		",":   returnStatus{false, nil},
		"42}": returnStatus{false, errors.New("expected 'comma', found 'integer literal'")},
	}

	for in, ret := range input {
		buf := bytes.NewBufferString(in)
		dec := newDecoder(buf)
		if status := dec.isEndObject(); status != ret.status {
			t.Errorf("isEndObject '%s': found %v, expected %v", in, status, ret.status)
		}
		if err := dec.err; err != nil && err.Error() != ret.err.Error() {
			t.Errorf("isEndObject '%s': found error \"%v\", expected error \"%v\"", in, dec.err, ret.err)
		}
	}
}

func TestIsEndArray(t *testing.T) {
	type returnStatus struct {
		status bool
		err    error
	}
	input := map[string]returnStatus{
		"]":   returnStatus{true, nil},
		",":   returnStatus{false, nil},
		"42}": returnStatus{false, errors.New("expected 'comma', found 'integer literal'")},
	}

	for in, ret := range input {
		buf := bytes.NewBufferString(in)
		dec := newDecoder(buf)
		if status := dec.isEndArray(); status != ret.status {
			t.Errorf("isEndArray '%s': found %v, expected %v", in, status, ret.status)
		}
		if err := dec.err; err != nil && err.Error() != ret.err.Error() {
			t.Errorf("isEndArray '%s': found error \"%v\", expected error \"%v\"", in, dec.err, ret.err)
		}
	}
}

func TestIsEmptyObject(t *testing.T) {
	type returnStatus struct {
		status bool
		err    error
	}
	input := map[string]returnStatus{
		"}":        returnStatus{true, nil},
		"":         returnStatus{false, errors.New("unexpected EOF")},
		"\"foo\":": returnStatus{false, nil},
	}

	for in, ret := range input {
		buf := bytes.NewBufferString(in)
		dec := newDecoder(buf)
		if status := dec.isEmptyObject(); status != ret.status {
			t.Errorf("isEmptyObject '%s': found %v, expected %v", in, status, ret.status)
		}
		if err := dec.err; err != nil && err.Error() != ret.err.Error() {
			t.Errorf("isEmptyObject '%s': found error \"%v\", expected error \"%v\"", in, dec.err, ret.err)
		}
	}
}

func TestIsEmptyArray(t *testing.T) {
	type returnStatus struct {
		status bool
		err    error
	}
	input := map[string]returnStatus{
		"]":  returnStatus{true, nil},
		"":   returnStatus{false, errors.New("unexpected EOF")},
		"42": returnStatus{false, nil},
	}

	for in, ret := range input {
		buf := bytes.NewBufferString(in)
		dec := newDecoder(buf)
		if status := dec.isEmptyArray(); status != ret.status {
			t.Errorf("isEmptyArray '%s': found %v, expected %v", in, status, ret.status)
		}
		if err := dec.err; err != nil && err.Error() != ret.err.Error() {
			t.Errorf("isEmptyArray '%s': found error \"%v\", expected error \"%v\"", in, dec.err, ret.err)
		}
	}
}

func TestIsNull(t *testing.T) {
	input := map[string]bool{
		"null":  true,
		"nan":   false,
		`"foo"`: false,
	}

	for in, expected := range input {
		buf := bytes.NewBufferString(in)
		dec := newDecoder(buf)
		if b := dec.isNull(); b != expected {
			t.Errorf("isNull '%s': found '%v', expected '%v'", in, b, expected)
		}
	}
}

func compareLanguages(t *testing.T, found, expected *Language) {
	if found == nil {
		t.Fatal("decodeLanguage: should not be nil")
	}

	if expected.Lang != found.Lang {
		t.Errorf("decodeLanguage.Lang: found '%s', expected '%s'", found.Lang, expected.Lang)
	}
	if !stringsSlicesEquals(expected.Paradigms, found.Paradigms) {
		t.Errorf("decodeLanguage.Paradigms: found '%v', expected '%v'", found.Paradigms, expected.Paradigms)
	}
}

func stringsSlicesEquals(sl1, sl2 []string) bool {
	if len(sl1) != len(sl2) {
		return false
	}
	for i := 0; i < len(sl1); i++ {
		if sl1[i] != sl2[i] {
			return false
		}
	}
	return true
}
<|endoftext|>


<commit_before>// Copyright 2021 Google LLC
//
// 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 topo

import (
	"context"
	"fmt"
	"io/ioutil"
	"sync"

	"github.com/kr/pretty"
	log "github.com/sirupsen/logrus"
	"google.golang.org/protobuf/encoding/prototext"
	"google.golang.org/protobuf/proto"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"

	topologyclientv1 "github.com/google/kne/api/clientset/v1beta1"
	topologyv1 "github.com/google/kne/api/types/v1beta1"
	topopb "github.com/google/kne/proto/topo"
	"github.com/google/kne/topo/node"

	_ "github.com/google/kne/topo/node/ceos"
	_ "github.com/google/kne/topo/node/csr"
	_ "github.com/google/kne/topo/node/cxr"
	_ "github.com/google/kne/topo/node/frr"
	_ "github.com/google/kne/topo/node/host"
	_ "github.com/google/kne/topo/node/ixia"
	_ "github.com/google/kne/topo/node/quagga"
	_ "github.com/google/kne/topo/node/vmx"
)

// Manager is a topology instance manager for k8s cluster instance.
type Manager struct {
	kClient kubernetes.Interface
	tClient topologyclientv1.Interface
	rCfg    *rest.Config
	tpb     *topopb.Topology
	nodes   map[string]*node.Node
	links   map[string]*node.Link
}

// New creates a new topology manager based on the provided kubecfg and topology.
func New(kubecfg string, tpb *topopb.Topology) (*Manager, error) {
	log.Infof("Creating manager for: %s", tpb.Name)
	// use the current context in kubeconfig try in-cluster first if not fallback to kubeconfig
	log.Infof("Trying in-cluster configuration")
	rCfg, err := rest.InClusterConfig()
	if err != nil {
		log.Infof("Falling back to kubeconfig: %q", kubecfg)
		rCfg, err = clientcmd.BuildConfigFromFlags("", kubecfg)
		if err != nil {
			return nil, err
		}
	}
	// create the clientset
	kClient, err := kubernetes.NewForConfig(rCfg)
	if err != nil {
		return nil, err
	}
	tClient, err := topologyclientv1.NewForConfig(rCfg)
	if err != nil {
		return nil, err
	}

	return &Manager{
		kClient: kClient,
		tClient: tClient,
		rCfg:    rCfg,
		tpb:     tpb,
		nodes:   map[string]*node.Node{},
		links:   map[string]*node.Link{},
	}, nil
}

// Load creates an instance of the managed topology.
func (m *Manager) Load(ctx context.Context) error {
	for _, n := range m.tpb.Nodes {
		log.Infof("Adding Node: %s:%s", n.Name, n.Type)
		nn, err := node.New(m.tpb.Name, n, m.kClient, m.rCfg)
		if err != nil {
			return fmt.Errorf("failed to load topology: %w", err)
		}
		m.nodes[n.Name] = nn
	}
	uid := 0
	for _, l := range m.tpb.Links {
		log.Infof("Adding Link: %s:%s %s:%s", l.ANode, l.AInt, l.ZNode, l.ZInt)
		sNode, ok := m.nodes[l.ANode]
		if !ok {
			return fmt.Errorf("invalid topology: missing node %q", l.ANode)
		}
		dNode, ok := m.nodes[l.ZNode]
		if !ok {
			return fmt.Errorf("invalid topology: missing node %q", l.ZNode)
		}
		if _, ok := sNode.Interfaces[l.AInt]; ok {
			return fmt.Errorf("interface %s:%s already connected", l.ANode, l.AInt)
		}
		if _, ok := dNode.Interfaces[l.ZInt]; ok {
			return fmt.Errorf("interface %s:%s already connected", l.ZNode, l.ZInt)
		}
		link := &node.Link{
			UID:   uid,
			Proto: l,
		}
		sNode.Interfaces[l.AInt] = link
		dl := proto.Clone(l).(*topopb.Link)
		dl.AInt, dl.ZInt = dl.ZInt, dl.AInt
		dl.ANode, dl.ZNode = dl.ZNode, dl.ANode
		dLink := &node.Link{
			UID:   uid,
			Proto: dl,
		}
		dNode.Interfaces[l.ZInt] = dLink
		uid++
	}
	return nil
}

// Pods gets all pods in the managed k8s cluster.
func (m *Manager) Pods(ctx context.Context) error {
	pods, err := m.kClient.CoreV1().Pods(m.tpb.Name).List(ctx, metav1.ListOptions{})
	if err != nil {
		return err
	}
	for _, p := range pods.Items {
		fmt.Println(p.Namespace, p.Name)
	}
	return nil
}

// Topology gets the topology CRDs for the cluster.
func (m *Manager) Topology(ctx context.Context) ([]topologyv1.Topology, error) {
	topology, err := m.tClient.Topology(m.tpb.Name).List(ctx, metav1.ListOptions{})
	if err != nil {
		return nil, fmt.Errorf("failed to get topology CRDs: %v", err)
	}
	return topology.Items, nil
}

// Push pushes the current topology to k8s.
func (m *Manager) Push(ctx context.Context) error {
	if _, err := m.kClient.CoreV1().Namespaces().Get(ctx, m.tpb.Name, metav1.GetOptions{}); err != nil {
		log.Infof("Creating namespace for topology: %q", m.tpb.Name)
		ns := &corev1.Namespace{
			ObjectMeta: metav1.ObjectMeta{
				Name: m.tpb.Name,
			},
		}
		sNs, err := m.kClient.CoreV1().Namespaces().Create(ctx, ns, metav1.CreateOptions{})
		if err != nil {
			return err
		}
		log.Infof("Server Namespace: %+v", sNs)
	}

	log.Infof("Pushing Topology to k8s: %q", m.tpb.Name)
	for _, n := range m.nodes {
		t := &topologyv1.Topology{
			ObjectMeta: metav1.ObjectMeta{
				Name: n.Name(),
			},
			Spec: topologyv1.TopologySpec{},
		}
		var links []topologyv1.Link
		for _, intf := range n.Interfaces {
			link := topologyv1.Link{
				LocalIntf: intf.Proto.AInt,
				LocalIP:   "",
				PeerIntf:  intf.Proto.ZInt,
				PeerIP:    "",
				PeerPod:   intf.Proto.ZNode,
				UID:       intf.UID,
			}
			links = append(links, link)
		}
		t.Spec.Links = links
		sT, err := m.tClient.Topology(m.tpb.Name).Create(ctx, t)
		if err != nil {
			return err
		}
		log.Infof("Topology:\n%+v\n", sT)
	}
	log.Infof("Creating Node Pods")
	for k, n := range m.nodes {
		if err := n.Configure(ctx); err != nil {
			return err
		}
		if err := n.CreateService(ctx); err != nil {
			return err
		}
		if err := n.CreateResource(ctx); err != nil {
			return err
		}
		log.Infof("Node %q resource created", k)
	}
	return nil
}

// Delete deletes the topology from k8s.
func (m *Manager) Delete(ctx context.Context) error {
	if _, err := m.kClient.CoreV1().Namespaces().Get(ctx, m.tpb.Name, metav1.GetOptions{}); err != nil {
		return fmt.Errorf("topology %q does not exist in cluster", m.tpb.Name)
	}
	// Delete topology pods
	for _, n := range m.nodes {
		// Delete Service for node
		n.DeleteService(ctx)
		// Delete config maps for node
		n.Delete(ctx)
		// Delete Resource for node
		n.DeleteResource(ctx)
		// Delete Topology for node
		if err := m.tClient.Topology(m.tpb.Name).Delete(ctx, n.Name(), metav1.DeleteOptions{}); err != nil {
			log.Warnf("Error deleting topology %q: %v", n.Name(), err)
		}
	}
	// Delete namespace
	prop := metav1.DeletePropagationForeground
	if err := m.kClient.CoreV1().Namespaces().Delete(ctx, m.tpb.Name, metav1.DeleteOptions{
		PropagationPolicy: &prop,
	}); err != nil {
		return err
	}
	return nil
}

// Load loads a Topology from fName.
func Load(fName string) (*topopb.Topology, error) {
	b, err := ioutil.ReadFile(fName)
	if err != nil {
		return nil, err
	}
	t := &topopb.Topology{}
	if err := prototext.Unmarshal(b, t); err != nil {
		return nil, err
	}
	return t, nil
}

type Resources struct {
	Services   map[string]*corev1.Service
	Pods       map[string]*corev1.Pod
	ConfigMaps map[string]*corev1.ConfigMap
	Topologies map[string]*topologyv1.Topology
}

// Resources gets the currently configured resources from the topology.
func (m *Manager) Resources(ctx context.Context) (*Resources, error) {
	r := Resources{
		Services:   map[string]*corev1.Service{},
		Pods:       map[string]*corev1.Pod{},
		ConfigMaps: map[string]*corev1.ConfigMap{},
		Topologies: map[string]*topologyv1.Topology{},
	}
	for _, n := range m.nodes {
		p, err := n.Pod(ctx)
		if err != nil {
			return nil, err
		}
		r.Pods[p.Name] = p
	}
	tList, err := m.Topology(ctx)
	if err != nil {
		return nil, err
	}
	for _, t := range tList {
		v := t
		r.Topologies[v.Name] = &v
	}
	return &r, nil
}

func (m *Manager) Watch(ctx context.Context) error {
	watcher, err := m.tClient.Topology(m.tpb.Name).Watch(ctx, metav1.ListOptions{})
	if err != nil {
		return err
	}
	ch := watcher.ResultChan()
	for e := range ch {
		fmt.Println(e.Type)
		pretty.Print(e.Object)
		fmt.Println("")
	}
	return nil
}

var (
	muPort   sync.Mutex
	nextPort uint32 = 30001
)

func GetNextPort() uint32 {
	muPort.Lock()
	p := nextPort
	nextPort++
	muPort.Unlock()
	return p
}
<commit_msg>adding error checks in Delete path<commit_after>// Copyright 2021 Google LLC
//
// 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 topo

import (
	"context"
	"fmt"
	"io/ioutil"
	"sync"

	"github.com/kr/pretty"
	log "github.com/sirupsen/logrus"
	"google.golang.org/protobuf/encoding/prototext"
	"google.golang.org/protobuf/proto"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"

	topologyclientv1 "github.com/google/kne/api/clientset/v1beta1"
	topologyv1 "github.com/google/kne/api/types/v1beta1"
	topopb "github.com/google/kne/proto/topo"
	"github.com/google/kne/topo/node"

	_ "github.com/google/kne/topo/node/ceos"
	_ "github.com/google/kne/topo/node/csr"
	_ "github.com/google/kne/topo/node/cxr"
	_ "github.com/google/kne/topo/node/frr"
	_ "github.com/google/kne/topo/node/host"
	_ "github.com/google/kne/topo/node/ixia"
	_ "github.com/google/kne/topo/node/quagga"
	_ "github.com/google/kne/topo/node/vmx"
)

// Manager is a topology instance manager for k8s cluster instance.
type Manager struct {
	kClient kubernetes.Interface
	tClient topologyclientv1.Interface
	rCfg    *rest.Config
	tpb     *topopb.Topology
	nodes   map[string]*node.Node
	links   map[string]*node.Link
}

// New creates a new topology manager based on the provided kubecfg and topology.
func New(kubecfg string, tpb *topopb.Topology) (*Manager, error) {
	log.Infof("Creating manager for: %s", tpb.Name)
	// use the current context in kubeconfig try in-cluster first if not fallback to kubeconfig
	log.Infof("Trying in-cluster configuration")
	rCfg, err := rest.InClusterConfig()
	if err != nil {
		log.Infof("Falling back to kubeconfig: %q", kubecfg)
		rCfg, err = clientcmd.BuildConfigFromFlags("", kubecfg)
		if err != nil {
			return nil, err
		}
	}
	// create the clientset
	kClient, err := kubernetes.NewForConfig(rCfg)
	if err != nil {
		return nil, err
	}
	tClient, err := topologyclientv1.NewForConfig(rCfg)
	if err != nil {
		return nil, err
	}

	return &Manager{
		kClient: kClient,
		tClient: tClient,
		rCfg:    rCfg,
		tpb:     tpb,
		nodes:   map[string]*node.Node{},
		links:   map[string]*node.Link{},
	}, nil
}

// Load creates an instance of the managed topology.
func (m *Manager) Load(ctx context.Context) error {
	for _, n := range m.tpb.Nodes {
		log.Infof("Adding Node: %s:%s", n.Name, n.Type)
		nn, err := node.New(m.tpb.Name, n, m.kClient, m.rCfg)
		if err != nil {
			return fmt.Errorf("failed to load topology: %w", err)
		}
		m.nodes[n.Name] = nn
	}
	uid := 0
	for _, l := range m.tpb.Links {
		log.Infof("Adding Link: %s:%s %s:%s", l.ANode, l.AInt, l.ZNode, l.ZInt)
		sNode, ok := m.nodes[l.ANode]
		if !ok {
			return fmt.Errorf("invalid topology: missing node %q", l.ANode)
		}
		dNode, ok := m.nodes[l.ZNode]
		if !ok {
			return fmt.Errorf("invalid topology: missing node %q", l.ZNode)
		}
		if _, ok := sNode.Interfaces[l.AInt]; ok {
			return fmt.Errorf("interface %s:%s already connected", l.ANode, l.AInt)
		}
		if _, ok := dNode.Interfaces[l.ZInt]; ok {
			return fmt.Errorf("interface %s:%s already connected", l.ZNode, l.ZInt)
		}
		link := &node.Link{
			UID:   uid,
			Proto: l,
		}
		sNode.Interfaces[l.AInt] = link
		dl := proto.Clone(l).(*topopb.Link)
		dl.AInt, dl.ZInt = dl.ZInt, dl.AInt
		dl.ANode, dl.ZNode = dl.ZNode, dl.ANode
		dLink := &node.Link{
			UID:   uid,
			Proto: dl,
		}
		dNode.Interfaces[l.ZInt] = dLink
		uid++
	}
	return nil
}

// Pods gets all pods in the managed k8s cluster.
func (m *Manager) Pods(ctx context.Context) error {
	pods, err := m.kClient.CoreV1().Pods(m.tpb.Name).List(ctx, metav1.ListOptions{})
	if err != nil {
		return err
	}
	for _, p := range pods.Items {
		fmt.Println(p.Namespace, p.Name)
	}
	return nil
}

// Topology gets the topology CRDs for the cluster.
func (m *Manager) Topology(ctx context.Context) ([]topologyv1.Topology, error) {
	topology, err := m.tClient.Topology(m.tpb.Name).List(ctx, metav1.ListOptions{})
	if err != nil {
		return nil, fmt.Errorf("failed to get topology CRDs: %v", err)
	}
	return topology.Items, nil
}

// Push pushes the current topology to k8s.
func (m *Manager) Push(ctx context.Context) error {
	if _, err := m.kClient.CoreV1().Namespaces().Get(ctx, m.tpb.Name, metav1.GetOptions{}); err != nil {
		log.Infof("Creating namespace for topology: %q", m.tpb.Name)
		ns := &corev1.Namespace{
			ObjectMeta: metav1.ObjectMeta{
				Name: m.tpb.Name,
			},
		}
		sNs, err := m.kClient.CoreV1().Namespaces().Create(ctx, ns, metav1.CreateOptions{})
		if err != nil {
			return err
		}
		log.Infof("Server Namespace: %+v", sNs)
	}

	log.Infof("Pushing Topology to k8s: %q", m.tpb.Name)
	for _, n := range m.nodes {
		t := &topologyv1.Topology{
			ObjectMeta: metav1.ObjectMeta{
				Name: n.Name(),
			},
			Spec: topologyv1.TopologySpec{},
		}
		var links []topologyv1.Link
		for _, intf := range n.Interfaces {
			link := topologyv1.Link{
				LocalIntf: intf.Proto.AInt,
				LocalIP:   "",
				PeerIntf:  intf.Proto.ZInt,
				PeerIP:    "",
				PeerPod:   intf.Proto.ZNode,
				UID:       intf.UID,
			}
			links = append(links, link)
		}
		t.Spec.Links = links
		sT, err := m.tClient.Topology(m.tpb.Name).Create(ctx, t)
		if err != nil {
			return err
		}
		log.Infof("Topology:\n%+v\n", sT)
	}
	log.Infof("Creating Node Pods")
	for k, n := range m.nodes {
		if err := n.Configure(ctx); err != nil {
			return err
		}
		if err := n.CreateService(ctx); err != nil {
			return err
		}
		if err := n.CreateResource(ctx); err != nil {
			return err
		}
		log.Infof("Node %q resource created", k)
	}
	return nil
}

// Delete deletes the topology from k8s.
func (m *Manager) Delete(ctx context.Context) error {
	if _, err := m.kClient.CoreV1().Namespaces().Get(ctx, m.tpb.Name, metav1.GetOptions{}); err != nil {
		return fmt.Errorf("topology %q does not exist in cluster", m.tpb.Name)
	}

	// Delete topology pods
	for _, n := range m.nodes {
		// Delete Service for node
		if err := n.DeleteService(ctx); err != nil {
			log.Warnf("Error deleting service %q: %v", n.Name(), err)
		}
		// Delete config maps for node
		if err := n.Delete(ctx); err != nil {
			log.Warnf("Error deleting configmaps %q: %v", n.Name(), err)
		}
		// Delete Resource for node
		if err := n.DeleteResource(ctx); err != nil {
			log.Warnf("Error deleting resource %q: %v", n.Name(), err)
		}
		// Delete Topology for node
		if err := m.tClient.Topology(m.tpb.Name).Delete(ctx, n.Name(), metav1.DeleteOptions{}); err != nil {
			log.Warnf("Error deleting topology %q: %v", n.Name(), err)
		}
	}
	// Delete namespace
	prop := metav1.DeletePropagationForeground
	if err := m.kClient.CoreV1().Namespaces().Delete(ctx, m.tpb.Name, metav1.DeleteOptions{
		PropagationPolicy: &prop,
	}); err != nil {
		return err
	}
	return nil
}

// Load loads a Topology from fName.
func Load(fName string) (*topopb.Topology, error) {
	b, err := ioutil.ReadFile(fName)
	if err != nil {
		return nil, err
	}
	t := &topopb.Topology{}
	if err := prototext.Unmarshal(b, t); err != nil {
		return nil, err
	}
	return t, nil
}

type Resources struct {
	Services   map[string]*corev1.Service
	Pods       map[string]*corev1.Pod
	ConfigMaps map[string]*corev1.ConfigMap
	Topologies map[string]*topologyv1.Topology
}

// Resources gets the currently configured resources from the topology.
func (m *Manager) Resources(ctx context.Context) (*Resources, error) {
	r := Resources{
		Services:   map[string]*corev1.Service{},
		Pods:       map[string]*corev1.Pod{},
		ConfigMaps: map[string]*corev1.ConfigMap{},
		Topologies: map[string]*topologyv1.Topology{},
	}
	for _, n := range m.nodes {
		p, err := n.Pod(ctx)
		if err != nil {
			return nil, err
		}
		r.Pods[p.Name] = p
	}
	tList, err := m.Topology(ctx)
	if err != nil {
		return nil, err
	}
	for _, t := range tList {
		v := t
		r.Topologies[v.Name] = &v
	}
	return &r, nil
}

func (m *Manager) Watch(ctx context.Context) error {
	watcher, err := m.tClient.Topology(m.tpb.Name).Watch(ctx, metav1.ListOptions{})
	if err != nil {
		return err
	}
	ch := watcher.ResultChan()
	for e := range ch {
		fmt.Println(e.Type)
		pretty.Print(e.Object)
		fmt.Println("")
	}
	return nil
}

var (
	muPort   sync.Mutex
	nextPort uint32 = 30001
)

func GetNextPort() uint32 {
	muPort.Lock()
	p := nextPort
	nextPort++
	muPort.Unlock()
	return p
}
<|endoftext|>


<commit_before>package totp

import (
	"bytes"
	"crypto/hmac"
	"encoding/binary"
	"errors"
	"fmt"
	"hash"
)

var step int64 = 30
var epoch int64 = 0

func Totp(k []byte, t int64, h func() hash.Hash, l int64) (string, error) {

	if l > 9 || l < 1 {
		return "", errors.New("Totp: Length out of range.")
	}

	time := new(bytes.Buffer)

	err := binary.Write(time, binary.BigEndian, (t-epoch)/step)
	if err != nil {
		return "", err
	}

	hash := hmac.New(h, k)
	hash.Write(time.Bytes())
	v := hash.Sum(nil)

	o := v[len(v)-1] & 0xf
	c := (int32(v[o]&0x7f)<<24 | int32(v[o+1])<<16 | int32(v[o+2])<<8 | int32(v[o+3])) % 1000000000

	return fmt.Sprintf("%010d", c)[10-l : 10], nil
}
<commit_msg>add app to generate codes from stdin.<commit_after>package totp

import (
	"bytes"
	"crypto/hmac"
	"encoding/binary"
	"errors"
	"fmt"
	"hash"
)

var step int64 = 30
var epoch int64 = 0

func Totp(k []byte, t int64, h func() hash.Hash, l int64) (string, error) {

	if l > 9 || l < 1 {
		return "", errors.New("Totp: Length out of range.")
	}

	time := new(bytes.Buffer)

	err := binary.Write(time, binary.BigEndian, (t-epoch)/step)
	if err != nil {
		return "", err
	}

	// fmt.Printf("TIME Hex: %x\n", time.Bytes())

	hash := hmac.New(h, k)
	hash.Write(time.Bytes())
	v := hash.Sum(nil)

	// fmt.Printf("HMAC: %x\n", v)

	o := v[len(v)-1] & 0xf
	c := (int32(v[o]&0x7f)<<24 | int32(v[o+1])<<16 | int32(v[o+2])<<8 | int32(v[o+3])) % 1000000000

	return fmt.Sprintf("%010d", c)[10-l : 10], nil
}
<|endoftext|>


<commit_before>// Copyright 2017 The Cockroach Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License. See the AUTHORS file
// for names of contributors.
//
// Author: Arjun Narayan
//
// The TPC-H loader loads data generated by the TPC DBGen utility (currently
// version 2.17.0) into Cockroach.

package main

import (
	"bufio"
	"database/sql"
	"fmt"
	"os"
	"strings"

	"github.com/cockroachdb/cockroach-go/crdb"
	"github.com/pkg/errors"
)

func doInserts(db *sql.DB, preamble string, inserts []string) error {
	return crdb.ExecuteTx(db, func(*sql.Tx) error {
		allInserts := strings.Join(inserts, ", ")
		_, inErr := db.Exec(fmt.Sprintf("%s%s", preamble, allInserts))
		return inErr
	})
}

func insertTableFromFile(db *sql.DB, filename string, tableType table) error {
	if *verbose {
		fmt.Printf("Inserting table from file: %s\n", filename)
	}
	file, err := os.Open(filename)
	if err != nil {
		return err
	}
	defer func() {
		if err := file.Close(); err != nil {
			fmt.Printf("Error encountered when closing file '%s'\n: %s", filename, err)
		}
	}()

	scanner := bufio.NewScanner(file)
	var queuedInserts, numTotalInserts uint
	inserts := make([]string, *insertsPerTransaction)

	var insertPreamble, insertValues string
	switch tableType {
	case nation:
		insertPreamble = `INSERT INTO nation (n_nationkey, n_name, n_regionkey, n_comment) VALUES`
		insertValues = `(%s, '%s', %s, '%s')`
	case region:
		insertPreamble = `INSERT INTO region (r_regionkey, r_name, r_comment) VALUES`
		insertValues = ` (%s, '%s', '%s')`
	case part:
		insertPreamble = `INSERT INTO part (p_partkey, p_name, p_mfgr, p_brand, p_type,
                                            p_size, p_container, p_retailprice, p_comment) VALUES`
		insertValues = ` (%s, '%s', '%s', '%s', '%s', %s, '%s', %s, '%s')`
	case supplier:
		insertPreamble = `INSERT INTO supplier (s_suppkey, s_name, s_address, s_nationkey,
                                                s_phone, s_acctbal, s_comment) VALUES`
		insertValues = ` (%s, '%s', '%s', %s, '%s', %s, '%s')`
	case partsupp:
		insertPreamble = `INSERT INTO partsupp (ps_partkey, ps_suppkey, ps_availqty,
                                                ps_supplycost, ps_comment) VALUES`
		insertValues = ` (%s, %s, %s, %s, '%s')`
	case customer:
		insertPreamble = `INSERT INTO customer (c_custkey, c_name, c_address, c_nationkey,
                                                c_phone, c_acctbal, c_mktsegment, c_comment) VALUES`
		insertValues = ` (%s, '%s', '%s', %s, '%s', %s, '%s', '%s')`
	case orders:
		insertPreamble = `INSERT INTO orders (o_orderkey, o_custkey, o_orderstatus, o_totalprice,
                                              o_orderdate, o_orderpriority, o_clerk,
                                              o_shippriority, o_comment) VALUES`
		insertValues = ` (%s, %s, '%s', %s, '%s', '%s', '%s', %s, '%s')`
	case lineitem:
		insertPreamble = `INSERT INTO lineitem
                    (l_orderkey, l_partkey, l_suppkey, l_linenumber,
                     l_quantity, l_extendedprice, l_discount, l_tax,
                     l_returnflag, l_linestatus, l_shipdate, l_commitdate,
                     l_receiptdate, l_shipinstruct, l_shipmode, l_comment) VALUES`
		insertValues = ` (%s, %s, %s, %s, %s, %s, %s, %s,
                      '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s')`
	default:
		return errors.Errorf("Unknown table type: %d", tableType)

	}

	for scanner.Scan() {
		if queuedInserts == *insertsPerTransaction {
			if err := doInserts(db, insertPreamble, inserts); err != nil {
				return err
			}
			numTotalInserts += queuedInserts
			fmt.Printf("Inserts for table %2d:     %8d\n", tableType, numTotalInserts)
			queuedInserts = 0
			inserts = make([]string, *insertsPerTransaction)
		}

		line := scanner.Text()
		splits := strings.Split(line, "|")
		fields := make([]interface{}, len(splits)-1)
		// Ignore the last index since dbgen uses '|' as a terminator, not a separator.
		for i := 0; i < (len(splits) - 1); i++ {
			fields[i] = splits[i]
		}

		inserts[queuedInserts] = fmt.Sprintf(insertValues, fields...)
		queuedInserts++
	}

	// Do any remaining inserts
	return doInserts(db, insertPreamble, inserts)
}
<commit_msg>tpch: clean up loader to be more idiomatic<commit_after>// Copyright 2017 The Cockroach Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License. See the AUTHORS file
// for names of contributors.
//
// Author: Arjun Narayan
//
// The TPC-H loader loads data generated by the TPC DBGen utility (currently
// version 2.17.0) into Cockroach.

package main

import (
	"bufio"
	"database/sql"
	"fmt"
	"os"
	"strings"

	"github.com/cockroachdb/cockroach-go/crdb"
	"github.com/pkg/errors"
)

func doInserts(db *sql.DB, preamble string, inserts []string) error {
	return crdb.ExecuteTx(db, func(*sql.Tx) error {
		allInserts := strings.Join(inserts, ", ")
		_, inErr := db.Exec(fmt.Sprintf("%s%s", preamble, allInserts))
		return inErr
	})
}

func insertTableFromFile(db *sql.DB, filename string, tableType table) error {
	if *verbose {
		fmt.Printf("Inserting table from file: %s\n", filename)
	}
	file, err := os.Open(filename)
	if err != nil {
		return err
	}
	defer func() {
		if err := file.Close(); err != nil {
			fmt.Printf("Error encountered when closing file '%s'\n: %s", filename, err)
		}
	}()

	scanner := bufio.NewScanner(file)
	var numTotalInserts uint
	inserts := make([]string, 0, *insertsPerTransaction)

	var insertPreamble, insertValues string
	switch tableType {
	case nation:
		insertPreamble = `INSERT INTO nation (n_nationkey, n_name, n_regionkey, n_comment) VALUES`
		insertValues = `(%s, '%s', %s, '%s')`
	case region:
		insertPreamble = `INSERT INTO region (r_regionkey, r_name, r_comment) VALUES`
		insertValues = ` (%s, '%s', '%s')`
	case part:
		insertPreamble = `INSERT INTO part (p_partkey, p_name, p_mfgr, p_brand, p_type,
                                            p_size, p_container, p_retailprice, p_comment) VALUES`
		insertValues = ` (%s, '%s', '%s', '%s', '%s', %s, '%s', %s, '%s')`
	case supplier:
		insertPreamble = `INSERT INTO supplier (s_suppkey, s_name, s_address, s_nationkey,
                                                s_phone, s_acctbal, s_comment) VALUES`
		insertValues = ` (%s, '%s', '%s', %s, '%s', %s, '%s')`
	case partsupp:
		insertPreamble = `INSERT INTO partsupp (ps_partkey, ps_suppkey, ps_availqty,
                                                ps_supplycost, ps_comment) VALUES`
		insertValues = ` (%s, %s, %s, %s, '%s')`
	case customer:
		insertPreamble = `INSERT INTO customer (c_custkey, c_name, c_address, c_nationkey,
                                                c_phone, c_acctbal, c_mktsegment, c_comment) VALUES`
		insertValues = ` (%s, '%s', '%s', %s, '%s', %s, '%s', '%s')`
	case orders:
		insertPreamble = `INSERT INTO orders (o_orderkey, o_custkey, o_orderstatus, o_totalprice,
                                              o_orderdate, o_orderpriority, o_clerk,
                                              o_shippriority, o_comment) VALUES`
		insertValues = ` (%s, %s, '%s', %s, '%s', '%s', '%s', %s, '%s')`
	case lineitem:
		insertPreamble = `INSERT INTO lineitem
                    (l_orderkey, l_partkey, l_suppkey, l_linenumber,
                     l_quantity, l_extendedprice, l_discount, l_tax,
                     l_returnflag, l_linestatus, l_shipdate, l_commitdate,
                     l_receiptdate, l_shipinstruct, l_shipmode, l_comment) VALUES`
		insertValues = ` (%s, %s, %s, %s, %s, %s, %s, %s,
                      '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s')`
	default:
		return errors.Errorf("Unknown table type: %d", tableType)

	}

	for scanner.Scan() {
		line := scanner.Text()
		splits := strings.Split(line, "|")
		fields := make([]interface{}, len(splits)-1)
		// Ignore the last index since dbgen uses '|' as a terminator, not a separator.
		for i := 0; i < (len(splits) - 1); i++ {
			fields[i] = splits[i]
		}

		inserts = append(inserts, fmt.Sprintf(insertValues, fields...))
		numTotalInserts++

		if numTotalInserts%(*insertsPerTransaction) == 0 {
			if err := doInserts(db, insertPreamble, inserts); err != nil {
				return err
			}
			fmt.Printf("Inserts for table %2d:     %8d\n", tableType, numTotalInserts)
			inserts = inserts[:0]
		}
	}

	// Do any remaining inserts
	if len(inserts) > 0 {
		return doInserts(db, insertPreamble, inserts)
	}
	return nil
}
<|endoftext|>


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

package oauth2

import (
	"net/http"
	"sync"
	"time"
)

const (
	defaultTokenType = "Bearer"
)

// Token represents the crendentials used to authorize
// the requests to access protected resources on the OAuth 2.0
// provider's backend.
type Token struct {
	// A token that authorizes and authenticates the requests.
	AccessToken string `json:"access_token"`

	// Identifies the type of token returned.
	TokenType string `json:"token_type,omitempty"`

	// A token that may be used to obtain a new access token.
	RefreshToken string `json:"refresh_token,omitempty"`

	// The remaining lifetime of the access token.
	Expiry time.Time `json:"expiry,omitempty"`

	Extra map[string]string `json:"extra,omitempty"`

	// JWT related fields
	Subject string `json:"subject,omitempty"`
}

// Expired returns true if there is no access token or the
// access token is expired.
func (t *Token) Expired() bool {
	if t.AccessToken == "" {
		return true
	}
	if t.Expiry.IsZero() {
		return false
	}
	return t.Expiry.Before(time.Now())
}

// Transport represents an authorized transport.
// Provides currently in-use user token and allows to set a token to
// be used. If token expires, it tries to fetch a new token,
// if possible. Token fetching is thread-safe. If two or more
// concurrent requests are being made with the same expired token,
// one of the requests will wait for the other to refresh
// the existing token.
type Transport interface {
	// Authenticates the request with the existing token. If token is
	// expired, tries to refresh/fetch a new token.
	// Makes the request by delegating it to the default transport.
	RoundTrip(*http.Request) (*http.Response, error)

	// Returns the token authenticates the transport.
	// This operation is thread-safe.
	Token() *Token

	// Sets a new token to authenticate the transport.
	// This operation is thread-safe.
	SetToken(token *Token)

	// Refreshes the token if refresh is possible (such as in the
	// presense of a refresh token). Returns an error if refresh is
	// not possible. Refresh is thread-safe.
	RefreshToken() error
}

type authorizedTransport struct {
	// Cache to persist changes to the token that
	// authorizes the current transport.
	cache   Cache
	fetcher TokenFetcher
	token   *Token

	// Mutex to protect token during auto refreshments.
	mu sync.RWMutex
}

// NewAuthorizedTransport creates a tranport that uses the provided
// token fetcher to retrieve new tokens if there is no access token
// provided or it is expired.
func NewAuthorizedTransport(fetcher TokenFetcher, token *Token) Transport {
	return &authorizedTransport{fetcher: fetcher, token: token}
}

func NewAuthorizedTransportWithCache(fetcher TokenFetcher, cache Cache) (transport Transport, err error) {
	var token *Token
	if token, err = cache.Read(); err != nil {
		return
	}
	transport = &authorizedTransport{fetcher: fetcher, cache: cache, token: token}
	return
}

// RoundTrip authorizes the request with the existing token.
// If token is expired, tries to refresh/fetch a new token.
func (t *authorizedTransport) RoundTrip(req *http.Request) (resp *http.Response, err error) {
	token := t.Token()

	if token == nil || token.Expired() {
		// Check if the token is refreshable.
		// If token is refreshable, don't return an error,
		// rather refresh.

		if err := t.RefreshToken(); err != nil {
			return nil, err
		}
		token = t.Token()
	}

	// To set the Authorization header, we must make a copy of the Request
	// so that we don't modify the Request we were given.
	// This is required by the specification of http.RoundTripper.
	req = cloneRequest(req)
	typ := token.TokenType
	if typ == "" {
		typ = defaultTokenType
	}

	req.Header.Set("Authorization", typ+" "+token.AccessToken)

	// Make the HTTP request.
	return DefaultTransport.RoundTrip(req)
}

// Token returns the existing token that authorizes the Transport.
func (t *authorizedTransport) Token() *Token {
	t.mu.RLock()
	defer t.mu.RUnlock()
	if t.token == nil {
		return nil
	}
	token := &Token{
		AccessToken:  t.token.AccessToken,
		TokenType:    t.token.TokenType,
		RefreshToken: t.token.RefreshToken,
		Expiry:       t.token.Expiry,
		Extra:        t.token.Extra,
		Subject:      t.token.Subject,
	}
	return token
}

// SetToken sets a token to the transport in a thread-safe way.
func (t *authorizedTransport) SetToken(token *Token) {
	t.mu.Lock()
	defer t.mu.Unlock()

	t.token = token
}

// RefreshToken retrieves a new token, if a refreshing/fetching
// method is known and required credentials are presented
// (such as a refresh token).
func (t *authorizedTransport) RefreshToken() error {
	t.mu.Lock()
	defer t.mu.Unlock()

	token, err := t.fetcher.FetchToken(t.token)
	if err != nil {
		return err
	}

	t.token = token
	if t.cache != nil {
		t.cache.Write(token)
	}

	return nil
}

// cloneRequest returns a clone of the provided *http.Request.
// The clone is a shallow copy of the struct and its Header map.
func cloneRequest(r *http.Request) *http.Request {
	// shallow copy of the struct
	r2 := new(http.Request)
	*r2 = *r
	// deep copy of the Header
	r2.Header = make(http.Header)
	for k, s := range r.Header {
		r2.Header[k] = s
	}
	return r2
}
<commit_msg>Add docs for NewAuthorizedTransportWithCache.<commit_after>// Copyright 2014 The oauth2 Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package oauth2

import (
	"net/http"
	"sync"
	"time"
)

const (
	defaultTokenType = "Bearer"
)

// Token represents the crendentials used to authorize
// the requests to access protected resources on the OAuth 2.0
// provider's backend.
type Token struct {
	// A token that authorizes and authenticates the requests.
	AccessToken string `json:"access_token"`

	// Identifies the type of token returned.
	TokenType string `json:"token_type,omitempty"`

	// A token that may be used to obtain a new access token.
	RefreshToken string `json:"refresh_token,omitempty"`

	// The remaining lifetime of the access token.
	Expiry time.Time `json:"expiry,omitempty"`

	Extra map[string]string `json:"extra,omitempty"`

	// JWT related fields
	Subject string `json:"subject,omitempty"`
}

// Expired returns true if there is no access token or the
// access token is expired.
func (t *Token) Expired() bool {
	if t.AccessToken == "" {
		return true
	}
	if t.Expiry.IsZero() {
		return false
	}
	return t.Expiry.Before(time.Now())
}

// Transport represents an authorized transport.
// Provides currently in-use user token and allows to set a token to
// be used. If token expires, it tries to fetch a new token,
// if possible. Token fetching is thread-safe. If two or more
// concurrent requests are being made with the same expired token,
// one of the requests will wait for the other to refresh
// the existing token.
type Transport interface {
	// Authenticates the request with the existing token. If token is
	// expired, tries to refresh/fetch a new token.
	// Makes the request by delegating it to the default transport.
	RoundTrip(*http.Request) (*http.Response, error)

	// Returns the token authenticates the transport.
	// This operation is thread-safe.
	Token() *Token

	// Sets a new token to authenticate the transport.
	// This operation is thread-safe.
	SetToken(token *Token)

	// Refreshes the token if refresh is possible (such as in the
	// presense of a refresh token). Returns an error if refresh is
	// not possible. Refresh is thread-safe.
	RefreshToken() error
}

type authorizedTransport struct {
	// Cache to persist changes to the token that
	// authorizes the current transport.
	cache   Cache
	fetcher TokenFetcher
	token   *Token

	// Mutex to protect token during auto refreshments.
	mu sync.RWMutex
}

// NewAuthorizedTransport creates a transport that uses the provided
// token fetcher to retrieve new tokens if there is no access token
// provided or it is expired.
func NewAuthorizedTransport(fetcher TokenFetcher, token *Token) Transport {
	return &authorizedTransport{fetcher: fetcher, token: token}
}

// NewAuthorizedTransportWithCache creates a new transport that uses
// the provided token fetcher and cache. Before constructing the new
// transport, it will try to read from the cache to see if there
// is an existing token.
func NewAuthorizedTransportWithCache(fetcher TokenFetcher, cache Cache) (transport Transport, err error) {
	var token *Token
	if token, err = cache.Read(); err != nil {
		return
	}
	transport = &authorizedTransport{fetcher: fetcher, cache: cache, token: token}
	return
}

// RoundTrip authorizes the request with the existing token.
// If token is expired, tries to refresh/fetch a new token.
func (t *authorizedTransport) RoundTrip(req *http.Request) (resp *http.Response, err error) {
	token := t.Token()

	if token == nil || token.Expired() {
		// Check if the token is refreshable.
		// If token is refreshable, don't return an error,
		// rather refresh.

		if err := t.RefreshToken(); err != nil {
			return nil, err
		}
		token = t.Token()
	}

	// To set the Authorization header, we must make a copy of the Request
	// so that we don't modify the Request we were given.
	// This is required by the specification of http.RoundTripper.
	req = cloneRequest(req)
	typ := token.TokenType
	if typ == "" {
		typ = defaultTokenType
	}

	req.Header.Set("Authorization", typ+" "+token.AccessToken)

	// Make the HTTP request.
	return DefaultTransport.RoundTrip(req)
}

// Token returns the existing token that authorizes the Transport.
func (t *authorizedTransport) Token() *Token {
	t.mu.RLock()
	defer t.mu.RUnlock()
	if t.token == nil {
		return nil
	}
	token := &Token{
		AccessToken:  t.token.AccessToken,
		TokenType:    t.token.TokenType,
		RefreshToken: t.token.RefreshToken,
		Expiry:       t.token.Expiry,
		Extra:        t.token.Extra,
		Subject:      t.token.Subject,
	}
	return token
}

// SetToken sets a token to the transport in a thread-safe way.
func (t *authorizedTransport) SetToken(token *Token) {
	t.mu.Lock()
	defer t.mu.Unlock()

	t.token = token
}

// RefreshToken retrieves a new token, if a refreshing/fetching
// method is known and required credentials are presented
// (such as a refresh token).
func (t *authorizedTransport) RefreshToken() error {
	t.mu.Lock()
	defer t.mu.Unlock()

	token, err := t.fetcher.FetchToken(t.token)
	if err != nil {
		return err
	}

	t.token = token
	if t.cache != nil {
		t.cache.Write(token)
	}

	return nil
}

// cloneRequest returns a clone of the provided *http.Request.
// The clone is a shallow copy of the struct and its Header map.
func cloneRequest(r *http.Request) *http.Request {
	// shallow copy of the struct
	r2 := new(http.Request)
	*r2 = *r
	// deep copy of the Header
	r2.Header = make(http.Header)
	for k, s := range r.Header {
		r2.Header[k] = s
	}
	return r2
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/base64"
	"encoding/json"
	"fmt"
	"time"

	"github.com/koding/kite"
	kiteConfig "github.com/koding/kite/config"
)

// Transport defines communication between this package and user VM.
type Transport interface {
	Trip(string, interface{}, interface{}) error
}

//----------------------------------------------------------
// KlientTransport
//----------------------------------------------------------

const (
	kiteName    = "fuseproto"
	kiteVersion = "0.0.1"
	kiteTimeout = 10 * time.Second
)

// KlientTransport is a Transport using Klient on user VM.
type KlientTransport struct {
	client *kite.Client
}

// NewKlientTransport initializes KlientTransport with Klient connection.
func NewKlientTransport(klientIP string) (*KlientTransport, error) {
	config, err := kiteConfig.Get()
	if err != nil {
		return nil, err
	}

	k := kite.New(kiteName, kiteVersion)
	k.Config = config

	// TODO: will Klient always be running on 56789?
	kiteClient := k.NewClient(fmt.Sprintf("http://%s:56789/kite", klientIP))

	// TODO: add authentication
	kiteClient.Auth = &kite.Auth{}
	kiteClient.Reconnect = true

	if err := kiteClient.DialTimeout(kiteTimeout); err != nil {
		return nil, err
	}

	return &KlientTransport{client: kiteClient}, nil
}

// Trip is a generic method for communication. It accepts `req` to pass args
// to Klient and `res` to store unmarshalled response from Klient.
func (k *KlientTransport) Trip(methodName string, req interface{}, res interface{}) error {
	raw, err := k.client.Tell(methodName, req)
	if err != nil {
		return err
	}

	return raw.Unmarshal(&res)
}

//----------------------------------------------------------
// Responses
//----------------------------------------------------------

type fsReadDirectoryRes struct {
	Files []fsGetInfoRes `json:"files"`
}

type fsGetInfoRes struct {
	Exists   bool   `json:"exists"`
	FullPath string `json:"fullPath"`
	IsBroken bool   `json:"isBroken"`
	IsDir    bool   `json:"isDir"`
	Mode     int    `json:"mode"`
	Name     string `json:"name"`
	Readable bool   `json:"readable"`
	Size     int    `json:"size"`
	Time     string `json:"time"`
	Writable bool   `json:"writable"`
}

type fsReadFileRes struct {
	Content []byte
}

func (f *fsReadFileRes) UnmarshalJSON(b []byte) error {
	var m map[string]string
	if err := json.Unmarshal(b, &m); err != nil {
		return err
	}

	data, err := base64.StdEncoding.DecodeString(m["content"])
	if err != nil {
		return err
	}

	f.Content = data

	return nil
}
<commit_msg>TODO: remove hardcoded port to Klient on my vm<commit_after>package main

import (
	"encoding/base64"
	"encoding/json"
	"fmt"
	"time"

	"github.com/koding/kite"
	kiteConfig "github.com/koding/kite/config"
)

// Transport defines communication between this package and user VM.
type Transport interface {
	Trip(string, interface{}, interface{}) error
}

//----------------------------------------------------------
// KlientTransport
//----------------------------------------------------------

const (
	kiteName    = "fuseproto"
	kiteVersion = "0.0.1"
	kiteTimeout = 10 * time.Second
)

// KlientTransport is a Transport using Klient on user VM.
type KlientTransport struct {
	client *kite.Client
}

// NewKlientTransport initializes KlientTransport with Klient connection.
func NewKlientTransport(klientIP string) (*KlientTransport, error) {
	config, err := kiteConfig.Get()
	if err != nil {
		return nil, err
	}

	k := kite.New(kiteName, kiteVersion)
	k.Config = config

	// TODO: will Klient always be running on 56789?
	kiteClient := k.NewClient(fmt.Sprintf("http://%s:62193/kite", klientIP))

	// TODO: add authentication
	kiteClient.Auth = &kite.Auth{}
	kiteClient.Reconnect = true

	if err := kiteClient.DialTimeout(kiteTimeout); err != nil {
		return nil, err
	}

	return &KlientTransport{client: kiteClient}, nil
}

// Trip is a generic method for communication. It accepts `req` to pass args
// to Klient and `res` to store unmarshalled response from Klient.
func (k *KlientTransport) Trip(methodName string, req interface{}, res interface{}) error {
	raw, err := k.client.Tell(methodName, req)
	if err != nil {
		return err
	}

	return raw.Unmarshal(&res)
}

//----------------------------------------------------------
// Responses
//----------------------------------------------------------

type fsReadDirectoryRes struct {
	Files []fsGetInfoRes `json:"files"`
}

type fsGetInfoRes struct {
	Exists   bool   `json:"exists"`
	FullPath string `json:"fullPath"`
	IsBroken bool   `json:"isBroken"`
	IsDir    bool   `json:"isDir"`
	Mode     int    `json:"mode"`
	Name     string `json:"name"`
	Readable bool   `json:"readable"`
	Size     int    `json:"size"`
	Time     string `json:"time"`
	Writable bool   `json:"writable"`
}

type fsReadFileRes struct {
	Content []byte
}

func (f *fsReadFileRes) UnmarshalJSON(b []byte) error {
	var m map[string]string
	if err := json.Unmarshal(b, &m); err != nil {
		return err
	}

	data, err := base64.StdEncoding.DecodeString(m["content"])
	if err != nil {
		return err
	}

	f.Content = data

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2014 The lime Authors.
// Use of this source code is governed by a 2-clause
// BSD-style license that can be found in the LICENSE file.

package backend

import (
	"fmt"
	"testing"
)

type (
	DummyApplicationCommand struct {
		DefaultCommand
	}

	DummyWindowCommand struct {
		DefaultCommand
	}
)

func (c *DummyApplicationCommand) Run() error {
	return fmt.Errorf("Ran")
}

func (c *DummyApplicationCommand) IsChecked() bool {
	return false
}

func (c *DummyWindowCommand) Run(w *Window) error {
	return fmt.Errorf("Ran")
}

func TestPascalCaseToSnakeCase(t *testing.T) {
	tests := []struct {
		in  string
		out string
	}{
		{
			"TestString",
			"test_string",
		},
		{
			"Teststring",
			"teststring",
		},
	}

	for i, test := range tests {
		out := PascalCaseToSnakeCase(test.in)

		if out != test.out {
			t.Errorf("Test %d: Expected %s, but got %s", i, test.out, out)
		}
	}
}

func TestRegisterApplicationCommand(t *testing.T) {
	name := "app_test_command"
	ac := DummyApplicationCommand{}
	ch := GetEditor().CommandHandler()

	err := ch.Register(name, &ac)

	if err != nil {
		t.Errorf("Got error while registering: %s", err)
	}

	err = ch.RunApplicationCommand(name, Args{})

	if err == nil {
		t.Errorf("Expected %s to run, but it didn't", name)
	} else if err.Error() != "Ran" {
		t.Errorf("Expected %s to run, but it got an error: %v", name, err)
	}
}

func TestRegisterWindowCommand(t *testing.T) {
	var w Window

	name := "wnd_test_command"
	ac := DummyWindowCommand{}
	ch := GetEditor().CommandHandler()

	err := ch.Register(name, &ac)

	if err != nil {
		t.Errorf("Got error while registering: %s", err)
	}

	err = ch.RunWindowCommand(&w, name, Args{})

	if err == nil {
		t.Errorf("Expected %s to run, but it didn't", name)
	} else if err.Error() != "Ran" {
		t.Errorf("Expected %s to run, but it got an error: %v", name, err)
	}
}
<commit_msg>Add a TextCommand registration test.<commit_after>// Copyright 2014 The lime Authors.
// Use of this source code is governed by a 2-clause
// BSD-style license that can be found in the LICENSE file.

package backend

import (
	"fmt"
	"testing"
)

type (
	DummyApplicationCommand struct {
		DefaultCommand
	}

	DummyWindowCommand struct {
		DefaultCommand
	}

	DummyTextCommand struct {
		DefaultCommand
	}
)

func (c *DummyApplicationCommand) Run() error {
	return fmt.Errorf("Ran")
}

func (c *DummyApplicationCommand) IsChecked() bool {
	return false
}

func (c *DummyWindowCommand) Run(w *Window) error {
	return fmt.Errorf("Ran")
}

func (c *DummyTextCommand) Run(v *View, e *Edit) error {
	return fmt.Errorf("Ran")
}

func TestPascalCaseToSnakeCase(t *testing.T) {
	tests := []struct {
		in  string
		out string
	}{
		{
			"TestString",
			"test_string",
		},
		{
			"Teststring",
			"teststring",
		},
	}

	for i, test := range tests {
		out := PascalCaseToSnakeCase(test.in)

		if out != test.out {
			t.Errorf("Test %d: Expected %s, but got %s", i, test.out, out)
		}
	}
}

func TestRegisterApplicationCommand(t *testing.T) {
	name := "app_test_command"
	ac := DummyApplicationCommand{}
	ch := GetEditor().CommandHandler()

	err := ch.Register(name, &ac)

	if err != nil {
		t.Errorf("Got error while registering: %s", err)
	}

	err = ch.RunApplicationCommand(name, Args{})

	if err == nil {
		t.Errorf("Expected %s to run, but it didn't", name)
	} else if err.Error() != "Ran" {
		t.Errorf("Expected %s to run, but it got an error: %v", name, err)
	}
}

func TestRegisterWindowCommand(t *testing.T) {
	var w Window

	name := "wnd_test_command"
	wc := DummyWindowCommand{}
	ch := GetEditor().CommandHandler()

	err := ch.Register(name, &wc)

	if err != nil {
		t.Errorf("Got error while registering: %s", err)
	}

	err = ch.RunWindowCommand(&w, name, Args{})

	if err == nil {
		t.Errorf("Expected %s to run, but it didn't", name)
	} else if err.Error() != "Ran" {
		t.Errorf("Expected %s to run, but it got an error: %v", name, err)
	}
}

func TestRegisterTextCommand(t *testing.T) {
	ed := GetEditor()

	name := "text_test_command"
	tc := DummyTextCommand{}
	ch := ed.CommandHandler()

	err := ch.Register(name, &tc)

	if err != nil {
		t.Errorf("Got error while registering: %s", err)
	}

	v := ed.NewWindow().NewFile()
	err = ch.RunTextCommand(v, name, Args{})

	if err == nil {
		t.Errorf("Expected %s to run, but it didn't", name)
	} else if err.Error() != "Ran" {
		t.Errorf("Expected %s to run, but it got an error: %v", name, err)
	}
}
<|endoftext|>