<commit_before>package server

import (
	"encoding/json"
	"fmt"
	"net/http"
	"path"
	"strconv"
	"strings"

	"github.com/NYTimes/gziphandler"
	"github.com/bouk/httprouter"
	"github.com/influxdata/chronograf" // When julienschmidt/httprouter v2 w/ context is out, switch
	"github.com/influxdata/chronograf/oauth2"
)

const (
	// JSONType the mimetype for a json request
	JSONType = "application/json"
)

// MuxOpts are the options for the router.  Mostly related to auth.
type MuxOpts struct {
	Logger        chronograf.Logger
	Develop       bool                 // Develop loads assets from filesystem instead of bindata
	Basepath      string               // URL path prefix under which all chronograf routes will be mounted
	PrefixRoutes  bool                 // Mounts all backend routes under route specified by the Basepath
	UseAuth       bool                 // UseAuth turns on Github OAuth and JWT
	Auth          oauth2.Authenticator // Auth is used to authenticate and authorize
	ProviderFuncs []func(func(oauth2.Provider, oauth2.Mux))
}

// NewMux attaches all the route handlers; handler returned servers chronograf.
func NewMux(opts MuxOpts, service Service) http.Handler {
	hr := httprouter.New()

	/* React Application */
	assets := Assets(AssetsOpts{
		Develop: opts.Develop,
		Logger:  opts.Logger,
	})

	// Prefix any URLs found in the React assets with any configured basepath
	prefixedAssets := NewDefaultURLPrefixer(basepath, assets, opts.Logger)

	// Compress the assets with gzip if an accepted encoding
	compressed := gziphandler.GzipHandler(prefixedAssets)

	// The react application handles all the routing if the server does not
	// know about the route.  This means that we never have unknown routes on
	// the server.
	hr.NotFound = compressed

	var router chronograf.Router = hr

	// Set route prefix for all routes if basepath is present
	if opts.PrefixRoutes {
		router = &MountableRouter{
			Prefix:   opts.Basepath,
			Delegate: hr,
		}

		//The assets handler is always unaware of basepaths, so the
		// basepath needs to always be removed before sending requests to it
		hr.NotFound = http.StripPrefix(opts.Basepath, hr.NotFound)
	}

	/* Documentation */
	router.GET("/swagger.json", Spec())
	router.GET("/docs", Redoc("/swagger.json"))

	/* API */
	// Sources
	router.GET("/chronograf/v1/sources", service.Sources)
	router.POST("/chronograf/v1/sources", service.NewSource)

	router.GET("/chronograf/v1/sources/:id", service.SourcesID)
	router.PATCH("/chronograf/v1/sources/:id", service.UpdateSource)
	router.DELETE("/chronograf/v1/sources/:id", service.RemoveSource)

	// Source Proxy to Influx; Has gzip compression around the handler
	influx := gziphandler.GzipHandler(http.HandlerFunc(service.Influx))
	router.Handler("POST", "/chronograf/v1/sources/:id/proxy", influx)

	// Write proxies line protocol write requests to InfluxDB
	router.POST("/chronograf/v1/sources/:id/write", service.Write)

	// Queries is used to analyze a specific queries
	router.POST("/chronograf/v1/sources/:id/queries", service.Queries)

	// All possible permissions for users in this source
	router.GET("/chronograf/v1/sources/:id/permissions", service.Permissions)

	// Users associated with the data source
	router.GET("/chronograf/v1/sources/:id/users", service.SourceUsers)
	router.POST("/chronograf/v1/sources/:id/users", service.NewSourceUser)

	router.GET("/chronograf/v1/sources/:id/users/:uid", service.SourceUserID)
	router.DELETE("/chronograf/v1/sources/:id/users/:uid", service.RemoveSourceUser)
	router.PATCH("/chronograf/v1/sources/:id/users/:uid", service.UpdateSourceUser)

	// Roles associated with the data source
	router.GET("/chronograf/v1/sources/:id/roles", service.Roles)
	router.POST("/chronograf/v1/sources/:id/roles", service.NewRole)

	router.GET("/chronograf/v1/sources/:id/roles/:rid", service.RoleID)
	router.DELETE("/chronograf/v1/sources/:id/roles/:rid", service.RemoveRole)
	router.PATCH("/chronograf/v1/sources/:id/roles/:rid", service.UpdateRole)

	// Kapacitor
	router.GET("/chronograf/v1/sources/:id/kapacitors", service.Kapacitors)
	router.POST("/chronograf/v1/sources/:id/kapacitors", service.NewKapacitor)

	router.GET("/chronograf/v1/sources/:id/kapacitors/:kid", service.KapacitorsID)
	router.PATCH("/chronograf/v1/sources/:id/kapacitors/:kid", service.UpdateKapacitor)
	router.DELETE("/chronograf/v1/sources/:id/kapacitors/:kid", service.RemoveKapacitor)

	// Kapacitor rules
	router.GET("/chronograf/v1/sources/:id/kapacitors/:kid/rules", service.KapacitorRulesGet)
	router.POST("/chronograf/v1/sources/:id/kapacitors/:kid/rules", service.KapacitorRulesPost)

	router.GET("/chronograf/v1/sources/:id/kapacitors/:kid/rules/:tid", service.KapacitorRulesID)
	router.PUT("/chronograf/v1/sources/:id/kapacitors/:kid/rules/:tid", service.KapacitorRulesPut)
	router.PATCH("/chronograf/v1/sources/:id/kapacitors/:kid/rules/:tid", service.KapacitorRulesStatus)
	router.DELETE("/chronograf/v1/sources/:id/kapacitors/:kid/rules/:tid", service.KapacitorRulesDelete)

	// Kapacitor Proxy
	router.GET("/chronograf/v1/sources/:id/kapacitors/:kid/proxy", service.KapacitorProxyGet)
	router.POST("/chronograf/v1/sources/:id/kapacitors/:kid/proxy", service.KapacitorProxyPost)
	router.PATCH("/chronograf/v1/sources/:id/kapacitors/:kid/proxy", service.KapacitorProxyPatch)
	router.DELETE("/chronograf/v1/sources/:id/kapacitors/:kid/proxy", service.KapacitorProxyDelete)

	// Mappings
	router.GET("/chronograf/v1/mappings", service.GetMappings)

	// Layouts
	router.GET("/chronograf/v1/layouts", service.Layouts)
	router.POST("/chronograf/v1/layouts", service.NewLayout)

	router.GET("/chronograf/v1/layouts/:id", service.LayoutsID)
	router.PUT("/chronograf/v1/layouts/:id", service.UpdateLayout)
	router.DELETE("/chronograf/v1/layouts/:id", service.RemoveLayout)

	// Users
	router.GET("/chronograf/v1/me", service.Me)

	// Dashboards
	router.GET("/chronograf/v1/dashboards", service.Dashboards)
	router.POST("/chronograf/v1/dashboards", service.NewDashboard)

	router.GET("/chronograf/v1/dashboards/:id", service.DashboardID)
	router.DELETE("/chronograf/v1/dashboards/:id", service.RemoveDashboard)
	router.PUT("/chronograf/v1/dashboards/:id", service.ReplaceDashboard)
	router.PATCH("/chronograf/v1/dashboards/:id", service.UpdateDashboard)
	// Dashboard Cells
	router.GET("/chronograf/v1/dashboards/:id/cells", service.DashboardCells)
	router.POST("/chronograf/v1/dashboards/:id/cells", service.NewDashboardCell)

	router.GET("/chronograf/v1/dashboards/:id/cells/:cid", service.DashboardCellID)
	router.DELETE("/chronograf/v1/dashboards/:id/cells/:cid", service.RemoveDashboardCell)
	router.PUT("/chronograf/v1/dashboards/:id/cells/:cid", service.ReplaceDashboardCell)
	// Dashboard Templates
	router.GET("/chronograf/v1/dashboards/:id/templates", service.Templates)
	router.POST("/chronograf/v1/dashboards/:id/templates", service.NewTemplate)

	router.GET("/chronograf/v1/dashboards/:id/templates/:tid", service.TemplateID)
	router.DELETE("/chronograf/v1/dashboards/:id/templates/:tid", service.RemoveTemplate)
	router.PUT("/chronograf/v1/dashboards/:id/templates/:tid", service.ReplaceTemplate)

	// Databases
	router.GET("/chronograf/v1/sources/:id/dbs", service.GetDatabases)
	router.POST("/chronograf/v1/sources/:id/dbs", service.NewDatabase)

	router.DELETE("/chronograf/v1/sources/:id/dbs/:dbid", service.DropDatabase)

	// Retention Policies
	router.GET("/chronograf/v1/sources/:id/dbs/:dbid/rps", service.RetentionPolicies)
	router.POST("/chronograf/v1/sources/:id/dbs/:dbid/rps", service.NewRetentionPolicy)

	router.PUT("/chronograf/v1/sources/:id/dbs/:dbid/rps/:rpid", service.UpdateRetentionPolicy)
	router.DELETE("/chronograf/v1/sources/:id/dbs/:dbid/rps/:rpid", service.DropRetentionPolicy)
	var authRoutes AuthRoutes
	var out http.Handler

	/* Authentication */
	logout := "/oauth/logout"
	basepath := ""
	if opts.PrefixRoutes {
		basepath = opts.Basepath
	}
	if opts.UseAuth {
		// Encapsulate the router with OAuth2
		var auth http.Handler
		auth, authRoutes = AuthAPI(opts, router)

		// Create middleware to redirect to the appropriate provider logout
		targetURL := "/"
		router.GET(logout, Logout(targetURL, basepath, authRoutes))
		out = Logger(opts.Logger, PrefixedRedirect(opts.Basepath, auth))
	} else {
		out = Logger(opts.Logger, PrefixedRedirect(opts.Basepath, router))
	}

	router.GET("/chronograf/v1/", AllRoutes(authRoutes, path.Join(basepath, logout), opts.Logger))

	return out
}

// AuthAPI adds the OAuth routes if auth is enabled.
func AuthAPI(opts MuxOpts, router chronograf.Router) (http.Handler, AuthRoutes) {
	routes := AuthRoutes{}
	for _, pf := range opts.ProviderFuncs {
		pf(func(p oauth2.Provider, m oauth2.Mux) {
			urlName := PathEscape(strings.ToLower(p.Name()))

			loginPath := path.Join("oauth", urlName, "login")
			logoutPath := path.Join("oauth", urlName, "logout")
			callbackPath := path.Join("oauth", urlName, "callback")

			basepath := ""
			if opts.PrefixRoutes {
				basepath = opts.Basepath
			}

			router.Handler("GET", loginPath, m.Login())
			router.Handler("GET", logoutPath, m.Logout())
			router.Handler("GET", callbackPath, m.Callback())
			routes = append(routes, AuthRoute{
				Name:     p.Name(),
				Label:    strings.Title(p.Name()),
				Login:    path.Join(basepath, loginPath),
				Logout:   path.Join(basepath, logoutPath),
				Callback: path.Join(basepath, callbackPath),
			})
		})
	}

	rootPath := path.Join(opts.Basepath, "/chronograf/v1/")
	logoutPath := path.Join(opts.Basepath, "/oauth/logout")

	tokenMiddleware := AuthorizedToken(opts.Auth, opts.Logger, router)
	// Wrap the API with token validation middleware.
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if (strings.HasPrefix(r.URL.Path, rootPath) && len(r.URL.Path) > len(rootPath)) || r.URL.Path == logoutPath {
			tokenMiddleware.ServeHTTP(w, r)
			return
		}
		router.ServeHTTP(w, r)
	}), routes
}

func encodeJSON(w http.ResponseWriter, status int, v interface{}, logger chronograf.Logger) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(status)
	if err := json.NewEncoder(w).Encode(v); err != nil {
		unknownErrorWithMessage(w, err, logger)
	}
}

// Error writes an JSON message
func Error(w http.ResponseWriter, code int, msg string, logger chronograf.Logger) {
	e := ErrorMessage{
		Code:    code,
		Message: msg,
	}
	b, err := json.Marshal(e)
	if err != nil {
		code = http.StatusInternalServerError
		b = []byte(`{"code": 500, "message":"server_error"}`)
	}

	logger.
		WithField("component", "server").
		WithField("http_status ", code).
		Error("Error message ", msg)
	w.Header().Set("Content-Type", JSONType)
	w.WriteHeader(code)
	_, _ = w.Write(b)
}

func invalidData(w http.ResponseWriter, err error, logger chronograf.Logger) {
	Error(w, http.StatusUnprocessableEntity, fmt.Sprintf("%v", err), logger)
}

