<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"syscall"

	"github.com/gorilla/mux"
	"github.com/gorilla/websocket"

	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/api"
	"github.com/lxc/lxd/shared/version"

	log "gopkg.in/inconshreveable/log15.v2"
)

type execWs struct {
	command   []string
	container container
	env       map[string]string

	rootUid          int64
	rootGid          int64
	conns            map[int]*websocket.Conn
	connsLock        sync.Mutex
	allConnected     chan bool
	controlConnected chan bool
	interactive      bool
	fds              map[int]string
	width            int
	height           int
}

func (s *execWs) Metadata() interface{} {
	fds := shared.Jmap{}
	for fd, secret := range s.fds {
		if fd == -1 {
			fds["control"] = secret
		} else {
			fds[strconv.Itoa(fd)] = secret
		}
	}

	return shared.Jmap{"fds": fds}
}

func (s *execWs) Connect(op *operation, r *http.Request, w http.ResponseWriter) error {
	secret := r.FormValue("secret")
	if secret == "" {
		return fmt.Errorf("missing secret")
	}

	for fd, fdSecret := range s.fds {
		if secret == fdSecret {
			conn, err := shared.WebsocketUpgrader.Upgrade(w, r, nil)
			if err != nil {
				return err
			}

			s.connsLock.Lock()
			s.conns[fd] = conn
			s.connsLock.Unlock()

			if fd == -1 {
				s.controlConnected <- true
				return nil
			}

			s.connsLock.Lock()
			for i, c := range s.conns {
				if i != -1 && c == nil {
					s.connsLock.Unlock()
					return nil
				}
			}
			s.connsLock.Unlock()

			s.allConnected <- true
			return nil
		}
	}

	/* If we didn't find the right secret, the user provided a bad one,
	 * which 403, not 404, since this operation actually exists */
	return os.ErrPermission
}

func (s *execWs) Do(op *operation) error {
	<-s.allConnected

	var err error
	var ttys []*os.File
	var ptys []*os.File

	var stdin *os.File
	var stdout *os.File
	var stderr *os.File

	if s.interactive {
		ttys = make([]*os.File, 1)
		ptys = make([]*os.File, 1)
		ptys[0], ttys[0], err = shared.OpenPty(s.rootUid, s.rootGid)

		stdin = ttys[0]
		stdout = ttys[0]
		stderr = ttys[0]

		if s.width > 0 && s.height > 0 {
			shared.SetSize(int(ptys[0].Fd()), s.width, s.height)
		}
	} else {
		ttys = make([]*os.File, 3)
		ptys = make([]*os.File, 3)
		for i := 0; i < len(ttys); i++ {
			ptys[i], ttys[i], err = shared.Pipe()
			if err != nil {
				return err
			}
		}

		stdin = ptys[0]
		stdout = ttys[1]
		stderr = ttys[2]
	}

	controlExit := make(chan bool)
	attachedChildIsBorn := make(chan int)
	attachedChildIsDead := make(chan bool, 1)
	var wgEOF sync.WaitGroup

	if s.interactive {
		wgEOF.Add(1)
		go func() {
			attachedChildPid := <-attachedChildIsBorn
			select {
			case <-s.controlConnected:
				break

			case <-controlExit:
				return
			}

			for {
				s.connsLock.Lock()
				conn := s.conns[-1]
				s.connsLock.Unlock()

				mt, r, err := conn.NextReader()
				if mt == websocket.CloseMessage {
					break
				}

				if err != nil {
					shared.LogDebugf("Got error getting next reader %s", err)
					break
				}

				buf, err := ioutil.ReadAll(r)
				if err != nil {
					shared.LogDebugf("Failed to read message %s", err)
					break
				}

				command := api.ContainerExecControl{}

				if err := json.Unmarshal(buf, &command); err != nil {
					shared.LogDebugf("Failed to unmarshal control socket command: %s", err)
					continue
				}

				if command.Command == "window-resize" {
					winchWidth, err := strconv.Atoi(command.Args["width"])
					if err != nil {
						shared.LogDebugf("Unable to extract window width: %s", err)
						continue
					}

					winchHeight, err := strconv.Atoi(command.Args["height"])
					if err != nil {
						shared.LogDebugf("Unable to extract window height: %s", err)
						continue
					}

					err = shared.SetSize(int(ptys[0].Fd()), winchWidth, winchHeight)
					if err != nil {
						shared.LogDebugf("Failed to set window size to: %dx%d", winchWidth, winchHeight)
						continue
					}
				} else if command.Command == "signal" {
					if err := syscall.Kill(attachedChildPid, syscall.Signal(command.Signal)); err != nil {
						shared.LogDebugf("Failed forwarding signal '%s' to PID %d.", command.Signal, attachedChildPid)
						continue
					}
					shared.LogDebugf("Forwarded signal '%d' to PID %d.", command.Signal, attachedChildPid)
				}
			}
		}()

		go func() {
			s.connsLock.Lock()
			conn := s.conns[0]
			s.connsLock.Unlock()

			readDone, writeDone := shared.WebsocketExecMirror(conn, ptys[0], ptys[0], attachedChildIsDead, int(ptys[0].Fd()))

			<-readDone
			<-writeDone

			conn.Close()
			wgEOF.Done()
		}()

	} else {
		wgEOF.Add(len(ttys) - 1)
		for i := 0; i < len(ttys); i++ {
			go func(i int) {
				if i == 0 {
					s.connsLock.Lock()
					conn := s.conns[i]
					s.connsLock.Unlock()

					<-shared.WebsocketRecvStream(ttys[i], conn)
					ttys[i].Close()
				} else {
					s.connsLock.Lock()
					conn := s.conns[i]
					s.connsLock.Unlock()

					<-shared.WebsocketSendStream(conn, ptys[i], -1)
					ptys[i].Close()
					wgEOF.Done()
				}
			}(i)
		}
	}

	finisher := func(cmdResult int, cmdErr error) error {
		for _, tty := range ttys {
			tty.Close()
		}

		s.connsLock.Lock()
		conn := s.conns[-1]
		s.connsLock.Unlock()

		if conn == nil {
			if s.interactive {
				controlExit <- true
			}
		} else {
			conn.Close()
		}

		attachedChildIsDead <- true

		wgEOF.Wait()

		for _, pty := range ptys {
			pty.Close()
		}

		metadata := shared.Jmap{"return": cmdResult}
		err = op.UpdateMetadata(metadata)
		if err != nil {
			return err
		}

		return cmdErr
	}

	pid, attachedPid, err := s.container.Exec(s.command, s.env, stdin, stdout, stderr, false)
	if err != nil {
		return err
	}

	if s.interactive {
		attachedChildIsBorn <- attachedPid
	}

	proc, err := os.FindProcess(pid)
	if err != nil {
		return finisher(-1, fmt.Errorf("Failed finding process: %q", err))
	}

	procState, err := proc.Wait()
	if err != nil {
		return finisher(-1, fmt.Errorf("Failed waiting on process %d: %q", pid, err))
	}

	if procState.Success() {
		return finisher(0, nil)
	}

	status, ok := procState.Sys().(syscall.WaitStatus)
	if ok {
		if status.Exited() {
			return finisher(status.ExitStatus(), nil)
		}

		if status.Signaled() {
			// 128 + n == Fatal error signal "n"
			return finisher(128+int(status.Signal()), nil)
		}
	}

	return finisher(-1, nil)
}

func containerExecPost(d *Daemon, r *http.Request) Response {
	name := mux.Vars(r)["name"]
	c, err := containerLoadByName(d, name)
	if err != nil {
		return SmartError(err)
	}

	if !c.IsRunning() {
		return BadRequest(fmt.Errorf("Container is not running."))
	}

	if c.IsFrozen() {
		return BadRequest(fmt.Errorf("Container is frozen."))
	}

	post := api.ContainerExecPost{}
	buf, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return BadRequest(err)
	}

	if err := json.Unmarshal(buf, &post); err != nil {
		return BadRequest(err)
	}

	env := map[string]string{}

	for k, v := range c.ExpandedConfig() {
		if strings.HasPrefix(k, "environment.") {
			env[strings.TrimPrefix(k, "environment.")] = v
		}
	}

	if post.Environment != nil {
		for k, v := range post.Environment {
			env[k] = v
		}
	}

	// Set default value for PATH
	_, ok := env["PATH"]
	if !ok {
		env["PATH"] = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
		if c.FileExists("/snap") == nil {
			env["PATH"] = fmt.Sprintf("%s:/snap/bin", env["PATH"])
		}
	}

	// Set default value for HOME
	_, ok = env["HOME"]
	if !ok {
		env["HOME"] = "/root"
	}

	// Set default value for USER
	_, ok = env["USER"]
	if !ok {
		env["USER"] = "root"
	}

	// Set default value for USER
	_, ok = env["LANG"]
	if !ok {
		env["LANG"] = "C.UTF-8"
	}

	if post.WaitForWS {
		ws := &execWs{}
		ws.fds = map[int]string{}

		idmapset, err := c.IdmapSet()
		if err != nil {
			return InternalError(err)
		}

		if idmapset != nil {
			ws.rootUid, ws.rootGid = idmapset.ShiftIntoNs(0, 0)
		}

		ws.conns = map[int]*websocket.Conn{}
		ws.conns[-1] = nil
		ws.conns[0] = nil
		if !post.Interactive {
			ws.conns[1] = nil
			ws.conns[2] = nil
		}
		ws.allConnected = make(chan bool, 1)
		ws.controlConnected = make(chan bool, 1)
		ws.interactive = post.Interactive
		for i := -1; i < len(ws.conns)-1; i++ {
			ws.fds[i], err = shared.RandomCryptoString()
			if err != nil {
				return InternalError(err)
			}
		}

		ws.command = post.Command
		ws.container = c
		ws.env = env

		ws.width = post.Width
		ws.height = post.Height

		resources := map[string][]string{}
		resources["containers"] = []string{ws.container.Name()}

		op, err := operationCreate(operationClassWebsocket, resources, ws.Metadata(), ws.Do, nil, ws.Connect)
		if err != nil {
			return InternalError(err)
		}

		return OperationResponse(op)
	}

	run := func(op *operation) error {
		var cmdErr error
		var cmdResult int
		metadata := shared.Jmap{}

		if post.RecordOutput {
			// Prepare stdout and stderr recording
			stdout, err := os.OpenFile(filepath.Join(c.LogPath(), fmt.Sprintf("exec_%s.stdout", op.id)), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
			if err != nil {
				return err
			}
			defer stdout.Close()

			stderr, err := os.OpenFile(filepath.Join(c.LogPath(), fmt.Sprintf("exec_%s.stderr", op.id)), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
			if err != nil {
				return err
			}
			defer stderr.Close()

			// Run the command
			cmdResult, _, cmdErr = c.Exec(post.Command, env, nil, stdout, stderr, true)

			// Update metadata with the right URLs
			metadata["return"] = cmdResult
			metadata["output"] = shared.Jmap{
				"1": fmt.Sprintf("/%s/containers/%s/logs/%s", version.APIVersion, c.Name(), filepath.Base(stdout.Name())),
				"2": fmt.Sprintf("/%s/containers/%s/logs/%s", version.APIVersion, c.Name(), filepath.Base(stderr.Name())),
			}
		} else {
			cmdResult, _, cmdErr = c.Exec(post.Command, env, nil, nil, nil, true)
			metadata["return"] = cmdResult
		}

		err = op.UpdateMetadata(metadata)
		if err != nil {
			shared.LogError("error updating metadata for cmd", log.Ctx{"err": err, "cmd": post.Command})
		}

		return cmdErr
	}

	resources := map[string][]string{}
	resources["containers"] = []string{name}

	op, err := operationCreate(operationClassTask, resources, nil, run, nil, nil)
	if err != nil {
		return InternalError(err)
	}

	return OperationResponse(op)
}
<commit_msg>exec: kill forkexec on abnormal websocket closure<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"syscall"

	"github.com/gorilla/mux"
	"github.com/gorilla/websocket"

	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/api"
	"github.com/lxc/lxd/shared/version"

	log "gopkg.in/inconshreveable/log15.v2"
)

type execWs struct {
	command   []string
	container container
	env       map[string]string

	rootUid          int64
	rootGid          int64
	conns            map[int]*websocket.Conn
	connsLock        sync.Mutex
	allConnected     chan bool
	controlConnected chan bool
	interactive      bool
	fds              map[int]string
	width            int
	height           int
}

func (s *execWs) Metadata() interface{} {
	fds := shared.Jmap{}
	for fd, secret := range s.fds {
		if fd == -1 {
			fds["control"] = secret
		} else {
			fds[strconv.Itoa(fd)] = secret
		}
	}

	return shared.Jmap{"fds": fds}
}

func (s *execWs) Connect(op *operation, r *http.Request, w http.ResponseWriter) error {
	secret := r.FormValue("secret")
	if secret == "" {
		return fmt.Errorf("missing secret")
	}

	for fd, fdSecret := range s.fds {
		if secret == fdSecret {
			conn, err := shared.WebsocketUpgrader.Upgrade(w, r, nil)
			if err != nil {
				return err
			}

			s.connsLock.Lock()
			s.conns[fd] = conn
			s.connsLock.Unlock()

			if fd == -1 {
				s.controlConnected <- true
				return nil
			}

			s.connsLock.Lock()
			for i, c := range s.conns {
				if i != -1 && c == nil {
					s.connsLock.Unlock()
					return nil
				}
			}
			s.connsLock.Unlock()

			s.allConnected <- true
			return nil
		}
	}

	/* If we didn't find the right secret, the user provided a bad one,
	 * which 403, not 404, since this operation actually exists */
	return os.ErrPermission
}

