<commit_before>package revel

import (
	"go/build"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path"
	"path/filepath"
	"runtime"
	"strings"

	"github.com/agtorre/gocolorize"
	"github.com/revel/config"
)

const (
	REVEL_IMPORT_PATH = "github.com/revel/revel"
)

type revelLogs struct {
	c gocolorize.Colorize
	w io.Writer
}

func (r *revelLogs) Write(p []byte) (n int, err error) {
	return r.w.Write([]byte(r.c.Paint(string(p))))
}

var (
	// App details
	AppName    string // e.g. "sample"
	AppRoot    string // e.g. "/app1"
	BasePath   string // e.g. "/Users/robfig/gocode/src/corp/sample"
	AppPath    string // e.g. "/Users/robfig/gocode/src/corp/sample/app"
	ViewsPath  string // e.g. "/Users/robfig/gocode/src/corp/sample/app/views"
	ImportPath string // e.g. "corp/sample"
	SourcePath string // e.g. "/Users/robfig/gocode/src"

	Config  *config.Context
	RunMode string // Application-defined (by default, "dev" or "prod")
	DevMode bool   // if true, RunMode is a development mode.

	// Revel installation details
	RevelPath string // e.g. "/Users/robfig/gocode/src/revel"

	// Where to look for templates and configuration.
	// Ordered by priority.  (Earlier paths take precedence over later paths.)
	CodePaths     []string
	ConfPaths     []string
	TemplatePaths []string

	Modules []Module

	// Server config.
	//
	// Alert: This is how the app is configured, which may be different from
	// the current process reality.  For example, if the app is configured for
	// port 9000, HttpPort will always be 9000, even though in dev mode it is
	// run on a random port and proxied.
	HttpPort    int    // e.g. 9000
	HttpAddr    string // e.g. "", "127.0.0.1"
	HttpSsl     bool   // e.g. true if using ssl
	HttpSslCert string // e.g. "/path/to/cert.pem"
	HttpSslKey  string // e.g. "/path/to/key.pem"

	// All cookies dropped by the framework begin with this prefix.
	CookiePrefix string
	// Cookie domain
	CookieDomain string
	// Cookie flags
	CookieSecure bool

	// Delimiters to use when rendering templates
	TemplateDelims string

	//Logger colors
	colors = map[string]gocolorize.Colorize{
		"trace": gocolorize.NewColor("magenta"),
		"info":  gocolorize.NewColor("white"),
		"warn":  gocolorize.NewColor("yellow"),
		"error": gocolorize.NewColor("red"),
	}

	errorLog = revelLogs{c: colors["error"], w: os.Stderr}

	// Loggers
	TRACE = log.New(ioutil.Discard, "TRACE ", log.Ldate|log.Ltime|log.Lshortfile)
	INFO  = log.New(ioutil.Discard, "INFO ", log.Ldate|log.Ltime|log.Lshortfile)
	WARN  = log.New(ioutil.Discard, "WARN ", log.Ldate|log.Ltime|log.Lshortfile)
	ERROR = log.New(&errorLog, "ERROR ", log.Ldate|log.Ltime|log.Lshortfile)

	// Revel request access log, not exposed from package.
	// However output settings can be controlled from app.conf
	requestLog           = log.New(ioutil.Discard, "", 0)
	requestLogTimeFormat = "2006/01/02 15:04:05.000"

	Initialized bool

	// Private
	secretKey []byte // Key used to sign cookies. An empty key disables signing.
	packaged  bool   // If true, this is running from a pre-built package.
)

func init() {
	log.SetFlags(INFO.Flags())
}

// Init initializes Revel -- it provides paths for getting around the app.
//
// Params:
//   mode - the run mode, which determines which app.conf settings are used.
//   importPath - the Go import path of the application.
//   srcPath - the path to the source directory, containing Revel and the app.
//     If not specified (""), then a functioning Go installation is required.
func Init(mode, importPath, srcPath string) {
	// Ignore trailing slashes.
	ImportPath = strings.TrimRight(importPath, "/")
	SourcePath = srcPath
	RunMode = mode

	if runtime.GOOS == "windows" {
		gocolorize.SetPlain(true)
	}

	// If the SourcePath is not specified, find it using build.Import.
	var revelSourcePath string // may be different from the app source path
	if SourcePath == "" {
		revelSourcePath, SourcePath = findSrcPaths(importPath)
	} else {
		// If the SourcePath was specified, assume both Revel and the app are within it.
		SourcePath = path.Clean(SourcePath)
		revelSourcePath = SourcePath
		packaged = true
	}

	RevelPath = path.Join(revelSourcePath, filepath.FromSlash(REVEL_IMPORT_PATH))
	BasePath = path.Join(SourcePath, filepath.FromSlash(importPath))
	AppPath = path.Join(BasePath, "app")
	ViewsPath = path.Join(AppPath, "views")

	CodePaths = []string{AppPath}

	if ConfPaths == nil {
		ConfPaths = []string{}
	}
	ConfPaths = append(
		ConfPaths,
		path.Join(BasePath, "conf"),
		path.Join(RevelPath, "conf"),
	)

	TemplatePaths = []string{
		ViewsPath,
		path.Join(RevelPath, "templates"),
	}

	// Load app.conf
	var err error
	Config, err = config.LoadContext("app.conf", ConfPaths)
	if err != nil || Config == nil {
		log.Fatalln("Failed to load app.conf:", err)
	}
	// Ensure that the selected runmode appears in app.conf.
	// If empty string is passed as the mode, treat it as "DEFAULT"
	if mode == "" {
		mode = config.DEFAULT_SECTION
	}
	if !Config.HasSection(mode) {
		log.Fatalln("app.conf: No mode found:", mode)
	}
	Config.SetSection(mode)

	// Configure properties from app.conf
	DevMode = Config.BoolDefault("mode.dev", false)
	HttpPort = Config.IntDefault("http.port", 9000)
	HttpAddr = Config.StringDefault("http.addr", "")
	HttpSsl = Config.BoolDefault("http.ssl", false)
	HttpSslCert = Config.StringDefault("http.sslcert", "")
	HttpSslKey = Config.StringDefault("http.sslkey", "")
	if HttpSsl {
		if HttpSslCert == "" {
			log.Fatalln("No http.sslcert provided.")
		}
		if HttpSslKey == "" {
			log.Fatalln("No http.sslkey provided.")
		}
	}

	AppName = Config.StringDefault("app.name", "(not set)")
	AppRoot = Config.StringDefault("app.root", "")
	CookiePrefix = Config.StringDefault("cookie.prefix", "REVEL")
	CookieDomain = Config.StringDefault("cookie.domain", "")
	CookieSecure = Config.BoolDefault("cookie.secure", !DevMode)
	TemplateDelims = Config.StringDefault("template.delimiters", "")
	if secretStr := Config.StringDefault("app.secret", ""); secretStr != "" {
		secretKey = []byte(secretStr)
	}

	// Configure logging
	if !Config.BoolDefault("log.colorize", true) {
		gocolorize.SetPlain(true)
	}

	TRACE = getLogger("trace")
	INFO = getLogger("info")
	WARN = getLogger("warn")
	ERROR = getLogger("error")

	// Revel request access logger, not exposed from package.
	// However output settings can be controlled from app.conf
	requestLog = getLogger("request")

	loadModules()

	Initialized = true
	INFO.Printf("Initialized Revel v%s (%s) for %s", Version, BuildDate, MinimumGoVersion)
}