func invalidJSON(w http.ResponseWriter, logger chronograf.Logger) {
	Error(w, http.StatusBadRequest, "Unparsable JSON", logger)
}

func unknownErrorWithMessage(w http.ResponseWriter, err error, logger chronograf.Logger) {
	Error(w, http.StatusInternalServerError, fmt.Sprintf("Unknown error: %v", err), logger)
}

func notFound(w http.ResponseWriter, id int, logger chronograf.Logger) {
	Error(w, http.StatusNotFound, fmt.Sprintf("ID %d not found", id), logger)
}

func paramID(key string, r *http.Request) (int, error) {
	ctx := r.Context()
	param := httprouter.GetParamFromContext(ctx, key)
	id, err := strconv.Atoi(param)
	if err != nil {
		return -1, fmt.Errorf("Error converting ID %s", param)
	}
	return id, nil
}
<commit_msg>Force prefixing in several locations<commit_after>package server

import (
	"encoding/json"
	"fmt"
	"net/http"
	"path"
	"strconv"
	"strings"

	"github.com/NYTimes/gziphandler"
	"github.com/bouk/httprouter"
	"github.com/influxdata/chronograf" // When julienschmidt/httprouter v2 w/ context is out, switch
	"github.com/influxdata/chronograf/oauth2"
)

const (
	// JSONType the mimetype for a json request
	JSONType = "application/json"
)

// MuxOpts are the options for the router.  Mostly related to auth.
type MuxOpts struct {
	Logger        chronograf.Logger
	Develop       bool                 // Develop loads assets from filesystem instead of bindata
	Basepath      string               // URL path prefix under which all chronograf routes will be mounted
	PrefixRoutes  bool                 // Mounts all backend routes under route specified by the Basepath
	UseAuth       bool                 // UseAuth turns on Github OAuth and JWT
	Auth          oauth2.Authenticator // Auth is used to authenticate and authorize
	ProviderFuncs []func(func(oauth2.Provider, oauth2.Mux))
}

// NewMux attaches all the route handlers; handler returned servers chronograf.
func NewMux(opts MuxOpts, service Service) http.Handler {
	hr := httprouter.New()

	/* React Application */
	assets := Assets(AssetsOpts{
		Develop: opts.Develop,
		Logger:  opts.Logger,
	})

	// Prefix any URLs found in the React assets with any configured basepath
	prefixedAssets := NewDefaultURLPrefixer(basepath, assets, opts.Logger)

	// Compress the assets with gzip if an accepted encoding
	compressed := gziphandler.GzipHandler(prefixedAssets)

	// The react application handles all the routing if the server does not
	// know about the route.  This means that we never have unknown routes on
	// the server.
	hr.NotFound = compressed

	var router chronograf.Router = hr

	// Set route prefix for all routes if basepath is present
	if opts.PrefixRoutes {
		router = &MountableRouter{
			Prefix:   opts.Basepath,
			Delegate: hr,
		}

		//The assets handler is always unaware of basepaths, so the
		// basepath needs to always be removed before sending requests to it
		hr.NotFound = http.StripPrefix(opts.Basepath, hr.NotFound)
	}

	/* Documentation */
	router.GET("/swagger.json", Spec())
	router.GET("/docs", Redoc("/swagger.json"))

	/* API */
	// Sources
	router.GET("/chronograf/v1/sources", service.Sources)
	router.POST("/chronograf/v1/sources", service.NewSource)

	router.GET("/chronograf/v1/sources/:id", service.SourcesID)
	router.PATCH("/chronograf/v1/sources/:id", service.UpdateSource)
	router.DELETE("/chronograf/v1/sources/:id", service.RemoveSource)

	// Source Proxy to Influx; Has gzip compression around the handler
	influx := gziphandler.GzipHandler(http.HandlerFunc(service.Influx))
	router.Handler("POST", "/chronograf/v1/sources/:id/proxy", influx)

	// Write proxies line protocol write requests to InfluxDB
	router.POST("/chronograf/v1/sources/:id/write", service.Write)

	// Queries is used to analyze a specific queries
	router.POST("/chronograf/v1/sources/:id/queries", service.Queries)

	// All possible permissions for users in this source
	router.GET("/chronograf/v1/sources/:id/permissions", service.Permissions)

	// Users associated with the data source
	router.GET("/chronograf/v1/sources/:id/users", service.SourceUsers)
	router.POST("/chronograf/v1/sources/:id/users", service.NewSourceUser)

	router.GET("/chronograf/v1/sources/:id/users/:uid", service.SourceUserID)
	router.DELETE("/chronograf/v1/sources/:id/users/:uid", service.RemoveSourceUser)
	router.PATCH("/chronograf/v1/sources/:id/users/:uid", service.UpdateSourceUser)

	// Roles associated with the data source
	router.GET("/chronograf/v1/sources/:id/roles", service.Roles)
	router.POST("/chronograf/v1/sources/:id/roles", service.NewRole)

	router.GET("/chronograf/v1/sources/:id/roles/:rid", service.RoleID)
	router.DELETE("/chronograf/v1/sources/:id/roles/:rid", service.RemoveRole)
	router.PATCH("/chronograf/v1/sources/:id/roles/:rid", service.UpdateRole)

	// Kapacitor
	router.GET("/chronograf/v1/sources/:id/kapacitors", service.Kapacitors)
	router.POST("/chronograf/v1/sources/:id/kapacitors", service.NewKapacitor)

	router.GET("/chronograf/v1/sources/:id/kapacitors/:kid", service.KapacitorsID)
	router.PATCH("/chronograf/v1/sources/:id/kapacitors/:kid", service.UpdateKapacitor)
	router.DELETE("/chronograf/v1/sources/:id/kapacitors/:kid", service.RemoveKapacitor)

	// Kapacitor rules
	router.GET("/chronograf/v1/sources/:id/kapacitors/:kid/rules", service.KapacitorRulesGet)
	router.POST("/chronograf/v1/sources/:id/kapacitors/:kid/rules", service.KapacitorRulesPost)

	router.GET("/chronograf/v1/sources/:id/kapacitors/:kid/rules/:tid", service.KapacitorRulesID)
	router.PUT("/chronograf/v1/sources/:id/kapacitors/:kid/rules/:tid", service.KapacitorRulesPut)
	router.PATCH("/chronograf/v1/sources/:id/kapacitors/:kid/rules/:tid", service.KapacitorRulesStatus)
	router.DELETE("/chronograf/v1/sources/:id/kapacitors/:kid/rules/:tid", service.KapacitorRulesDelete)

	// Kapacitor Proxy
	router.GET("/chronograf/v1/sources/:id/kapacitors/:kid/proxy", service.KapacitorProxyGet)
	router.POST("/chronograf/v1/sources/:id/kapacitors/:kid/proxy", service.KapacitorProxyPost)
	router.PATCH("/chronograf/v1/sources/:id/kapacitors/:kid/proxy", service.KapacitorProxyPatch)
	router.DELETE("/chronograf/v1/sources/:id/kapacitors/:kid/proxy", service.KapacitorProxyDelete)

	// Mappings
	router.GET("/chronograf/v1/mappings", service.GetMappings)

	// Layouts
	router.GET("/chronograf/v1/layouts", service.Layouts)
	router.POST("/chronograf/v1/layouts", service.NewLayout)

	router.GET("/chronograf/v1/layouts/:id", service.LayoutsID)
	router.PUT("/chronograf/v1/layouts/:id", service.UpdateLayout)
	router.DELETE("/chronograf/v1/layouts/:id", service.RemoveLayout)

	// Users
	router.GET("/chronograf/v1/me", service.Me)

	// Dashboards
	router.GET("/chronograf/v1/dashboards", service.Dashboards)
	router.POST("/chronograf/v1/dashboards", service.NewDashboard)

	router.GET("/chronograf/v1/dashboards/:id", service.DashboardID)
	router.DELETE("/chronograf/v1/dashboards/:id", service.RemoveDashboard)
	router.PUT("/chronograf/v1/dashboards/:id", service.ReplaceDashboard)
	router.PATCH("/chronograf/v1/dashboards/:id", service.UpdateDashboard)
	// Dashboard Cells
	router.GET("/chronograf/v1/dashboards/:id/cells", service.DashboardCells)
	router.POST("/chronograf/v1/dashboards/:id/cells", service.NewDashboardCell)

	router.GET("/chronograf/v1/dashboards/:id/cells/:cid", service.DashboardCellID)
	router.DELETE("/chronograf/v1/dashboards/:id/cells/:cid", service.RemoveDashboardCell)
	router.PUT("/chronograf/v1/dashboards/:id/cells/:cid", service.ReplaceDashboardCell)
	// Dashboard Templates
	router.GET("/chronograf/v1/dashboards/:id/templates", service.Templates)
	router.POST("/chronograf/v1/dashboards/:id/templates", service.NewTemplate)

	router.GET("/chronograf/v1/dashboards/:id/templates/:tid", service.TemplateID)
	router.DELETE("/chronograf/v1/dashboards/:id/templates/:tid", service.RemoveTemplate)
	router.PUT("/chronograf/v1/dashboards/:id/templates/:tid", service.ReplaceTemplate)

	// Databases
	router.GET("/chronograf/v1/sources/:id/dbs", service.GetDatabases)
	router.POST("/chronograf/v1/sources/:id/dbs", service.NewDatabase)

	router.DELETE("/chronograf/v1/sources/:id/dbs/:dbid", service.DropDatabase)

	// Retention Policies
	router.GET("/chronograf/v1/sources/:id/dbs/:dbid/rps", service.RetentionPolicies)
	router.POST("/chronograf/v1/sources/:id/dbs/:dbid/rps", service.NewRetentionPolicy)

	router.PUT("/chronograf/v1/sources/:id/dbs/:dbid/rps/:rpid", service.UpdateRetentionPolicy)
	router.DELETE("/chronograf/v1/sources/:id/dbs/:dbid/rps/:rpid", service.DropRetentionPolicy)
	var authRoutes AuthRoutes
	var out http.Handler

	/* Authentication */
	logout := "/oauth/logout"
	basepath := ""
	if opts.PrefixRoutes {
		basepath = opts.Basepath
	}
	if opts.UseAuth {
		// Encapsulate the router with OAuth2
		var auth http.Handler
		auth, authRoutes = AuthAPI(opts, router)

		// Create middleware to redirect to the appropriate provider logout
		targetURL := "/"
		router.GET(logout, Logout(targetURL, basepath, authRoutes))
		out = Logger(opts.Logger, PrefixedRedirect(opts.Basepath, auth))
	} else {
		out = Logger(opts.Logger, PrefixedRedirect(opts.Basepath, router))
	}

	router.GET("/chronograf/v1/", AllRoutes(authRoutes, path.Join(opts.Basepath, logout), opts.Logger))

	return out
}

// AuthAPI adds the OAuth routes if auth is enabled.
func AuthAPI(opts MuxOpts, router chronograf.Router) (http.Handler, AuthRoutes) {
	routes := AuthRoutes{}
	for _, pf := range opts.ProviderFuncs {
		pf(func(p oauth2.Provider, m oauth2.Mux) {
			urlName := PathEscape(strings.ToLower(p.Name()))

			loginPath := path.Join("/oauth", urlName, "login")
			logoutPath := path.Join("/oauth", urlName, "logout")
			callbackPath := path.Join("/oauth", urlName, "callback")

			router.Handler("GET", loginPath, m.Login())
			router.Handler("GET", logoutPath, m.Logout())
			router.Handler("GET", callbackPath, m.Callback())
			routes = append(routes, AuthRoute{
				Name:  p.Name(),
				Label: strings.Title(p.Name()),
				// AuthRoutes are content served to the page. When Basepath is set, it
				// says that all content served to the page will be prefixed with the
				// basepath. Since these routes are consumed by JS, it will need the
				// basepath set to traverse a proxy correctly
				Login:    path.Join(opts.Basepath, loginPath),
				Logout:   path.Join(opts.Basepath, logoutPath),
				Callback: path.Join(opts.Basepath, callbackPath),
			})
		})
	}

	rootPath := "/chronograf/v1"
	logoutPath := "/oauth/logout"

	if opts.PrefixRoutes {
		rootPath = path.Join(opts.Basepath, rootPath)
		logoutPath = path.Join(opts.Basepath, logoutPath)
	}

	tokenMiddleware := AuthorizedToken(opts.Auth, opts.Logger, router)
	// Wrap the API with token validation middleware.
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		cleanPath := path.Clean(r.URL.Path) // compare ignoring path garbage, trailing slashes, etc.
		if (strings.HasPrefix(cleanPath, rootPath) && len(cleanPath) > len(rootPath)) || cleanPath == logoutPath {
			tokenMiddleware.ServeHTTP(w, r)
			return
		}
		router.ServeHTTP(w, r)
	}), routes
}