func (s *execWs) Do(op *operation) error {
	<-s.allConnected

	var err error
	var ttys []*os.File
	var ptys []*os.File

	var stdin *os.File
	var stdout *os.File
	var stderr *os.File

	if s.interactive {
		ttys = make([]*os.File, 1)
		ptys = make([]*os.File, 1)
		ptys[0], ttys[0], err = shared.OpenPty(s.rootUid, s.rootGid)

		stdin = ttys[0]
		stdout = ttys[0]
		stderr = ttys[0]

		if s.width > 0 && s.height > 0 {
			shared.SetSize(int(ptys[0].Fd()), s.width, s.height)
		}
	} else {
		ttys = make([]*os.File, 3)
		ptys = make([]*os.File, 3)
		for i := 0; i < len(ttys); i++ {
			ptys[i], ttys[i], err = shared.Pipe()
			if err != nil {
				return err
			}
		}

		stdin = ptys[0]
		stdout = ttys[1]
		stderr = ttys[2]
	}

	controlExit := make(chan bool)
	attachedChildIsBorn := make(chan int)
	attachedChildIsDead := make(chan bool, 1)
	var wgEOF sync.WaitGroup

	if s.interactive {
		wgEOF.Add(1)
		go func() {
			attachedChildPid := <-attachedChildIsBorn
			select {
			case <-s.controlConnected:
				break

			case <-controlExit:
				return
			}

			for {
				s.connsLock.Lock()
				conn := s.conns[-1]
				s.connsLock.Unlock()

				mt, r, err := conn.NextReader()
				if mt == websocket.CloseMessage {
					break
				}

				if err != nil {
					shared.LogDebugf("Got error getting next reader %s", err)
					er, ok := err.(*websocket.CloseError)
					if !ok {
						break
					}

					if er.Code != websocket.CloseAbnormalClosure {
						break
					}

					// If an abnormal closure occured, kill the attached process.
					err := syscall.Kill(attachedChildPid, syscall.SIGKILL)
					if err != nil {
						shared.LogDebugf("Failed to send SIGKILL to pid %d.", attachedChildPid)
					} else {
						shared.LogDebugf("Sent SIGKILL to pid %d.", attachedChildPid)
					}
					return
				}

				buf, err := ioutil.ReadAll(r)
				if err != nil {
					shared.LogDebugf("Failed to read message %s", err)
					break
				}

				command := api.ContainerExecControl{}

				if err := json.Unmarshal(buf, &command); err != nil {
					shared.LogDebugf("Failed to unmarshal control socket command: %s", err)
					continue
				}

				if command.Command == "window-resize" {
					winchWidth, err := strconv.Atoi(command.Args["width"])
					if err != nil {
						shared.LogDebugf("Unable to extract window width: %s", err)
						continue
					}

					winchHeight, err := strconv.Atoi(command.Args["height"])
					if err != nil {
						shared.LogDebugf("Unable to extract window height: %s", err)
						continue
					}

					err = shared.SetSize(int(ptys[0].Fd()), winchWidth, winchHeight)
					if err != nil {
						shared.LogDebugf("Failed to set window size to: %dx%d", winchWidth, winchHeight)
						continue
					}
				} else if command.Command == "signal" {
					if err := syscall.Kill(attachedChildPid, syscall.Signal(command.Signal)); err != nil {
						shared.LogDebugf("Failed forwarding signal '%s' to PID %d.", command.Signal, attachedChildPid)
						continue
					}
					shared.LogDebugf("Forwarded signal '%d' to PID %d.", command.Signal, attachedChildPid)
				}
			}
		}()

		go func() {
			s.connsLock.Lock()
			conn := s.conns[0]
			s.connsLock.Unlock()

			readDone, writeDone := shared.WebsocketExecMirror(conn, ptys[0], ptys[0], attachedChildIsDead, int(ptys[0].Fd()))

			<-readDone
			<-writeDone

			conn.Close()
			wgEOF.Done()
		}()

	} else {
		wgEOF.Add(len(ttys) - 1)
		for i := 0; i < len(ttys); i++ {
			go func(i int) {
				if i == 0 {
					s.connsLock.Lock()
					conn := s.conns[i]
					s.connsLock.Unlock()

					<-shared.WebsocketRecvStream(ttys[i], conn)
					ttys[i].Close()
				} else {
					s.connsLock.Lock()
					conn := s.conns[i]
					s.connsLock.Unlock()

					<-shared.WebsocketSendStream(conn, ptys[i], -1)
					ptys[i].Close()
					wgEOF.Done()
				}
			}(i)
		}
	}

	finisher := func(cmdResult int, cmdErr error) error {
		for _, tty := range ttys {
			tty.Close()
		}

		s.connsLock.Lock()
		conn := s.conns[-1]
		s.connsLock.Unlock()

		if conn == nil {
			if s.interactive {
				controlExit <- true
			}
		} else {
			conn.Close()
		}

		attachedChildIsDead <- true

		wgEOF.Wait()

		for _, pty := range ptys {
			pty.Close()
		}

		metadata := shared.Jmap{"return": cmdResult}
		err = op.UpdateMetadata(metadata)
		if err != nil {
			return err
		}

		return cmdErr
	}

	pid, attachedPid, err := s.container.Exec(s.command, s.env, stdin, stdout, stderr, false)
	if err != nil {
		return err
	}

	if s.interactive {
		attachedChildIsBorn <- attachedPid
	}

	proc, err := os.FindProcess(pid)
	if err != nil {
		return finisher(-1, fmt.Errorf("Failed finding process: %q", err))
	}

	procState, err := proc.Wait()
	if err != nil {
		return finisher(-1, fmt.Errorf("Failed waiting on process %d: %q", pid, err))
	}

	if procState.Success() {
		return finisher(0, nil)
	}

	status, ok := procState.Sys().(syscall.WaitStatus)
	if ok {
		if status.Exited() {
			return finisher(status.ExitStatus(), nil)
		}

		if status.Signaled() {
			// 128 + n == Fatal error signal "n"
			return finisher(128+int(status.Signal()), nil)
		}
	}

	return finisher(-1, nil)
}