// Create a logger using log.* directives in app.conf plus the current settings
// on the default logger.
func getLogger(name string) *log.Logger {
	var logger *log.Logger

	// Create a logger with the requested output. (default to stderr)
	output := Config.StringDefault("log."+name+".output", "stderr")
	var newlog revelLogs

	switch output {
	case "stdout":
		newlog = revelLogs{c: colors[name], w: os.Stdout}
		logger = newLogger(&newlog)
	case "stderr":
		newlog = revelLogs{c: colors[name], w: os.Stderr}
		logger = newLogger(&newlog)
	case "off":
		return newLogger(ioutil.Discard)
	default:
		if !filepath.IsAbs(output) {
			output = filepath.Join(BasePath, output)
		}

		logPath := filepath.Dir(output)
		if err := createDir(logPath); err != nil {
			log.Fatalln(err)
		}

		file, err := os.OpenFile(output, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
		if err != nil {
			log.Fatalln("Failed to open log file", output, ":", err)
		}
		logger = newLogger(file)
	}

	if strings.EqualFold(name, "request") {
		logger.SetFlags(0)
		return logger
	}

	// Set the prefix / flags.
	flags, found := Config.Int("log." + name + ".flags")
	if found {
		logger.SetFlags(flags)
	}

	prefix, found := Config.String("log." + name + ".prefix")
	if found {
		logger.SetPrefix(prefix)
	}

	return logger
}

func newLogger(wr io.Writer) *log.Logger {
	return log.New(wr, "", INFO.Flags())
}

// findSrcPaths uses the "go/build" package to find the source root for Revel
// and the app.
func findSrcPaths(importPath string) (revelSourcePath, appSourcePath string) {
	var (
		gopaths = filepath.SplitList(build.Default.GOPATH)
		goroot  = build.Default.GOROOT
	)

	if len(gopaths) == 0 {
		ERROR.Fatalln("GOPATH environment variable is not set. ",
			"Please refer to http://golang.org/doc/code.html to configure your Go environment.")
	}

	if ContainsString(gopaths, goroot) {
		ERROR.Fatalf("GOPATH (%s) must not include your GOROOT (%s). "+
			"Please refer to http://golang.org/doc/code.html to configure your Go environment.",
			gopaths, goroot)
	}

	appPkg, err := build.Import(importPath, "", build.FindOnly)
	if err != nil {
		ERROR.Fatalln("Failed to import", importPath, "with error:", err)
	}

	revelPkg, err := build.Import(REVEL_IMPORT_PATH, "", build.FindOnly)
	if err != nil {
		ERROR.Fatalln("Failed to find Revel with error:", err)
	}

	return revelPkg.SrcRoot, appPkg.SrcRoot
}

type Module struct {
	Name, ImportPath, Path string
}

func loadModules() {
	for _, key := range Config.Options("module.") {
		moduleImportPath := Config.StringDefault(key, "")
		if moduleImportPath == "" {
			continue
		}

		modulePath, err := ResolveImportPath(moduleImportPath)
		if err != nil {
			log.Fatalln("Failed to load module.  Import of", moduleImportPath, "failed:", err)
		}
		addModule(key[len("module."):], moduleImportPath, modulePath)
	}
}

// ResolveImportPath returns the filesystem path for the given import path.
// Returns an error if the import path could not be found.
func ResolveImportPath(importPath string) (string, error) {
	if packaged {
		return path.Join(SourcePath, importPath), nil
	}

	modPkg, err := build.Import(importPath, "", build.FindOnly)
	if err != nil {
		return "", err
	}
	return modPkg.Dir, nil
}

func addModule(name, importPath, modulePath string) {
	Modules = append(Modules, Module{Name: name, ImportPath: importPath, Path: modulePath})
	if codePath := path.Join(modulePath, "app"); DirExists(codePath) {
		CodePaths = append(CodePaths, codePath)
		if viewsPath := path.Join(modulePath, "app", "views"); DirExists(viewsPath) {
			TemplatePaths = append(TemplatePaths, viewsPath)
		}
	}

	INFO.Print("Loaded module ", path.Base(modulePath))

	// Hack: There is presently no way for the testrunner module to add the
	// "test" subdirectory to the CodePaths.  So this does it instead.
	if importPath == Config.StringDefault("module.testrunner", "github.com/revel/modules/testrunner") {
		CodePaths = append(CodePaths, path.Join(BasePath, "tests"))
	}
}

// ModuleByName returns the module of the given name, if loaded.
func ModuleByName(name string) (m Module, found bool) {
	for _, module := range Modules {
		if module.Name == name {
			return module, true
		}
	}
	return Module{}, false
}

func CheckInit() {
	if !Initialized {
		panic("Revel has not been initialized!")
	}
}
<commit_msg>revel/config#4 related changes applied here<commit_after>package revel

import (
	"go/build"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path"
	"path/filepath"
	"runtime"
	"strings"

	"github.com/agtorre/gocolorize"
	"github.com/revel/config"
)

const (
	REVEL_IMPORT_PATH = "github.com/revel/revel"
)

type revelLogs struct {
	c gocolorize.Colorize
	w io.Writer
}

func (r *revelLogs) Write(p []byte) (n int, err error) {
	return r.w.Write([]byte(r.c.Paint(string(p))))
}

var (
	// App details
	AppName    string // e.g. "sample"
	AppRoot    string // e.g. "/app1"
	BasePath   string // e.g. "/Users/robfig/gocode/src/corp/sample"
	AppPath    string // e.g. "/Users/robfig/gocode/src/corp/sample/app"
	ViewsPath  string // e.g. "/Users/robfig/gocode/src/corp/sample/app/views"
	ImportPath string // e.g. "corp/sample"
	SourcePath string // e.g. "/Users/robfig/gocode/src"

	Config  *config.Context
	RunMode string // Application-defined (by default, "dev" or "prod")
	DevMode bool   // if true, RunMode is a development mode.

	// Revel installation details
	RevelPath string // e.g. "/Users/robfig/gocode/src/revel"

	// Where to look for templates
	// Ordered by priority. (Earlier paths take precedence over later paths.)
	CodePaths     []string
	TemplatePaths []string

	// ConfPaths where to look for configurations
	// Config load order
	// 1. framework (revel/conf/*)
	// 2. application (conf/*)
	// 3. user supplied configs (...) - User configs can override/add any from above
	ConfPaths []string

	Modules []Module

	// Server config.
	//
	// Alert: This is how the app is configured, which may be different from
	// the current process reality.  For example, if the app is configured for
	// port 9000, HttpPort will always be 9000, even though in dev mode it is
	// run on a random port and proxied.
	HttpPort    int    // e.g. 9000
	HttpAddr    string // e.g. "", "127.0.0.1"
	HttpSsl     bool   // e.g. true if using ssl
	HttpSslCert string // e.g. "/path/to/cert.pem"
	HttpSslKey  string // e.g. "/path/to/key.pem"

	// All cookies dropped by the framework begin with this prefix.
	CookiePrefix string
	// Cookie domain
	CookieDomain string
	// Cookie flags
	CookieSecure bool

	// Delimiters to use when rendering templates
	TemplateDelims string

	//Logger colors
	colors = map[string]gocolorize.Colorize{
		"trace": gocolorize.NewColor("magenta"),
		"info":  gocolorize.NewColor("white"),
		"warn":  gocolorize.NewColor("yellow"),
		"error": gocolorize.NewColor("red"),
	}

	errorLog = revelLogs{c: colors["error"], w: os.Stderr}

	// Loggers
	TRACE = log.New(ioutil.Discard, "TRACE ", log.Ldate|log.Ltime|log.Lshortfile)
	INFO  = log.New(ioutil.Discard, "INFO ", log.Ldate|log.Ltime|log.Lshortfile)
	WARN  = log.New(ioutil.Discard, "WARN ", log.Ldate|log.Ltime|log.Lshortfile)
	ERROR = log.New(&errorLog, "ERROR ", log.Ldate|log.Ltime|log.Lshortfile)

	// Revel request access log, not exposed from package.
	// However output settings can be controlled from app.conf
	requestLog           = log.New(ioutil.Discard, "", 0)
	requestLogTimeFormat = "2006/01/02 15:04:05.000"

	Initialized bool

	// Private
	secretKey []byte // Key used to sign cookies. An empty key disables signing.
	packaged  bool   // If true, this is running from a pre-built package.
)

func init() {
	log.SetFlags(INFO.Flags())
}

// Init initializes Revel -- it provides paths for getting around the app.
//
// Params:
//   mode - the run mode, which determines which app.conf settings are used.
//   importPath - the Go import path of the application.
//   srcPath - the path to the source directory, containing Revel and the app.
//     If not specified (""), then a functioning Go installation is required.
func Init(mode, importPath, srcPath string) {
	// Ignore trailing slashes.
	ImportPath = strings.TrimRight(importPath, "/")
	SourcePath = srcPath
	RunMode = mode

	if runtime.GOOS == "windows" {
		gocolorize.SetPlain(true)
	}

	// If the SourcePath is not specified, find it using build.Import.
	var revelSourcePath string // may be different from the app source path
	if SourcePath == "" {
		revelSourcePath, SourcePath = findSrcPaths(importPath)
	} else {
		// If the SourcePath was specified, assume both Revel and the app are within it.
		SourcePath = path.Clean(SourcePath)
		revelSourcePath = SourcePath
		packaged = true
	}

	RevelPath = path.Join(revelSourcePath, filepath.FromSlash(REVEL_IMPORT_PATH))
	BasePath = path.Join(SourcePath, filepath.FromSlash(importPath))
	AppPath = path.Join(BasePath, "app")
	ViewsPath = path.Join(AppPath, "views")

	CodePaths = []string{AppPath}

	if ConfPaths == nil {
		ConfPaths = []string{}
	}

	// Config load order
	// 1. framework (revel/conf/*)
	// 2. application (conf/*)
	// 3. user supplied configs (...) - User configs can override/add any from above
	ConfPaths := append(
		[]string{
			path.Join(RevelPath, "conf"),
			path.Join(BasePath, "conf"),
		},
		ConfPaths...)

	TemplatePaths = []string{
		ViewsPath,
		path.Join(RevelPath, "templates"),
	}

	// Load app.conf
	var err error
	Config, err = config.LoadContext("app.conf", ConfPaths)
	if err != nil || Config == nil {
		log.Fatalln("Failed to load app.conf:", err)
	}
	// Ensure that the selected runmode appears in app.conf.
	// If empty string is passed as the mode, treat it as "DEFAULT"
	if mode == "" {
		mode = config.DEFAULT_SECTION
	}
	if !Config.HasSection(mode) {
		log.Fatalln("app.conf: No mode found:", mode)
	}
	Config.SetSection(mode)

	// Configure properties from app.conf
	DevMode = Config.BoolDefault("mode.dev", false)
	HttpPort = Config.IntDefault("http.port", 9000)
	HttpAddr = Config.StringDefault("http.addr", "")
	HttpSsl = Config.BoolDefault("http.ssl", false)
	HttpSslCert = Config.StringDefault("http.sslcert", "")
	HttpSslKey = Config.StringDefault("http.sslkey", "")
	if HttpSsl {
		if HttpSslCert == "" {
			log.Fatalln("No http.sslcert provided.")
		}
		if HttpSslKey == "" {
			log.Fatalln("No http.sslkey provided.")
		}
	}

	AppName = Config.StringDefault("app.name", "(not set)")
	AppRoot = Config.StringDefault("app.root", "")
	CookiePrefix = Config.StringDefault("cookie.prefix", "REVEL")
	CookieDomain = Config.StringDefault("cookie.domain", "")
	CookieSecure = Config.BoolDefault("cookie.secure", !DevMode)
	TemplateDelims = Config.StringDefault("template.delimiters", "")
	if secretStr := Config.StringDefault("app.secret", ""); secretStr != "" {
		secretKey = []byte(secretStr)
	}

	// Configure logging
	if !Config.BoolDefault("log.colorize", true) {
		gocolorize.SetPlain(true)
	}

	TRACE = getLogger("trace")
	INFO = getLogger("info")
	WARN = getLogger("warn")
	ERROR = getLogger("error")

	// Revel request access logger, not exposed from package.
	// However output settings can be controlled from app.conf
	requestLog = getLogger("request")

	loadModules()

	Initialized = true
	INFO.Printf("Initialized Revel v%s (%s) for %s", Version, BuildDate, MinimumGoVersion)
}

// Create a logger using log.* directives in app.conf plus the current settings
// on the default logger.
func getLogger(name string) *log.Logger {
	var logger *log.Logger

	// Create a logger with the requested output. (default to stderr)
	output := Config.StringDefault("log."+name+".output", "stderr")
	var newlog revelLogs

	switch output {
	case "stdout":
		newlog = revelLogs{c: colors[name], w: os.Stdout}
		logger = newLogger(&newlog)
	case "stderr":
		newlog = revelLogs{c: colors[name], w: os.Stderr}
		logger = newLogger(&newlog)
	case "off":
		return newLogger(ioutil.Discard)
	default:
		if !filepath.IsAbs(output) {
			output = filepath.Join(BasePath, output)
		}

		logPath := filepath.Dir(output)
		if err := createDir(logPath); err != nil {
			log.Fatalln(err)
		}

		file, err := os.OpenFile(output, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
		if err != nil {
			log.Fatalln("Failed to open log file", output, ":", err)
		}
		logger = newLogger(file)
	}

	if strings.EqualFold(name, "request") {
		logger.SetFlags(0)
		return logger
	}

	// Set the prefix / flags.
	flags, found := Config.Int("log." + name + ".flags")
	if found {
		logger.SetFlags(flags)
	}

	prefix, found := Config.String("log." + name + ".prefix")
	if found {
		logger.SetPrefix(prefix)
	}

	return logger
}

func newLogger(wr io.Writer) *log.Logger {
	return log.New(wr, "", INFO.Flags())
}

// findSrcPaths uses the "go/build" package to find the source root for Revel
// and the app.
func findSrcPaths(importPath string) (revelSourcePath, appSourcePath string) {
	var (
		gopaths = filepath.SplitList(build.Default.GOPATH)
		goroot  = build.Default.GOROOT
	)

	if len(gopaths) == 0 {
		ERROR.Fatalln("GOPATH environment variable is not set. ",
			"Please refer to http://golang.org/doc/code.html to configure your Go environment.")
	}

	if ContainsString(gopaths, goroot) {
		ERROR.Fatalf("GOPATH (%s) must not include your GOROOT (%s). "+
			"Please refer to http://golang.org/doc/code.html to configure your Go environment.",
			gopaths, goroot)
	}

	appPkg, err := build.Import(importPath, "", build.FindOnly)
	if err != nil {
		ERROR.Fatalln("Failed to import", importPath, "with error:", err)
	}

	revelPkg, err := build.Import(REVEL_IMPORT_PATH, "", build.FindOnly)
	if err != nil {
		ERROR.Fatalln("Failed to find Revel with error:", err)
	}

	return revelPkg.SrcRoot, appPkg.SrcRoot
}

type Module struct {
	Name, ImportPath, Path string
}

func loadModules() {
	for _, key := range Config.Options("module.") {
		moduleImportPath := Config.StringDefault(key, "")
		if moduleImportPath == "" {
			continue
		}

		modulePath, err := ResolveImportPath(moduleImportPath)
		if err != nil {
			log.Fatalln("Failed to load module.  Import of", moduleImportPath, "failed:", err)
		}
		addModule(key[len("module."):], moduleImportPath, modulePath)
	}
}

// ResolveImportPath returns the filesystem path for the given import path.
// Returns an error if the import path could not be found.
func ResolveImportPath(importPath string) (string, error) {
	if packaged {
		return path.Join(SourcePath, importPath), nil
	}

	modPkg, err := build.Import(importPath, "", build.FindOnly)
	if err != nil {
		return "", err
	}
	return modPkg.Dir, nil
}

func addModule(name, importPath, modulePath string) {
	Modules = append(Modules, Module{Name: name, ImportPath: importPath, Path: modulePath})
	if codePath := path.Join(modulePath, "app"); DirExists(codePath) {
		CodePaths = append(CodePaths, codePath)
		if viewsPath := path.Join(modulePath, "app", "views"); DirExists(viewsPath) {
			TemplatePaths = append(TemplatePaths, viewsPath)
		}
	}

	INFO.Print("Loaded module ", path.Base(modulePath))

	// Hack: There is presently no way for the testrunner module to add the
	// "test" subdirectory to the CodePaths.  So this does it instead.
	if importPath == Config.StringDefault("module.testrunner", "github.com/revel/modules/testrunner") {
		CodePaths = append(CodePaths, path.Join(BasePath, "tests"))
	}
}

// ModuleByName returns the module of the given name, if loaded.
func ModuleByName(name string) (m Module, found bool) {
	for _, module := range Modules {
		if module.Name == name {
			return module, true
		}
	}
	return Module{}, false
}

func CheckInit() {
	if !Initialized {
		panic("Revel has not been initialized!")
	}
}
<|endoftext|>


<commit_before>package models_test

import (
	"time"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/zippelmann/gtt/models"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

var _ = Describe("IntervalDao", func() {
	var (
		collection *mgo.Collection
		dao        *IntervalDao
	)

	BeforeEach(func() {
		session, err := createSession()
		Expect(err).To(BeNil(), "All tests need a connection to a mongodb.")

		collection = getCollection(session, "timetracker", "intervals")

		cleanCollection(collection)

		dao = NewIntervalDao(session, "timetracker")
	})

	It("should save an interval.", func() {
		userID := bson.NewObjectId()
		start := time.Now()
		stop := time.Now()

		Expect(dao.Save(NewInterval(userID, start, stop))).To(Succeed())

		var interval Interval
		findErr := collection.Find(bson.M{"userid": userID}).One(&interval)
		Expect(findErr).To(BeNil())
		Expect(interval.Start.Unix()).To(Equal(start.Unix()))
		Expect(interval.Stop.Unix()).To(Equal(stop.Unix()))
		Expect(interval.UserID).To(Equal(userID))
		Expect(interval.ID.Valid()).To(BeTrue())
	})

	It("should find all by userID.", func() {
		userID := bson.NewObjectId()
		dao.Save(NewIntervalWithStart(userID, time.Now()))
		dao.Save(NewIntervalWithStart(userID, time.Now()))
		dao.Save(NewIntervalWithStart(bson.NewObjectId(), time.Now()))

		intervals, err := dao.FindByUserID(userID)

		Expect(err).To(BeNil())
		Expect(intervals).To(HaveLen(2))
		Expect(intervals[0].UserID).To(Equal(userID))
		Expect(intervals[1].UserID).To(Equal(userID))
	})

	It("should return an empty array when no intervals found.", func() {
		intervals, err := dao.FindByUserID(bson.NewObjectId())

		Expect(err).To(BeNil())
		Expect(intervals).To(HaveLen(0))
	})

	It("should find a not working user.", func() {
		userID := bson.NewObjectId()
		dao.Save(NewInterval(userID, time.Now(), time.Now()))

		working, err := dao.IsUserWorking(userID)

		Expect(err).To(BeNil())
		Expect(working).To(BeFalse())
	})

	It("should find a working user.", func() {
		userID := bson.NewObjectId()
		dao.Save(NewIntervalWithStart(userID, time.Now()))

		working, err := dao.IsUserWorking(userID)

		Expect(err).To(BeNil())
		Expect(working).To(BeTrue())
	})

	It("should start a new interval with current start time.", func() {
		userID := bson.NewObjectId()

		Expect(dao.Start(userID)).To(Succeed())

		intervals, findErr := dao.FindByUserID(userID)
		Expect(findErr).To(BeNil())
		Expect(intervals[0].Stop).To(BeZero())
		Expect(intervals[0].Start).NotTo(BeZero())
	})

	It("should return all open intervals", func() {
		userID := bson.NewObjectId()
		dao.Start(userID)
		dao.Start(userID)
		dao.Save(NewInterval(userID, time.Now(), time.Now()))

		openIntervals, err := dao.FindOpenIntervals(userID)

		Expect(err).To(BeNil())
		Expect(openIntervals).To(HaveLen(2))
		Expect(openIntervals[0].Stop).To(BeZero())
		Expect(openIntervals[1].Stop).To(BeZero())
	})

	It("should return an error when stop does not find an open interval.", func() {
		userID := bson.NewObjectId()

		err := dao.Stop(userID)

		Expect(err.Error()).To(Equal("user is not working"))
	})

	It("should return an error when stop finds more than one open interval.", func() {
		userID := bson.NewObjectId()
		dao.Start(userID)
		dao.Start(userID)

		err := dao.Stop(userID)

		Expect(err.Error()).To(Equal("more than one open interval"))
	})

	It("should stop the last open interval.", func() {
		userID := bson.NewObjectId()
		dao.Start(userID)

		Expect(dao.Stop(userID)).To(Succeed())
	})

	PIt("should return all intervals in a given range.")
})
<commit_msg>clarified test description<commit_after>package models_test

import (
	"time"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/zippelmann/gtt/models"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

var _ = Describe("IntervalDao", func() {
	var (
		collection *mgo.Collection
		dao        *IntervalDao
	)

	BeforeEach(func() {
		session, err := createSession()
		Expect(err).To(BeNil(), "All tests need a connection to a mongodb.")

		collection = getCollection(session, "timetracker", "intervals")

		cleanCollection(collection)

		dao = NewIntervalDao(session, "timetracker")
	})

	It("should save an interval.", func() {
		userID := bson.NewObjectId()
		start := time.Now()
		stop := time.Now()

		Expect(dao.Save(NewInterval(userID, start, stop))).To(Succeed())

		var interval Interval
		findErr := collection.Find(bson.M{"userid": userID}).One(&interval)
		Expect(findErr).To(BeNil())
		Expect(interval.Start.Unix()).To(Equal(start.Unix()))
		Expect(interval.Stop.Unix()).To(Equal(stop.Unix()))
		Expect(interval.UserID).To(Equal(userID))
		Expect(interval.ID.Valid()).To(BeTrue())
	})

	It("should find all by userID.", func() {
		userID := bson.NewObjectId()
		dao.Save(NewIntervalWithStart(userID, time.Now()))
		dao.Save(NewIntervalWithStart(userID, time.Now()))
		dao.Save(NewIntervalWithStart(bson.NewObjectId(), time.Now()))

		intervals, err := dao.FindByUserID(userID)

		Expect(err).To(BeNil())
		Expect(intervals).To(HaveLen(2))
		Expect(intervals[0].UserID).To(Equal(userID))
		Expect(intervals[1].UserID).To(Equal(userID))
	})

	It("should return an empty array when no intervals found.", func() {
		intervals, err := dao.FindByUserID(bson.NewObjectId())

		Expect(err).To(BeNil())
		Expect(intervals).To(HaveLen(0))
	})

	It("should find a not working user.", func() {
		userID := bson.NewObjectId()
		dao.Save(NewInterval(userID, time.Now(), time.Now()))

		working, err := dao.IsUserWorking(userID)

		Expect(err).To(BeNil())
		Expect(working).To(BeFalse())
	})

	It("should find a working user.", func() {
		userID := bson.NewObjectId()
		dao.Save(NewIntervalWithStart(userID, time.Now()))

		working, err := dao.IsUserWorking(userID)

		Expect(err).To(BeNil())
		Expect(working).To(BeTrue())
	})

	It("should start a new interval with current start time.", func() {
		userID := bson.NewObjectId()

		Expect(dao.Start(userID)).To(Succeed())

		intervals, findErr := dao.FindByUserID(userID)
		Expect(findErr).To(BeNil())
		Expect(intervals[0].Stop).To(BeZero())
		Expect(intervals[0].Start).NotTo(BeZero())
	})

	It("should return all open intervals", func() {
		userID := bson.NewObjectId()
		dao.Start(userID)
		dao.Start(userID)
		dao.Save(NewInterval(userID, time.Now(), time.Now()))

		openIntervals, err := dao.FindOpenIntervals(userID)

		Expect(err).To(BeNil())
		Expect(openIntervals).To(HaveLen(2))
		Expect(openIntervals[0].Stop).To(BeZero())
		Expect(openIntervals[1].Stop).To(BeZero())
	})

	It("should return an error when stop does not find an open interval.", func() {
		userID := bson.NewObjectId()

		err := dao.Stop(userID)

		Expect(err.Error()).To(Equal("user is not working"))
	})

	It("should return an error when stop finds more than one open interval.", func() {
		userID := bson.NewObjectId()
		dao.Start(userID)
		dao.Start(userID)

		err := dao.Stop(userID)

		Expect(err.Error()).To(Equal("more than one open interval"))
	})

	It("should stop open interval.", func() {
		userID := bson.NewObjectId()
		dao.Start(userID)

		Expect(dao.Stop(userID)).To(Succeed())
	})

	PIt("should return all intervals in a given range.")
})
<|endoftext|>


<commit_before>package gcng_test

import (
	"time"

	"code.cloudfoundry.org/lager/lagertest"
	"github.com/concourse/atc"
	"github.com/concourse/atc/dbng"
	"github.com/concourse/atc/gcng"
	sq "github.com/masterminds/squirrel"

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

var psql = sq.StatementBuilder.PlaceholderFormat(sq.Dollar)

var _ = Describe("ResourceCacheUseCollector", func() {
	var (
		collector gcng.ResourceCacheUseCollector

		dbConn               dbng.Conn
		err                  error
		resourceCacheFactory dbng.ResourceCacheFactory

		teamFactory     dbng.TeamFactory
		buildFactory    *dbng.BuildFactory
		pipelineFactory *dbng.PipelineFactory
		resourceFactory *dbng.ResourceFactory

		defaultTeam     *dbng.Team
		defaultPipeline *dbng.Pipeline
		defaultBuild    *dbng.Build

		resourceType1     atc.ResourceType
		resourceType1Used *dbng.UsedResourceType
		usedResource      *dbng.Resource
	)

	BeforeEach(func() {
		postgresRunner.Truncate()

		dbConn = dbng.Wrap(postgresRunner.Open())

		teamFactory = dbng.NewTeamFactory(dbConn)
		buildFactory = dbng.NewBuildFactory(dbConn)
		pipelineFactory = dbng.NewPipelineFactory(dbConn)
		resourceFactory = dbng.NewResourceFactory(dbConn)

		defaultTeam, err = teamFactory.CreateTeam("default-team")
		Expect(err).NotTo(HaveOccurred())

		defaultBuild, err = buildFactory.CreateOneOffBuild(defaultTeam)
		Expect(err).NotTo(HaveOccurred())

		defaultPipeline, err = pipelineFactory.CreatePipeline(defaultTeam, "default-pipeline", "some-config")
		Expect(err).NotTo(HaveOccurred())

		usedResource, err = resourceFactory.CreateResource(
			defaultPipeline,
			"some-resource",
			`{"some": "config"}`,
		)
		Expect(err).NotTo(HaveOccurred())

		setupTx, err := dbConn.Begin()
		Expect(err).ToNot(HaveOccurred())

		baseResourceType := dbng.BaseResourceType{
			Name: "some-base-type",
		}
		_, err = baseResourceType.FindOrCreate(setupTx)
		Expect(err).NotTo(HaveOccurred())

		resourceType1 = atc.ResourceType{
			Name: "some-type",
			Type: "some-base-type",
			Source: atc.Source{
				"some-type": "source",
			},
		}
		resourceType1Used, err = dbng.ResourceType{
			ResourceType: resourceType1,
			Pipeline:     defaultPipeline,
			Version:      atc.Version{"some-type": "version"},
		}.Create(setupTx)
		Expect(err).NotTo(HaveOccurred())

		Expect(setupTx.Commit()).To(Succeed())

		resourceCacheFactory = dbng.NewResourceCacheFactory(dbConn)

		logger := lagertest.NewTestLogger("resource-cache-use-collector")
		collector = gcng.NewResourceCacheUseCollector(logger, resourceCacheFactory)
	})

	AfterEach(func() {
		err := dbConn.Close()
		Expect(err).NotTo(HaveOccurred())
	})

	Describe("Run", func() {
		countResourceCacheUses := func() int {
			tx, err := dbConn.Begin()
			Expect(err).NotTo(HaveOccurred())
			defer tx.Rollback()

			var result int
			err = psql.Select("count(*)").
				From("resource_cache_uses").
				RunWith(tx).
				QueryRow().
				Scan(&result)
			Expect(err).NotTo(HaveOccurred())

			return result
		}

		Describe("cache uses for builds", func() {
			BeforeEach(func() {
				_, err = resourceCacheFactory.FindOrCreateResourceCacheForBuild(
					defaultBuild,
					"some-type",
					atc.Version{"some": "version"},
					atc.Source{
						"some": "source",
					},
					atc.Params{"some": "params"},
					defaultPipeline,
					atc.ResourceTypes{
						resourceType1,
					},
				)
				Expect(err).NotTo(HaveOccurred())
			})

			finishBuild := func(status string) {
				tx, err := dbConn.Begin()
				Expect(err).NotTo(HaveOccurred())
				defer tx.Rollback()

				var result time.Time
				err = psql.Update("builds").
					SetMap(map[string]interface{}{
						"status":    status,
						"end_time":  sq.Expr("NOW()"),
						"completed": true,
					}).Where(sq.Eq{
					"id": defaultBuild.ID,
				}).Suffix("RETURNING end_time").
					RunWith(tx).
					QueryRow().Scan(&result)
				Expect(err).NotTo(HaveOccurred())

				err = tx.Commit()
				Expect(err).NotTo(HaveOccurred())
			}

			Context("before the build has completed", func() {
				It("does not clean up the uses", func() {
					Expect(countResourceCacheUses()).NotTo(BeZero())
					collector.Run()
					Expect(countResourceCacheUses()).NotTo(BeZero())
				})
			})

			Context("once the build has completed successfully", func() {
				It("cleans up the uses", func() {
					Expect(countResourceCacheUses()).NotTo(BeZero())
					finishBuild("succeeded")
					collector.Run()
					Expect(countResourceCacheUses()).To(BeZero())
				})
			})

			Context("once the build has been aborted", func() {
				It("cleans up the uses", func() {
					Expect(countResourceCacheUses()).NotTo(BeZero())
					finishBuild("aborted")
					collector.Run()
					Expect(countResourceCacheUses()).To(BeZero())
				})
			})

			Context("once the build has failed", func() {
				It("cleans up the uses", func() {
					Expect(countResourceCacheUses()).NotTo(BeZero())
					finishBuild("failed")
					collector.Run()
					Expect(countResourceCacheUses()).To(BeZero())
				})
			})
		})

		Describe("cache uses for resource types", func() {
			setActiveResourceType := func(active bool) {
				tx, err := dbConn.Begin()
				Expect(err).NotTo(HaveOccurred())
				defer tx.Rollback()

				var id int
				err = psql.Update("resource_types").
					Set("active", active).
					Where(sq.Eq{
						"id": resourceType1Used.ID,
					}).Suffix("RETURNING id").
					RunWith(tx).
					QueryRow().Scan(&id)
				Expect(err).NotTo(HaveOccurred())

				err = tx.Commit()
				Expect(err).NotTo(HaveOccurred())
			}

			BeforeEach(func() {
				_, err = resourceCacheFactory.FindOrCreateResourceCacheForResourceType(
					"some-type",
					atc.Version{"some-type": "version"},
					atc.Source{
						"cache": "source",
					},
					atc.Params{"some": "params"},
					defaultPipeline,
					atc.ResourceTypes{
						resourceType1,
					},
				)
				Expect(err).NotTo(HaveOccurred())
				setActiveResourceType(true)
			})

			Context("while the resource type is still active", func() {
				It("does not clean up the uses", func() {
					Expect(countResourceCacheUses()).NotTo(BeZero())
					collector.Run()
					Expect(countResourceCacheUses()).NotTo(BeZero())
				})
			})

			Context("once the resource type is made inactive", func() {
				It("cleans up the uses", func() {
					Expect(countResourceCacheUses()).NotTo(BeZero())
					setActiveResourceType(false)
					collector.Run()
					Expect(countResourceCacheUses()).To(BeZero())
				})
			})
		})

		Describe("cache uses for resource types", func() {
			setActiveResource := func(active bool) {
				tx, err := dbConn.Begin()
				Expect(err).NotTo(HaveOccurred())
				defer tx.Rollback()

				var id int
				err = psql.Update("resources").
					Set("active", active).
					Where(sq.Eq{
						"id": usedResource.ID,
					}).Suffix("RETURNING id").
					RunWith(tx).
					QueryRow().Scan(&id)
				Expect(err).NotTo(HaveOccurred())

				err = tx.Commit()
				Expect(err).NotTo(HaveOccurred())
			}

			BeforeEach(func() {
				_, err = resourceCacheFactory.FindOrCreateResourceCacheForResource(
					usedResource,
					"some-type",
					atc.Version{"some-type": "version"},
					atc.Source{
						"cache": "source",
					},
					atc.Params{"some": "params"},
					defaultPipeline,
					atc.ResourceTypes{
						resourceType1,
					},
				)
				Expect(err).NotTo(HaveOccurred())
				setActiveResource(true)
			})

			Context("while the resource is still active", func() {
				It("does not clean up the uses", func() {
					Expect(countResourceCacheUses()).NotTo(BeZero())
					collector.Run()
					Expect(countResourceCacheUses()).NotTo(BeZero())
				})
			})

			Context("once the resource is made inactive", func() {
				It("cleans up the uses", func() {
					Expect(countResourceCacheUses()).NotTo(BeZero())
					setActiveResource(false)
					collector.Run()
					Expect(countResourceCacheUses()).To(BeZero())
				})
			})
		})
	})
})
<commit_msg>fix import casing<commit_after>package gcng_test

import (
	"time"

	"code.cloudfoundry.org/lager/lagertest"
	sq "github.com/Masterminds/squirrel"
	"github.com/concourse/atc"
	"github.com/concourse/atc/dbng"
	"github.com/concourse/atc/gcng"

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

var psql = sq.StatementBuilder.PlaceholderFormat(sq.Dollar)

var _ = Describe("ResourceCacheUseCollector", func() {
	var (
		collector gcng.ResourceCacheUseCollector

		dbConn               dbng.Conn
		err                  error
		resourceCacheFactory dbng.ResourceCacheFactory

		teamFactory     dbng.TeamFactory
		buildFactory    *dbng.BuildFactory
		pipelineFactory *dbng.PipelineFactory
		resourceFactory *dbng.ResourceFactory

		defaultTeam     *dbng.Team
		defaultPipeline *dbng.Pipeline
		defaultBuild    *dbng.Build

		resourceType1     atc.ResourceType
		resourceType1Used *dbng.UsedResourceType
		usedResource      *dbng.Resource
	)

	BeforeEach(func() {
		postgresRunner.Truncate()

		dbConn = dbng.Wrap(postgresRunner.Open())

		teamFactory = dbng.NewTeamFactory(dbConn)
		buildFactory = dbng.NewBuildFactory(dbConn)
		pipelineFactory = dbng.NewPipelineFactory(dbConn)
		resourceFactory = dbng.NewResourceFactory(dbConn)

		defaultTeam, err = teamFactory.CreateTeam("default-team")
		Expect(err).NotTo(HaveOccurred())

		defaultBuild, err = buildFactory.CreateOneOffBuild(defaultTeam)
		Expect(err).NotTo(HaveOccurred())

		defaultPipeline, err = pipelineFactory.CreatePipeline(defaultTeam, "default-pipeline", "some-config")
		Expect(err).NotTo(HaveOccurred())

		usedResource, err = resourceFactory.CreateResource(
			defaultPipeline,
			"some-resource",
			`{"some": "config"}`,
		)
		Expect(err).NotTo(HaveOccurred())

		setupTx, err := dbConn.Begin()
		Expect(err).ToNot(HaveOccurred())

		baseResourceType := dbng.BaseResourceType{
			Name: "some-base-type",
		}
		_, err = baseResourceType.FindOrCreate(setupTx)
		Expect(err).NotTo(HaveOccurred())

		resourceType1 = atc.ResourceType{
			Name: "some-type",
			Type: "some-base-type",
			Source: atc.Source{
				"some-type": "source",
			},
		}
		resourceType1Used, err = dbng.ResourceType{
			ResourceType: resourceType1,
			Pipeline:     defaultPipeline,
			Version:      atc.Version{"some-type": "version"},
		}.Create(setupTx)
		Expect(err).NotTo(HaveOccurred())

		Expect(setupTx.Commit()).To(Succeed())

		resourceCacheFactory = dbng.NewResourceCacheFactory(dbConn)

		logger := lagertest.NewTestLogger("resource-cache-use-collector")
		collector = gcng.NewResourceCacheUseCollector(logger, resourceCacheFactory)
	})

	AfterEach(func() {
		err := dbConn.Close()
		Expect(err).NotTo(HaveOccurred())
	})

	Describe("Run", func() {
		countResourceCacheUses := func() int {
			tx, err := dbConn.Begin()
			Expect(err).NotTo(HaveOccurred())
			defer tx.Rollback()

			var result int
			err = psql.Select("count(*)").
				From("resource_cache_uses").
				RunWith(tx).
				QueryRow().
				Scan(&result)
			Expect(err).NotTo(HaveOccurred())

			return result
		}

		Describe("cache uses for builds", func() {
			BeforeEach(func() {
				_, err = resourceCacheFactory.FindOrCreateResourceCacheForBuild(
					defaultBuild,
					"some-type",
					atc.Version{"some": "version"},
					atc.Source{
						"some": "source",
					},
					atc.Params{"some": "params"},
					defaultPipeline,
					atc.ResourceTypes{
						resourceType1,
					},
				)
				Expect(err).NotTo(HaveOccurred())
			})

			finishBuild := func(status string) {
				tx, err := dbConn.Begin()
				Expect(err).NotTo(HaveOccurred())
				defer tx.Rollback()

				var result time.Time
				err = psql.Update("builds").
					SetMap(map[string]interface{}{
						"status":    status,
						"end_time":  sq.Expr("NOW()"),
						"completed": true,
					}).Where(sq.Eq{
					"id": defaultBuild.ID,
				}).Suffix("RETURNING end_time").
					RunWith(tx).
					QueryRow().Scan(&result)
				Expect(err).NotTo(HaveOccurred())

				err = tx.Commit()
				Expect(err).NotTo(HaveOccurred())
			}

			Context("before the build has completed", func() {
				It("does not clean up the uses", func() {
					Expect(countResourceCacheUses()).NotTo(BeZero())
					collector.Run()
					Expect(countResourceCacheUses()).NotTo(BeZero())
				})
			})

			Context("once the build has completed successfully", func() {
				It("cleans up the uses", func() {
					Expect(countResourceCacheUses()).NotTo(BeZero())
					finishBuild("succeeded")
					collector.Run()
					Expect(countResourceCacheUses()).To(BeZero())
				})
			})

			Context("once the build has been aborted", func() {
				It("cleans up the uses", func() {
					Expect(countResourceCacheUses()).NotTo(BeZero())
					finishBuild("aborted")
					collector.Run()
					Expect(countResourceCacheUses()).To(BeZero())
				})
			})

			Context("once the build has failed", func() {
				It("cleans up the uses", func() {
					Expect(countResourceCacheUses()).NotTo(BeZero())
					finishBuild("failed")
					collector.Run()
					Expect(countResourceCacheUses()).To(BeZero())
				})
			})
		})

		Describe("cache uses for resource types", func() {
			setActiveResourceType := func(active bool) {
				tx, err := dbConn.Begin()
				Expect(err).NotTo(HaveOccurred())
				defer tx.Rollback()

				var id int
				err = psql.Update("resource_types").
					Set("active", active).
					Where(sq.Eq{
						"id": resourceType1Used.ID,
					}).Suffix("RETURNING id").
					RunWith(tx).
					QueryRow().Scan(&id)
				Expect(err).NotTo(HaveOccurred())

				err = tx.Commit()
				Expect(err).NotTo(HaveOccurred())
			}

			BeforeEach(func() {
				_, err = resourceCacheFactory.FindOrCreateResourceCacheForResourceType(
					"some-type",
					atc.Version{"some-type": "version"},
					atc.Source{
						"cache": "source",
					},
					atc.Params{"some": "params"},
					defaultPipeline,
					atc.ResourceTypes{
						resourceType1,
					},
				)
				Expect(err).NotTo(HaveOccurred())
				setActiveResourceType(true)
			})

			Context("while the resource type is still active", func() {
				It("does not clean up the uses", func() {
					Expect(countResourceCacheUses()).NotTo(BeZero())
					collector.Run()
					Expect(countResourceCacheUses()).NotTo(BeZero())
				})
			})

			Context("once the resource type is made inactive", func() {
				It("cleans up the uses", func() {
					Expect(countResourceCacheUses()).NotTo(BeZero())
					setActiveResourceType(false)
					collector.Run()
					Expect(countResourceCacheUses()).To(BeZero())
				})
			})
		})

		Describe("cache uses for resource types", func() {
			setActiveResource := func(active bool) {
				tx, err := dbConn.Begin()
				Expect(err).NotTo(HaveOccurred())
				defer tx.Rollback()

				var id int
				err = psql.Update("resources").
					Set("active", active).
					Where(sq.Eq{
						"id": usedResource.ID,
					}).Suffix("RETURNING id").
					RunWith(tx).
					QueryRow().Scan(&id)
				Expect(err).NotTo(HaveOccurred())

				err = tx.Commit()
				Expect(err).NotTo(HaveOccurred())
			}

			BeforeEach(func() {
				_, err = resourceCacheFactory.FindOrCreateResourceCacheForResource(
					usedResource,
					"some-type",
					atc.Version{"some-type": "version"},
					atc.Source{
						"cache": "source",
					},
					atc.Params{"some": "params"},
					defaultPipeline,
					atc.ResourceTypes{
						resourceType1,
					},
				)
				Expect(err).NotTo(HaveOccurred())
				setActiveResource(true)
			})

			Context("while the resource is still active", func() {
				It("does not clean up the uses", func() {
					Expect(countResourceCacheUses()).NotTo(BeZero())
					collector.Run()
					Expect(countResourceCacheUses()).NotTo(BeZero())
				})
			})

			Context("once the resource is made inactive", func() {
				It("cleans up the uses", func() {
					Expect(countResourceCacheUses()).NotTo(BeZero())
					setActiveResource(false)
					collector.Run()
					Expect(countResourceCacheUses()).To(BeZero())
				})
			})
		})
	})
})
<|endoftext|>


<commit_before>// Copyright (C) 2014 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package table

import (
	//"fmt"
	"github.com/osrg/gobgp/packet/bgp"
	"github.com/stretchr/testify/assert"
	"net"
	"testing"
	"time"
)

func TestDestinationNewIPv4(t *testing.T) {
	peerD := DestCreatePeer()
	pathD := DestCreatePath(peerD)
	ipv4d := NewDestination(pathD[0].GetNlri())
	assert.NotNil(t, ipv4d)
}
func TestDestinationNewIPv6(t *testing.T) {
	peerD := DestCreatePeer()
	pathD := DestCreatePath(peerD)
	ipv6d := NewDestination(pathD[0].GetNlri())
	assert.NotNil(t, ipv6d)
}

func TestDestinationSetRouteFamily(t *testing.T) {
	dd := &Destination{}
	dd.setRouteFamily(bgp.RF_IPv4_UC)
	rf := dd.Family()
	assert.Equal(t, rf, bgp.RF_IPv4_UC)
}
func TestDestinationGetRouteFamily(t *testing.T) {
	dd := &Destination{}
	dd.setRouteFamily(bgp.RF_IPv6_UC)
	rf := dd.Family()
	assert.Equal(t, rf, bgp.RF_IPv6_UC)
}
func TestDestinationSetNlri(t *testing.T) {
	dd := &Destination{}
	nlri := bgp.NewIPAddrPrefix(24, "13.2.3.1")
	dd.setNlri(nlri)
	r_nlri := dd.GetNlri()
	assert.Equal(t, r_nlri, nlri)
}
func TestDestinationGetNlri(t *testing.T) {
	dd := &Destination{}
	nlri := bgp.NewIPAddrPrefix(24, "10.110.123.1")
	dd.setNlri(nlri)
	r_nlri := dd.GetNlri()
	assert.Equal(t, r_nlri, nlri)
}

func TestCalculate(t *testing.T) {
	origin := bgp.NewPathAttributeOrigin(0)
	aspathParam := []bgp.AsPathParamInterface{bgp.NewAs4PathParam(2, []uint32{65001})}
	aspath := bgp.NewPathAttributeAsPath(aspathParam)
	nexthop := bgp.NewPathAttributeNextHop("10.0.0.1")
	med := bgp.NewPathAttributeMultiExitDisc(0)
	pathAttributes := []bgp.PathAttributeInterface{origin, aspath, nexthop, med}
	nlri := bgp.NewIPAddrPrefix(24, "10.10.0.101")
	updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, []*bgp.IPAddrPrefix{nlri})
	peer1 := &PeerInfo{AS: 1, Address: net.IP{1, 1, 1, 1}}
	path1 := ProcessMessage(updateMsg, peer1, time.Now())[0]
	path1.Filter("1", POLICY_DIRECTION_IMPORT)

	action := &AsPathPrependAction{
		asn:    100,
		repeat: 10,
	}

	path2 := action.Apply(path1.Clone(false))
	path1.Filter("2", POLICY_DIRECTION_IMPORT)
	path2.Filter("1", POLICY_DIRECTION_IMPORT)

	d := NewDestination(nlri)
	d.addNewPath(path1)
	d.addNewPath(path2)

	d.Calculate([]string{"1", "2"})

	assert.Equal(t, len(d.GetKnownPathList("1")), 0)
	assert.Equal(t, len(d.GetKnownPathList("2")), 1)
	assert.Equal(t, len(d.knownPathList), 2)

	d.addWithdraw(path1.Clone(true))

	d.Calculate([]string{"1", "2"})

	assert.Equal(t, len(d.GetKnownPathList("1")), 0)
	assert.Equal(t, len(d.GetKnownPathList("2")), 0)
	assert.Equal(t, len(d.knownPathList), 0)
}

func TestCalculate2(t *testing.T) {

	origin := bgp.NewPathAttributeOrigin(0)
	aspathParam := []bgp.AsPathParamInterface{bgp.NewAs4PathParam(2, []uint32{65001})}
	aspath := bgp.NewPathAttributeAsPath(aspathParam)
	nexthop := bgp.NewPathAttributeNextHop("10.0.0.1")
	med := bgp.NewPathAttributeMultiExitDisc(0)
	pathAttributes := []bgp.PathAttributeInterface{origin, aspath, nexthop, med}
	nlri := bgp.NewIPAddrPrefix(24, "10.10.0.0")

	// peer1 sends normal update message 10.10.0.0/24
	update1 := bgp.NewBGPUpdateMessage(nil, pathAttributes, []*bgp.IPAddrPrefix{nlri})
	peer1 := &PeerInfo{AS: 1, Address: net.IP{1, 1, 1, 1}}
	path1 := ProcessMessage(update1, peer1, time.Now())[0]

	d := NewDestination(nlri)
	d.addNewPath(path1)
	d.Calculate(nil)

	// suppose peer2 sends grammaatically correct but semantically flawed update message
	// which has a withdrawal nlri not advertised before
	update2 := bgp.NewBGPUpdateMessage([]*bgp.IPAddrPrefix{nlri}, pathAttributes, nil)
	peer2 := &PeerInfo{AS: 2, Address: net.IP{2, 2, 2, 2}}
	path2 := ProcessMessage(update2, peer2, time.Now())[0]
	assert.Equal(t, path2.IsWithdraw, true)

	d.addWithdraw(path2)
	d.Calculate(nil)

	// we have a path from peer1 here
	assert.Equal(t, len(d.knownPathList), 1)

	// after that, new update with the same nlri comes from peer2
	update3 := bgp.NewBGPUpdateMessage(nil, pathAttributes, []*bgp.IPAddrPrefix{nlri})
	path3 := ProcessMessage(update3, peer2, time.Now())[0]
	assert.Equal(t, path3.IsWithdraw, false)

	d.addNewPath(path3)
	d.Calculate(nil)

	// this time, we have paths from peer1 and peer2
	assert.Equal(t, len(d.knownPathList), 2)

	// now peer3 sends normal update message 10.10.0.0/24
	peer3 := &PeerInfo{AS: 3, Address: net.IP{3, 3, 3, 3}}
	update4 := bgp.NewBGPUpdateMessage(nil, pathAttributes, []*bgp.IPAddrPrefix{nlri})
	path4 := ProcessMessage(update4, peer3, time.Now())[0]

	d.addNewPath(path4)
	d.Calculate(nil)

	// we must have paths from peer1, peer2 and peer3
	assert.Equal(t, len(d.knownPathList), 3)
}

func DestCreatePeer() []*PeerInfo {
	peerD1 := &PeerInfo{AS: 65000}
	peerD2 := &PeerInfo{AS: 65001}
	peerD3 := &PeerInfo{AS: 65002}
	peerD := []*PeerInfo{peerD1, peerD2, peerD3}
	return peerD
}

func DestCreatePath(peerD []*PeerInfo) []*Path {
	bgpMsgD1 := updateMsgD1()
	bgpMsgD2 := updateMsgD2()
	bgpMsgD3 := updateMsgD3()
	pathD := make([]*Path, 3)
	for i, msg := range []*bgp.BGPMessage{bgpMsgD1, bgpMsgD2, bgpMsgD3} {
		updateMsgD := msg.Body.(*bgp.BGPUpdate)
		nlriList := updateMsgD.NLRI
		pathAttributes := updateMsgD.PathAttributes
		nlri_info := nlriList[0]
		pathD[i] = NewPath(peerD[i], nlri_info, false, pathAttributes, time.Now(), false)
	}
	return pathD
}

func updateMsgD1() *bgp.BGPMessage {

	origin := bgp.NewPathAttributeOrigin(0)
	aspathParam := []bgp.AsPathParamInterface{bgp.NewAsPathParam(2, []uint16{65000})}
	aspath := bgp.NewPathAttributeAsPath(aspathParam)
	nexthop := bgp.NewPathAttributeNextHop("192.168.50.1")
	med := bgp.NewPathAttributeMultiExitDisc(0)

	pathAttributes := []bgp.PathAttributeInterface{
		origin,
		aspath,
		nexthop,
		med,
	}

	nlri := []*bgp.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.10.0")}
	updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
	UpdatePathAttrs4ByteAs(updateMsg.Body.(*bgp.BGPUpdate))
	return updateMsg
}

func updateMsgD2() *bgp.BGPMessage {

	origin := bgp.NewPathAttributeOrigin(0)
	aspathParam := []bgp.AsPathParamInterface{bgp.NewAsPathParam(2, []uint16{65100})}
	aspath := bgp.NewPathAttributeAsPath(aspathParam)
	nexthop := bgp.NewPathAttributeNextHop("192.168.100.1")
	med := bgp.NewPathAttributeMultiExitDisc(100)

	pathAttributes := []bgp.PathAttributeInterface{
		origin,
		aspath,
		nexthop,
		med,
	}

	nlri := []*bgp.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "20.20.20.0")}
	updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
	UpdatePathAttrs4ByteAs(updateMsg.Body.(*bgp.BGPUpdate))
	return updateMsg
}
func updateMsgD3() *bgp.BGPMessage {
	origin := bgp.NewPathAttributeOrigin(0)
	aspathParam := []bgp.AsPathParamInterface{bgp.NewAsPathParam(2, []uint16{65100})}
	aspath := bgp.NewPathAttributeAsPath(aspathParam)
	nexthop := bgp.NewPathAttributeNextHop("192.168.150.1")
	med := bgp.NewPathAttributeMultiExitDisc(100)

	pathAttributes := []bgp.PathAttributeInterface{
		origin,
		aspath,
		nexthop,
		med,
	}

	nlri := []*bgp.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "30.30.30.0")}
	w1 := bgp.NewIPAddrPrefix(23, "40.40.40.0")
	withdrawnRoutes := []*bgp.IPAddrPrefix{w1}
	updateMsg := bgp.NewBGPUpdateMessage(withdrawnRoutes, pathAttributes, nlri)
	UpdatePathAttrs4ByteAs(updateMsg.Body.(*bgp.BGPUpdate))
	return updateMsg
}

func TestRadixkey(t *testing.T) {
	assert.Equal(t, "000010100000001100100000", CidrToRadixkey("10.3.32.0/24"))
	assert.Equal(t, "000010100000001100100000", IpToRadixkey(net.ParseIP("10.3.32.0").To4(), 24))
	assert.Equal(t, "000010100000001100100000", IpToRadixkey(net.ParseIP("10.3.32.0").To4(), 24))
}
<commit_msg>table: add a test to check implicit withdrawal behavior with mod action<commit_after>// Copyright (C) 2014 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package table

import (
	//"fmt"
	"github.com/osrg/gobgp/packet/bgp"
	"github.com/stretchr/testify/assert"
	"net"
	"testing"
	"time"
)

func TestDestinationNewIPv4(t *testing.T) {
	peerD := DestCreatePeer()
	pathD := DestCreatePath(peerD)
	ipv4d := NewDestination(pathD[0].GetNlri())
	assert.NotNil(t, ipv4d)
}
func TestDestinationNewIPv6(t *testing.T) {
	peerD := DestCreatePeer()
	pathD := DestCreatePath(peerD)
	ipv6d := NewDestination(pathD[0].GetNlri())
	assert.NotNil(t, ipv6d)
}

func TestDestinationSetRouteFamily(t *testing.T) {
	dd := &Destination{}
	dd.setRouteFamily(bgp.RF_IPv4_UC)
	rf := dd.Family()
	assert.Equal(t, rf, bgp.RF_IPv4_UC)
}
func TestDestinationGetRouteFamily(t *testing.T) {
	dd := &Destination{}
	dd.setRouteFamily(bgp.RF_IPv6_UC)
	rf := dd.Family()
	assert.Equal(t, rf, bgp.RF_IPv6_UC)
}
func TestDestinationSetNlri(t *testing.T) {
	dd := &Destination{}
	nlri := bgp.NewIPAddrPrefix(24, "13.2.3.1")
	dd.setNlri(nlri)
	r_nlri := dd.GetNlri()
	assert.Equal(t, r_nlri, nlri)
}
func TestDestinationGetNlri(t *testing.T) {
	dd := &Destination{}
	nlri := bgp.NewIPAddrPrefix(24, "10.110.123.1")
	dd.setNlri(nlri)
	r_nlri := dd.GetNlri()
	assert.Equal(t, r_nlri, nlri)
}

func TestCalculate(t *testing.T) {
	origin := bgp.NewPathAttributeOrigin(0)
	aspathParam := []bgp.AsPathParamInterface{bgp.NewAs4PathParam(2, []uint32{65001})}
	aspath := bgp.NewPathAttributeAsPath(aspathParam)
	nexthop := bgp.NewPathAttributeNextHop("10.0.0.1")
	med := bgp.NewPathAttributeMultiExitDisc(0)
	pathAttributes := []bgp.PathAttributeInterface{origin, aspath, nexthop, med}
	nlri := bgp.NewIPAddrPrefix(24, "10.10.0.101")
	updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, []*bgp.IPAddrPrefix{nlri})
	peer1 := &PeerInfo{AS: 1, Address: net.IP{1, 1, 1, 1}}
	path1 := ProcessMessage(updateMsg, peer1, time.Now())[0]
	path1.Filter("1", POLICY_DIRECTION_IMPORT)

	action := &AsPathPrependAction{
		asn:    100,
		repeat: 10,
	}

	path2 := action.Apply(path1.Clone(false))
	path1.Filter("2", POLICY_DIRECTION_IMPORT)
	path2.Filter("1", POLICY_DIRECTION_IMPORT)

	d := NewDestination(nlri)
	d.addNewPath(path1)
	d.addNewPath(path2)

	d.Calculate([]string{"1", "2"})

	assert.Equal(t, len(d.GetKnownPathList("1")), 0)
	assert.Equal(t, len(d.GetKnownPathList("2")), 1)
	assert.Equal(t, len(d.knownPathList), 2)

	d.addWithdraw(path1.Clone(true))

	d.Calculate([]string{"1", "2"})

	assert.Equal(t, len(d.GetKnownPathList("1")), 0)
	assert.Equal(t, len(d.GetKnownPathList("2")), 0)
	assert.Equal(t, len(d.knownPathList), 0)
}