func encodeJSON(w http.ResponseWriter, status int, v interface{}, logger chronograf.Logger) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(status)
	if err := json.NewEncoder(w).Encode(v); err != nil {
		unknownErrorWithMessage(w, err, logger)
	}
}

// Error writes an JSON message
func Error(w http.ResponseWriter, code int, msg string, logger chronograf.Logger) {
	e := ErrorMessage{
		Code:    code,
		Message: msg,
	}
	b, err := json.Marshal(e)
	if err != nil {
		code = http.StatusInternalServerError
		b = []byte(`{"code": 500, "message":"server_error"}`)
	}

	logger.
		WithField("component", "server").
		WithField("http_status ", code).
		Error("Error message ", msg)
	w.Header().Set("Content-Type", JSONType)
	w.WriteHeader(code)
	_, _ = w.Write(b)
}

func invalidData(w http.ResponseWriter, err error, logger chronograf.Logger) {
	Error(w, http.StatusUnprocessableEntity, fmt.Sprintf("%v", err), logger)
}

func invalidJSON(w http.ResponseWriter, logger chronograf.Logger) {
	Error(w, http.StatusBadRequest, "Unparsable JSON", logger)
}

func unknownErrorWithMessage(w http.ResponseWriter, err error, logger chronograf.Logger) {
	Error(w, http.StatusInternalServerError, fmt.Sprintf("Unknown error: %v", err), logger)
}

func notFound(w http.ResponseWriter, id int, logger chronograf.Logger) {
	Error(w, http.StatusNotFound, fmt.Sprintf("ID %d not found", id), logger)
}

func paramID(key string, r *http.Request) (int, error) {
	ctx := r.Context()
	param := httprouter.GetParamFromContext(ctx, key)
	id, err := strconv.Atoi(param)
	if err != nil {
		return -1, fmt.Errorf("Error converting ID %s", param)
	}
	return id, nil
}
<|endoftext|>


<commit_before>/* Copyright (C) 2013 CompleteDB LLC.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have idxeived a copy of the GNU Affero General Public License
 * along with PubSubSQL.  If not, see <http://www.gnu.org/licenses/>.
 */

package pubsubsql

// tag implemented as doubly linked list
type tag struct {
	prev *tag
	next *tag
	idx  int // idx index into table.records
}

// addTag adds tag as next element after the head
// returns added tag
func addTag(head *tag, idx int) *tag {
	t := &tag{
		idx: idx,
	}
	if head != nil {
		head.next, t.next, t.prev = t, head.next, head
	}
	if t.next != nil {
		t.next.prev = t
	}
	return t
}

// removeTag removes tag from the list and
// returns true if last element was removed

type removeTagReturn int8

const (
	removeTagLast  removeTagReturn = iota // indicates that last element was removed
	removeTagSlide                        // indicates that slide has happened external pointer need to be updated
	removeTagNormal
)

func removeTag(t *tag) removeTagReturn {
	ret := removeTagNormal
	freeMe := t
	// handle head case
	if t.prev == nil {
		if t.next == nil {
			// last element, let caller(columns tag map) handle the rest
			return removeTagLast
		}
		// slide and remove
		ret = removeTagSlide
		freeMe = t.next
		t.idx, t.next = freeMe.idx, freeMe.next
		if t.next != nil {
			t.next.prev = t
		}
	} else {
		t.prev.next = t.next
		if t.next != nil {
			t.next.prev = t.prev
		}
	}
	// let GC know that we need to go....
	freeMe.prev = nil
	freeMe.next = nil
	return ret
}
<commit_msg>tag refactor<commit_after>/* Copyright (C) 2013 CompleteDB LLC.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have idxeived a copy of the GNU Affero General Public License
 * along with PubSubSQL.  If not, see <http://www.gnu.org/licenses/>.
 */

package pubsubsql

type removeTagReturn int8

const (
	removeTagLast  removeTagReturn = iota // indicates that last element was removed
	removeTagSlide                        // indicates that slide has happened external pointer need to be updated
	removeTagNormal
)

// tag implemented as doubly linked list.
type tag struct {
	prev *tag
	next *tag
	idx  int // idx index into table.records
}

// Adds tag as next element after the head.
// Returns added tag.
func addTag(head *tag, idx int) *tag {
	t := &tag{
		idx: idx,
	}
	if head != nil {
		head.next, t.next, t.prev = t, head.next, head
	}
	if t.next != nil {
		t.next.prev = t
	}
	return t
}

// Removes tag from the list.
// Returns true if last element was removed.
func removeTag(t *tag) removeTagReturn {
	ret := removeTagNormal
	freeMe := t
	// handle head case
	if t.prev == nil {
		if t.next == nil {
			// last element, let caller(columns tag map) handle the rest
			return removeTagLast
		}
		// slide and remove
		ret = removeTagSlide
		freeMe = t.next
		t.idx, t.next = freeMe.idx, freeMe.next
		if t.next != nil {
			t.next.prev = t
		}
	} else {
		t.prev.next = t.next
		if t.next != nil {
			t.next.prev = t.prev
		}
	}
	// let GC know that we need to go....
	freeMe.prev = nil
	freeMe.next = nil
	return ret
}

<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"math/rand"
	"time"

	"github.com/seiflotfy/hashlog"
)

func main() {
	hl := hashlog.New()

	max := 100000
	now := time.Now()
	expected := make([]uint, max, max)
	zipf := rand.NewZipf(rand.New(rand.NewSource(now.UnixNano())), 1.1, 4.0, uint64(max)-1)

	seen := map[string]bool{}
	for k := uint64(0); len(seen) != max; k++ {
		if k%uint64(max) == 0 {
			fmt.Printf("\rCardinality %06d\t Hits: %d", len(seen), k)
		}
		i := zipf.Uint64()
		expected[i]++
		id := []byte(fmt.Sprintf("flow-%05d", i))
		seen[string(id)] = true
		hl.Increment(id)
	}

	for i := range expected {
		// some minor print for easier visuals
		if i == 100 || i-50 == (len(expected)/2)+1 || i == len(expected)-100 {
			fmt.Printf("\n---")
		}

		if (i > len(expected)-100 || i < 100) || (i < (len(expected)/2)+50 && i > (len(expected)/2)-50) {
			// id
			id := fmt.Sprintf("flow-%05d", i)

			// estimation
			est1 := float64(hl.Count([]byte(id)))

			// error ratio
			ratio1 := 100*est1/float64(expected[i]) - 100

			fmt.Printf("\n%s:\t\texpected %d\t\thlg ~= %.2f%%", id, expected[i], ratio1)
		}
	}
	fmt.Println(time.Since(now))
}
<commit_msg>minor clean up<commit_after>package main

import (
	"fmt"
	"math/rand"
	"time"

	"github.com/seiflotfy/hashlog"
)

func main() {
	hl := hashlog.New()

	max := 100000
	now := time.Now()
	expected := make([]uint, max, max)
	zipf := rand.NewZipf(rand.New(rand.NewSource(now.UnixNano())), 1.1, 4.0, uint64(max)-1)

	seen := map[string]bool{}
	for k := uint64(0); len(seen) != max; k++ {
		if k%uint64(max) == 0 {
			fmt.Printf("\rCardinality %06d\t Hits: %d", len(seen), k)
		}
		i := zipf.Uint64()
		expected[i]++
		id := []byte(fmt.Sprintf("flow-%05d", i))
		seen[string(id)] = true
		hl.Increment(id)
	}

	for i := range expected {
		// some minor print for easier visuals
		if i == 100 || i-50 == (len(expected)/2)+1 || i == len(expected)-100 {
			fmt.Printf("\n---")
		}

		if (i > len(expected)-100 || i < 100) || (i < (len(expected)/2)+50 && i > (len(expected)/2)-50) {
			// id
			id := fmt.Sprintf("flow-%05d", i)
			// estimation
			est1 := float64(hl.Count([]byte(id)))
			// error ratio
			ratio1 := 100*est1/float64(expected[i]) - 100
			fmt.Printf("\n%s:\t\texpected %d\t\thlg ~= %.2f%%", id, expected[i], ratio1)
		}
	}
	fmt.Println(time.Since(now))
}
<|endoftext|>


<commit_before>package jsontree

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

func TestDeserializeNode(t *testing.T) {
	tests := []struct {
		in   string
		want *Node
		err  string
	}{
		{
			// Top level is leaf
			in:   `{"a":"b"}`,
			want: &Node{Key: "a", Value: val("b")},
		},
		{
			// Sibling leaf nodes
			in: `{"root":{"a":"b","c":"d"}}`,
			want: &Node{Key: "root", Nodes: []*Node{
				{Key: "a", Value: val("b")},
				{Key: "c", Value: val("d")},
			}},
		},
		{
			// Sibling non-leaf nodes
			in: `{"root":{"a":{"a1":"v1"},"b":{"b1":"v2"}}}`,
			want: &Node{Key: "root", Nodes: []*Node{
				{Key: "a", Nodes: []*Node{
					{Key: "a1", Value: val("v1")},
				}},
				{Key: "b", Nodes: []*Node{
					{Key: "b1", Value: val("v2")},
				}},
			}},
		},
		{
			// Leaf nodes on different levels
			in: `{"root":{"a":"v1","b":{"b1":{"b11":"v3"},"b2":"v2"}}}`,
			want: &Node{Key: "root", Nodes: []*Node{
				{Key: "a", Value: val("v1")},
				{Key: "b", Nodes: []*Node{
					{Key: "b1", Nodes: []*Node{
						{Key: "b11", Value: val("v3")},
					}},
					{Key: "b2", Value: val("v2")},
				}},
			}},
		},
		{
			// Nodes are ordered non-alphabetically
			in: `{"root":{"b":"3","c":"1","a":"2"}}`,
			want: &Node{Key: "root", Nodes: []*Node{
				{Key: "b", Value: val("3")},
				{Key: "c", Value: val("1")},
				{Key: "a", Value: val("2")},
			}},
		},
		// Weird but valid input
		{
			in: `{"ro\"ot":{"{a}":"\"hello\"","b}":"\\backslash\nnewline"}}`,
			want: &Node{Key: `ro\"ot`, Nodes: []*Node{
				{Key: `{a}`, Value: val(`\"hello\"`)},
				{Key: `b}`, Value: val(`\\backslash\nnewline`)},
			}},
		},
		// Handling invalid input
		// -- JSON syntax error
		{
			in:  `{"a":"b"},`,
			err: "expected end of input. Got ','",
		},
		{
			in:  `{"a":"b"`,
			err: "reader returned io.EOF before expected",
		},
		// -- Semantic error
		{
			in:  `{"a":"b","c":"d"}`,
			err: "invalid json. Expected 1 root node",
		},
	}
	for _, test := range tests {
		r := bytes.NewReader([]byte(test.in))
		getValFn := func() Value { return new(testValue) }
		node, err := DeserializeNode(r, getValFn)
		if test.err != "" {
			want := fmt.Errorf(test.err)
			if !errEqual(want, err) {
				t.Errorf("%s\nWrong error.\nWant %v\nGot  %v", test.in, want, err)
			}
			continue
		} else {
			if err != nil {
				t.Errorf("%s\nUnexpected error %v", test.in, err)
				continue
			}
		}
		if !nodeEqual(node, test.want) {
			t.Errorf("%s: Node was not as expected\nWant %v\nGot  %v", test.in, nodeString(test.want), nodeString(node))
		}
	}
}

// ========== Benchmarking ==========

func benchmarkNodeDeserialization(n int, b *testing.B) {
	for i := 0; i < b.N; i++ {
		r := bytes.NewBuffer(benchmarks.deserialization.ins[n-1])
		getValFn := func() Value { return new(testValue) }
		if _, err := DeserializeNode(r, getValFn); err != nil {
			b.Fatalf("Error: %v", err)
		}
	}
}

func BenchmarkNodeDeserialization1(b *testing.B) { benchmarkNodeDeserialization(1, b) }
func BenchmarkNodeDeserialization2(b *testing.B) { benchmarkNodeDeserialization(2, b) }
func BenchmarkNodeDeserialization3(b *testing.B) { benchmarkNodeDeserialization(3, b) }
func BenchmarkNodeDeserialization4(b *testing.B) { benchmarkNodeDeserialization(4, b) }
func BenchmarkNodeDeserialization5(b *testing.B) { benchmarkNodeDeserialization(5, b) }