func containerExecPost(d *Daemon, r *http.Request) Response {
	name := mux.Vars(r)["name"]
	c, err := containerLoadByName(d, name)
	if err != nil {
		return SmartError(err)
	}

	if !c.IsRunning() {
		return BadRequest(fmt.Errorf("Container is not running."))
	}

	if c.IsFrozen() {
		return BadRequest(fmt.Errorf("Container is frozen."))
	}

	post := api.ContainerExecPost{}
	buf, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return BadRequest(err)
	}

	if err := json.Unmarshal(buf, &post); err != nil {
		return BadRequest(err)
	}

	env := map[string]string{}

	for k, v := range c.ExpandedConfig() {
		if strings.HasPrefix(k, "environment.") {
			env[strings.TrimPrefix(k, "environment.")] = v
		}
	}

	if post.Environment != nil {
		for k, v := range post.Environment {
			env[k] = v
		}
	}

	// Set default value for PATH
	_, ok := env["PATH"]
	if !ok {
		env["PATH"] = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
		if c.FileExists("/snap") == nil {
			env["PATH"] = fmt.Sprintf("%s:/snap/bin", env["PATH"])
		}
	}

	// Set default value for HOME
	_, ok = env["HOME"]
	if !ok {
		env["HOME"] = "/root"
	}

	// Set default value for USER
	_, ok = env["USER"]
	if !ok {
		env["USER"] = "root"
	}

	// Set default value for USER
	_, ok = env["LANG"]
	if !ok {
		env["LANG"] = "C.UTF-8"
	}

	if post.WaitForWS {
		ws := &execWs{}
		ws.fds = map[int]string{}

		idmapset, err := c.IdmapSet()
		if err != nil {
			return InternalError(err)
		}

		if idmapset != nil {
			ws.rootUid, ws.rootGid = idmapset.ShiftIntoNs(0, 0)
		}

		ws.conns = map[int]*websocket.Conn{}
		ws.conns[-1] = nil
		ws.conns[0] = nil
		if !post.Interactive {
			ws.conns[1] = nil
			ws.conns[2] = nil
		}
		ws.allConnected = make(chan bool, 1)
		ws.controlConnected = make(chan bool, 1)
		ws.interactive = post.Interactive
		for i := -1; i < len(ws.conns)-1; i++ {
			ws.fds[i], err = shared.RandomCryptoString()
			if err != nil {
				return InternalError(err)
			}
		}

		ws.command = post.Command
		ws.container = c
		ws.env = env

		ws.width = post.Width
		ws.height = post.Height

		resources := map[string][]string{}
		resources["containers"] = []string{ws.container.Name()}

		op, err := operationCreate(operationClassWebsocket, resources, ws.Metadata(), ws.Do, nil, ws.Connect)
		if err != nil {
			return InternalError(err)
		}

		return OperationResponse(op)
	}

	run := func(op *operation) error {
		var cmdErr error
		var cmdResult int
		metadata := shared.Jmap{}

		if post.RecordOutput {
			// Prepare stdout and stderr recording
			stdout, err := os.OpenFile(filepath.Join(c.LogPath(), fmt.Sprintf("exec_%s.stdout", op.id)), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
			if err != nil {
				return err
			}
			defer stdout.Close()

			stderr, err := os.OpenFile(filepath.Join(c.LogPath(), fmt.Sprintf("exec_%s.stderr", op.id)), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
			if err != nil {
				return err
			}
			defer stderr.Close()

			// Run the command
			cmdResult, _, cmdErr = c.Exec(post.Command, env, nil, stdout, stderr, true)

			// Update metadata with the right URLs
			metadata["return"] = cmdResult
			metadata["output"] = shared.Jmap{
				"1": fmt.Sprintf("/%s/containers/%s/logs/%s", version.APIVersion, c.Name(), filepath.Base(stdout.Name())),
				"2": fmt.Sprintf("/%s/containers/%s/logs/%s", version.APIVersion, c.Name(), filepath.Base(stderr.Name())),
			}
		} else {
			cmdResult, _, cmdErr = c.Exec(post.Command, env, nil, nil, nil, true)
			metadata["return"] = cmdResult
		}

		err = op.UpdateMetadata(metadata)
		if err != nil {
			shared.LogError("error updating metadata for cmd", log.Ctx{"err": err, "cmd": post.Command})
		}

		return cmdErr
	}

	resources := map[string][]string{}
	resources["containers"] = []string{name}

	op, err := operationCreate(operationClassTask, resources, nil, run, nil, nil)
	if err != nil {
		return InternalError(err)
	}

	return OperationResponse(op)
}
<|endoftext|>


<commit_before>package conio

import (
	"bytes"
	"fmt"
	"strings"

	"github.com/atotto/clipboard"
)

func KeyFuncPass(this *Buffer) Result {
	return CONTINUE
}

func KeyFuncEnter(this *Buffer) Result { // Ctrl-M
	return ENTER
}

func KeyFuncIntr(this *Buffer) Result { // Ctrl-C
	this.Length = 0
	this.Cursor = 0
	this.Buffer = []rune{}
	return ENTER
}

func KeyFuncHead(this *Buffer) Result { // Ctrl-A
	Backspace(this.GetWidthBetween(this.ViewStart, this.Cursor))
	this.Cursor = 0
	this.ViewStart = 0
	this.Repaint(0, 1)
	return CONTINUE
}

func KeyFuncBackword(this *Buffer) Result { // Ctrl-B
	if this.Cursor <= 0 {
		return CONTINUE
	}
	this.Cursor--
	if this.Cursor < this.ViewStart {
		this.ViewStart--
		this.Repaint(this.Cursor, 1)
	} else {
		Backspace(GetCharWidth(this.Buffer[this.Cursor]))
	}
	return CONTINUE
}

func KeyFuncTail(this *Buffer) Result { // Ctrl-E
	allength := this.GetWidthBetween(this.ViewStart, this.Length)
	if allength < this.ViewWidth {
		for ; this.Cursor < this.Length; this.Cursor++ {
			PutRune(this.Buffer[this.Cursor])
		}
	} else {
		PutRune('\a')
		Backspace(this.GetWidthBetween(this.ViewStart, this.Cursor))
		this.ViewStart = this.Length - 1
		w := GetCharWidth(this.Buffer[this.ViewStart])
		for {
			if this.ViewStart <= 0 {
				break
			}
			w_ := w + GetCharWidth(this.Buffer[this.ViewStart-1])
			if w_ >= this.ViewWidth {
				break
			}
			w = w_
			this.ViewStart--
		}
		for this.Cursor = this.ViewStart; this.Cursor < this.Length; this.Cursor++ {
			PutRune(this.Buffer[this.Cursor])
		}
	}
	return CONTINUE
}

func KeyFuncForward(this *Buffer) Result { // Ctrl-F
	if this.Cursor >= this.Length {
		return CONTINUE
	}
	w := this.GetWidthBetween(this.ViewStart, this.Cursor+1)
	if w < this.ViewWidth {
		// No Scroll
		PutRune(this.Buffer[this.Cursor])
	} else {
		// Right Scroll
		Backspace(this.GetWidthBetween(this.ViewStart, this.Cursor))
		if GetCharWidth(this.Buffer[this.Cursor]) > GetCharWidth(this.Buffer[this.ViewStart]) {
			this.ViewStart++
		}
		this.ViewStart++
		for i := this.ViewStart; i <= this.Cursor; i++ {
			PutRune(this.Buffer[i])
		}
		PutRune(' ')
		Backspace(1)
	}
	this.Cursor++
	return CONTINUE
}

func KeyFuncBackSpace(this *Buffer) Result { // Backspace
	if this.Cursor > 0 {
		this.Cursor--
		delw := this.Delete(this.Cursor, 1)
		if this.Cursor >= this.ViewStart {
			Backspace(delw)
		} else {
			this.ViewStart = this.Cursor
		}
		this.Repaint(this.Cursor, delw)
	}
	return CONTINUE
}

func KeyFuncDelete(this *Buffer) Result { // Del
	delw := this.Delete(this.Cursor, 1)
	this.Repaint(this.Cursor, delw)
	return CONTINUE
}

func KeyFuncDeleteOrAbort(this *Buffer) Result { // Ctrl-D
	if this.Length > 0 {
		return KeyFuncDelete(this)
	} else {
		return ABORT
	}
}

func KeyFuncInsertSelf(this *Buffer) Result {
	ch := this.Unicode
	if ch < 0x20 {
		return CONTINUE
	}
	this.Insert(this.Cursor, []rune{ch})

	w := this.GetWidthBetween(this.ViewStart, this.Cursor)
	w1 := GetCharWidth(ch)
	if w+w1 >= this.ViewWidth {
		// scroll left
		Backspace(w)
		if GetCharWidth(this.Buffer[this.ViewStart]) < w1 {
			this.ViewStart++
		}
		this.ViewStart++
		for i := this.ViewStart; i <= this.Cursor; i++ {
			PutRune(this.Buffer[i])
		}
		PutRune(' ')
		Backspace(1)
	} else {
		this.Repaint(this.Cursor, -w1)
	}
	this.Cursor++
	return CONTINUE
}

func KeyFuncInsertReport(this *Buffer) Result {
	this.InsertAndRepaint(fmt.Sprintf("[%X]", this.Unicode))
	return CONTINUE
}

func KeyFuncClearAfter(this *Buffer) Result {
	w := this.GetWidthBetween(this.ViewStart, this.Cursor)
	i := this.Cursor
	bs := 0

	var killbuf bytes.Buffer
	for j := this.Cursor; j < this.Length; j++ {
		killbuf.WriteRune(this.Buffer[j])
	}
	clipboard.WriteAll(killbuf.String())

	for i < this.Length && w < this.ViewWidth {
		w1 := GetCharWidth(this.Buffer[i])
		PutRunes(' ', w1)
		i++
		w += w1
		bs += w1
	}
	Backspace(bs)
	this.Length = this.Cursor
	return CONTINUE
}

func KeyFuncClear(this *Buffer) Result {
	width := this.GetWidthBetween(this.ViewStart, this.Cursor)
	Backspace(width)
	PutRunes(' ', this.ViewWidth)
	Backspace(this.ViewWidth)
	this.Length = 0
	this.Cursor = 0
	this.ViewStart = 0
	return CONTINUE
}

func KeyFuncClearBefore(this *Buffer) Result {
	var killbuf bytes.Buffer
	for i := 0; i < this.Cursor; i++ {
		killbuf.WriteRune(this.Buffer[i])
	}
	clipboard.WriteAll(killbuf.String())
	keta := this.Delete(0, this.Cursor)
	Backspace(keta)
	this.Cursor = 0
	this.Repaint(0, keta)
	return CONTINUE
}

func KeyFuncCLS(this *Buffer) Result {
	Cls()
	this.RepaintAll()
	return CONTINUE
}

func KeyFuncPaste(this *Buffer) Result {
	text, err := clipboard.ReadAll()
	if err == nil {
		this.InsertAndRepaint(
			strings.Replace(
				strings.Replace(
					strings.Replace(text, "\n", " ", -1),
					"\r", "", -1),
				"\t", " ", -1))
	}
	return CONTINUE
}

func maxInt(a, b int) int {
	if a < b {
		return b
	} else {
		return a
	}
}

func KeyFuncSwapChar(this *Buffer) Result {
	if this.Length == this.Cursor {
		if this.Cursor < 2 {
			return CONTINUE
		}
		this.Buffer[this.Cursor-2], this.Buffer[this.Cursor-1] = this.Buffer[this.Cursor-1], this.Buffer[this.Cursor-2]

		redrawStart := maxInt(this.Cursor-2, this.ViewStart)
		Backspace(this.GetWidthBetween(redrawStart, this.Cursor))
		for i := redrawStart; i < this.Cursor; i++ {
			PutRune(this.Buffer[i])
		}
	} else {
		if this.Cursor < 1 {
			return CONTINUE
		}
		this.Buffer[this.Cursor-1], this.Buffer[this.Cursor] = this.Buffer[this.Cursor], this.Buffer[this.Cursor-1]
		redrawStart := maxInt(this.Cursor-1, this.ViewStart)
		Backspace(this.GetWidthBetween(redrawStart, this.Cursor))
		for i := redrawStart; i <= this.Cursor; i++ {
			PutRune(this.Buffer[i])
		}
		this.Cursor++
	}
	return CONTINUE
}
<commit_msg>Fix: never scrolled after Ctrl-T typed even if it overflows<commit_after>package conio

import (
	"bytes"
	"fmt"
	"strings"

	"github.com/atotto/clipboard"
)

func KeyFuncPass(this *Buffer) Result {
	return CONTINUE
}

func KeyFuncEnter(this *Buffer) Result { // Ctrl-M
	return ENTER
}

func KeyFuncIntr(this *Buffer) Result { // Ctrl-C
	this.Length = 0
	this.Cursor = 0
	this.Buffer = []rune{}
	return ENTER
}

func KeyFuncHead(this *Buffer) Result { // Ctrl-A
	Backspace(this.GetWidthBetween(this.ViewStart, this.Cursor))
	this.Cursor = 0
	this.ViewStart = 0
	this.Repaint(0, 1)
	return CONTINUE
}

func KeyFuncBackword(this *Buffer) Result { // Ctrl-B
	if this.Cursor <= 0 {
		return CONTINUE
	}
	this.Cursor--
	if this.Cursor < this.ViewStart {
		this.ViewStart--
		this.Repaint(this.Cursor, 1)
	} else {
		Backspace(GetCharWidth(this.Buffer[this.Cursor]))
	}
	return CONTINUE
}

func KeyFuncTail(this *Buffer) Result { // Ctrl-E
	allength := this.GetWidthBetween(this.ViewStart, this.Length)
	if allength < this.ViewWidth {
		for ; this.Cursor < this.Length; this.Cursor++ {
			PutRune(this.Buffer[this.Cursor])
		}
	} else {
		PutRune('\a')
		Backspace(this.GetWidthBetween(this.ViewStart, this.Cursor))
		this.ViewStart = this.Length - 1
		w := GetCharWidth(this.Buffer[this.ViewStart])
		for {
			if this.ViewStart <= 0 {
				break
			}
			w_ := w + GetCharWidth(this.Buffer[this.ViewStart-1])
			if w_ >= this.ViewWidth {
				break
			}
			w = w_
			this.ViewStart--
		}
		for this.Cursor = this.ViewStart; this.Cursor < this.Length; this.Cursor++ {
			PutRune(this.Buffer[this.Cursor])
		}
	}
	return CONTINUE
}

func KeyFuncForward(this *Buffer) Result { // Ctrl-F
	if this.Cursor >= this.Length {
		return CONTINUE
	}
	w := this.GetWidthBetween(this.ViewStart, this.Cursor+1)
	if w < this.ViewWidth {
		// No Scroll
		PutRune(this.Buffer[this.Cursor])
	} else {
		// Right Scroll
		Backspace(this.GetWidthBetween(this.ViewStart, this.Cursor))
		if GetCharWidth(this.Buffer[this.Cursor]) > GetCharWidth(this.Buffer[this.ViewStart]) {
			this.ViewStart++
		}
		this.ViewStart++
		for i := this.ViewStart; i <= this.Cursor; i++ {
			PutRune(this.Buffer[i])
		}
		PutRune(' ')
		Backspace(1)
	}
	this.Cursor++
	return CONTINUE
}

func KeyFuncBackSpace(this *Buffer) Result { // Backspace
	if this.Cursor > 0 {
		this.Cursor--
		delw := this.Delete(this.Cursor, 1)
		if this.Cursor >= this.ViewStart {
			Backspace(delw)
		} else {
			this.ViewStart = this.Cursor
		}
		this.Repaint(this.Cursor, delw)
	}
	return CONTINUE
}

func KeyFuncDelete(this *Buffer) Result { // Del
	delw := this.Delete(this.Cursor, 1)
	this.Repaint(this.Cursor, delw)
	return CONTINUE
}

func KeyFuncDeleteOrAbort(this *Buffer) Result { // Ctrl-D
	if this.Length > 0 {
		return KeyFuncDelete(this)
	} else {
		return ABORT
	}
}

func KeyFuncInsertSelf(this *Buffer) Result {
	ch := this.Unicode
	if ch < 0x20 {
		return CONTINUE
	}
	this.Insert(this.Cursor, []rune{ch})

	w := this.GetWidthBetween(this.ViewStart, this.Cursor)
	w1 := GetCharWidth(ch)
	if w+w1 >= this.ViewWidth {
		// scroll left
		Backspace(w)
		if GetCharWidth(this.Buffer[this.ViewStart]) < w1 {
			this.ViewStart++
		}
		this.ViewStart++
		for i := this.ViewStart; i <= this.Cursor; i++ {
			PutRune(this.Buffer[i])
		}
		PutRune(' ')
		Backspace(1)
	} else {
		this.Repaint(this.Cursor, -w1)
	}
	this.Cursor++
	return CONTINUE
}

func KeyFuncInsertReport(this *Buffer) Result {
	this.InsertAndRepaint(fmt.Sprintf("[%X]", this.Unicode))
	return CONTINUE
}

func KeyFuncClearAfter(this *Buffer) Result {
	w := this.GetWidthBetween(this.ViewStart, this.Cursor)
	i := this.Cursor
	bs := 0

	var killbuf bytes.Buffer
	for j := this.Cursor; j < this.Length; j++ {
		killbuf.WriteRune(this.Buffer[j])
	}
	clipboard.WriteAll(killbuf.String())

	for i < this.Length && w < this.ViewWidth {
		w1 := GetCharWidth(this.Buffer[i])
		PutRunes(' ', w1)
		i++
		w += w1
		bs += w1
	}
	Backspace(bs)
	this.Length = this.Cursor
	return CONTINUE
}

func KeyFuncClear(this *Buffer) Result {
	width := this.GetWidthBetween(this.ViewStart, this.Cursor)
	Backspace(width)
	PutRunes(' ', this.ViewWidth)
	Backspace(this.ViewWidth)
	this.Length = 0
	this.Cursor = 0
	this.ViewStart = 0
	return CONTINUE
}

func KeyFuncClearBefore(this *Buffer) Result {
	var killbuf bytes.Buffer
	for i := 0; i < this.Cursor; i++ {
		killbuf.WriteRune(this.Buffer[i])
	}
	clipboard.WriteAll(killbuf.String())
	keta := this.Delete(0, this.Cursor)
	Backspace(keta)
	this.Cursor = 0
	this.Repaint(0, keta)
	return CONTINUE
}

func KeyFuncCLS(this *Buffer) Result {
	Cls()
	this.RepaintAll()
	return CONTINUE
}

func KeyFuncPaste(this *Buffer) Result {
	text, err := clipboard.ReadAll()
	if err == nil {
		this.InsertAndRepaint(
			strings.Replace(
				strings.Replace(
					strings.Replace(text, "\n", " ", -1),
					"\r", "", -1),
				"\t", " ", -1))
	}
	return CONTINUE
}

func maxInt(a, b int) int {
	if a < b {
		return b
	} else {
		return a
	}
}

func KeyFuncSwapChar(this *Buffer) Result {
	if this.Length == this.Cursor {
		if this.Cursor < 2 {
			return CONTINUE
		}
		this.Buffer[this.Cursor-2], this.Buffer[this.Cursor-1] = this.Buffer[this.Cursor-1], this.Buffer[this.Cursor-2]

		redrawStart := maxInt(this.Cursor-2, this.ViewStart)
		Backspace(this.GetWidthBetween(redrawStart, this.Cursor))
		for i := redrawStart; i < this.Cursor; i++ {
			PutRune(this.Buffer[i])
		}
	} else {
		if this.Cursor < 1 {
			return CONTINUE
		}

		w := this.GetWidthBetween(this.ViewStart, this.Cursor+1)
		this.Buffer[this.Cursor-1], this.Buffer[this.Cursor] = this.Buffer[this.Cursor], this.Buffer[this.Cursor-1]
		if w >= this.ViewWidth {
			// cursor move right and scroll
			w_1 := w - GetCharWidth(this.Buffer[this.Cursor])
			Backspace(w_1)
			this.ViewStart++
			for i := this.ViewStart; i <= this.Cursor; i++ {
				PutRune(this.Buffer[i])
			}
		} else {
			// no neccesary to scroll
			redrawStart := maxInt(this.Cursor-1, this.ViewStart)
			Backspace(this.GetWidthBetween(redrawStart, this.Cursor))
			for i := redrawStart; i <= this.Cursor; i++ {
				PutRune(this.Buffer[i])
			}
		}
		this.Cursor++
	}
	return CONTINUE
}
<|endoftext|>


<commit_before>package gamq

import (
	"bufio"
	"bytes"
	"testing"
)

func TestConnectionManager_parseClientCommand_helpMessageReturns(t *testing.T) {
	underTest := ConnectionManager{}

	buf := new(bytes.Buffer)
	bufWriter := bufio.NewWriter(buf)
	mockClient := Client{Name: "Mock", Writer: bufWriter}

	underTest.parseClientCommand("HELP", &mockClient)

	if buf.String() == UNRECOGNISEDCOMMANDTEXT {
		t.Fail()
	}
}

func TestConnectionManager_parseClientCommand_isCaseInsensitive(t *testing.T) {
	underTest := ConnectionManager{}

	buf := new(bytes.Buffer)
	bufWriter := bufio.NewWriter(buf)
	mockClient := Client{Name: "Mock", Writer: bufWriter}

	underTest.parseClientCommand("help", &mockClient)

	if buf.String() == UNRECOGNISEDCOMMANDTEXT {
		t.Fail()
	}
}
<commit_msg>Added initialization test for connectionmanager.go.<commit_after>package gamq

import (
	"bufio"
	"bytes"
	"fmt"
	"net"
	"testing"
)

func TestConnectionManager_parseClientCommand_helpMessageReturns(t *testing.T) {
	underTest := ConnectionManager{}

	buf := new(bytes.Buffer)
	bufWriter := bufio.NewWriter(buf)
	mockClient := Client{Name: "Mock", Writer: bufWriter}

	underTest.parseClientCommand("HELP", &mockClient)

	if buf.String() == UNRECOGNISEDCOMMANDTEXT {
		t.Fail()
	}
}

func TestConnectionManager_parseClientCommand_isCaseInsensitive(t *testing.T) {
	underTest := ConnectionManager{}

	buf := new(bytes.Buffer)
	bufWriter := bufio.NewWriter(buf)
	mockClient := Client{Name: "Mock", Writer: bufWriter}

	underTest.parseClientCommand("help", &mockClient)

	if buf.String() == UNRECOGNISEDCOMMANDTEXT {
		t.Fail()
	}
}

func TestConnectionManager_whenInitialized_acceptsConnectionsCorrectly(t *testing.T) {
	// Choose a high port, so we don't need sudo to run tests
	config := Config{}
	config.Port = 55555
	SetConfig(&config)

	underTest := ConnectionManager{}
	go underTest.Initialize()

	testConn, err := net.Dial("tcp", "localhost:55555")
	if err != nil {
		t.Fail()
	}

	fmt.Fprintf(testConn, "PINGREQ\n")
	response, err := bufio.NewReader(testConn).ReadString('\n')

	if err != nil || response != "PINGRESP\n" {
		t.Fail()
	}
}
<|endoftext|>


<commit_before>package response

import (
	"database/sql"
	"errors"
	"net/http"
	"os"

	pkgErrors "github.com/pkg/errors"

	"github.com/lxc/lxd/lxd/db"
)

var httpResponseErrors = map[int][]error{
	http.StatusNotFound:  {os.ErrNotExist, sql.ErrNoRows, db.ErrNoSuchObject},
	http.StatusForbidden: {os.ErrPermission},
	http.StatusConflict:  {db.ErrAlreadyDefined},
}

// SmartError returns the right error message based on err.
// It uses both the stdlib errors and the github.com/pkg/errors packages to unwrap the error and find the cause.
func SmartError(err error) Response {
	if err == nil {
		return EmptySyncResponse
	}

	for httpStatusCode, checkErrs := range httpResponseErrors {
		for _, checkErr := range checkErrs {
			if errors.Is(err, checkErr) || pkgErrors.Cause(err) == checkErr {
				if err != checkErr {
					// If the error has been wrapped return the top-level error message.
					return &errorResponse{httpStatusCode, err.Error()}
				}

				// If the error hasn't been wrapped, replace the error message with the generic
				// HTTP status text.
				return &errorResponse{httpStatusCode, http.StatusText(httpStatusCode)}
			}
		}
	}

	return &errorResponse{http.StatusInternalServerError, err.Error()}
}
<commit_msg>lxd/response/smart: Updates SmartError to detect and use api.StatusError type errors<commit_after>package response

import (
	"database/sql"
	"errors"
	"net/http"
	"os"

	pkgErrors "github.com/pkg/errors"

	"github.com/lxc/lxd/lxd/db"
	"github.com/lxc/lxd/shared/api"
)

var httpResponseErrors = map[int][]error{
	http.StatusNotFound:  {os.ErrNotExist, sql.ErrNoRows, db.ErrNoSuchObject},
	http.StatusForbidden: {os.ErrPermission},
	http.StatusConflict:  {db.ErrAlreadyDefined},
}

// SmartError returns the right error message based on err.
// It uses both the stdlib errors and the github.com/pkg/errors packages to unwrap the error and find the cause.
func SmartError(err error) Response {
	if err == nil {
		return EmptySyncResponse
	}

	var statusErr *api.StatusError

	if errors.As(err, &statusErr) {
		return &errorResponse{statusErr.Status(), err.Error()}
	}

	for httpStatusCode, checkErrs := range httpResponseErrors {
		for _, checkErr := range checkErrs {
			if errors.Is(err, checkErr) || pkgErrors.Cause(err) == checkErr {
				if err != checkErr {
					// If the error has been wrapped return the top-level error message.
					return &errorResponse{httpStatusCode, err.Error()}
				}

				// If the error hasn't been wrapped, replace the error message with the generic
				// HTTP status text.
				return &errorResponse{httpStatusCode, http.StatusText(httpStatusCode)}
			}
		}
	}

	return &errorResponse{http.StatusInternalServerError, err.Error()}
}
<|endoftext|>


<commit_before>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package constraints

import (
	"fmt"
	"math"
	"reflect"

	"github.com/juju/utils/set"
)

// Validator defines operations on constraints attributes which are
// used to ensure a constraints value is valid, as well as being able
// to handle overridden attributes.
type Validator interface {

	// RegisterConflicts is used to define cross-constraint override behaviour.
	// The red and blue attribute lists contain attribute names which conflict
	// with those in the other list.
	// When two constraints conflict:
	//  it is an error to set both constraints in the same constraints Value.
	//  when a constraints Value overrides another which specifies a conflicting
	//   attribute, the attribute in the overridden Value is cleared.
	RegisterConflicts(reds, blues []string)

	// RegisterUnsupported records attributes which are not supported by a constraints Value.
	RegisterUnsupported(unsupported []string)

	// RegisterVocabulary records allowed values for the specified constraint attribute.
	// allowedValues is expected to be a slice/array but is declared as interface{} so
	// that vocabs of different types can be passed in.
	RegisterVocabulary(attributeName string, allowedValues interface{})

	// Validate returns an error if the given constraints are not valid, and also
	// any unsupported attributes.
	Validate(cons Value) ([]string, error)

	// Merge merges cons into consFallback, with any conflicting attributes from cons
	// overriding those from consFallback.
	Merge(consFallback, cons Value) (Value, error)

	// UpdateVocabulary merges new attribute values with existing values.
	// This method does not overwrite or delete values, i.e.
	//     if existing values are {a, b}
	//     and new values are {c, d},
	//     then the merge result would be {a, b, c, d}.
	UpdateVocabulary(attributeName string, newValues interface{})

	// IntersectVocabulary determines an intersection
	// between new attribute values and existing ones and updates vocabulary
	// with the result.
	// If existing values are {a, b} and new values are {b, d},
	// then the values after this call would be {b}.
	// If either existing values or new values are empty {},
	// intersection result would be empty too.
	IntersectVocabulary(attributeName string, newValues interface{})
}

// NewValidator returns a new constraints Validator instance.
func NewValidator() Validator {
	return &validator{
		conflicts: make(map[string]set.Strings),
		vocab:     make(map[string][]interface{}),
	}
}

type validator struct {
	unsupported set.Strings
	conflicts   map[string]set.Strings
	vocab       map[string][]interface{}
}

// RegisterConflicts is defined on Validator.
func (v *validator) RegisterConflicts(reds, blues []string) {
	for _, red := range reds {
		v.conflicts[red] = set.NewStrings(blues...)
	}
	for _, blue := range blues {
		v.conflicts[blue] = set.NewStrings(reds...)
	}
}

// RegisterUnsupported is defined on Validator.
func (v *validator) RegisterUnsupported(unsupported []string) {
	v.unsupported = set.NewStrings(unsupported...)
}

// RegisterVocabulary is defined on Validator.
func (v *validator) RegisterVocabulary(attributeName string, allowedValues interface{}) {
	v.vocab[attributeName] = convertToSlice(allowedValues)
}

var checkIsCollection = func(coll interface{}) {
	k := reflect.TypeOf(coll).Kind()
	if k != reflect.Slice && k != reflect.Array {
		panic(fmt.Errorf("invalid vocab: %v of type %T is not a slice", coll, coll))
	}
}

var convertToSlice = func(coll interface{}) []interface{} {
	checkIsCollection(coll)
	var slice []interface{}
	val := reflect.ValueOf(coll)
	for i := 0; i < val.Len(); i++ {
		slice = append(slice, val.Index(i).Interface())
	}
	return slice
}

// UpdateVocabulary is defined on Validator.
func (v *validator) UpdateVocabulary(attributeName string, allowedValues interface{}) {
	// If this attribute is not registered, delegate to RegisterVocabulary()
	currentValues, ok := v.vocab[attributeName]
	if !ok {
		v.RegisterVocabulary(attributeName, allowedValues)
	}

	unique := map[interface{}]bool{}
	writeUnique := func(all []interface{}) {
		for _, one := range all {
			unique[one] = true
		}
	}

	// merge existing values with new, ensuring uniqueness
	writeUnique(currentValues)
	newValues := convertToSlice(allowedValues)
	writeUnique(newValues)

	v.updateVocabularyFromMap(attributeName, unique)
}

// IntersectVocabulary is defined on Validator.
func (v *validator) IntersectVocabulary(attributeName string, allowedValues interface{}) {
	newValues := convertToSlice(allowedValues)
	currentValues := v.vocab[attributeName]

	// contains determines if given item is in the supplied collection.
	contains := func(one interface{}, all []interface{}) bool {
		for _, item := range all {
			if item == one {
				return true
			}
		}
		return false
	}

	intersection := map[interface{}]bool{}
	for _, current := range currentValues {
		if contains(current, newValues) {
			intersection[current] = true
		}
	}
	v.updateVocabularyFromMap(attributeName, intersection)
}

func (v *validator) updateVocabularyFromMap(attributeName string, valuesMap map[interface{}]bool) {
	var merged []interface{}
	for one, _ := range valuesMap {
		// TODO (anastasiamac) Because it's coming from the map, the order maybe affected
		// and can be unreliable. Not sure how to fix it yet...
		// How can we guarantee the order here?
		merged = append(merged, one)
	}
	v.RegisterVocabulary(attributeName, merged)
}

// checkConflicts returns an error if the constraints Value contains conflicting attributes.
func (v *validator) checkConflicts(cons Value) error {
	attrValues := cons.attributesWithValues()
	attrSet := make(set.Strings)
	for attrTag := range attrValues {
		attrSet.Add(attrTag)
	}
	for _, attrTag := range attrSet.SortedValues() {
		conflicts, ok := v.conflicts[attrTag]
		if !ok {
			continue
		}
		for _, conflict := range conflicts.SortedValues() {
			if attrSet.Contains(conflict) {
				return fmt.Errorf("ambiguous constraints: %q overlaps with %q", attrTag, conflict)
			}
		}
	}
	return nil
}

// checkUnsupported returns any unsupported attributes.
func (v *validator) checkUnsupported(cons Value) []string {
	return cons.hasAny(v.unsupported.Values()...)
}

// checkValidValues returns an error if the constraints value contains an
// attribute value which is not allowed by the vocab which may have been
// registered for it.
func (v *validator) checkValidValues(cons Value) error {
	for attrTag, attrValue := range cons.attributesWithValues() {
		k := reflect.TypeOf(attrValue).Kind()
		if k == reflect.Slice || k == reflect.Array {
			// For slices we check that all values are valid.
			val := reflect.ValueOf(attrValue)
			for i := 0; i < val.Len(); i++ {
				if err := v.checkInVocab(attrTag, val.Index(i).Interface()); err != nil {
					return err
				}
			}
		} else {
			if err := v.checkInVocab(attrTag, attrValue); err != nil {
				return err
			}
		}
	}
	return nil
}

// checkInVocab returns an error if the attribute value is not allowed by the
// vocab which may have been registered for it.
func (v *validator) checkInVocab(attributeName string, attributeValue interface{}) error {
	validValues, ok := v.vocab[attributeName]
	if !ok {
		return nil
	}
	for _, validValue := range validValues {
		if coerce(validValue) == coerce(attributeValue) {
			return nil
		}
	}
	return fmt.Errorf(
		"invalid constraint value: %v=%v\nvalid values are: %v", attributeName, attributeValue, validValues)
}

// coerce returns v in a format that allows constraint values to be easily compared.
// Its main purpose is to cast all numeric values to int64 or float64.
func coerce(v interface{}) interface{} {
	if v != nil {
		switch vv := reflect.TypeOf(v); vv.Kind() {
		case reflect.String:
			return v
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			return int64(reflect.ValueOf(v).Int())
		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
			uval := reflect.ValueOf(v).Uint()
			// Just double check the value is in range.
			if uval > math.MaxInt64 {
				panic(fmt.Errorf("constraint value %v is too large", uval))
			}
			return int64(uval)
		case reflect.Float32, reflect.Float64:
			return float64(reflect.ValueOf(v).Float())
		}
	}
	return v
}

// withFallbacks returns a copy of v with nil values taken from vFallback.
func withFallbacks(v Value, vFallback Value) Value {
	result := vFallback
	for _, fieldName := range fieldNames {
		resultVal := reflect.ValueOf(&result).Elem().FieldByName(fieldName)
		val := reflect.ValueOf(&v).Elem().FieldByName(fieldName)
		if !val.IsNil() {
			resultVal.Set(val)
		}
	}
	return result
}

// Validate is defined on Validator.
func (v *validator) Validate(cons Value) ([]string, error) {
	unsupported := v.checkUnsupported(cons)
	if err := v.checkConflicts(cons); err != nil {
		return unsupported, err
	}
	if err := v.checkValidValues(cons); err != nil {
		return unsupported, err
	}
	return unsupported, nil
}

// Merge is defined on Validator.
func (v *validator) Merge(consFallback, cons Value) (Value, error) {
	// First ensure both constraints are valid. We don't care if there
	// are constraint attributes that are unsupported.
	if _, err := v.Validate(consFallback); err != nil {
		return Value{}, err
	}
	if _, err := v.Validate(cons); err != nil {
		return Value{}, err
	}
	// Gather any attributes from consFallback which conflict with those on cons.
	attrValues := cons.attributesWithValues()
	var fallbackConflicts []string
	for attrTag := range attrValues {
		fallbackConflicts = append(fallbackConflicts, v.conflicts[attrTag].Values()...)
	}
	// Null out the conflicting consFallback attribute values because
	// cons takes priority. We can't error here because we
	// know that aConflicts contains valid attr names.
	consFallbackMinusConflicts, _ := consFallback.without(fallbackConflicts...)
	// The result is cons with fallbacks coming from any
	// non conflicting consFallback attributes.
	return withFallbacks(cons, consFallbackMinusConflicts), nil
}
<commit_msg>Changed the order from containt(one, all) to contains(all,one)<commit_after>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package constraints

import (
	"fmt"
	"math"
	"reflect"

	"github.com/juju/utils/set"
)

// Validator defines operations on constraints attributes which are
// used to ensure a constraints value is valid, as well as being able
// to handle overridden attributes.
type Validator interface {

	// RegisterConflicts is used to define cross-constraint override behaviour.
	// The red and blue attribute lists contain attribute names which conflict
	// with those in the other list.
	// When two constraints conflict:
	//  it is an error to set both constraints in the same constraints Value.
	//  when a constraints Value overrides another which specifies a conflicting
	//   attribute, the attribute in the overridden Value is cleared.
	RegisterConflicts(reds, blues []string)

	// RegisterUnsupported records attributes which are not supported by a constraints Value.
	RegisterUnsupported(unsupported []string)

	// RegisterVocabulary records allowed values for the specified constraint attribute.
	// allowedValues is expected to be a slice/array but is declared as interface{} so
	// that vocabs of different types can be passed in.
	RegisterVocabulary(attributeName string, allowedValues interface{})

	// Validate returns an error if the given constraints are not valid, and also
	// any unsupported attributes.
	Validate(cons Value) ([]string, error)

	// Merge merges cons into consFallback, with any conflicting attributes from cons
	// overriding those from consFallback.
	Merge(consFallback, cons Value) (Value, error)

	// UpdateVocabulary merges new attribute values with existing values.
	// This method does not overwrite or delete values, i.e.
	//     if existing values are {a, b}
	//     and new values are {c, d},
	//     then the merge result would be {a, b, c, d}.
	UpdateVocabulary(attributeName string, newValues interface{})

	// IntersectVocabulary determines an intersection
	// between new attribute values and existing ones and updates vocabulary
	// with the result.
	// If existing values are {a, b} and new values are {b, d},
	// then the values after this call would be {b}.
	// If either existing values or new values are empty {},
	// intersection result would be empty too.
	IntersectVocabulary(attributeName string, newValues interface{})
}

// NewValidator returns a new constraints Validator instance.
func NewValidator() Validator {
	return &validator{
		conflicts: make(map[string]set.Strings),
		vocab:     make(map[string][]interface{}),
	}
}

type validator struct {
	unsupported set.Strings
	conflicts   map[string]set.Strings
	vocab       map[string][]interface{}
}

// RegisterConflicts is defined on Validator.
func (v *validator) RegisterConflicts(reds, blues []string) {
	for _, red := range reds {
		v.conflicts[red] = set.NewStrings(blues...)
	}
	for _, blue := range blues {
		v.conflicts[blue] = set.NewStrings(reds...)
	}
}

// RegisterUnsupported is defined on Validator.
func (v *validator) RegisterUnsupported(unsupported []string) {
	v.unsupported = set.NewStrings(unsupported...)
}

// RegisterVocabulary is defined on Validator.
func (v *validator) RegisterVocabulary(attributeName string, allowedValues interface{}) {
	v.vocab[attributeName] = convertToSlice(allowedValues)
}

var checkIsCollection = func(coll interface{}) {
	k := reflect.TypeOf(coll).Kind()
	if k != reflect.Slice && k != reflect.Array {
		panic(fmt.Errorf("invalid vocab: %v of type %T is not a slice", coll, coll))
	}
}

var convertToSlice = func(coll interface{}) []interface{} {
	checkIsCollection(coll)
	var slice []interface{}
	val := reflect.ValueOf(coll)
	for i := 0; i < val.Len(); i++ {
		slice = append(slice, val.Index(i).Interface())
	}
	return slice
}

// UpdateVocabulary is defined on Validator.
func (v *validator) UpdateVocabulary(attributeName string, allowedValues interface{}) {
	// If this attribute is not registered, delegate to RegisterVocabulary()
	currentValues, ok := v.vocab[attributeName]
	if !ok {
		v.RegisterVocabulary(attributeName, allowedValues)
	}

	unique := map[interface{}]bool{}
	writeUnique := func(all []interface{}) {
		for _, one := range all {
			unique[one] = true
		}
	}

	// merge existing values with new, ensuring uniqueness
	writeUnique(currentValues)
	newValues := convertToSlice(allowedValues)
	writeUnique(newValues)

	v.updateVocabularyFromMap(attributeName, unique)
}

// IntersectVocabulary is defined on Validator.
func (v *validator) IntersectVocabulary(attributeName string, allowedValues interface{}) {
	newValues := convertToSlice(allowedValues)
	currentValues := v.vocab[attributeName]

	// contains determines if given item is in the supplied collection.
	contains := func(all []interface{}, one interface{}) bool {
		for _, item := range all {
			if item == one {
				return true
			}
		}
		return false
	}

	intersection := map[interface{}]bool{}
	for _, current := range currentValues {
		if contains(newValues, current) {
			intersection[current] = true
		}
	}
	v.updateVocabularyFromMap(attributeName, intersection)
}

func (v *validator) updateVocabularyFromMap(attributeName string, valuesMap map[interface{}]bool) {
	var merged []interface{}
	for one, _ := range valuesMap {
		// TODO (anastasiamac) Because it's coming from the map, the order maybe affected
		// and can be unreliable. Not sure how to fix it yet...
		// How can we guarantee the order here?
		merged = append(merged, one)
	}
	v.RegisterVocabulary(attributeName, merged)
}

// checkConflicts returns an error if the constraints Value contains conflicting attributes.
func (v *validator) checkConflicts(cons Value) error {
	attrValues := cons.attributesWithValues()
	attrSet := make(set.Strings)
	for attrTag := range attrValues {
		attrSet.Add(attrTag)
	}
	for _, attrTag := range attrSet.SortedValues() {
		conflicts, ok := v.conflicts[attrTag]
		if !ok {
			continue
		}
		for _, conflict := range conflicts.SortedValues() {
			if attrSet.Contains(conflict) {
				return fmt.Errorf("ambiguous constraints: %q overlaps with %q", attrTag, conflict)
			}
		}
	}
	return nil
}

// checkUnsupported returns any unsupported attributes.
func (v *validator) checkUnsupported(cons Value) []string {
	return cons.hasAny(v.unsupported.Values()...)
}

// checkValidValues returns an error if the constraints value contains an
// attribute value which is not allowed by the vocab which may have been
// registered for it.
func (v *validator) checkValidValues(cons Value) error {
	for attrTag, attrValue := range cons.attributesWithValues() {
		k := reflect.TypeOf(attrValue).Kind()
		if k == reflect.Slice || k == reflect.Array {
			// For slices we check that all values are valid.
			val := reflect.ValueOf(attrValue)
			for i := 0; i < val.Len(); i++ {
				if err := v.checkInVocab(attrTag, val.Index(i).Interface()); err != nil {
					return err
				}
			}
		} else {
			if err := v.checkInVocab(attrTag, attrValue); err != nil {
				return err
			}
		}
	}
	return nil
}

// checkInVocab returns an error if the attribute value is not allowed by the
// vocab which may have been registered for it.
func (v *validator) checkInVocab(attributeName string, attributeValue interface{}) error {
	validValues, ok := v.vocab[attributeName]
	if !ok {
		return nil
	}
	for _, validValue := range validValues {
		if coerce(validValue) == coerce(attributeValue) {
			return nil
		}
	}
	return fmt.Errorf(
		"invalid constraint value: %v=%v\nvalid values are: %v", attributeName, attributeValue, validValues)
}

// coerce returns v in a format that allows constraint values to be easily compared.
// Its main purpose is to cast all numeric values to int64 or float64.
func coerce(v interface{}) interface{} {
	if v != nil {
		switch vv := reflect.TypeOf(v); vv.Kind() {
		case reflect.String:
			return v
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			return int64(reflect.ValueOf(v).Int())
		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
			uval := reflect.ValueOf(v).Uint()
			// Just double check the value is in range.
			if uval > math.MaxInt64 {
				panic(fmt.Errorf("constraint value %v is too large", uval))
			}
			return int64(uval)
		case reflect.Float32, reflect.Float64:
			return float64(reflect.ValueOf(v).Float())
		}
	}
	return v
}

// withFallbacks returns a copy of v with nil values taken from vFallback.
func withFallbacks(v Value, vFallback Value) Value {
	result := vFallback
	for _, fieldName := range fieldNames {
		resultVal := reflect.ValueOf(&result).Elem().FieldByName(fieldName)
		val := reflect.ValueOf(&v).Elem().FieldByName(fieldName)
		if !val.IsNil() {
			resultVal.Set(val)
		}
	}
	return result
}

// Validate is defined on Validator.
func (v *validator) Validate(cons Value) ([]string, error) {
	unsupported := v.checkUnsupported(cons)
	if err := v.checkConflicts(cons); err != nil {
		return unsupported, err
	}
	if err := v.checkValidValues(cons); err != nil {
		return unsupported, err
	}
	return unsupported, nil
}

// Merge is defined on Validator.
func (v *validator) Merge(consFallback, cons Value) (Value, error) {
	// First ensure both constraints are valid. We don't care if there
	// are constraint attributes that are unsupported.
	if _, err := v.Validate(consFallback); err != nil {
		return Value{}, err
	}
	if _, err := v.Validate(cons); err != nil {
		return Value{}, err
	}
	// Gather any attributes from consFallback which conflict with those on cons.
	attrValues := cons.attributesWithValues()
	var fallbackConflicts []string
	for attrTag := range attrValues {
		fallbackConflicts = append(fallbackConflicts, v.conflicts[attrTag].Values()...)
	}
	// Null out the conflicting consFallback attribute values because
	// cons takes priority. We can't error here because we
	// know that aConflicts contains valid attr names.
	consFallbackMinusConflicts, _ := consFallback.without(fallbackConflicts...)
	// The result is cons with fallbacks coming from any
	// non conflicting consFallback attributes.
	return withFallbacks(cons, consFallbackMinusConflicts), nil
}
<|endoftext|>


<commit_before>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package lxc_test

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	stdtesting "testing"

	. "launchpad.net/gocheck"
	"launchpad.net/goyaml"
	"launchpad.net/juju-core/container/lxc"
	"launchpad.net/juju-core/instance"
	jujutesting "launchpad.net/juju-core/juju/testing"
	"launchpad.net/juju-core/state"
	"launchpad.net/juju-core/testing"
	. "launchpad.net/juju-core/testing/checkers"
	"launchpad.net/juju-core/version"
)