func TestCalculate2(t *testing.T) {

	origin := bgp.NewPathAttributeOrigin(0)
	aspathParam := []bgp.AsPathParamInterface{bgp.NewAs4PathParam(2, []uint32{65001})}
	aspath := bgp.NewPathAttributeAsPath(aspathParam)
	nexthop := bgp.NewPathAttributeNextHop("10.0.0.1")
	med := bgp.NewPathAttributeMultiExitDisc(0)
	pathAttributes := []bgp.PathAttributeInterface{origin, aspath, nexthop, med}
	nlri := bgp.NewIPAddrPrefix(24, "10.10.0.0")

	// peer1 sends normal update message 10.10.0.0/24
	update1 := bgp.NewBGPUpdateMessage(nil, pathAttributes, []*bgp.IPAddrPrefix{nlri})
	peer1 := &PeerInfo{AS: 1, Address: net.IP{1, 1, 1, 1}}
	path1 := ProcessMessage(update1, peer1, time.Now())[0]

	d := NewDestination(nlri)
	d.addNewPath(path1)
	d.Calculate(nil)

	// suppose peer2 sends grammaatically correct but semantically flawed update message
	// which has a withdrawal nlri not advertised before
	update2 := bgp.NewBGPUpdateMessage([]*bgp.IPAddrPrefix{nlri}, pathAttributes, nil)
	peer2 := &PeerInfo{AS: 2, Address: net.IP{2, 2, 2, 2}}
	path2 := ProcessMessage(update2, peer2, time.Now())[0]
	assert.Equal(t, path2.IsWithdraw, true)

	d.addWithdraw(path2)
	d.Calculate(nil)

	// we have a path from peer1 here
	assert.Equal(t, len(d.knownPathList), 1)

	// after that, new update with the same nlri comes from peer2
	update3 := bgp.NewBGPUpdateMessage(nil, pathAttributes, []*bgp.IPAddrPrefix{nlri})
	path3 := ProcessMessage(update3, peer2, time.Now())[0]
	assert.Equal(t, path3.IsWithdraw, false)

	d.addNewPath(path3)
	d.Calculate(nil)

	// this time, we have paths from peer1 and peer2
	assert.Equal(t, len(d.knownPathList), 2)

	// now peer3 sends normal update message 10.10.0.0/24
	peer3 := &PeerInfo{AS: 3, Address: net.IP{3, 3, 3, 3}}
	update4 := bgp.NewBGPUpdateMessage(nil, pathAttributes, []*bgp.IPAddrPrefix{nlri})
	path4 := ProcessMessage(update4, peer3, time.Now())[0]

	d.addNewPath(path4)
	d.Calculate(nil)

	// we must have paths from peer1, peer2 and peer3
	assert.Equal(t, len(d.knownPathList), 3)
}