// ========== Utility ==========

func nodeString(node *Node) string {
	if node == nil {
		return "<nil>"
	}
	var buf bytes.Buffer
	if err := SerializeNode(node, &buf); err != nil {
		return "<unserializable node>"
	} else {
		return buf.String()
	}
}

func nodesString(nodes []*Node) string {
	s := make([]string, len(nodes))
	for i, node := range nodes {
		s[i] = nodeString(node)
	}
	return "\t" + strings.Join(s, "\n\t")
}

func errEqual(want, got error) bool {
	return got != nil && want.Error() == got.Error()
}

func nodeEqual(want, got *Node) bool {
	if got == nil {
		return false
	}
	if got.Key != want.Key {
		return false
	}
	if (got.Value == nil && want.Value != nil) || (got.Value != nil && want.Value == nil) {
		return false
	}
	if got.Value != nil && !got.Value.(*testValue).Equal(want.Value.(*testValue)) {
		return false
	}
	if gn, wn := got.Nodes, want.Nodes; len(gn) != len(wn) || (gn == nil && wn != nil) || (gn != nil && wn == nil) {
		return false
	}
	for i := range want.Nodes {
		if !nodeEqual(want.Nodes[i], got.Nodes[i]) {
			return false
		}
	}
	return true
}
<commit_msg>Added nodesEqual<commit_after>package jsontree

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

func TestDeserializeNode(t *testing.T) {
	tests := []struct {
		in   string
		want *Node
		err  string
	}{
		{
			// Top level is leaf
			in:   `{"a":"b"}`,
			want: &Node{Key: "a", Value: val("b")},
		},
		{
			// Sibling leaf nodes
			in: `{"root":{"a":"b","c":"d"}}`,
			want: &Node{Key: "root", Nodes: []*Node{
				{Key: "a", Value: val("b")},
				{Key: "c", Value: val("d")},
			}},
		},
		{
			// Sibling non-leaf nodes
			in: `{"root":{"a":{"a1":"v1"},"b":{"b1":"v2"}}}`,
			want: &Node{Key: "root", Nodes: []*Node{
				{Key: "a", Nodes: []*Node{
					{Key: "a1", Value: val("v1")},
				}},
				{Key: "b", Nodes: []*Node{
					{Key: "b1", Value: val("v2")},
				}},
			}},
		},
		{
			// Leaf nodes on different levels
			in: `{"root":{"a":"v1","b":{"b1":{"b11":"v3"},"b2":"v2"}}}`,
			want: &Node{Key: "root", Nodes: []*Node{
				{Key: "a", Value: val("v1")},
				{Key: "b", Nodes: []*Node{
					{Key: "b1", Nodes: []*Node{
						{Key: "b11", Value: val("v3")},
					}},
					{Key: "b2", Value: val("v2")},
				}},
			}},
		},
		{
			// Nodes are ordered non-alphabetically
			in: `{"root":{"b":"3","c":"1","a":"2"}}`,
			want: &Node{Key: "root", Nodes: []*Node{
				{Key: "b", Value: val("3")},
				{Key: "c", Value: val("1")},
				{Key: "a", Value: val("2")},
			}},
		},
		// Weird but valid input
		{
			in: `{"ro\"ot":{"{a}":"\"hello\"","b}":"\\backslash\nnewline"}}`,
			want: &Node{Key: `ro\"ot`, Nodes: []*Node{
				{Key: `{a}`, Value: val(`\"hello\"`)},
				{Key: `b}`, Value: val(`\\backslash\nnewline`)},
			}},
		},
		// Handling invalid input
		// -- JSON syntax error
		{
			in:  `{"a":"b"},`,
			err: "expected end of input. Got ','",
		},
		{
			in:  `{"a":"b"`,
			err: "reader returned io.EOF before expected",
		},
		// -- Semantic error
		{
			in:  `{"a":"b","c":"d"}`,
			err: "invalid json. Expected 1 root node",
		},
	}
	for _, test := range tests {
		r := bytes.NewReader([]byte(test.in))
		getValFn := func() Value { return new(testValue) }
		node, err := DeserializeNode(r, getValFn)
		if test.err != "" {
			want := fmt.Errorf(test.err)
			if !errEqual(want, err) {
				t.Errorf("%s\nWrong error.\nWant %v\nGot  %v", test.in, want, err)
			}
			continue
		} else {
			if err != nil {
				t.Errorf("%s\nUnexpected error %v", test.in, err)
				continue
			}
		}
		if !nodeEqual(node, test.want) {
			t.Errorf("%s: Node was not as expected\nWant %v\nGot  %v", test.in, nodeString(test.want), nodeString(node))
		}
	}
}

// ========== Benchmarking ==========

func benchmarkNodeDeserialization(n int, b *testing.B) {
	for i := 0; i < b.N; i++ {
		r := bytes.NewBuffer(benchmarks.deserialization.ins[n-1])
		getValFn := func() Value { return new(testValue) }
		if _, err := DeserializeNode(r, getValFn); err != nil {
			b.Fatalf("Error: %v", err)
		}
	}
}

func BenchmarkNodeDeserialization1(b *testing.B) { benchmarkNodeDeserialization(1, b) }
func BenchmarkNodeDeserialization2(b *testing.B) { benchmarkNodeDeserialization(2, b) }
func BenchmarkNodeDeserialization3(b *testing.B) { benchmarkNodeDeserialization(3, b) }
func BenchmarkNodeDeserialization4(b *testing.B) { benchmarkNodeDeserialization(4, b) }
func BenchmarkNodeDeserialization5(b *testing.B) { benchmarkNodeDeserialization(5, b) }

// ========== Utility ==========

func nodeString(node *Node) string {
	if node == nil {
		return "<nil>"
	}
	var buf bytes.Buffer
	if err := SerializeNode(node, &buf); err != nil {
		return "<unserializable node>"
	} else {
		return buf.String()
	}
}

func nodesString(nodes []*Node) string {
	s := make([]string, len(nodes))
	for i, node := range nodes {
		s[i] = nodeString(node)
	}
	return "\t" + strings.Join(s, "\n\t")
}

func errEqual(want, got error) bool {
	return got != nil && want.Error() == got.Error()
}

func nodeEqual(want, got *Node) bool {
	if got == nil {
		return false
	}
	if got.Key != want.Key {
		return false
	}
	if (got.Value == nil && want.Value != nil) || (got.Value != nil && want.Value == nil) {
		return false
	}
	if got.Value != nil && !got.Value.(*testValue).Equal(want.Value.(*testValue)) {
		return false
	}
	return nodesEqual(want.Nodes, got.Nodes)
}

func nodesEqual(want, got []*Node) bool {
	if len(got) != len(want) || (got == nil && want != nil) || (got != nil && want == nil) {
		return false
	}
	for i := range want {
		if !nodeEqual(want[i], got[i]) {
			return false
		}
	}
	return true
}
<|endoftext|>


<commit_before>package supervisor

import (
	"sync"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/docker/containerd/runtime"
)

// Worker interface
type Worker interface {
	Start()
}

type startTask struct {
	Container      runtime.Container
	CheckpointPath string
	Stdin          string
	Stdout         string
	Stderr         string
	Err            chan error
	StartResponse  chan StartResponse
}

// NewWorker return a new initialized worker
func NewWorker(s *Supervisor, wg *sync.WaitGroup) Worker {
	return &worker{
		s:  s,
		wg: wg,
	}
}

type worker struct {
	wg *sync.WaitGroup
	s  *Supervisor
}

// Start runs a loop in charge of starting new containers
func (w *worker) Start() {
	defer w.wg.Done()
	for t := range w.s.startTasks {
		started := time.Now()
		process, err := t.Container.Start(t.CheckpointPath, runtime.NewStdio(t.Stdin, t.Stdout, t.Stderr))
		if err != nil {
			logrus.WithFields(logrus.Fields{
				"error": err,
				"id":    t.Container.ID(),
			}).Error("containerd: start container")
			t.Err <- err
			evt := &DeleteTask{
				ID:      t.Container.ID(),
				NoEvent: true,
				Process: process,
			}
			w.s.SendTask(evt)
			continue
		}
		if err := w.s.monitor.MonitorOOM(t.Container); err != nil && err != runtime.ErrContainerExited {
			if process.State() != runtime.Stopped {
				logrus.WithField("error", err).Error("containerd: notify OOM events")
			}
		}
		if err := w.s.monitorProcess(process); err != nil {
			logrus.WithField("error", err).Error("containerd: add process to monitor")
			t.Err <- err
			evt := &DeleteTask{
				ID:      t.Container.ID(),
				NoEvent: true,
				Process: process,
			}
			w.s.SendTask(evt)
			continue
		}
		if err := process.Start(); err != nil {
			logrus.WithField("error", err).Error("containerd: start init process")
			t.Err <- err
			evt := &DeleteTask{
				ID:      t.Container.ID(),
				NoEvent: true,
				Process: process,
			}
			w.s.SendTask(evt)
			continue
		}
		ContainerStartTimer.UpdateSince(started)
		t.Err <- nil
		t.StartResponse <- StartResponse{
			Container: t.Container,
		}
		w.s.notifySubscribers(Event{
			Timestamp: time.Now(),
			ID:        t.Container.ID(),
			Type:      StateStart,
		})
	}
}
<commit_msg>Don't call runc start when restoring a checkpoint (#302)<commit_after>package supervisor

import (
	"sync"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/docker/containerd/runtime"
)

// Worker interface
type Worker interface {
	Start()
}

type startTask struct {
	Container      runtime.Container
	CheckpointPath string
	Stdin          string
	Stdout         string
	Stderr         string
	Err            chan error
	StartResponse  chan StartResponse
}

// NewWorker return a new initialized worker
func NewWorker(s *Supervisor, wg *sync.WaitGroup) Worker {
	return &worker{
		s:  s,
		wg: wg,
	}
}

type worker struct {
	wg *sync.WaitGroup
	s  *Supervisor
}

// Start runs a loop in charge of starting new containers
func (w *worker) Start() {
	defer w.wg.Done()
	for t := range w.s.startTasks {
		started := time.Now()
		process, err := t.Container.Start(t.CheckpointPath, runtime.NewStdio(t.Stdin, t.Stdout, t.Stderr))
		if err != nil {
			logrus.WithFields(logrus.Fields{
				"error": err,
				"id":    t.Container.ID(),
			}).Error("containerd: start container")
			t.Err <- err
			evt := &DeleteTask{
				ID:      t.Container.ID(),
				NoEvent: true,
				Process: process,
			}
			w.s.SendTask(evt)
			continue
		}
		if err := w.s.monitor.MonitorOOM(t.Container); err != nil && err != runtime.ErrContainerExited {
			if process.State() != runtime.Stopped {
				logrus.WithField("error", err).Error("containerd: notify OOM events")
			}
		}
		if err := w.s.monitorProcess(process); err != nil {
			logrus.WithField("error", err).Error("containerd: add process to monitor")
			t.Err <- err
			evt := &DeleteTask{
				ID:      t.Container.ID(),
				NoEvent: true,
				Process: process,
			}
			w.s.SendTask(evt)
			continue
		}
		// only call process start if we aren't restoring from a checkpoint
		// if we have restored from a checkpoint then the process is already started
		if t.CheckpointPath == "" {
			if err := process.Start(); err != nil {
				logrus.WithField("error", err).Error("containerd: start init process")
				t.Err <- err
				evt := &DeleteTask{
					ID:      t.Container.ID(),
					NoEvent: true,
					Process: process,
				}
				w.s.SendTask(evt)
				continue
			}
		}
		ContainerStartTimer.UpdateSince(started)
		t.Err <- nil
		t.StartResponse <- StartResponse{
			Container: t.Container,
		}
		w.s.notifySubscribers(Event{
			Timestamp: time.Now(),
			ID:        t.Container.ID(),
			Type:      StateStart,
		})
	}
}
<|endoftext|>


<commit_before>package shortening // import "vallon.me/shortening"

import (
	"errors"
	"math"
)

var (
	charSet     = []byte(`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_`)
	lookupTable = makeTable(charSet)
)

// Encode turns an uint64 into a slice of characters from 'charSet'
func Encode(n uint64) []byte {
	var buf [11]byte
	var i int

	for {
		buf[i], n = charSet[n%64], (n/64)-1
		i++

		if n == math.MaxUint64 {
			return buf[:i]
		}
	}
}