func Test(t *stdtesting.T) {
	TestingT(t)
}

type LxcSuite struct {
	testing.LoggingSuite
	lxc.TestSuite
}

var _ = Suite(&LxcSuite{})

func (s *LxcSuite) SetUpSuite(c *C) {
	s.LoggingSuite.SetUpSuite(c)
	s.TestSuite.SetUpSuite(c)
}

func (s *LxcSuite) TearDownSuite(c *C) {
	s.TestSuite.TearDownSuite(c)
	s.LoggingSuite.TearDownSuite(c)
}

func (s *LxcSuite) SetUpTest(c *C) {
	s.LoggingSuite.SetUpTest(c)
	s.TestSuite.SetUpTest(c)
}

func (s *LxcSuite) TearDownTest(c *C) {
	s.TestSuite.TearDownTest(c)
	s.LoggingSuite.TearDownTest(c)
}

func StartContainer(c *C, manager lxc.ContainerManager, machineId string) instance.Instance {
	config := testing.EnvironConfig(c)
	stateInfo := jujutesting.FakeStateInfo(machineId)
	apiInfo := jujutesting.FakeAPIInfo(machineId)

	series := "series"
	nonce := "fake-nonce"
	tools := &state.Tools{
		Binary: version.MustParseBinary("2.3.4-foo-bar"),
		URL:    "http://tools.testing.invalid/2.3.4-foo-bar.tgz",
	}

	inst, err := manager.StartContainer(machineId, series, nonce, tools, config, stateInfo, apiInfo)
	c.Assert(err, IsNil)
	return inst
}