func TestImplicitWithdrawCalculate(t *testing.T) {
	origin := bgp.NewPathAttributeOrigin(0)
	aspathParam := []bgp.AsPathParamInterface{bgp.NewAs4PathParam(2, []uint32{65001})}
	aspath := bgp.NewPathAttributeAsPath(aspathParam)
	nexthop := bgp.NewPathAttributeNextHop("10.0.0.1")
	med := bgp.NewPathAttributeMultiExitDisc(0)
	pathAttributes := []bgp.PathAttributeInterface{origin, aspath, nexthop, med}
	nlri := bgp.NewIPAddrPrefix(24, "10.10.0.101")
	updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, []*bgp.IPAddrPrefix{nlri})
	peer1 := &PeerInfo{AS: 1, Address: net.IP{1, 1, 1, 1}}
	path1 := ProcessMessage(updateMsg, peer1, time.Now())[0]
	path1.Filter("1", POLICY_DIRECTION_IMPORT)

	// suppose peer2 has import policy to prepend as-path
	action := &AsPathPrependAction{
		asn:    100,
		repeat: 1,
	}

	path2 := action.Apply(path1.Clone(false))
	path1.Filter("2", POLICY_DIRECTION_IMPORT)
	path2.Filter("1", POLICY_DIRECTION_IMPORT)
	path2.Filter("3", POLICY_DIRECTION_IMPORT)

	d := NewDestination(nlri)
	d.addNewPath(path1)
	d.addNewPath(path2)

	d.Calculate(nil)

	assert.Equal(t, len(d.GetKnownPathList("1")), 0) // peer "1" is the originator
	assert.Equal(t, len(d.GetKnownPathList("2")), 1)
	assert.Equal(t, d.GetKnownPathList("2")[0].GetAsString(), "100 65001") // peer "2" has modified path {100, 65001}
	assert.Equal(t, len(d.GetKnownPathList("3")), 1)
	assert.Equal(t, d.GetKnownPathList("3")[0].GetAsString(), "65001") // peer "3" has original path {65001}
	assert.Equal(t, len(d.knownPathList), 2)

	// say, we removed peer2's import policy and
	// peer1 advertised new path with the same prefix
	aspathParam = []bgp.AsPathParamInterface{bgp.NewAs4PathParam(2, []uint32{65001, 65002})}
	aspath = bgp.NewPathAttributeAsPath(aspathParam)
	pathAttributes = []bgp.PathAttributeInterface{origin, aspath, nexthop, med}
	updateMsg = bgp.NewBGPUpdateMessage(nil, pathAttributes, []*bgp.IPAddrPrefix{nlri})
	path3 := ProcessMessage(updateMsg, peer1, time.Now())[0]
	path3.Filter("1", POLICY_DIRECTION_IMPORT)

	d.addNewPath(path3)
	d.Calculate(nil)

	assert.Equal(t, len(d.GetKnownPathList("1")), 0) // peer "1" is the originator
	assert.Equal(t, len(d.GetKnownPathList("2")), 1)
	assert.Equal(t, d.GetKnownPathList("2")[0].GetAsString(), "65001 65002") // peer "2" has new original path {65001, 65002}
	assert.Equal(t, len(d.GetKnownPathList("3")), 1)
	assert.Equal(t, d.GetKnownPathList("3")[0].GetAsString(), "65001 65002") // peer "3" has new original path {65001, 65002}
	assert.Equal(t, len(d.knownPathList), 1)
}