// Decode turns a slice of characters back into the original unit64.
//
// Errors are returned for invalid characters or input that would
// cause an overflow.
func Decode(b []byte) (n uint64, err error) {
	if 11 < len(b) || len(b) == 0 {
		return 0, errors.New("shortening: invalid decode length")
	}

	for i, c := range b {
		ind := lookupTable[c]
		if ind == 0 {
			return 0, errors.New("shortening: invalid decode character")
		}

		nn := n + uint64(ind)<<uint(6*i)
		if nn-1 < n {
			return 0, errors.New("shortening: int64 overflow")
		}

		n = nn
	}

	return n - 1, nil
}

func makeTable(cs []byte) (t [256]uint8) {
	for i, c := range cs {
		t[c] = uint8(i + 1)
	}
	return t
}
<commit_msg>more bit twiddling<commit_after>package shortening // import "vallon.me/shortening"

import (
	"errors"
	"math"
)

var (
	charSet     = []byte(`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_`)
	lookupTable = makeTable(charSet)
)

// Encode turns an uint64 into a slice of characters from 'charSet'
func Encode(n uint64) []byte {
	var buf [11]byte
	var i int

	for {
		buf[i], n = charSet[n&63], (n>>6)-1
		i++

		if n == math.MaxUint64 {
			return buf[:i]
		}
	}
}

// Decode turns a slice of characters back into the original unit64.
//
// Errors are returned for invalid characters or input that would
// cause an overflow.
func Decode(b []byte) (n uint64, err error) {
	if 11 < len(b) || len(b) == 0 {
		return 0, errors.New("shortening: invalid decode length")
	}

	for i, c := range b {
		ind := lookupTable[c]
		if ind == 0 {
			return 0, errors.New("shortening: invalid decode character")
		}

		nn := n + uint64(ind)<<uint(6*i)
		if nn-1 < n {
			return 0, errors.New("shortening: int64 overflow")
		}

		n = nn
	}

	return n - 1, nil
}

func makeTable(cs []byte) (t [256]uint8) {
	for i, c := range cs {
		t[c] = uint8(i + 1)
	}
	return t
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"testing"
	"time"

	"github.com/datawire/ambassador/pkg/dtest"
	"github.com/datawire/ambassador/pkg/dtest/testprocess"

	"github.com/stretchr/testify/require"
)

var kubeconfig string

func TestMain(m *testing.M) {
	testprocess.Dispatch()
	kubeconfig = dtest.Kubeconfig()
	os.Setenv("DTEST_KUBECONFIG", kubeconfig)
	dtest.WithMachineLock(func() {
		os.Exit(m.Run())
	})
}

func showArgs(args []string) {
	fmt.Print("+")
	for _, arg := range args {
		fmt.Print(" ", arg)
	}
	fmt.Println()
}

func run(args ...string) error {
	showArgs(args)
	cmd := exec.Command(args[0], args[1:]...)
	return runCmd(cmd)
}

func runCmd(cmd *exec.Cmd) error {
	cmd.Env = append(os.Environ(), "KUBECONFIG="+kubeconfig)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err := cmd.Run()
	if err != nil {
		fmt.Println("==>", err)
	}
	return err
}

// nolint deadcode
func capture(args ...string) (string, error) {
	showArgs(args)
	cmd := exec.Command(args[0], args[1:]...)
	return captureCmd(cmd)
}

func captureCmd(cmd *exec.Cmd) (string, error) {
	cmd.Env = append(os.Environ(), "KUBECONFIG="+kubeconfig)
	cmd.Stdout = nil
	cmd.Stderr = nil
	outBytes, err := cmd.CombinedOutput()
	out := string(outBytes)
	if len(out) > 0 {
		fmt.Print(out)
		if out[len(out)-1] != '\n' {
			fmt.Println(" [no newline]")
		}
	}
	if err != nil {
		fmt.Println("==>", err)
	}
	return out, err
}

var executable = filepath.Join("build-output", "bin", "/telepresence")

// doBuildExecutable calls go build
func doBuildExecutable() {
	err := run("go", "build", "-o", executable, ".")
	if err != nil {
		log.Fatalf("build executable: %v", err)
	}
}

var buildExecutable = testprocess.Make(doBuildExecutable)

func TestSmokeOutbound(t *testing.T) {
	var out string
	var err error

	namespace := fmt.Sprintf("telepresence-%d", os.Getpid())
	nsArg := fmt.Sprintf("--namespace=%s", namespace)

	fmt.Println("setup")
	require.NoError(t, run("sudo", "true"), "setup: acquire privileges")
	require.NoError(t, run("printenv", "KUBECONFIG"), "setup: ensure cluster is set")
	require.NoError(t, run("sudo", "rm", "-f", "/tmp/telepresence.log"), "setup: remove old log")
	require.NoError(t,
		run("kubectl", "delete", "pod", "teleproxy", "--ignore-not-found", "--wait=true"),
		"setup: check cluster connectivity",
	)
	require.NoError(t, runCmd(buildExecutable), "setup: build executable")
	require.NoError(t, run("kubectl", "create", "namespace", namespace), "setup: create test namespace")
	require.NoError(t,
		run("kubectl", nsArg, "create", "deploy", "hello-world", "--image=ark3/hello-world"),
		"setup: create deployment",
	)
	require.NoError(t,
		run("kubectl", nsArg, "expose", "deploy", "hello-world", "--port=80", "--target-port=8000"),
		"setup: create service",
	)
	require.NoError(t,
		run("kubectl", nsArg, "get", "svc,deploy", "hello-world"),
		"setup: check svc/deploy",
	)
	defer func() {
		require.NoError(t,
			run("kubectl", "delete", "namespace", namespace, "--wait=false"),
			"cleanup: delete test namespace",
		)
	}()

	fmt.Println("pre-daemon")
	require.NoError(t, run(executable, "status"), "status with no daemon")
	require.Error(t, run(executable, "daemon"), "daemon without sudo")

	fmt.Println("launch daemon")
	require.NoError(t, run("sudo", executable, "daemon"), "launch daemon")
	require.NoError(t, run(executable, "version"), "version with daemon")
	require.NoError(t, run(executable, "status"), "status with daemon")
	defer func() { require.NoError(t, run(executable, "quit"), "quit daemon") }()

	fmt.Println("await net overrides")
	func() {
		for i := 0; i < 120; i++ {
			out, _ := capture(executable, "status")
			if !strings.Contains(out, "Network overrides NOT established") {
				return
			}
			time.Sleep(500 * time.Millisecond)
		}
		t.Fatal("timed out waiting for net overrides")
	}()

	fmt.Println("connect")
	require.NoError(t, run(executable, "connect", "-n", namespace), "connect")
	out, err = capture(executable, "status")
	require.NoError(t, err, "status connected")
	if !strings.Contains(out, "Context") {
		t.Fatal("Expected Context in connected status output")
	}
	defer func() {
		require.NoError(t,
			run("kubectl", "delete", "pod", "teleproxy", "--ignore-not-found", "--wait=false"),
			"make next time quicker",
		)
	}()

	fmt.Println("await bridge")
	func() {
		for i := 0; i < 120; i++ {
			out, _ := capture(executable, "status")
			if strings.Contains(out, "Proxy:         ON") {
				return
			}
			time.Sleep(500 * time.Millisecond)
		}
		_ = run("kubectl", "get", "pod", "teleproxy")
		t.Fatal("timed out waiting for bridge")
	}()

	fmt.Println("await service")
	func() {
		for i := 0; i < 120; i++ {
			err := run(
				"kubectl", nsArg, "run", "curl-from-cluster", "--rm", "-it",
				"--image=pstauffer/curl", "--restart=Never", "--",
				"curl", "--silent", "--output", "/dev/null",
				"http://hello-world."+namespace,
			)
			if err == nil {
				return
			}
			time.Sleep(500 * time.Millisecond)
		}
		t.Fatal("timed out waiting for hello-world service")
	}()

	fmt.Println("check bridge")
	require.NoError(t, run("curl", "-sv", "hello-world."+namespace), "check bridge")

	fmt.Println("wind down")
	out, err = capture(executable, "status")
	require.NoError(t, err, "status connected")
	if !strings.Contains(out, "Context") {
		t.Fatal("Expected Context in connected status output")
	}
	require.NoError(t, run(executable, "disconnect"), "disconnect")
	out, err = capture(executable, "status")
	require.NoError(t, err, "status disconnected")
	if !strings.Contains(out, "Not connected") {
		t.Fatal("Expected Not connected in status output")
	}
	require.Error(t, run("curl", "-sv", "hello-world."+namespace), "check disconnected")
}
<commit_msg>Run SmokeTest stages as sub-tests<commit_after>package main

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"testing"
	"time"

	"github.com/datawire/ambassador/pkg/dtest"
	"github.com/datawire/ambassador/pkg/dtest/testprocess"

	"github.com/stretchr/testify/require"
)

var kubeconfig string

func TestMain(m *testing.M) {
	testprocess.Dispatch()
	kubeconfig = dtest.Kubeconfig()
	os.Setenv("DTEST_KUBECONFIG", kubeconfig)
	dtest.WithMachineLock(func() {
		os.Exit(m.Run())
	})
}

func showArgs(args []string) {
	fmt.Print("+")
	for _, arg := range args {
		fmt.Print(" ", arg)
	}
	fmt.Println()
}

func run(args ...string) error {
	showArgs(args)
	cmd := exec.Command(args[0], args[1:]...)
	return runCmd(cmd)
}

func runCmd(cmd *exec.Cmd) error {
	cmd.Env = append(os.Environ(), "KUBECONFIG="+kubeconfig)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err := cmd.Run()
	if err != nil {
		fmt.Println("==>", err)
	}
	return err
}

// nolint deadcode
func capture(args ...string) (string, error) {
	showArgs(args)
	cmd := exec.Command(args[0], args[1:]...)
	return captureCmd(cmd)
}

func captureCmd(cmd *exec.Cmd) (string, error) {
	cmd.Env = append(os.Environ(), "KUBECONFIG="+kubeconfig)
	cmd.Stdout = nil
	cmd.Stderr = nil
	outBytes, err := cmd.CombinedOutput()
	out := string(outBytes)
	if len(out) > 0 {
		fmt.Print(out)
		if out[len(out)-1] != '\n' {
			fmt.Println(" [no newline]")
		}
	}
	if err != nil {
		fmt.Println("==>", err)
	}
	return out, err
}

var executable = filepath.Join("build-output", "bin", "/telepresence")

// doBuildExecutable calls go build
func doBuildExecutable() {
	err := run("go", "build", "-o", executable, ".")
	if err != nil {
		log.Fatalf("build executable: %v", err)
	}
}

var buildExecutable = testprocess.Make(doBuildExecutable)