func (s *LxcSuite) TestStartContainer(c *C) {
	manager := lxc.NewContainerManager(lxc.ManagerConfig{})
	instance := StartContainer(c, manager, "1/lxc/0")

	name := string(instance.Id())
	// Check our container config files.
	c.Assert(filepath.Join(s.ContainerDir, name, "lxc.conf"), IsNonEmptyFile)
	cloudInitFilename := filepath.Join(s.ContainerDir, name, "cloud-init")
	c.Assert(cloudInitFilename, IsNonEmptyFile)
	data, err := ioutil.ReadFile(cloudInitFilename)
	c.Assert(err, IsNil)
	c.Assert(string(data), HasPrefix, "#cloud-config\n")

	x := make(map[interface{}]interface{})
	err = goyaml.Unmarshal(data, &x)
	c.Assert(err, IsNil)

	var scripts []string
	for _, s := range x["runcmd"].([]interface{}) {
		scripts = append(scripts, s.(string))
	}

	c.Assert(scripts[len(scripts)-1], Equals, "start jujud-machine-1-lxc-0")

	// Check the mount point has been created inside the container.
	c.Assert(filepath.Join(s.LxcDir, name, "rootfs/var/log/juju"), IsDirectory)
}

func (s *LxcSuite) TestStopContainer(c *C) {
	manager := lxc.NewContainerManager(lxc.ManagerConfig{})
	instance := StartContainer(c, manager, "1/lxc/0")

	err := manager.StopContainer(instance)
	c.Assert(err, IsNil)

	name := string(instance.Id())
	// Check that the container dir is no longer in the container dir
	c.Assert(filepath.Join(s.ContainerDir, name), DoesNotExist)
	// but instead, in the removed container dir
	c.Assert(filepath.Join(s.RemovedDir, name), IsDirectory)
}