func DestCreatePeer() []*PeerInfo {
	peerD1 := &PeerInfo{AS: 65000}
	peerD2 := &PeerInfo{AS: 65001}
	peerD3 := &PeerInfo{AS: 65002}
	peerD := []*PeerInfo{peerD1, peerD2, peerD3}
	return peerD
}

func DestCreatePath(peerD []*PeerInfo) []*Path {
	bgpMsgD1 := updateMsgD1()
	bgpMsgD2 := updateMsgD2()
	bgpMsgD3 := updateMsgD3()
	pathD := make([]*Path, 3)
	for i, msg := range []*bgp.BGPMessage{bgpMsgD1, bgpMsgD2, bgpMsgD3} {
		updateMsgD := msg.Body.(*bgp.BGPUpdate)
		nlriList := updateMsgD.NLRI
		pathAttributes := updateMsgD.PathAttributes
		nlri_info := nlriList[0]
		pathD[i] = NewPath(peerD[i], nlri_info, false, pathAttributes, time.Now(), false)
	}
	return pathD
}

func updateMsgD1() *bgp.BGPMessage {

	origin := bgp.NewPathAttributeOrigin(0)
	aspathParam := []bgp.AsPathParamInterface{bgp.NewAsPathParam(2, []uint16{65000})}
	aspath := bgp.NewPathAttributeAsPath(aspathParam)
	nexthop := bgp.NewPathAttributeNextHop("192.168.50.1")
	med := bgp.NewPathAttributeMultiExitDisc(0)

	pathAttributes := []bgp.PathAttributeInterface{
		origin,
		aspath,
		nexthop,
		med,
	}

	nlri := []*bgp.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.10.0")}
	updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
	UpdatePathAttrs4ByteAs(updateMsg.Body.(*bgp.BGPUpdate))
	return updateMsg
}