func TestSmokeOutbound(t *testing.T) {
	var out string
	var err error

	namespace := fmt.Sprintf("telepresence-%d", os.Getpid())
	nsArg := fmt.Sprintf("--namespace=%s", namespace)

	t.Run("setup", func(t *testing.T) {
		require.NoError(t, run("sudo", "true"), "setup: acquire privileges")
		require.NoError(t, run("printenv", "KUBECONFIG"), "setup: ensure cluster is set")
		require.NoError(t, run("sudo", "rm", "-f", "/tmp/telepresence.log"), "setup: remove old log")
		require.NoError(t,
			run("kubectl", "delete", "pod", "teleproxy", "--ignore-not-found", "--wait=true"),
			"setup: check cluster connectivity",
		)
		require.NoError(t, runCmd(buildExecutable), "setup: build executable")
		require.NoError(t, run("kubectl", "create", "namespace", namespace), "setup: create test namespace")
		require.NoError(t,
			run("kubectl", nsArg, "create", "deploy", "hello-world", "--image=ark3/hello-world"),
			"setup: create deployment",
		)
		require.NoError(t,
			run("kubectl", nsArg, "expose", "deploy", "hello-world", "--port=80", "--target-port=8000"),
			"setup: create service",
		)
		require.NoError(t,
			run("kubectl", nsArg, "get", "svc,deploy", "hello-world"),
			"setup: check svc/deploy",
		)
	})

	defer func() {
		require.NoError(t,
			run("kubectl", "delete", "namespace", namespace, "--wait=false"),
			"cleanup: delete test namespace",
		)
	}()

	t.Run("pre-daemon", func(t *testing.T) {
		require.NoError(t, run(executable, "status"), "status with no daemon")
		require.Error(t, run(executable, "daemon"), "daemon without sudo")

		fmt.Println("launch daemon")
		require.NoError(t, run("sudo", executable, "daemon"), "launch daemon")
		require.NoError(t, run(executable, "version"), "version with daemon")
		require.NoError(t, run(executable, "status"), "status with daemon")
	})
	defer func() { require.NoError(t, run(executable, "quit"), "quit daemon") }()

	t.Run("await net overrides", func(t *testing.T) {
		for i := 0; i < 120; i++ {
			out, _ := capture(executable, "status")
			if !strings.Contains(out, "Network overrides NOT established") {
				return
			}
			time.Sleep(500 * time.Millisecond)
		}
		t.Fatal("timed out waiting for net overrides")
	})

	t.Run("connect", func(t *testing.T) {
		require.NoError(t, run(executable, "connect", "-n", namespace), "connect")
		out, err = capture(executable, "status")
		require.NoError(t, err, "status connected")
		if !strings.Contains(out, "Context") {
			t.Fatal("Expected Context in connected status output")
		}
	})
	defer func() {
		require.NoError(t,
			run("kubectl", "delete", "pod", "teleproxy", "--ignore-not-found", "--wait=false"),
			"make next time quicker",
		)
	}()

	t.Run("await bridge", func(t *testing.T) {
		for i := 0; i < 120; i++ {
			out, _ := capture(executable, "status")
			if strings.Contains(out, "Proxy:         ON") {
				return
			}
			time.Sleep(500 * time.Millisecond)
		}
		_ = run("kubectl", "get", "pod", "teleproxy")
		t.Fatal("timed out waiting for bridge")
	})

	t.Run("await service", func(t *testing.T) {
		for i := 0; i < 120; i++ {
			err := run(
				"kubectl", nsArg, "run", "curl-from-cluster", "--rm", "-it",
				"--image=pstauffer/curl", "--restart=Never", "--",
				"curl", "--silent", "--output", "/dev/null",
				"http://hello-world."+namespace,
			)
			if err == nil {
				return
			}
			time.Sleep(500 * time.Millisecond)
		}
		t.Fatal("timed out waiting for hello-world service")
	})

	t.Run("check bridge", func(t *testing.T) {
		require.NoError(t, run("curl", "-sv", "hello-world."+namespace), "check bridge")
	})

	t.Run("wind down", func(t *testing.T) {
		out, err = capture(executable, "status")
		require.NoError(t, err, "status connected")
		if !strings.Contains(out, "Context") {
			t.Fatal("Expected Context in connected status output")
		}
		require.NoError(t, run(executable, "disconnect"), "disconnect")
		out, err = capture(executable, "status")
		require.NoError(t, err, "status disconnected")
		if !strings.Contains(out, "Not connected") {
			t.Fatal("Expected Not connected in status output")
		}
		require.Error(t, run("curl", "-sv", "hello-world."+namespace), "check disconnected")
	})
}
<|endoftext|>


<commit_before>package model

import (
	"github.com/monopole/mdrip/scanner"
	"strings"
	"testing"
	"time"
)

const timeout = 2 * time.Second

var noLabels []Label = []Label{}
var labels = []Label{Label("foo"), Label("bar")}
var emptyCommandBlock *CommandBlock = NewCommandBlock(noLabels, "")

func TestRunnerWithNothing(t *testing.T) {
	if NewProgram(timeout).RunInSubShell().Problem() != nil {
		t.Fail()
	}
}

func doIt(blocks []*CommandBlock) *RunResult {
	p := NewProgram(timeout).Add(NewScript("iAmFileName", blocks))
	return p.RunInSubShell()
}

func TestRunnerWithGoodStuff(t *testing.T) {
	blocks := []*CommandBlock{
		NewCommandBlock(labels, "echo kale\ndate\n"),
		NewCommandBlock(labels, "echo beans\necho apple\n"),
		NewCommandBlock(labels, "echo hasta\necho la vista\n")}
	result := doIt(blocks)
	if result.Problem() != nil {
		t.Fail()
	}
}

func checkFail(t *testing.T, got, want *RunResult) {
	if got.Problem() == nil {
		t.Fail()
	}
	if got.Index() != want.Index() {
		t.Errorf("%s got\n\t%v\nwant\n\t%v", "script", got.Index(), want.Index())
	}
	if !strings.Contains(got.Message(), want.Message()) {
		t.Errorf("%s got\n\t%v\nwant\n\t%v", "message", got.Message(), want.Message())
	}
}

func TestStartWithABadCommand(t *testing.T) {

	want := NoCommandsRunResult(
		NewFailureOutput("dunno"),
		"fileNameTestStartWithABadCommand",
		0,
		"line 1: notagoodcommand: command not found")

	blocks := []*CommandBlock{
		NewCommandBlock(labels, "notagoodcommand\ndate\n"),
		NewCommandBlock(labels, "echo beans\necho cheese\n")}
	checkFail(t, doIt(blocks), want)
}

func TestBadCommandInTheMiddle(t *testing.T) {

	want := NoCommandsRunResult(
		NewFailureOutput("dunno"),
		"fileNameTestBadCommandInTheMiddle",
		2,
		"line 9: lochNessMonster: command not found")

	blocks := []*CommandBlock{
		NewCommandBlock(labels, "echo tofu\ndate\n"),
		NewCommandBlock(labels, "echo beans\necho kale\n"),
		NewCommandBlock(labels, "lochNessMonster\n"),
		NewCommandBlock(labels, "echo hasta\necho la vista\n")}

	checkFail(t, doIt(blocks), want)
}

func TestTimeOut(t *testing.T) {
	want := NoCommandsRunResult(
		NewFailureOutput("dunno"),
		"fileNameTestTimeOut",
		0,
		scanner.MsgTimeout)

	// Insert this sleep in a command block.
	// Arrange to sleep for two seconds longer than the timeout.
	sleep := timeout + (2 * time.Second)

	blocks := []*CommandBlock{
		NewCommandBlock(labels, "date\nsleep "+sleep.String()+"\necho kale"),
		NewCommandBlock(labels, "echo beans\necho cheese\n")}
	checkFail(t, doIt(blocks), want)
}
<commit_msg>fix test<commit_after>package model

import (
	"strings"
	"testing"
	"time"

	"github.com/monopole/mdrip/scanner"
)

const timeout = 2 * time.Second

var noLabels []Label = []Label{}
var labels = []Label{Label("foo"), Label("bar")}
var emptyCommandBlock *CommandBlock = NewCommandBlock(noLabels, "")

func TestRunnerWithNothing(t *testing.T) {
	if NewProgram(timeout, labels[0]).RunInSubShell().Problem() != nil {
		t.Fail()
	}
}

func doIt(blocks []*CommandBlock) *RunResult {
	p := NewProgram(timeout, labels[0]).Add(NewScript("iAmFileName", blocks))
	return p.RunInSubShell()
}

func TestRunnerWithGoodStuff(t *testing.T) {
	blocks := []*CommandBlock{
		NewCommandBlock(labels, "echo kale\ndate\n"),
		NewCommandBlock(labels, "echo beans\necho apple\n"),
		NewCommandBlock(labels, "echo hasta\necho la vista\n")}
	result := doIt(blocks)
	if result.Problem() != nil {
		t.Fail()
	}
}

func checkFail(t *testing.T, got, want *RunResult) {
	if got.Problem() == nil {
		t.Fail()
	}
	if got.Index() != want.Index() {
		t.Errorf("%s got\n\t%v\nwant\n\t%v", "script", got.Index(), want.Index())
	}
	if !strings.Contains(got.Message(), want.Message()) {
		t.Errorf("%s got\n\t%v\nwant\n\t%v", "message", got.Message(), want.Message())
	}
}

func TestStartWithABadCommand(t *testing.T) {

	want := NoCommandsRunResult(
		NewFailureOutput("dunno"),
		"fileNameTestStartWithABadCommand",
		0,
		"line 1: notagoodcommand: command not found")

	blocks := []*CommandBlock{
		NewCommandBlock(labels, "notagoodcommand\ndate\n"),
		NewCommandBlock(labels, "echo beans\necho cheese\n")}
	checkFail(t, doIt(blocks), want)
}

func TestBadCommandInTheMiddle(t *testing.T) {

	want := NoCommandsRunResult(
		NewFailureOutput("dunno"),
		"fileNameTestBadCommandInTheMiddle",
		2,
		"line 9: lochNessMonster: command not found")

	blocks := []*CommandBlock{
		NewCommandBlock(labels, "echo tofu\ndate\n"),
		NewCommandBlock(labels, "echo beans\necho kale\n"),
		NewCommandBlock(labels, "lochNessMonster\n"),
		NewCommandBlock(labels, "echo hasta\necho la vista\n")}

	checkFail(t, doIt(blocks), want)
}