func (s *LxcSuite) TestStopContainerNameClash(c *C) {
	manager := lxc.NewContainerManager(lxc.ManagerConfig{})
	instance := StartContainer(c, manager, "1/lxc/0")

	name := string(instance.Id())
	targetDir := filepath.Join(s.RemovedDir, name)
	err := os.MkdirAll(targetDir, 0755)
	c.Assert(err, IsNil)

	err = manager.StopContainer(instance)
	c.Assert(err, IsNil)

	// Check that the container dir is no longer in the container dir
	c.Assert(filepath.Join(s.ContainerDir, name), DoesNotExist)
	// but instead, in the removed container dir with a ".1" suffix as there was already a directory there.
	c.Assert(filepath.Join(s.RemovedDir, fmt.Sprintf("%s.1", name)), IsDirectory)
}

func (s *LxcSuite) TestNamedManagerPrefix(c *C) {
	manager := lxc.NewContainerManager(lxc.ManagerConfig{Name: "eric"})
	instance := StartContainer(c, manager, "1/lxc/0")
	c.Assert(string(instance.Id()), Equals, "eric-machine-1-lxc-0")
}

func (s *LxcSuite) TestListContainers(c *C) {
	foo := lxc.NewContainerManager(lxc.ManagerConfig{Name: "foo"})
	bar := lxc.NewContainerManager(lxc.ManagerConfig{Name: "bar"})

	foo1 := StartContainer(c, foo, "1/lxc/0")
	foo2 := StartContainer(c, foo, "1/lxc/1")
	foo3 := StartContainer(c, foo, "1/lxc/2")

	bar1 := StartContainer(c, bar, "1/lxc/0")
	bar2 := StartContainer(c, bar, "1/lxc/1")

	result, err := foo.ListContainers()
	c.Assert(err, IsNil)
	testing.MatchInstances(c, result, foo1, foo2, foo3)

	result, err = bar.ListContainers()
	c.Assert(err, IsNil)
	testing.MatchInstances(c, result, bar1, bar2)
}
<commit_msg>Add gc prefix for gocheck.<commit_after>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package lxc_test

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	stdtesting "testing"

	gc "launchpad.net/gocheck"
	"launchpad.net/goyaml"

	"launchpad.net/juju-core/container/lxc"
	"launchpad.net/juju-core/instance"
	jujutesting "launchpad.net/juju-core/juju/testing"
	"launchpad.net/juju-core/state"
	"launchpad.net/juju-core/testing"
	jc "launchpad.net/juju-core/testing/checkers"
	"launchpad.net/juju-core/version"
)

func Test(t *stdtesting.T) {
	gc.TestingT(t)
}

type LxcSuite struct {
	testing.LoggingSuite
	lxc.TestSuite
}

var _ = gc.Suite(&LxcSuite{})

func (s *LxcSuite) SetUpSuite(c *gc.C) {
	s.LoggingSuite.SetUpSuite(c)
	s.TestSuite.SetUpSuite(c)
}

func (s *LxcSuite) TearDownSuite(c *gc.C) {
	s.TestSuite.TearDownSuite(c)
	s.LoggingSuite.TearDownSuite(c)
}

func (s *LxcSuite) SetUpTest(c *gc.C) {
	s.LoggingSuite.SetUpTest(c)
	s.TestSuite.SetUpTest(c)
}

func (s *LxcSuite) TearDownTest(c *gc.C) {
	s.TestSuite.TearDownTest(c)
	s.LoggingSuite.TearDownTest(c)
}

func StartContainer(c *gc.C, manager lxc.ContainerManager, machineId string) instance.Instance {
	config := testing.EnvironConfig(c)
	stateInfo := jujutesting.FakeStateInfo(machineId)
	apiInfo := jujutesting.FakeAPIInfo(machineId)

	series := "series"
	nonce := "fake-nonce"
	tools := &state.Tools{
		Binary: version.MustParseBinary("2.3.4-foo-bar"),
		URL:    "http://tools.testing.invalid/2.3.4-foo-bar.tgz",
	}

	inst, err := manager.StartContainer(machineId, series, nonce, tools, config, stateInfo, apiInfo)
	c.Assert(err, gc.IsNil)
	return inst
}

func (s *LxcSuite) TestStartContainer(c *gc.C) {
	manager := lxc.NewContainerManager(lxc.ManagerConfig{})
	instance := StartContainer(c, manager, "1/lxc/0")

	name := string(instance.Id())
	// Check our container config files.
	c.Assert(filepath.Join(s.ContainerDir, name, "lxc.conf"), jc.IsNonEmptyFile)
	cloudInitFilename := filepath.Join(s.ContainerDir, name, "cloud-init")
	c.Assert(cloudInitFilename, jc.IsNonEmptyFile)
	data, err := ioutil.ReadFile(cloudInitFilename)
	c.Assert(err, gc.IsNil)
	c.Assert(string(data), jc.HasPrefix, "#cloud-config\n")

	x := make(map[interface{}]interface{})
	err = goyaml.Unmarshal(data, &x)
	c.Assert(err, gc.IsNil)

	var scripts []string
	for _, s := range x["runcmd"].([]interface{}) {
		scripts = append(scripts, s.(string))
	}

	c.Assert(scripts[len(scripts)-1], gc.Equals, "start jujud-machine-1-lxc-0")

	// Check the mount point has been created inside the container.
	c.Assert(filepath.Join(s.LxcDir, name, "rootfs/var/log/juju"), jc.IsDirectory)
}

func (s *LxcSuite) TestStopContainer(c *gc.C) {
	manager := lxc.NewContainerManager(lxc.ManagerConfig{})
	instance := StartContainer(c, manager, "1/lxc/0")

	err := manager.StopContainer(instance)
	c.Assert(err, gc.IsNil)

	name := string(instance.Id())
	// Check that the container dir is no longer in the container dir
	c.Assert(filepath.Join(s.ContainerDir, name), jc.DoesNotExist)
	// but instead, in the removed container dir
	c.Assert(filepath.Join(s.RemovedDir, name), jc.IsDirectory)
}

func (s *LxcSuite) TestStopContainerNameClash(c *gc.C) {
	manager := lxc.NewContainerManager(lxc.ManagerConfig{})
	instance := StartContainer(c, manager, "1/lxc/0")

	name := string(instance.Id())
	targetDir := filepath.Join(s.RemovedDir, name)
	err := os.MkdirAll(targetDir, 0755)
	c.Assert(err, gc.IsNil)

	err = manager.StopContainer(instance)
	c.Assert(err, gc.IsNil)

	// Check that the container dir is no longer in the container dir
	c.Assert(filepath.Join(s.ContainerDir, name), jc.DoesNotExist)
	// but instead, in the removed container dir with a ".1" suffix as there was already a directory there.
	c.Assert(filepath.Join(s.RemovedDir, fmt.Sprintf("%s.1", name)), jc.IsDirectory)
}

func (s *LxcSuite) TestNamedManagerPrefix(c *gc.C) {
	manager := lxc.NewContainerManager(lxc.ManagerConfig{Name: "eric"})
	instance := StartContainer(c, manager, "1/lxc/0")
	c.Assert(string(instance.Id()), gc.Equals, "eric-machine-1-lxc-0")
}

func (s *LxcSuite) TestListContainers(c *gc.C) {
	foo := lxc.NewContainerManager(lxc.ManagerConfig{Name: "foo"})
	bar := lxc.NewContainerManager(lxc.ManagerConfig{Name: "bar"})

	foo1 := StartContainer(c, foo, "1/lxc/0")
	foo2 := StartContainer(c, foo, "1/lxc/1")
	foo3 := StartContainer(c, foo, "1/lxc/2")

	bar1 := StartContainer(c, bar, "1/lxc/0")
	bar2 := StartContainer(c, bar, "1/lxc/1")

	result, err := foo.ListContainers()
	c.Assert(err, gc.IsNil)
	testing.MatchInstances(c, result, foo1, foo2, foo3)

	result, err = bar.ListContainers()
	c.Assert(err, gc.IsNil)
	testing.MatchInstances(c, result, bar1, bar2)
}
<|endoftext|>


<commit_before>package doggy

import (
	"github.com/gorilla/mux"
	"github.com/urfave/negroni"
)

func New(handlers ...negroni.Handler) *negroni.Negroni {
	return negroni.New()
}

func NewStd() *negroni.Negroni {
	n := negroni.New()
	n.UseFunc(Recovery)
	n.UseFunc(Logger)
	n.UseFunc(TraceID)
	n.UseFunc(RealIP)
	n.UseFunc(CloseNotify)
	n.UseFunc(Timeout)
	return n
}

func NewMux() *mux.Router {
	return mux.NewRouter()
}

func init() {
	LoadConfig("config.ini")
}
<commit_msg>rename<commit_after>package doggy

import (
	"github.com/gorilla/mux"
	"github.com/urfave/negroni"
)

func New(handlers ...negroni.Handler) *negroni.Negroni {
	return negroni.New()
}

func Classic() *negroni.Negroni {
	n := negroni.New()
	n.UseFunc(Recovery)
	n.UseFunc(Logger)
	n.UseFunc(TraceID)
	n.UseFunc(RealIP)
	n.UseFunc(CloseNotify)
	n.UseFunc(Timeout)
	return n
}

func NewMux() *mux.Router {
	return mux.NewRouter()
}

func init() {
	LoadConfig("config.ini")
}
<|endoftext|>


<commit_before>package controller

import (
	"testing"
	"time"

	"github.com/juju/errgo"
	"github.com/stretchr/testify/mock"
	"golang.org/x/net/context"

	"github.com/giantswarm/inago/fleet"
	"github.com/giantswarm/inago/task"
)

var (
	testError = errgo.New("test error")
)

func IsTestError(err error) bool {
	return errgo.Cause(err) == testError
}

// Return a controller for testing the updates with.
func getTestController() (controller, *fleetMock) {
	newFleetMock := newFleetMock(defaultFleetMockConfig())

	newTaskServiceConfig := task.DefaultConfig()
	newTaskServiceConfig.WaitSleep = 1 * time.Millisecond

	newTaskService := task.NewTaskService(newTaskServiceConfig)

	newControllerConfig := DefaultConfig()
	newControllerConfig.Fleet = newFleetMock
	newControllerConfig.TaskService = newTaskService
	newControllerConfig.WaitCount = 1
	newControllerConfig.WaitSleep = 1 * time.Millisecond
	newControllerConfig.WaitTimeout = 3 * time.Millisecond

	newController := controller{newControllerConfig}

	return newController, newFleetMock
}

// TestExecuteTaskAction tests the executeTaskAction method.
func TestExecuteTaskAction(t *testing.T) {
	testController, _ := getTestController()

	var tests = []struct {
		function   func(context.Context, Request) (*task.Task, error)
		ctx        context.Context
		req        Request
		errMatcher func(err error) bool
	}{
		// Test a task that does nothing.
		{
			function: func(ctx context.Context, req Request) (*task.Task, error) {
				taskObject, _ := testController.TaskService.Create(
					ctx,
					func(ctx context.Context) error {
						time.Sleep(5 * time.Millisecond)
						return nil
					},
				)

				return taskObject, nil
			},
			ctx:        context.Background(),
			req:        Request{},
			errMatcher: nil,
		},
		// Test a task that returns an error.
		{
			function: func(ctx context.Context, req Request) (*task.Task, error) {
				taskObject, _ := testController.TaskService.Create(
					ctx,
					func(ctx context.Context) error {
						return testError
					},
				)

				return taskObject, nil
			},
			ctx:        context.Background(),
			req:        Request{},
			errMatcher: IsTestError,
		},
	}

	for i, test := range tests {
		err := testController.executeTaskAction(
			test.function,
			test.ctx,
			test.req,
		)

		if err != nil && test.errMatcher == nil {
			t.Logf("%v: method return error '%v', when it should not return any errors", i, err)
			t.Fail()
		}

		if err != nil && test.errMatcher != nil && test.errMatcher(err) {
			t.Logf("%v: method returned error '%v', which does not match error matcher '%v'", i, err, test.errMatcher)
			t.Fail()
		}
	}
}