func updateMsgD2() *bgp.BGPMessage {

	origin := bgp.NewPathAttributeOrigin(0)
	aspathParam := []bgp.AsPathParamInterface{bgp.NewAsPathParam(2, []uint16{65100})}
	aspath := bgp.NewPathAttributeAsPath(aspathParam)
	nexthop := bgp.NewPathAttributeNextHop("192.168.100.1")
	med := bgp.NewPathAttributeMultiExitDisc(100)

	pathAttributes := []bgp.PathAttributeInterface{
		origin,
		aspath,
		nexthop,
		med,
	}

	nlri := []*bgp.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "20.20.20.0")}
	updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
	UpdatePathAttrs4ByteAs(updateMsg.Body.(*bgp.BGPUpdate))
	return updateMsg
}
func updateMsgD3() *bgp.BGPMessage {
	origin := bgp.NewPathAttributeOrigin(0)
	aspathParam := []bgp.AsPathParamInterface{bgp.NewAsPathParam(2, []uint16{65100})}
	aspath := bgp.NewPathAttributeAsPath(aspathParam)
	nexthop := bgp.NewPathAttributeNextHop("192.168.150.1")
	med := bgp.NewPathAttributeMultiExitDisc(100)

	pathAttributes := []bgp.PathAttributeInterface{
		origin,
		aspath,
		nexthop,
		med,
	}

	nlri := []*bgp.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "30.30.30.0")}
	w1 := bgp.NewIPAddrPrefix(23, "40.40.40.0")
	withdrawnRoutes := []*bgp.IPAddrPrefix{w1}
	updateMsg := bgp.NewBGPUpdateMessage(withdrawnRoutes, pathAttributes, nlri)
	UpdatePathAttrs4ByteAs(updateMsg.Body.(*bgp.BGPUpdate))
	return updateMsg
}