func TestTimeOut(t *testing.T) {
	want := NoCommandsRunResult(
		NewFailureOutput("dunno"),
		"fileNameTestTimeOut",
		0,
		scanner.MsgTimeout)

	// Insert this sleep in a command block.
	// Arrange to sleep for two seconds longer than the timeout.
	sleep := timeout + (2 * time.Second)

	blocks := []*CommandBlock{
		NewCommandBlock(labels, "date\nsleep "+sleep.String()+"\necho kale"),
		NewCommandBlock(labels, "echo beans\necho cheese\n")}
	checkFail(t, doIt(blocks), want)
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.

package model

import (
	"fmt"
	"testing"
)

func TestSplitVersion(t *testing.T) {
	major1, minor1, patch1 := SplitVersion("junk")
	if major1 != 0 || minor1 != 0 || patch1 != 0 {
		t.Fatal()
	}

	major2, minor2, patch2 := SplitVersion("1.2.3")
	if major2 != 1 || minor2 != 2 || patch2 != 3 {
		t.Fatal()
	}

	major3, minor3, patch3 := SplitVersion("1.2")
	if major3 != 1 || minor3 != 2 || patch3 != 0 {
		t.Fatal()
	}

	major4, minor4, patch4 := SplitVersion("1")
	if major4 != 1 || minor4 != 0 || patch4 != 0 {
		t.Fatal()
	}

	major5, minor5, patch5 := SplitVersion("1.2.3.junkgoeswhere")
	if major5 != 1 || minor5 != 2 || patch5 != 3 {
		t.Fatal()
	}
}

func TestGetPreviousVersion(t *testing.T) {
	if GetPreviousVersion("1.3.0") != "1.2.0" {
		t.Fatal()
	}

	if GetPreviousVersion("1.2.1") != "1.1.0" {
		t.Fatal()
	}

	if GetPreviousVersion("1.1.0") != "1.0.0" {
		t.Fatal()
	}

	if GetPreviousVersion("1.0.0") != "0.7.0" {
		t.Fatal()
	}

	if GetPreviousVersion("0.7.1") != "0.6.0" {
		t.Fatal()
	}

	if GetPreviousVersion("0.5.0") != "" {
		t.Fatal()
	}
}

func TestIsCurrentVersion(t *testing.T) {
	major, minor, patch := SplitVersion(CurrentVersion)

	if !IsCurrentVersion(CurrentVersion) {
		t.Fatal()
	}

	if !IsCurrentVersion(fmt.Sprintf("%v.%v.%v", major, minor, patch+100)) {
		t.Fatal()
	}

	if IsCurrentVersion(fmt.Sprintf("%v.%v.%v", major, minor+1, patch)) {
		t.Fatal()
	}

	if IsCurrentVersion(fmt.Sprintf("%v.%v.%v", major+1, minor, patch)) {
		t.Fatal()
	}
}

func TestIsPreviousVersionsSupported(t *testing.T) {

	// 1.4.0 CURRENT RELEASED VERSION
	if !IsPreviousVersionsSupported(versions[0]) {
		t.Fatal()
	}

	// 1.3.0
	if !IsPreviousVersionsSupported(versions[1]) {
		t.Fatal()
	}

	// 1.2.1
	if !IsPreviousVersionsSupported(versions[2]) {
		t.Fatal()
	}

	// 1.2.0
	if !IsPreviousVersionsSupported(versions[3]) {
		t.Fatal()
	}

	// 1.1.0 NOT SUPPORTED
	if IsPreviousVersionsSupported(versions[4]) {
		t.Fatal()
	}
}
<commit_msg>Fixing version unit test<commit_after>// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.

package model

import (
	"fmt"
	"testing"
)

func TestSplitVersion(t *testing.T) {
	major1, minor1, patch1 := SplitVersion("junk")
	if major1 != 0 || minor1 != 0 || patch1 != 0 {
		t.Fatal()
	}

	major2, minor2, patch2 := SplitVersion("1.2.3")
	if major2 != 1 || minor2 != 2 || patch2 != 3 {
		t.Fatal()
	}

	major3, minor3, patch3 := SplitVersion("1.2")
	if major3 != 1 || minor3 != 2 || patch3 != 0 {
		t.Fatal()
	}

	major4, minor4, patch4 := SplitVersion("1")
	if major4 != 1 || minor4 != 0 || patch4 != 0 {
		t.Fatal()
	}

	major5, minor5, patch5 := SplitVersion("1.2.3.junkgoeswhere")
	if major5 != 1 || minor5 != 2 || patch5 != 3 {
		t.Fatal()
	}
}

func TestGetPreviousVersion(t *testing.T) {
	if GetPreviousVersion("1.3.0") != "1.2.0" {
		t.Fatal()
	}

	if GetPreviousVersion("1.2.1") != "1.1.0" {
		t.Fatal()
	}

	if GetPreviousVersion("1.1.0") != "1.0.0" {
		t.Fatal()
	}

	if GetPreviousVersion("1.0.0") != "0.7.0" {
		t.Fatal()
	}

	if GetPreviousVersion("0.7.1") != "0.6.0" {
		t.Fatal()
	}

	if GetPreviousVersion("0.5.0") != "" {
		t.Fatal()
	}
}

func TestIsCurrentVersion(t *testing.T) {
	major, minor, patch := SplitVersion(CurrentVersion)

	if !IsCurrentVersion(CurrentVersion) {
		t.Fatal()
	}

	if !IsCurrentVersion(fmt.Sprintf("%v.%v.%v", major, minor, patch+100)) {
		t.Fatal()
	}

	if IsCurrentVersion(fmt.Sprintf("%v.%v.%v", major, minor+1, patch)) {
		t.Fatal()
	}

	if IsCurrentVersion(fmt.Sprintf("%v.%v.%v", major+1, minor, patch)) {
		t.Fatal()
	}
}

func TestIsPreviousVersionsSupported(t *testing.T) {

	if !IsPreviousVersionsSupported(versionsWithoutHotFixes[0]) {
		t.Fatal()
	}

	if !IsPreviousVersionsSupported(versionsWithoutHotFixes[1]) {
		t.Fatal()
	}

	if !IsPreviousVersionsSupported(versionsWithoutHotFixes[2]) {
		t.Fatal()
	}

	if IsPreviousVersionsSupported(versionsWithoutHotFixes[4]) {
		t.Fatal()
	}

	if IsPreviousVersionsSupported(versionsWithoutHotFixes[5]) {
		t.Fatal()
	}
}
<|endoftext|>


<commit_before>package terraform

import (
	"fmt"

	"github.com/hashicorp/go-version"
)

// The main version number that is being run at the moment.
const Version = "0.9.8"

// A pre-release marker for the version. If this is "" (empty string)
// then it means that it is a final release. Otherwise, this is a pre-release
// such as "dev" (in development), "beta", "rc1", etc.
var VersionPrerelease = "dev"

// SemVersion is an instance of version.Version. This has the secondary
// benefit of verifying during tests and init time that our version is a
// proper semantic version, which should always be the case.
var SemVersion = version.Must(version.NewVersion(Version))

// VersionHeader is the header name used to send the current terraform version
// in http requests.
const VersionHeader = "Terraform-Version"

func VersionString() string {
	if VersionPrerelease != "" {
		return fmt.Sprintf("%s-%s", Version, VersionPrerelease)
	}
	return Version
}
<commit_msg>v0.9.8<commit_after>package terraform

import (
	"fmt"

	"github.com/hashicorp/go-version"
)

// The main version number that is being run at the moment.
const Version = "0.9.8"

// A pre-release marker for the version. If this is "" (empty string)
// then it means that it is a final release. Otherwise, this is a pre-release
// such as "dev" (in development), "beta", "rc1", etc.
var VersionPrerelease = ""

// SemVersion is an instance of version.Version. This has the secondary
// benefit of verifying during tests and init time that our version is a
// proper semantic version, which should always be the case.
var SemVersion = version.Must(version.NewVersion(Version))

// VersionHeader is the header name used to send the current terraform version
// in http requests.
const VersionHeader = "Terraform-Version"

func VersionString() string {
	if VersionPrerelease != "" {
		return fmt.Sprintf("%s-%s", Version, VersionPrerelease)
	}
	return Version
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/fairlyblank/md2min"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"strings"
)

// 定义一个访问者结构体
type Visitor struct{}

func (self *Visitor) md2html(arg map[string]string) error {
	from := arg["from"]
	to := arg["to"]
	err := filepath.Walk(from+"/", func(path string, f os.FileInfo, err error) error {
		if f == nil {
			return err
		}
		if f.IsDir() {
			return nil
		}
		if (f.Mode() & os.ModeSymlink) > 0 {
			return nil
		}
		if !strings.HasSuffix(f.Name(), ".md") {
			return nil
		}

		file, err := os.Open(path)
		if err != nil {
			return err
		}

		input_byte, _ := ioutil.ReadAll(file)
		input := string(input_byte)
		input = regexp.MustCompile(`\[(.*?)\]\(<?(.*?)\.md>?\)`).ReplaceAllString(input, "[$1](<$2.html>)")

		if f.Name() == "README.md" {
			input = regexp.MustCompile(`https:\/\/github\.com\/astaxie\/build-web-application-with-golang\/blob\/master\/`).ReplaceAllString(input, "")
		}

		// 以#开头的行，在#后增加空格
		// 以#开头的行, 删除多余的空格
		input = FixHeader(input)

		// 删除页面链接
		input = RemoveFooterLink(input)

		// remove image suffix
 		input = RemoveImageLinkSuffix(input)

		var out *os.File
		filename := strings.Replace(f.Name(), ".md", ".html", -1)
		fmt.Println(to + "/" + filename)
		if out, err = os.Create(to + "/" + filename); err != nil {
			fmt.Fprintf(os.Stderr, "Error creating %s: %v", f.Name(), err)
			os.Exit(-1)
		}
		defer out.Close()
		md := md2min.New("none")
		err = md.Parse([]byte(input), out)
		if err != nil {
			fmt.Fprintln(os.Stderr, "Parsing Error", err)
			os.Exit(-1)
		}

		return nil
	})
	return err
}

func FixHeader(input string) string {
	re_header := regexp.MustCompile(`(?m)^#.+$`)
	re_sub := regexp.MustCompile(`^(#+)\s*(.+)$`)
	fixer := func(header string) string {
		s := re_sub.FindStringSubmatch(header)
		return s[1] + " " + s[2]
	}
	return re_header.ReplaceAllStringFunc(input, fixer)
}

func RemoveFooterLink(input string) string {
	re_footer := regexp.MustCompile(`(?m)^#{2,} links.*?\n(.+\n)*`)
	return re_footer.ReplaceAllString(input, "")
}

func RemoveImageLinkSuffix(input string) string {
	re_footer := regexp.MustCompile(`png\?raw=true`)
	return re_footer.ReplaceAllString(input, "png")
}

func main() {
	tmp := os.Getenv("TMP")
	if tmp == "" {
		tmp = "."
	}

	workdir := os.Getenv("WORKDIR")
	if workdir == "" {
		workdir = "."
	}

	arg := map[string]string{
		"from": workdir,
		"to":   tmp,
	}

	v := &Visitor{}
	err := v.md2html(arg)
	if err != nil {
		fmt.Printf("filepath.Walk() returned %v\n", err)
	}
}
<commit_msg>remove build.go<commit_after><|endoftext|>


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

package os

import "time"

// FindProcess looks for a running process by its pid.
// The Process it returns can be used to obtain information
// about the underlying operating system process.
func FindProcess(pid int) (p *Process, err error) {
	return findProcess(pid)
}

// StartProcess starts a new process with the program, arguments and attributes
// specified by name, argv and attr.
//
// StartProcess is a low-level interface. The os/exec package provides
// higher-level interfaces.
//
// If there is an error, it will be of type *PathError.
func StartProcess(name string, argv []string, attr *ProcAttr) (*Process, error) {
	return startProcess(name, argv, attr)
}

// Release releases any resources associated with the Process p,
// rendering it unusable in the future.
// Release only needs to be called if Wait is not.
func (p *Process) Release() error {
	return p.release()
}

// Kill causes the Process to exit immediately.
func (p *Process) Kill() error {
	return p.kill()
}

// Wait waits for the Process to exit, and then returns a
// ProcessState describing its status and an error, if any.
// Wait releases any resources associated with the Process.
// On most operating systems, the Process must be a child
// of the current process or an error will be returned.
func (p *Process) Wait() (*ProcessState, error) {
	return p.wait()
}

// Signal sends a signal to the Process.
// Sending Interrupt on Windows is not implemented.
func (p *Process) Signal(sig Signal) error {
	return p.signal(sig)
}

// UserTime returns the user CPU time of the exited process and its children.
func (p *ProcessState) UserTime() time.Duration {
	return p.userTime()
}

// SystemTime returns the system CPU time of the exited process and its children.
func (p *ProcessState) SystemTime() time.Duration {
	return p.systemTime()
}

// Exited reports whether the program has exited.
func (p *ProcessState) Exited() bool {
	return p.exited()
}

// Success reports whether the program exited successfully,
// such as with exit status 0 on Unix.
func (p *ProcessState) Success() bool {
	return p.success()
}

// Sys returns system-dependent exit information about
// the process.  Convert it to the appropriate underlying
// type, such as syscall.WaitStatus on Unix, to access its contents.
func (p *ProcessState) Sys() interface{} {
	return p.sys()
}

// SysUsage returns system-dependent resource usage information about
// the exited process.  Convert it to the appropriate underlying
// type, such as *syscall.Rusage on Unix, to access its contents.
// (On Unix, *syscall.Rusage matches struct rusage as defined in the
// getrusage(2) manual page.)
func (p *ProcessState) SysUsage() interface{} {
	return p.sysUsage()
}

// Hostname returns the host name reported by the kernel.
func Hostname() (name string, err error) {
	return hostname()
}

// Readdir reads the contents of the directory associated with file and
// returns a slice of up to n FileInfo values, as would be returned
// by Lstat, in directory order. Subsequent calls on the same file will yield
// further FileInfos.
//
// If n > 0, Readdir returns at most n FileInfo structures. In this case, if
// Readdir returns an empty slice, it will return a non-nil error
// explaining why. At the end of a directory, the error is io.EOF.
//
// If n <= 0, Readdir returns all the FileInfo from the directory in
// a single slice. In this case, if Readdir succeeds (reads all
// the way to the end of the directory), it returns the slice and a
// nil error. If it encounters an error before the end of the
// directory, Readdir returns the FileInfo read until that point
// and a non-nil error.
func (f *File) Readdir(n int) (fi []FileInfo, err error) {
	if f == nil {
		return nil, ErrInvalid
	}
	return f.readdir(n)
}

// Readdirnames reads and returns a slice of names from the directory f.
//
// If n > 0, Readdirnames returns at most n names. In this case, if
// Readdirnames returns an empty slice, it will return a non-nil error
// explaining why. At the end of a directory, the error is io.EOF.
//
// If n <= 0, Readdirnames returns all the names from the directory in
// a single slice. In this case, if Readdirnames succeeds (reads all
// the way to the end of the directory), it returns the slice and a
// nil error. If it encounters an error before the end of the
// directory, Readdirnames returns the names read until that point and
// a non-nil error.
func (f *File) Readdirnames(n int) (names []string, err error) {
	if f == nil {
		return nil, ErrInvalid
	}
	return f.readdirnames(n)
}
<commit_msg>os: document that FindProcess always succeeds on Unix<commit_after>// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package os

import "time"

// FindProcess looks for a running process by its pid.
//
// The Process it returns can be used to obtain information
// about the underlying operating system process.
//
// On Unix systems, FindProcess always succeeds and returns a Process
// for the given pid, regardless of whether the process exists.
func FindProcess(pid int) (*Process, error) {
	return findProcess(pid)
}

// StartProcess starts a new process with the program, arguments and attributes
// specified by name, argv and attr.
//
// StartProcess is a low-level interface. The os/exec package provides
// higher-level interfaces.
//
// If there is an error, it will be of type *PathError.
func StartProcess(name string, argv []string, attr *ProcAttr) (*Process, error) {
	return startProcess(name, argv, attr)
}

// Release releases any resources associated with the Process p,
// rendering it unusable in the future.
// Release only needs to be called if Wait is not.
func (p *Process) Release() error {
	return p.release()
}

// Kill causes the Process to exit immediately.
func (p *Process) Kill() error {
	return p.kill()
}

// Wait waits for the Process to exit, and then returns a
// ProcessState describing its status and an error, if any.
// Wait releases any resources associated with the Process.
// On most operating systems, the Process must be a child
// of the current process or an error will be returned.
func (p *Process) Wait() (*ProcessState, error) {
	return p.wait()
}

// Signal sends a signal to the Process.
// Sending Interrupt on Windows is not implemented.
func (p *Process) Signal(sig Signal) error {
	return p.signal(sig)
}

// UserTime returns the user CPU time of the exited process and its children.
func (p *ProcessState) UserTime() time.Duration {
	return p.userTime()
}

// SystemTime returns the system CPU time of the exited process and its children.
func (p *ProcessState) SystemTime() time.Duration {
	return p.systemTime()
}

// Exited reports whether the program has exited.
func (p *ProcessState) Exited() bool {
	return p.exited()
}

// Success reports whether the program exited successfully,
// such as with exit status 0 on Unix.
func (p *ProcessState) Success() bool {
	return p.success()
}

// Sys returns system-dependent exit information about
// the process.  Convert it to the appropriate underlying
// type, such as syscall.WaitStatus on Unix, to access its contents.
func (p *ProcessState) Sys() interface{} {
	return p.sys()
}

// SysUsage returns system-dependent resource usage information about
// the exited process.  Convert it to the appropriate underlying
// type, such as *syscall.Rusage on Unix, to access its contents.
// (On Unix, *syscall.Rusage matches struct rusage as defined in the
// getrusage(2) manual page.)
func (p *ProcessState) SysUsage() interface{} {
	return p.sysUsage()
}

// Hostname returns the host name reported by the kernel.
func Hostname() (name string, err error) {
	return hostname()
}

// Readdir reads the contents of the directory associated with file and
// returns a slice of up to n FileInfo values, as would be returned
// by Lstat, in directory order. Subsequent calls on the same file will yield
// further FileInfos.
//
// If n > 0, Readdir returns at most n FileInfo structures. In this case, if
// Readdir returns an empty slice, it will return a non-nil error
// explaining why. At the end of a directory, the error is io.EOF.
//
// If n <= 0, Readdir returns all the FileInfo from the directory in
// a single slice. In this case, if Readdir succeeds (reads all
// the way to the end of the directory), it returns the slice and a
// nil error. If it encounters an error before the end of the
// directory, Readdir returns the FileInfo read until that point
// and a non-nil error.
func (f *File) Readdir(n int) (fi []FileInfo, err error) {
	if f == nil {
		return nil, ErrInvalid
	}
	return f.readdir(n)
}

// Readdirnames reads and returns a slice of names from the directory f.
//
// If n > 0, Readdirnames returns at most n names. In this case, if
// Readdirnames returns an empty slice, it will return a non-nil error
// explaining why. At the end of a directory, the error is io.EOF.
//
// If n <= 0, Readdirnames returns all the names from the directory in
// a single slice. In this case, if Readdirnames succeeds (reads all
// the way to the end of the directory), it returns the slice and a
// nil error. If it encounters an error before the end of the
// directory, Readdirnames returns the names read until that point and
// a non-nil error.
func (f *File) Readdirnames(n int) (names []string, err error) {
	if f == nil {
		return nil, ErrInvalid
	}
	return f.readdirnames(n)
}
<|endoftext|>


<commit_before>// Copyright 2013 Matthew Baird
// 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 elastigo

import (
	"bufio"
	"bytes"
	"compress/gzip"
	"crypto/md5"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"testing"
	"time"
)

/*

usage:

	test -v -host eshost -loaddata

*/

var (
	bulkStarted       bool
	hasStartedTesting bool
	hasLoadedData     bool
	loadData          *bool = flag.Bool("loaddata", false, "This loads a bunch of test data into elasticsearch for testing")
)

func InitTests(startIndexer bool) *Conn {
	c := NewConn()

	if !hasStartedTesting {
		flag.Parse()
		hasStartedTesting = true
		log.SetFlags(log.Ltime | log.Lshortfile)
		c.Domain = *eshost
	}
	if startIndexer && !bulkStarted {
		bulkStarted = true
		b := c.NewBulkIndexer(100)
		b.Start()
		if *loadData && !hasLoadedData {
			log.Println("loading test data ")
			hasLoadedData = true
			LoadTestData()
		}
		b.Stop()
	}
	c.Refresh()
	return c
}

// dumb simple assert for testing, printing
//    Assert(len(items) == 9, t, "Should be 9 but was %d", len(items))
func Assert(is bool, t *testing.T, format string, args ...interface{}) {
	if is == false {
		log.Printf(format, args...)
		t.Fail()
	}
}

// Wait for condition (defined by func) to be true, a utility to create a ticker
// checking every 100 ms to see if something (the supplied check func) is done
//
//   WaitFor(func() bool {
//      return ctr.Ct == 0
//   },10)
//
// @timeout (in seconds) is the last arg
func waitFor(check func() bool, timeoutSecs int) {
	timer := time.NewTicker(100 * time.Millisecond)
	tryct := 0
	for _ = range timer.C {
		if check() {
			timer.Stop()
			break
		}
		if tryct >= timeoutSecs*10 {
			timer.Stop()
			break
		}
		tryct++
	}
}

func TestFake(t *testing.T) {
}

type GithubEvent struct {
	Url     string
	Created time.Time `json:"created_at"`
	Type    string
}

// This loads test data from github archives (~6700 docs)
func LoadTestData() {
	c := NewConn()

	docCt := 0
	errCt := 0
	indexer := c.NewBulkIndexer(1)
	indexer.Sender = func(buf *bytes.Buffer) error {
		log.Printf("Sent %d bytes total %d docs sent", buf.Len(), docCt)
		req, err := c.NewRequest("POST", "/_bulk", "")
		if err != nil {
			errCt += 1
			log.Fatalf("ERROR: ", err)
			return err
		}
		req.SetBody(buf)
		//		res, err := http.DefaultClient.Do(*(api.Request(req)))
		var response map[string]interface{}
		httpStatusCode, _, err := req.Do(&response)
		if err != nil {
			errCt += 1
			log.Fatalf("ERROR: %v", err)
			return err
		}
		if httpStatusCode != 200 {
			log.Fatalf("Not 200! %d %q\n", httpStatusCode, buf.String())
		}
		return err
	}
	indexer.Start()
	resp, err := http.Get("http://data.githubarchive.org/2012-12-10-15.json.gz")
	if err != nil || resp == nil {
		panic("Could not download data")
	}
	defer resp.Body.Close()
	if err != nil {
		log.Println(err)
		return
	}
	gzReader, err := gzip.NewReader(resp.Body)
	defer gzReader.Close()
	if err != nil {
		panic(err)
	}
	r := bufio.NewReader(gzReader)
	var ge GithubEvent
	docsm := make(map[string]bool)
	h := md5.New()
	for {
		line, err := r.ReadBytes('\n')
		if err != nil && err != io.EOF {
			log.Println("FATAL:  could not read line? ", err)
		} else if err != nil {
			indexer.Flush()
			break
		}
		if err := json.Unmarshal(line, &ge); err == nil {
			// create an "ID"
			h.Write(line)
			id := fmt.Sprintf("%x", h.Sum(nil))
			if _, ok := docsm[id]; ok {
				log.Println("HM, already exists? ", ge.Url)
			}
			docsm[id] = true
			indexer.Index("github", ge.Type, id, "", &ge.Created, line, true)
			docCt++
		} else {
			log.Println("ERROR? ", string(line))
		}
	}
	if errCt != 0 {
		log.Println("FATAL, could not load ", errCt)
	}
	// lets wait a bit to ensure that elasticsearch finishes?
	indexer.Stop()
	if len(docsm) != docCt {
		panic(fmt.Sprintf("Docs didn't match?   %d:%d", len(docsm), docCt))
	}
}
<commit_msg>refresh _all indices<commit_after>// Copyright 2013 Matthew Baird
// 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 elastigo

import (
	"bufio"
	"bytes"
	"compress/gzip"
	"crypto/md5"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"testing"
	"time"
)

/*

usage:

	test -v -host eshost -loaddata

*/

var (
	bulkStarted       bool
	hasStartedTesting bool
	hasLoadedData     bool
	loadData          *bool = flag.Bool("loaddata", false, "This loads a bunch of test data into elasticsearch for testing")
)

func InitTests(startIndexer bool) *Conn {
	c := NewConn()

	if !hasStartedTesting {
		flag.Parse()
		hasStartedTesting = true
		log.SetFlags(log.Ltime | log.Lshortfile)
		c.Domain = *eshost
	}
	if startIndexer && !bulkStarted {
		bulkStarted = true
		b := c.NewBulkIndexer(100)
		b.Start()
		if *loadData && !hasLoadedData {
			log.Println("loading test data ")
			hasLoadedData = true
			LoadTestData()
		}
		b.Stop()
	}
	c.Refresh("_all")
	return c
}

// dumb simple assert for testing, printing
//    Assert(len(items) == 9, t, "Should be 9 but was %d", len(items))
func Assert(is bool, t *testing.T, format string, args ...interface{}) {
	if is == false {
		log.Printf(format, args...)
		t.Fail()
	}
}

// Wait for condition (defined by func) to be true, a utility to create a ticker
// checking every 100 ms to see if something (the supplied check func) is done
//
//   WaitFor(func() bool {
//      return ctr.Ct == 0
//   },10)
//
// @timeout (in seconds) is the last arg
func waitFor(check func() bool, timeoutSecs int) {
	timer := time.NewTicker(100 * time.Millisecond)
	tryct := 0
	for _ = range timer.C {
		if check() {
			timer.Stop()
			break
		}
		if tryct >= timeoutSecs*10 {
			timer.Stop()
			break
		}
		tryct++
	}
}

func TestFake(t *testing.T) {
}

type GithubEvent struct {
	Url     string
	Created time.Time `json:"created_at"`
	Type    string
}

// This loads test data from github archives (~6700 docs)
func LoadTestData() {
	c := NewConn()

	docCt := 0
	errCt := 0
	indexer := c.NewBulkIndexer(1)
	indexer.Sender = func(buf *bytes.Buffer) error {
		log.Printf("Sent %d bytes total %d docs sent", buf.Len(), docCt)
		req, err := c.NewRequest("POST", "/_bulk", "")
		if err != nil {
			errCt += 1
			log.Fatalf("ERROR: ", err)
			return err
		}
		req.SetBody(buf)
		//		res, err := http.DefaultClient.Do(*(api.Request(req)))
		var response map[string]interface{}
		httpStatusCode, _, err := req.Do(&response)
		if err != nil {
			errCt += 1
			log.Fatalf("ERROR: %v", err)
			return err
		}
		if httpStatusCode != 200 {
			log.Fatalf("Not 200! %d %q\n", httpStatusCode, buf.String())
		}
		return err
	}
	indexer.Start()
	resp, err := http.Get("http://data.githubarchive.org/2012-12-10-15.json.gz")
	if err != nil || resp == nil {
		panic("Could not download data")
	}
	defer resp.Body.Close()
	if err != nil {
		log.Println(err)
		return
	}
	gzReader, err := gzip.NewReader(resp.Body)
	defer gzReader.Close()
	if err != nil {
		panic(err)
	}
	r := bufio.NewReader(gzReader)
	var ge GithubEvent
	docsm := make(map[string]bool)
	h := md5.New()
	for {
		line, err := r.ReadBytes('\n')
		if err != nil && err != io.EOF {
			log.Println("FATAL:  could not read line? ", err)
		} else if err != nil {
			indexer.Flush()
			break
		}
		if err := json.Unmarshal(line, &ge); err == nil {
			// create an "ID"
			h.Write(line)
			id := fmt.Sprintf("%x", h.Sum(nil))
			if _, ok := docsm[id]; ok {
				log.Println("HM, already exists? ", ge.Url)
			}
			docsm[id] = true
			indexer.Index("github", ge.Type, id, "", &ge.Created, line, true)
			docCt++
		} else {
			log.Println("ERROR? ", string(line))
		}
	}
	if errCt != 0 {
		log.Println("FATAL, could not load ", errCt)
	}
	// lets wait a bit to ensure that elasticsearch finishes?
	indexer.Stop()
	if len(docsm) != docCt {
		panic(fmt.Sprintf("Docs didn't match?   %d:%d", len(docsm), docCt))
	}
}
<|endoftext|>