// TestGetNumRunningSlices tests the getNumRunningSlices method.
func TestGetNumRunningSlices(t *testing.T) {
	var tests = []struct {
		fleetMockSetUp func(*fleetMock)
		req            Request
		numSlices      int
		errMatcher     func(err error) bool
	}{
		{
			fleetMockSetUp: func(f *fleetMock) {
				f.On("GetStatusWithMatcher", mock.AnythingOfType("func(string) bool")).Return(
					[]fleet.UnitStatus{},
					nil,
				)
			},
			req:        Request{},
			numSlices:  0,
			errMatcher: nil,
		},
		{
			fleetMockSetUp: func(f *fleetMock) {
				f.On("GetStatusWithMatcher", mock.AnythingOfType("func(string) bool")).Return(
					[]fleet.UnitStatus{},
					nil,
				)
			},
			req: Request{
				RequestConfig: RequestConfig{
					Group: "some group",
				},
			},
			numSlices:  0,
			errMatcher: IsUnitNotFound,
		},
	}

	for i, test := range tests {
		testController, fleetMock := getTestController()

		if test.fleetMockSetUp != nil {
			test.fleetMockSetUp(fleetMock)
		}

		numSlices, err := testController.getNumRunningSlices(test.req)

		if err != nil && test.errMatcher == nil {
			t.Logf("%v: method returned unexpected error '%v'", i, err)
			t.Fail()
		}

		if err != nil && test.errMatcher != nil && test.errMatcher(err) {
			t.Logf("%v: method returned error '%v', which did not match expected error", i, err)
			t.Fail()
		}

		if numSlices != test.numSlices {
			t.Logf("%v: returned number of slices '%v' did not match expected: '%v'", i, numSlices, test.numSlices)
			t.Fail()
		}
	}
}
<commit_msg>Add another getNumRunningSlices test<commit_after>package controller

import (
	"testing"
	"time"

	"github.com/juju/errgo"
	"github.com/stretchr/testify/mock"
	"golang.org/x/net/context"

	"github.com/giantswarm/inago/fleet"
	"github.com/giantswarm/inago/task"
)

var (
	testError = errgo.New("test error")
)

func IsTestError(err error) bool {
	return errgo.Cause(err) == testError
}

// Return a controller for testing the updates with.
func getTestController() (controller, *fleetMock) {
	newFleetMock := newFleetMock(defaultFleetMockConfig())

	newTaskServiceConfig := task.DefaultConfig()
	newTaskServiceConfig.WaitSleep = 1 * time.Millisecond

	newTaskService := task.NewTaskService(newTaskServiceConfig)

	newControllerConfig := DefaultConfig()
	newControllerConfig.Fleet = newFleetMock
	newControllerConfig.TaskService = newTaskService
	newControllerConfig.WaitCount = 1
	newControllerConfig.WaitSleep = 1 * time.Millisecond
	newControllerConfig.WaitTimeout = 3 * time.Millisecond

	newController := controller{newControllerConfig}

	return newController, newFleetMock
}

// TestExecuteTaskAction tests the executeTaskAction method.
func TestExecuteTaskAction(t *testing.T) {
	testController, _ := getTestController()

	var tests = []struct {
		function   func(context.Context, Request) (*task.Task, error)
		ctx        context.Context
		req        Request
		errMatcher func(err error) bool
	}{
		// Test a task that does nothing.
		{
			function: func(ctx context.Context, req Request) (*task.Task, error) {
				taskObject, _ := testController.TaskService.Create(
					ctx,
					func(ctx context.Context) error {
						time.Sleep(5 * time.Millisecond)
						return nil
					},
				)

				return taskObject, nil
			},
			ctx:        context.Background(),
			req:        Request{},
			errMatcher: nil,
		},
		// Test a task that returns an error.
		{
			function: func(ctx context.Context, req Request) (*task.Task, error) {
				taskObject, _ := testController.TaskService.Create(
					ctx,
					func(ctx context.Context) error {
						return testError
					},
				)

				return taskObject, nil
			},
			ctx:        context.Background(),
			req:        Request{},
			errMatcher: IsTestError,
		},
	}

	for i, test := range tests {
		err := testController.executeTaskAction(
			test.function,
			test.ctx,
			test.req,
		)

		if err != nil && test.errMatcher == nil {
			t.Logf("%v: method return error '%v', when it should not return any errors", i, err)
			t.Fail()
		}

		if err != nil && test.errMatcher != nil && test.errMatcher(err) {
			t.Logf("%v: method returned error '%v', which does not match error matcher '%v'", i, err, test.errMatcher)
			t.Fail()
		}
	}
}

// TestGetNumRunningSlices tests the getNumRunningSlices method.
func TestGetNumRunningSlices(t *testing.T) {
	var tests = []struct {
		fleetMockSetUp func(*fleetMock)
		req            Request
		numSlices      int
		errMatcher     func(err error) bool
	}{
		{
			fleetMockSetUp: func(f *fleetMock) {
				f.On("GetStatusWithMatcher", mock.AnythingOfType("func(string) bool")).Return(
					[]fleet.UnitStatus{},
					nil,
				)
			},
			req:        Request{},
			numSlices:  0,
			errMatcher: nil,
		},
		{
			fleetMockSetUp: func(f *fleetMock) {
				f.On("GetStatusWithMatcher", mock.AnythingOfType("func(string) bool")).Return(
					[]fleet.UnitStatus{},
					nil,
				)
			},
			req: Request{
				RequestConfig: RequestConfig{
					Group: "some group",
				},
			},
			numSlices:  0,
			errMatcher: IsUnitNotFound,
		},
		{
			fleetMockSetUp: func(f *fleetMock) {
				f.On("GetStatusWithMatcher", mock.AnythingOfType("func(string) bool")).Return(
					[]fleet.UnitStatus{
						fleet.UnitStatus{
							Name: "kubernetes-api-server",
						},
					},
					nil,
				)
			},
			req: Request{
				RequestConfig: RequestConfig{
					Group: "kubernetes",
				},
			},
			numSlices:  1,
			errMatcher: nil,
		},
	}

	for i, test := range tests {
		testController, fleetMock := getTestController()

		if test.fleetMockSetUp != nil {
			test.fleetMockSetUp(fleetMock)
		}

		numSlices, err := testController.getNumRunningSlices(test.req)

		if err != nil && test.errMatcher == nil {
			t.Logf("%v: method returned unexpected error '%v'", i, err)
			t.Fail()
		}

		if err != nil && test.errMatcher != nil && test.errMatcher(err) {
			t.Logf("%v: method returned error '%v', which did not match expected error", i, err)
			t.Fail()
		}

		if numSlices != test.numSlices {
			t.Logf("%v: returned number of slices '%v' did not match expected: '%v'", i, numSlices, test.numSlices)
			t.Fail()
		}
	}
}
<|endoftext|>


<commit_before>package controllers

import (
	"github.com/gin-gonic/gin"
	"github.com/stretchr/testify/assert"
	"gopkg.in/DATA-DOG/go-sqlmock.v1"
	"testing"

	"github.com/eirka/eirka-libs/audit"
	"github.com/eirka/eirka-libs/db"
	//e "github.com/eirka/eirka-libs/errors"
	"github.com/eirka/eirka-libs/user"
)

func TestEmailController(t *testing.T) {

	var err error

	user.Secret = "secret"

	gin.SetMode(gin.ReleaseMode)

	router := gin.New()

	router.Use(user.Auth(true))

	router.POST("/email", EmailController)

	u := user.DefaultUser()
	u.SetId(2)
	u.SetAuthenticated()
	u.Password()

	assert.True(t, u.ComparePassword("testpassword"), "Test user password should be set")

	token, err := u.CreateToken()
	if assert.NoError(t, err, "An error was not expected") {
		assert.NotEmpty(t, token, "token should be returned")
	}

	mock, err := db.NewTestDb()
	assert.NoError(t, err, "An error was not expected")

	rows := sqlmock.NewRows([]string{"name", "email"}).AddRow("test", "old@test.com")
	mock.ExpectQuery(`SELECT user_name,user_email FROM users WHERE user_id`).WillReturnRows(rows)

	mock.ExpectExec("UPDATE users SET user_email").
		WithArgs("cool@test.com", 2).
		WillReturnResult(sqlmock.NewResult(1, 1))

	request := []byte(`{"ib": 1, "email": "test@test.com"}`)

	first := performJwtJsonRequest(router, "POST", "/email", token, request)

	assert.Equal(t, first.Code, 200, "HTTP request code should match")
	assert.JSONEq(t, first.Body.String(), successMessage(audit.AuditEmailUpdate), "HTTP response should match")

	assert.NoError(t, mock.ExpectationsWereMet(), "An error was not expected")

}
<commit_msg>add controller tests<commit_after>package controllers

import (
	"github.com/gin-gonic/gin"
	"github.com/stretchr/testify/assert"
	"gopkg.in/DATA-DOG/go-sqlmock.v1"
	"testing"

	"github.com/eirka/eirka-libs/audit"
	"github.com/eirka/eirka-libs/db"
	//e "github.com/eirka/eirka-libs/errors"
	"github.com/eirka/eirka-libs/user"
)

func TestEmailController(t *testing.T) {

	var err error

	user.Secret = "secret"

	gin.SetMode(gin.ReleaseMode)

	router := gin.New()

	router.Use(user.Auth(true))

	router.POST("/email", EmailController)

	user := DefaultUser()
	user.SetId(2)
	user.SetAuthenticated()

	user.hash, err = HashPassword("testpassword")
	if assert.NoError(t, err, "An error was not expected") {
		assert.NotNil(t, user.hash, "password should be returned")
	}

	assert.True(t, user.ComparePassword("testpassword"), "Password should validate")

	token, err := user.CreateToken()
	if assert.NoError(t, err, "An error was not expected") {
		assert.NotEmpty(t, badtoken, "token should be returned")
	}

	mock, err := db.NewTestDb()
	assert.NoError(t, err, "An error was not expected")

	rows := sqlmock.NewRows([]string{"name", "email"}).AddRow("test", "old@test.com")
	mock.ExpectQuery(`SELECT user_name,user_email FROM users WHERE user_id`).WillReturnRows(rows)

	mock.ExpectExec("UPDATE users SET user_email").
		WithArgs("cool@test.com", 2).
		WillReturnResult(sqlmock.NewResult(1, 1))

	request := []byte(`{"ib": 1, "email": "test@test.com"}`)

	first := performJwtJsonRequest(router, "POST", "/email", token, request)

	assert.Equal(t, first.Code, 200, "HTTP request code should match")
	assert.JSONEq(t, first.Body.String(), successMessage(audit.AuditEmailUpdate), "HTTP response should match")

	assert.NoError(t, mock.ExpectationsWereMet(), "An error was not expected")

}
<|endoftext|>


<commit_before>package network

import (
	"io"
	"fmt"
	"errors"
	"github.com/yaricom/goNEAT/neat"
)

// A NODE is either a NEURON or a SENSOR.
//   - If it's a sensor, it can be loaded with a value for output
//   - If it's a neuron, it has a list of its incoming input signals ([]*Link is used)
// Use an activation count to avoid flushing
type NNode struct {
	// The ID of the node
	Id               int

	// If true the node is active
	IsActive         bool

	// The the type of the node (NEURON or SENSOR)
	NType            int
	// The type of node activation function (SIGMOID, ...)
	FType            int
	// The placement of the node in the network layers (INPUT, HIDDEN, OUTPUT)
	GenNodeLabel     int

	// The activation for current step
	ActiveOut        float64
	// The activation from PREVIOUS (time-delayed) time step, if there is one
	ActiveOutTd      float64
	// The node's activation value
	Activation       float64
	// The number of activations for current node
	ActivationsCount int32
	// The activation sum
	ActivationSum    float64

	// The list of all incoming connections
	Incoming         []*Link
	// The list of all outgoing connections
	Outgoing         []*Link
	// The trait linked to the node
	Trait            *neat.Trait

	// Used for Gene decoding
	Analogue         *NNode
	// Used for Genome duplication
	Duplicate        *NNode

	/* ************ LEARNING PARAMETERS *********** */
	// The following parameters are for use in neurons that learn through habituation,
	// sensitization, or Hebbian-type processes  */
	Params           []float64

	// Activation value of node at time t-1; Holds the previous step's activation for recurrency
	lastActivation   float64
	// Activation value of node at time t-2 Holds the activation before  the previous step's
	// This is necessary for a special recurrent case when the innode of a recurrent link is one time step ahead of the outnode.
	// The innode then needs to send from TWO time steps ago
	lastActivation2  float64
}

// Creates new node with specified type (NEURON or SENSOR) and ID
func NewNNode(ntype, nodeid int) *NNode {
	n := newNode()
	n.NType = ntype
	n.Id = nodeid
	return n
}