func TestRadixkey(t *testing.T) {
	assert.Equal(t, "000010100000001100100000", CidrToRadixkey("10.3.32.0/24"))
	assert.Equal(t, "000010100000001100100000", IpToRadixkey(net.ParseIP("10.3.32.0").To4(), 24))
	assert.Equal(t, "000010100000001100100000", IpToRadixkey(net.ParseIP("10.3.32.0").To4(), 24))
}
<|endoftext|>


<commit_before>package downloader

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"github.com/ibmjstart/cf-download/cmd_exec"
	"github.com/ibmjstart/cf-download/dir_parser"
	"github.com/ibmjstart/cf-download/filter"
	"github.com/mgutz/ansi"
)

type Downloader interface {
	Download(files, dirs []string, readPath, writePath string, filterList []string) error
	DownloadFile(readPath, writePath string) error
	WriteFile(readPath, writePath string, output []byte, err error) error
	CheckDownload(readPath string, file []string, err error) error
	GetFilesDownloadedCount() int
	GetFailedDownloads() []string
}

type downloader struct {
	cmdExec         cmd_exec.CmdExec
	appName         string
	instance        string
	verbose         bool
	onWindows       bool
	failedDownloads []string
	filesDownloaded int
	parser          dir_parser.Parser
	wg              *sync.WaitGroup
}

func NewDownloader(cmdExec cmd_exec.CmdExec, WG *sync.WaitGroup, appName, instance string, verbose, onWindows bool) *downloader {

	return &downloader{
		cmdExec:   cmdExec,
		appName:   appName,
		instance:  instance,
		verbose:   verbose,
		onWindows: onWindows,
		parser:    dir_parser.NewParser(cmdExec, appName, instance, onWindows, verbose),
		wg:        WG,
	}
}

// error struct that allows appending error messages
type cliError struct {
	err    error
	errMsg string
}

/*
*	given file and directory names, download() will download the files from
* 	'readPath' and write them to disk on the 'writepath'.
* 	the function calls it's self recursively for each directory as it travels down the tree.
* 	Each call runs on a seperate go routine and and calls a go routine for every
* 	file download.
 */
func (d *downloader) Download(files, dirs []string, readPath, writePath string, filterList []string) error {
	defer d.wg.Done()

	//create dir if does not exist
	err := os.MkdirAll(writePath, 0755)
	check(err, "Error D1: failed to create directory.")

	// download each file
	for _, val := range files {
		fileWPath := writePath + val
		fileRPath := readPath + val

		if filter.CheckToFilter(fileRPath, filterList) {
			continue
		}

		d.wg.Add(1)
		go d.DownloadFile(fileRPath, fileWPath)
	}

	// call download on every sub directory
	for _, val := range dirs {
		dirWPath := writePath + filepath.FromSlash(val)
		dirRPath := readPath + val

		if filter.CheckToFilter(strings.TrimSuffix(dirRPath, "/"), filterList) {
			continue
		}

		err := os.MkdirAll(dirWPath, 0755)
		check(err, "Error D2: failed to create directory.")

		files, dirs = d.parser.ExecParseDir(dirRPath)

		d.wg.Add(1)
		go d.Download(files, dirs, dirRPath, dirWPath, filterList)
	}
	return nil
}

/*
*	downloadFile() takes a 'readPath' which corresponds to a file in the cf app. The file is
*	downloaded using the cmd_exec package which uses the os/exec library to call cf files with the given readPath. The output is
*	written to a file at writePath.
 */
func (d *downloader) DownloadFile(readPath, writePath string) error {
	defer d.wg.Done()

	output, err := d.cmdExec.GetFile(d.appName, readPath, d.instance)

	d.WriteFile(readPath, writePath, output, err)

	return nil
}

func (d *downloader) WriteFile(readPath, writePath string, output []byte, err error) error {
	file := strings.SplitAfterN(string(output), "\n", 3)

	// check for invalid files or download issues
	downloadErr := d.CheckDownload(readPath, file, err)

	if downloadErr == nil {
		fileAsString := file[2]

		// there is currently an issue open to change the behavior for empty files
		// https://github.com/cloudfoundry/cli/issues/869
		if strings.Contains(fileAsString, "No files found") {
			fileAsString = ""
		}

		if d.verbose {
			fmt.Printf("Writing file: %s\n", readPath)
		}

		// write downloaded file to writePath
		err = ioutil.WriteFile(writePath, []byte(fileAsString), 0644)

		for i := 1; i <= 32 && err != nil; i *= 2 {
			time.Sleep(time.Duration(i) * time.Second)
			err = ioutil.WriteFile(writePath, []byte(fileAsString), 0644)
		}

		if err == nil {
			// increment download counter for commandline display
			// see consoleWriter() in main.go
			d.filesDownloaded++
		} else {
			errMsg := createMessage(" Write Error: '"+readPath+"' encountered error while writing to local file", "yellow", d.onWindows)
			d.failedDownloads = append(d.failedDownloads, errMsg)
			if d.verbose {
				fmt.Println(errMsg)
				fmt.Println(err)
			}
		}

	}

	return err
}

func (d *downloader) CheckDownload(readPath string, file []string, err error) error {
	if len(file) >= 2 && strings.Contains(file[1], "OK") {
		return nil
	} else {
		errMsg := createMessage(" Server Error: '"+readPath+"' not downloaded", "yellow", d.onWindows)

		d.failedDownloads = append(d.failedDownloads, errMsg)

		if d.verbose {
			fmt.Println(errMsg)
			// check for other errors
			if err != nil && len(file) >= 2 {
				PrintSlice(file)
			}
		}
		return errors.New("download failed")
	}
}