// Creates new node with specified type (NEURON or SENSOR), ID and in the specified
// layer (INPUT, HIDDEN, OUTPUT)
func NewNNodeInPlace(ntype, nodeid, placement int) *NNode {
	n := newNode()
	n.NType = ntype
	n.Id = nodeid
	n.GenNodeLabel = placement
	return n
}

// Construct a NNode off another NNode with given trait for genome purposes
func NewNNodeCopy(n *NNode, t *neat.Trait) *NNode {
	node := newNode()
	node.NType = n.NType
	node.Id = n.Id
	node.GenNodeLabel = n.GenNodeLabel
	node.Trait = t
	node.deriveTrait(t)
	return node
}

// Read a NNode from specified Reader and applies corresponding trait to it from a list of traits provided
func ReadNNode(r io.Reader, traits []*neat.Trait) *NNode {
	n := newNode()
	var trait_id int
	fmt.Fscanf(r, "%d %d %d %d ", &n.Id, &trait_id, &n.NType, &n.GenNodeLabel)
	if trait_id != 0 && traits != nil {
		// find corresponding node trait from list
		for _, t := range traits {
			if trait_id == t.Id {
				n.Trait = t
				n.deriveTrait(t)
				break
			}
		}
	} else {
		// just create empty params
		n.deriveTrait(nil)
	}
	return n
}

// The private default constructor
func newNode() *NNode {
	return &NNode{
		FType:SIGMOID,
		Incoming:make([]*Link, 0),
		Outgoing:make([]*Link, 0),
		GenNodeLabel:HIDDEN,
	}
}

// Copy trait parameters into this node's parameters
func (n *NNode) deriveTrait(t *neat.Trait) {
	n.Params = make([]float64, neat.Num_trait_params)
	if t != nil {
		for i, p := range t.Params {
			n.Params[i] = p
		}
	}
}

// Saves current node's activations for potential time delayed connections
func (n *NNode) saveActivations() {
	n.lastActivation2 = n.lastActivation
	n.lastActivation = n.Activation
}

// Returns activation for a current step
func (n *NNode) GetActiveOut() float64 {
	if n.ActivationsCount > 0 {
		return n.Activation
	} else {
		return 0.0
	}
}

// Returns activation from PREVIOUS time step
func (n *NNode) GetActiveOutTd() float64 {
	if n.ActivationsCount > 1 {
		return n.lastActivation
	} else {
		return 0.0
	}
}

// Returns true if this node is SENSOR
func (n *NNode) IsSensor() bool {
	return n.NType == SENSOR
}

// returns true if this node is NEURON
func (n *NNode) IsNeuron() bool {
	return n.NType == NEURON
}

// If the node is a SENSOR, returns TRUE and loads the value
func (n *NNode) SensorLoad(load float64) bool {
	if n.IsSensor() {
		// Keep a memory of activations for potential time delayed connections
		n.saveActivations()
		// Puts sensor into next time-step
		n.ActivationsCount++
		n.Activation = load
		return true
	} else {
		return false
	}
}

// Adds a NONRECURRENT Link to an incoming NNode in the incoming List
func (n *NNode) AddIncoming(in *NNode, weight float64) {
	newLink := NewLink(weight, in, n, false)
	n.Incoming = append(n.Incoming, newLink)
}

// Adds a Link to a new NNode in the incoming List
func (n *NNode) AddIncomingRecurrent(in *NNode, weight float64, recur bool) {
	newLink := NewLink(weight, in, n, recur)
	n.Incoming = append(n.Incoming, newLink)
}

// Recursively deactivate backwards through the network
func (n *NNode) Flushback() {
	n.ActivationsCount = 0
	n.Activation = 0
	n.lastActivation = 0
	n.lastActivation2 = 0
}

// Verify flushing for debuginh
func (n *NNode) FlushbackCheck() error {
	if n.ActivationsCount > 0 {
		return errors.New(fmt.Sprintf("ALERT: %s has activation count %d", n, n.ActivationsCount))
	}
	if n.Activation > 0 {
		return errors.New(fmt.Sprintf("ALERT: %s has activation %f", n, n.Activation))
	}
	if n.lastActivation > 0 {
		return errors.New(fmt.Sprintf("ALERT: %s has last_activation %f", n, n.lastActivation))
	}
	if n.lastActivation2 > 0 {
		return errors.New(fmt.Sprintf("ALERT: %s has last_activation2 %f", n, n.lastActivation2))
	}
	return nil
}

// Dump node to a writer
func (n *NNode) WriteNode(w io.Writer) {
	trait_id := 0
	if n.Trait != nil {
		trait_id = n.Trait.Id
	}
	fmt.Fprintf(w, "%d %d %d %d", n.Id, trait_id, n.NType, n.GenNodeLabel)
}

// Find the greatest depth starting from this neuron at depth d
func (n *NNode) Depth(d int32) (int32, error) {
	if d > 100 {
		return 10, errors.New("** DEPTH NOT DETERMINED FOR NETWORK WITH LOOP");
	}
	// Base Case
	if n.IsSensor() {
		return d, nil
	} else {
		// recursion
		max := d // The max depth
		for _, l := range n.Incoming {
			cur_depth, err := l.InNode.Depth(d + 1)
			if err != nil {
				return cur_depth, err
			}
			if cur_depth > max {
				max = cur_depth
			}
		}
		return max, nil
	}

}

func (n *NNode) String() string {
	if n.IsSensor() {
		return fmt.Sprintf("(S %3d, type: %d, step %d = %.3f, %s)",
			n.Id, n.NType, n.ActivationsCount, n.Activation, n.Params)
	} else {
		return fmt.Sprintf("(N %3d, type: %d, step %d = %.3f %s)",
			n.Id, n.NType, n.ActivationsCount, n.Activation, n.Params)
	}
}

<commit_msg>Fixed string presentation of NNode<commit_after>package network

import (
	"io"
	"fmt"
	"errors"
	"github.com/yaricom/goNEAT/neat"
)

// A NODE is either a NEURON or a SENSOR.
//   - If it's a sensor, it can be loaded with a value for output
//   - If it's a neuron, it has a list of its incoming input signals ([]*Link is used)
// Use an activation count to avoid flushing
type NNode struct {
	// The ID of the node
	Id               int

	// If true the node is active
	IsActive         bool

	// The the type of the node (NEURON or SENSOR)
	NType            int
	// The type of node activation function (SIGMOID, ...)
	FType            int
	// The placement of the node in the network layers (INPUT, HIDDEN, OUTPUT)
	GenNodeLabel     int

	// The activation for current step
	ActiveOut        float64
	// The activation from PREVIOUS (time-delayed) time step, if there is one
	ActiveOutTd      float64
	// The node's activation value
	Activation       float64
	// The number of activations for current node
	ActivationsCount int32
	// The activation sum
	ActivationSum    float64

	// The list of all incoming connections
	Incoming         []*Link
	// The list of all outgoing connections
	Outgoing         []*Link
	// The trait linked to the node
	Trait            *neat.Trait

	// Used for Gene decoding
	Analogue         *NNode
	// Used for Genome duplication
	Duplicate        *NNode

	/* ************ LEARNING PARAMETERS *********** */
	// The following parameters are for use in neurons that learn through habituation,
	// sensitization, or Hebbian-type processes  */
	Params           []float64

	// Activation value of node at time t-1; Holds the previous step's activation for recurrency
	lastActivation   float64
	// Activation value of node at time t-2 Holds the activation before  the previous step's
	// This is necessary for a special recurrent case when the innode of a recurrent link is one time step ahead of the outnode.
	// The innode then needs to send from TWO time steps ago
	lastActivation2  float64
}

// Creates new node with specified type (NEURON or SENSOR) and ID
func NewNNode(ntype, nodeid int) *NNode {
	n := newNode()
	n.NType = ntype
	n.Id = nodeid
	return n
}

// Creates new node with specified type (NEURON or SENSOR), ID and in the specified
// layer (INPUT, HIDDEN, OUTPUT)
func NewNNodeInPlace(ntype, nodeid, placement int) *NNode {
	n := newNode()
	n.NType = ntype
	n.Id = nodeid
	n.GenNodeLabel = placement
	return n
}

// Construct a NNode off another NNode with given trait for genome purposes
func NewNNodeCopy(n *NNode, t *neat.Trait) *NNode {
	node := newNode()
	node.NType = n.NType
	node.Id = n.Id
	node.GenNodeLabel = n.GenNodeLabel
	node.Trait = t
	node.deriveTrait(t)
	return node
}

// Read a NNode from specified Reader and applies corresponding trait to it from a list of traits provided
func ReadNNode(r io.Reader, traits []*neat.Trait) *NNode {
	n := newNode()
	var trait_id int
	fmt.Fscanf(r, "%d %d %d %d ", &n.Id, &trait_id, &n.NType, &n.GenNodeLabel)
	if trait_id != 0 && traits != nil {
		// find corresponding node trait from list
		for _, t := range traits {
			if trait_id == t.Id {
				n.Trait = t
				n.deriveTrait(t)
				break
			}
		}
	} else {
		// just create empty params
		n.deriveTrait(nil)
	}
	return n
}

// The private default constructor
func newNode() *NNode {
	return &NNode{
		FType:SIGMOID,
		Incoming:make([]*Link, 0),
		Outgoing:make([]*Link, 0),
		GenNodeLabel:HIDDEN,
	}
}

// Copy trait parameters into this node's parameters
func (n *NNode) deriveTrait(t *neat.Trait) {
	n.Params = make([]float64, neat.Num_trait_params)
	if t != nil {
		for i, p := range t.Params {
			n.Params[i] = p
		}
	}
}

// Saves current node's activations for potential time delayed connections
func (n *NNode) saveActivations() {
	n.lastActivation2 = n.lastActivation
	n.lastActivation = n.Activation
}

// Returns activation for a current step
func (n *NNode) GetActiveOut() float64 {
	if n.ActivationsCount > 0 {
		return n.Activation
	} else {
		return 0.0
	}
}

// Returns activation from PREVIOUS time step
func (n *NNode) GetActiveOutTd() float64 {
	if n.ActivationsCount > 1 {
		return n.lastActivation
	} else {
		return 0.0
	}
}

// Returns true if this node is SENSOR
func (n *NNode) IsSensor() bool {
	return n.NType == SENSOR
}

// returns true if this node is NEURON
func (n *NNode) IsNeuron() bool {
	return n.NType == NEURON
}

// If the node is a SENSOR, returns TRUE and loads the value
func (n *NNode) SensorLoad(load float64) bool {
	if n.IsSensor() {
		// Keep a memory of activations for potential time delayed connections
		n.saveActivations()
		// Puts sensor into next time-step
		n.ActivationsCount++
		n.Activation = load
		return true
	} else {
		return false
	}
}

// Adds a NONRECURRENT Link to an incoming NNode in the incoming List
func (n *NNode) AddIncoming(in *NNode, weight float64) {
	newLink := NewLink(weight, in, n, false)
	n.Incoming = append(n.Incoming, newLink)
}

// Adds a Link to a new NNode in the incoming List
func (n *NNode) AddIncomingRecurrent(in *NNode, weight float64, recur bool) {
	newLink := NewLink(weight, in, n, recur)
	n.Incoming = append(n.Incoming, newLink)
}

// Recursively deactivate backwards through the network
func (n *NNode) Flushback() {
	n.ActivationsCount = 0
	n.Activation = 0
	n.lastActivation = 0
	n.lastActivation2 = 0
}

// Verify flushing for debuginh
func (n *NNode) FlushbackCheck() error {
	if n.ActivationsCount > 0 {
		return errors.New(fmt.Sprintf("ALERT: %s has activation count %d", n, n.ActivationsCount))
	}
	if n.Activation > 0 {
		return errors.New(fmt.Sprintf("ALERT: %s has activation %f", n, n.Activation))
	}
	if n.lastActivation > 0 {
		return errors.New(fmt.Sprintf("ALERT: %s has last_activation %f", n, n.lastActivation))
	}
	if n.lastActivation2 > 0 {
		return errors.New(fmt.Sprintf("ALERT: %s has last_activation2 %f", n, n.lastActivation2))
	}
	return nil
}

// Dump node to a writer
func (n *NNode) WriteNode(w io.Writer) {
	trait_id := 0
	if n.Trait != nil {
		trait_id = n.Trait.Id
	}
	fmt.Fprintf(w, "%d %d %d %d", n.Id, trait_id, n.NType, n.GenNodeLabel)
}

// Find the greatest depth starting from this neuron at depth d
func (n *NNode) Depth(d int32) (int32, error) {
	if d > 100 {
		return 10, errors.New("** DEPTH NOT DETERMINED FOR NETWORK WITH LOOP");
	}
	// Base Case
	if n.IsSensor() {
		return d, nil
	} else {
		// recursion
		max := d // The max depth
		for _, l := range n.Incoming {
			cur_depth, err := l.InNode.Depth(d + 1)
			if err != nil {
				return cur_depth, err
			}
			if cur_depth > max {
				max = cur_depth
			}
		}
		return max, nil
	}

}

func (n *NNode) String() string {
	if n.IsSensor() {
		return fmt.Sprintf("(S %3d, type: %d, step %d = %.3f %.3f)",
			n.Id, n.NType, n.ActivationsCount, n.Activation, n.Params)
	} else {
		return fmt.Sprintf("(N %3d, type: %d, step %d = %.3f %.3f)",
			n.Id, n.NType, n.ActivationsCount, n.Activation, n.Params)
	}
}

<|endoftext|>