func (d *downloader) GetFilesDownloadedCount() int {
	return d.filesDownloaded
}

func (d *downloader) GetFailedDownloads() []string {
	return d.failedDownloads
}

// error check function
func check(e error, errMsg string) {
	if e != nil {
		fmt.Println("\nError: ", e)
		if errMsg != "" {
			fmt.Println("Message: ", errMsg)
		}
		os.Exit(1)
	}
}

// prints slices in readable format
func PrintSlice(slice []string) error {
	for index, val := range slice {
		fmt.Println(index, ": ", val)
	}
	return nil
}

func createMessage(message, color string, onWindows bool) string {
	errmsg := ansi.Color(message, color)
	if onWindows == true {
		errmsg = message
	}

	return errmsg
}
<commit_msg>Remove nested goroutine creation<commit_after>package downloader

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"github.com/ibmjstart/cf-download/cmd_exec"
	"github.com/ibmjstart/cf-download/dir_parser"
	"github.com/ibmjstart/cf-download/filter"
	"github.com/mgutz/ansi"
)

type Downloader interface {
	Download(files, dirs []string, readPath, writePath string, filterList []string) error
	DownloadFile(readPath, writePath string) error
	WriteFile(readPath, writePath string, output []byte, err error) error
	CheckDownload(readPath string, file []string, err error) error
	GetFilesDownloadedCount() int
	GetFailedDownloads() []string
}

type downloader struct {
	cmdExec         cmd_exec.CmdExec
	appName         string
	instance        string
	verbose         bool
	onWindows       bool
	failedDownloads []string
	filesDownloaded int
	parser          dir_parser.Parser
	wg              *sync.WaitGroup
}

func NewDownloader(cmdExec cmd_exec.CmdExec, WG *sync.WaitGroup, appName, instance string, verbose, onWindows bool) *downloader {

	return &downloader{
		cmdExec:   cmdExec,
		appName:   appName,
		instance:  instance,
		verbose:   verbose,
		onWindows: onWindows,
		parser:    dir_parser.NewParser(cmdExec, appName, instance, onWindows, verbose),
		wg:        WG,
	}
}

// error struct that allows appending error messages
type cliError struct {
	err    error
	errMsg string
}

/*
*	given file and directory names, download() will download the files from
* 	'readPath' and write them to disk on the 'writepath'.
* 	the function calls it's self recursively for each directory as it travels down the tree.
* 	Each call runs on a seperate go routine and and calls a go routine for every
* 	file download.
 */
func (d *downloader) Download(files, dirs []string, readPath, writePath string, filterList []string) error {
	defer d.wg.Done()

	//create dir if does not exist
	err := os.MkdirAll(writePath, 0755)
	check(err, "Error D1: failed to create directory.")

	// download each file
	for _, val := range files {
		fileWPath := writePath + val
		fileRPath := readPath + val

		if filter.CheckToFilter(fileRPath, filterList) {
			continue
		}

		d.wg.Add(1)
		go d.DownloadFile(fileRPath, fileWPath)
	}

	// call download on every sub directory
	for _, val := range dirs {
		dirWPath := writePath + filepath.FromSlash(val)
		dirRPath := readPath + val

		if filter.CheckToFilter(strings.TrimSuffix(dirRPath, "/"), filterList) {
			continue
		}

		err := os.MkdirAll(dirWPath, 0755)
		check(err, "Error D2: failed to create directory.")

		files, dirs = d.parser.ExecParseDir(dirRPath)

		d.wg.Add(1)
		d.Download(files, dirs, dirRPath, dirWPath, filterList)
	}
	return nil
}

/*
*	downloadFile() takes a 'readPath' which corresponds to a file in the cf app. The file is
*	downloaded using the cmd_exec package which uses the os/exec library to call cf files with the given readPath. The output is
*	written to a file at writePath.
 */
func (d *downloader) DownloadFile(readPath, writePath string) error {
	defer d.wg.Done()

	output, err := d.cmdExec.GetFile(d.appName, readPath, d.instance)

	d.WriteFile(readPath, writePath, output, err)

	return nil
}

func (d *downloader) WriteFile(readPath, writePath string, output []byte, err error) error {
	file := strings.SplitAfterN(string(output), "\n", 3)

	// check for invalid files or download issues
	downloadErr := d.CheckDownload(readPath, file, err)

	if downloadErr == nil {
		fileAsString := file[2]

		// there is currently an issue open to change the behavior for empty files
		// https://github.com/cloudfoundry/cli/issues/869
		if strings.Contains(fileAsString, "No files found") {
			fileAsString = ""
		}

		if d.verbose {
			fmt.Printf("Writing file: %s\n", readPath)
		}

		// write downloaded file to writePath
		err = ioutil.WriteFile(writePath, []byte(fileAsString), 0644)

		for i := 1; i <= 32 && err != nil; i *= 2 {
			time.Sleep(time.Duration(i) * time.Second)
			err = ioutil.WriteFile(writePath, []byte(fileAsString), 0644)
		}

		if err == nil {
			// increment download counter for commandline display
			// see consoleWriter() in main.go
			d.filesDownloaded++
		} else {
			errMsg := createMessage(" Write Error: '"+readPath+"' encountered error while writing to local file", "yellow", d.onWindows)
			d.failedDownloads = append(d.failedDownloads, errMsg)
			if d.verbose {
				fmt.Println(errMsg)
				fmt.Println(err)
			}
		}

	}

	return err
}

func (d *downloader) CheckDownload(readPath string, file []string, err error) error {
	if len(file) >= 2 && strings.Contains(file[1], "OK") {
		return nil
	} else {
		errMsg := createMessage(" Server Error: '"+readPath+"' not downloaded", "yellow", d.onWindows)

		d.failedDownloads = append(d.failedDownloads, errMsg)

		if d.verbose {
			fmt.Println(errMsg)
			// check for other errors
			if err != nil && len(file) >= 2 {
				PrintSlice(file)
			}
		}
		return errors.New("download failed")
	}
}

func (d *downloader) GetFilesDownloadedCount() int {
	return d.filesDownloaded
}

func (d *downloader) GetFailedDownloads() []string {
	return d.failedDownloads
}

// error check function
func check(e error, errMsg string) {
	if e != nil {
		fmt.Println("\nError: ", e)
		if errMsg != "" {
			fmt.Println("Message: ", errMsg)
		}
		os.Exit(1)
	}
}

// prints slices in readable format
func PrintSlice(slice []string) error {
	for index, val := range slice {
		fmt.Println(index, ": ", val)
	}
	return nil
}

func createMessage(message, color string, onWindows bool) string {
	errmsg := ansi.Color(message, color)
	if onWindows == true {
		errmsg = message
	}

	return errmsg
}
<|endoftext|>


<commit_before>package server

import (
	"fmt"
	"time"
)

type CreateReq struct {
	Name                   string `valid:"required"`
	Description            string `json:"omitempty"`
	GroupId                string
	GroupName              string `json:"omitempty"`
	SourceServerId         string
	TemplateId             string
	TemplateName           string              `json:"omitempty"`
	IsManagedOS            bool                `json:"omitempty"`
	PrimaryDns             string              `json:"omitempty"`
	SecondaryDns           string              `json:"omitempty"`
	NetworkId              string              `json:"omitempty"`
	IpAddress              string              `json:"omitempty"`
	Password               string              `json:"omitempty"`
	SourceServerPassword   string              `json:"omitempty"`
	Cpu                    int64               `valid:"required"`
	CpuAutoscalePolicyId   string              `json:"omitempty"`
	MemoryGB               int64               `valid:"required"`
	Type                   string              `valid:"required"`
	StorageType            string              `json:"omitempty"`
	AntiAffinityPolicyId   string              `json:"omitempty"`
	AntiAffinityPolicyName string              `json:"omitempty"`
	CustomFields           []CustomFieldDef    `json:"omitempty"`
	AdditionalDisks        []AdditionalDiskDef `json:"omitempty"`
	Ttl                    time.Time           `json:"omitempty"`
	Packages               []PackageDef        `json:"omitempty"`
}

type CustomFieldDef struct {
	Id    string
	Value string
}

type AdditionalDiskDef struct {
	Path   string
	SizeGB int
	Type   string
}

type PackageDef struct {
	PackageId  string
	Parameters map[string]string
}

func (c *CreateReq) Validate() error {
	serverIdValues := []string{c.SourceServerId, c.TemplateId, c.TemplateName}
	numNonEmpty := 0
	for _, item := range serverIdValues {
		if item != "" {
			numNonEmpty++
		}
	}
	if numNonEmpty > 1 || numNonEmpty == 0 {
		return fmt.Errorf("Exactly one parameter from the following: source-server-id, source-server-name, template-id, template-name must be specified.")
	}

	return nil
}

func (c *CreateReq) ApplyDefaultBehaviour() error {
	if c.TemplateId != "" {
		c.SourceServerId = c.TemplateId
	}
	return nil
	//TODO: implement searching templates by name
}
<commit_msg>check that exactly one of the GroupName, GroupId parameters is specified<commit_after>package server

import (
	"fmt"
	"time"
)

type CreateReq struct {
	Name                   string `valid:"required"`
	Description            string `json:"omitempty"`
	GroupId                string
	GroupName              string `json:"omitempty"`
	SourceServerId         string
	TemplateId             string
	TemplateName           string              `json:"omitempty"`
	IsManagedOS            bool                `json:"omitempty"`
	PrimaryDns             string              `json:"omitempty"`
	SecondaryDns           string              `json:"omitempty"`
	NetworkId              string              `json:"omitempty"`
	IpAddress              string              `json:"omitempty"`
	Password               string              `json:"omitempty"`
	SourceServerPassword   string              `json:"omitempty"`
	Cpu                    int64               `valid:"required"`
	CpuAutoscalePolicyId   string              `json:"omitempty"`
	MemoryGB               int64               `valid:"required"`
	Type                   string              `valid:"required"`
	StorageType            string              `json:"omitempty"`
	AntiAffinityPolicyId   string              `json:"omitempty"`
	AntiAffinityPolicyName string              `json:"omitempty"`
	CustomFields           []CustomFieldDef    `json:"omitempty"`
	AdditionalDisks        []AdditionalDiskDef `json:"omitempty"`
	Ttl                    time.Time           `json:"omitempty"`
	Packages               []PackageDef        `json:"omitempty"`
}

type CustomFieldDef struct {
	Id    string
	Value string
}

type AdditionalDiskDef struct {
	Path   string
	SizeGB int
	Type   string
}

type PackageDef struct {
	PackageId  string
	Parameters map[string]string
}

func (c *CreateReq) Validate() error {
	serverIdValues := []string{c.SourceServerId, c.TemplateId, c.TemplateName}
	numNonEmpty := 0
	for _, item := range serverIdValues {
		if item != "" {
			numNonEmpty++
		}
	}
	if numNonEmpty > 1 || numNonEmpty == 0 {
		return fmt.Errorf("Exactly one parameter from the following: source-server-id, source-server-name, template-id, template-name must be specified.")
	}

	if (c.GroupName == "") == (c.GroupId == "") {
		return fmt.Errorf("Exactly one parameter from the following: group-id, group-name must be specified.")
	}

	return nil
}

func (c *CreateReq) ApplyDefaultBehaviour() error {
	if c.TemplateId != "" {
		c.SourceServerId = c.TemplateId
	}
	return nil
	//TODO: implement searching templates by name
	//TODO: implement searching groups by names
}
<|endoftext|>