<commit_before>package main

import (
	"html/template"
	"net"
	"net/http"
	"os"
	"path"
	"strconv"
	"strings"
	"time"

	"github.com/Zamiell/isaac-racing-server/src/log"
	"github.com/Zamiell/isaac-racing-server/src/models"
	"github.com/gin-contrib/sessions"
	"github.com/gin-gonic/gin"
	limiter "github.com/julianshen/gin-limiter"
)

const (
	sessionName = "isaac.sid"
)

var (
	sessionStore sessions.CookieStore
	GATrackingID string
	myHTTPClient = &http.Client{ // We don't want to use the default http.Client structure because it has no default timeout set
		Timeout: 10 * time.Second,
	}
)

/*
	Data structures
*/

type TemplateData struct {
	Title string

	// Races stuff
	RaceResults    []models.RaceHistory
	ResultsRaces   []models.RaceHistory
	TotalRaceCount int
	TotalPages     int
	PreviousPage   int
	NextPage       int

	// Profiles/profile stuff
	ResultsProfiles   []models.ProfilesRow
	ResultsProfile    models.ProfileData
	TotalProfileCount int
	UsersPerPage      int
}

/*
	Initialization function
*/

func httpInit() {
	// Create a new Gin HTTP router
	gin.SetMode(gin.ReleaseMode) // Comment this out to debug HTTP stuff
	httpRouter := gin.Default()

	// Read some HTTP server configuration values from environment variables
	// (they were loaded from the .env file in main.go)
	sessionSecret := os.Getenv("SESSION_SECRET")
	if len(sessionSecret) == 0 {
		log.Info("The \"SESSION_SECRET\" environment variable is blank; aborting HTTP initalization.")
		return
	}
	domain := os.Getenv("DOMAIN")
	if len(domain) == 0 {
		log.Info("The \"DOMAIN\" environment variable is blank; aborting HTTP initalization.")
		return
	}
	tlsCertFile := os.Getenv("TLS_CERT_FILE")
	tlsKeyFile := os.Getenv("TLS_KEY_FILE")
	useTLS := true
	if len(tlsCertFile) == 0 || len(tlsKeyFile) == 0 {
		useTLS = false
	}

	// Create a session store
	sessionStore = sessions.NewCookieStore([]byte(sessionSecret))
	options := sessions.Options{
		Path:   "/",
		Domain: domain,
		MaxAge: 5, // 5 seconds
		// After getting a cookie via "/login", the client will immediately
		// establish a WebSocket connection via "/ws", so the cookie only needs
		// to exist for that time frame
		Secure: true,
		// Only send the cookie over HTTPS:
		// https://www.owasp.org/index.php/Testing_for_cookies_attributes_(OTG-SESS-002)
		HttpOnly: true,
		// Mitigate XSS attacks:
		// https://www.owasp.org/index.php/HttpOnly
	}
	if !useTLS {
		options.Secure = false
	}
	sessionStore.Options(options)
	httpRouter.Use(sessions.Sessions(sessionName, sessionStore))

	/*
		Commented out because it doesn't work:
		https://github.com/didip/tollbooth_gin/issues/3

		// Use the Tollbooth Gin middleware for Google Analytics tracking
		limiter := tollbooth.NewLimiter(1, time.Second, nil) // Limit each user to 1 request per second
		httpRouter.Use(tollbooth_gin.LimitHandler(limiter))
	*/

	// Use the gin-limiter middleware for rate-limiting
	// (to only allow one request per second)
	// Based on: https://github.com/julianshen/gin-limiter/blob/master/example/web.go
	limiterMiddleware := limiter.NewRateLimiter(time.Second*60, 60, func(c *gin.Context) (string, error) {
		// Local variables
		r := c.Request
		ip, _, _ := net.SplitHostPort(r.RemoteAddr)

		// Just use the IP address as the key
		return ip, nil
	}).Middleware()
	httpRouter.Use(limiterMiddleware)

	// Use a custom middleware for Google Analytics tracking
	GATrackingID = os.Getenv("GA_TRACKING_ID")
	if len(GATrackingID) != 0 {
		httpRouter.Use(httpMwGoogleAnalytics)
	}

	// Path handlers (for the WebSocket server)
	httpRouter.POST("/login", httpLogin)
	httpRouter.POST("/register", httpRegister)
	httpRouter.GET("/ws", httpWS)

	// Path handlers (for the website)
	httpRouter.GET("/", httpHome)

	// Path handlers for single profile
	httpRouter.GET("/profile", httpProfile)
	httpRouter.GET("/profile/:player", httpProfile) // Handles profile username

	// Path handlers for all profiles
	httpRouter.GET("/profiles", httpProfiles)
	httpRouter.GET("/profiles/:page", httpProfiles) // Handles extra pages for profiles

	// Path handlers for race page
	httpRouter.GET("/race", httpRace)
	httpRouter.GET("/race/:raceid", httpRace)

	// Path handlers for races page
	httpRouter.GET("/races", httpRaces)
	httpRouter.GET("/races/:page", httpRaces)

	//	httpRouter.GET("/leaderboards", httpLeaderboards)
	httpRouter.GET("/info", httpInfo)
	httpRouter.GET("/download", httpDownload)
	httpRouter.Static("/public", "../public")

	// Figure out the port that we are using for the HTTP server
	var port int
	if useTLS {
		// We want all HTTP requests to be redirected to HTTPS
		// (but make an exception for Let's Encrypt)
		// The Gin router is using the default serve mux, so we need to create a
		// new fresh one for the HTTP handler
		HTTPServeMux := http.NewServeMux()
		HTTPServeMux.Handle("/.well-known/acme-challenge/", http.FileServer(http.FileSystem(http.Dir("letsencrypt"))))
		HTTPServeMux.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
			http.Redirect(w, req, "https://"+req.Host+req.URL.String(), http.StatusMovedPermanently)
		}))

		// ListenAndServe is blocking, so start listening on a new goroutine
		go func() {
			http.ListenAndServe(":80", HTTPServeMux) // Nothing before the colon implies 0.0.0.0
			log.Fatal("http.ListenAndServe ended for port 80.", nil)
		}()

		// 443 is the default port for HTTPS
		port = 443
	} else {
		// 80 is the defeault port for HTTP
		port = 80
	}

	// Start listening and serving requests (which is blocking)
	log.Info("Listening on port " + strconv.Itoa(port) + ".")
	if useTLS {
		if err := http.ListenAndServeTLS(
			":"+strconv.Itoa(port), // Nothing before the colon implies 0.0.0.0
			tlsCertFile,
			tlsKeyFile,
			httpRouter,
		); err != nil {
			log.Fatal("http.ListenAndServeTLS failed:", err)
		}
		log.Fatal("http.ListenAndServeTLS ended prematurely.", nil)
	} else {
		// Listen and serve (HTTP)
		if err := http.ListenAndServe(
			":"+strconv.Itoa(port), // Nothing before the colon implies 0.0.0.0
			httpRouter,
		); err != nil {
			log.Fatal("http.ListenAndServe failed:", err)
		}
		log.Fatal("http.ListenAndServe ended prematurely.", nil)
	}
}

/*
	HTTP miscellaneous subroutines
*/

func httpServeTemplate(w http.ResponseWriter, templateName string, data interface{}) {
	lp := path.Join("views", "layout.tmpl")
	fp := path.Join("views", templateName+".tmpl")

	// Return a 404 if the template doesn't exist
	info, err := os.Stat(fp)
	if err != nil {
		if os.IsNotExist(err) {
			http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
			return
		}
	}

	// Return a 404 if the request is for a directory
	if info.IsDir() {
		http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
		return
	}

	// Create the template
	tmpl, err := template.ParseFiles(lp, fp)
	if err != nil {
		log.Error("Failed to create the template: " + err.Error())
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}

	// Execute the template and send it to the user
	if err := tmpl.ExecuteTemplate(w, "layout", data); err != nil {
		if strings.HasSuffix(err.Error(), ": write: broken pipe") {
			// Broken pipe errors can occur when the user presses the "Stop" button while the template is executing
			// We don't want to reporting these errors to Sentry
			// https://stackoverflow.com/questions/26853200/filter-out-broken-pipe-errors-from-template-execution
			log.Info("Failed to execute the template: " + err.Error())
		} else {
			log.Error("Failed to execute the template: " + err.Error())
		}
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
	}
}
<commit_msg>going back to old (fixed) middleware<commit_after>package main

import (
	"html/template"
	"net/http"
	"os"
	"path"
	"strconv"
	"strings"
	"time"

	"github.com/Zamiell/isaac-racing-server/src/log"
	"github.com/Zamiell/isaac-racing-server/src/models"
	"github.com/didip/tollbooth"
	"github.com/didip/tollbooth_gin"
	"github.com/gin-contrib/sessions"
	"github.com/gin-gonic/gin"
)

const (
	sessionName = "isaac.sid"
)

var (
	sessionStore sessions.CookieStore
	GATrackingID string
	myHTTPClient = &http.Client{ // We don't want to use the default http.Client structure because it has no default timeout set
		Timeout: 10 * time.Second,
	}
)

/*
	Data structures
*/

type TemplateData struct {
	Title string

	// Races stuff
	RaceResults    []models.RaceHistory
	ResultsRaces   []models.RaceHistory
	TotalRaceCount int
	TotalPages     int
	PreviousPage   int
	NextPage       int

	// Profiles/profile stuff
	ResultsProfiles   []models.ProfilesRow
	ResultsProfile    models.ProfileData
	TotalProfileCount int
	UsersPerPage      int
}

/*
	Initialization function
*/

func httpInit() {
	// Create a new Gin HTTP router
	gin.SetMode(gin.ReleaseMode) // Comment this out to debug HTTP stuff
	httpRouter := gin.Default()

	// Read some HTTP server configuration values from environment variables
	// (they were loaded from the .env file in main.go)
	sessionSecret := os.Getenv("SESSION_SECRET")
	if len(sessionSecret) == 0 {
		log.Info("The \"SESSION_SECRET\" environment variable is blank; aborting HTTP initalization.")
		return
	}
	domain := os.Getenv("DOMAIN")
	if len(domain) == 0 {
		log.Info("The \"DOMAIN\" environment variable is blank; aborting HTTP initalization.")
		return
	}
	tlsCertFile := os.Getenv("TLS_CERT_FILE")
	tlsKeyFile := os.Getenv("TLS_KEY_FILE")
	useTLS := true
	if len(tlsCertFile) == 0 || len(tlsKeyFile) == 0 {
		useTLS = false
	}

	// Create a session store
	sessionStore = sessions.NewCookieStore([]byte(sessionSecret))
	options := sessions.Options{
		Path:   "/",
		Domain: domain,
		MaxAge: 5, // 5 seconds
		// After getting a cookie via "/login", the client will immediately
		// establish a WebSocket connection via "/ws", so the cookie only needs
		// to exist for that time frame
		Secure: true,
		// Only send the cookie over HTTPS:
		// https://www.owasp.org/index.php/Testing_for_cookies_attributes_(OTG-SESS-002)
		HttpOnly: true,
		// Mitigate XSS attacks:
		// https://www.owasp.org/index.php/HttpOnly
	}
	if !useTLS {
		options.Secure = false
	}
	sessionStore.Options(options)
	httpRouter.Use(sessions.Sessions(sessionName, sessionStore))

	// Use the Tollbooth Gin middleware for Google Analytics tracking
	limiter := tollbooth.NewLimiter(1, time.Second, nil) // Limit each user to 1 request per second
	// When a user requests "/", they will also request the CSS and images;
	// this middleware is smart enough to know that it is considered part of the first request
	// However, it is still not possible to spam download CSS or image files
	limiterMiddleware := tollbooth_gin.LimitHandler(limiter)
	httpRouter.Use(limiterMiddleware)

	/*
		This was used as an alterate to the Tollbooth middleware when it wasn't working

		// Use the gin-limiter middleware for rate-limiting
		// We only allow 60 request per minute, an average of 1 per second
		// This is because when a user requests "/", they will also request the CSS and images
		// Based on: https://github.com/julianshen/gin-limiter/blob/master/example/web.go
		limiterMiddleware := limiter.NewRateLimiter(time.Second*60, 60, func(c *gin.Context) (string, error) {
			// Local variables
			r := c.Request
			ip, _, _ := net.SplitHostPort(r.RemoteAddr)

			// Just use the IP address as the key
			return ip, nil
		}).Middleware()
		httpRouter.Use(limiterMiddleware)
	*/

	// Use a custom middleware for Google Analytics tracking
	GATrackingID = os.Getenv("GA_TRACKING_ID")
	if len(GATrackingID) != 0 {
		httpRouter.Use(httpMwGoogleAnalytics)
	}

	// Path handlers (for the WebSocket server)
	httpRouter.POST("/login", httpLogin)
	httpRouter.POST("/register", httpRegister)
	httpRouter.GET("/ws", httpWS)

	// Path handlers (for the website)
	httpRouter.GET("/", httpHome)

	// Path handlers for single profile
	httpRouter.GET("/profile", httpProfile)
	httpRouter.GET("/profile/:player", httpProfile) // Handles profile username

	// Path handlers for all profiles
	httpRouter.GET("/profiles", httpProfiles)
	httpRouter.GET("/profiles/:page", httpProfiles) // Handles extra pages for profiles

	// Path handlers for race page
	httpRouter.GET("/race", httpRace)
	httpRouter.GET("/race/:raceid", httpRace)

	// Path handlers for races page
	httpRouter.GET("/races", httpRaces)
	httpRouter.GET("/races/:page", httpRaces)

	//	httpRouter.GET("/leaderboards", httpLeaderboards)
	httpRouter.GET("/info", httpInfo)
	httpRouter.GET("/download", httpDownload)
	httpRouter.Static("/public", "../public")

	// Figure out the port that we are using for the HTTP server
	var port int
	if useTLS {
		// We want all HTTP requests to be redirected to HTTPS
		// (but make an exception for Let's Encrypt)
		// The Gin router is using the default serve mux, so we need to create a
		// new fresh one for the HTTP handler
		HTTPServeMux := http.NewServeMux()
		HTTPServeMux.Handle("/.well-known/acme-challenge/", http.FileServer(http.FileSystem(http.Dir("letsencrypt"))))
		HTTPServeMux.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
			http.Redirect(w, req, "https://"+req.Host+req.URL.String(), http.StatusMovedPermanently)
		}))

		// ListenAndServe is blocking, so start listening on a new goroutine
		go func() {
			http.ListenAndServe(":80", HTTPServeMux) // Nothing before the colon implies 0.0.0.0
			log.Fatal("http.ListenAndServe ended for port 80.", nil)
		}()

		// 443 is the default port for HTTPS
		port = 443
	} else {
		// 80 is the defeault port for HTTP
		port = 80
	}

	// Start listening and serving requests (which is blocking)
	log.Info("Listening on port " + strconv.Itoa(port) + ".")
	if useTLS {
		if err := http.ListenAndServeTLS(
			":"+strconv.Itoa(port), // Nothing before the colon implies 0.0.0.0
			tlsCertFile,
			tlsKeyFile,
			httpRouter,
		); err != nil {
			log.Fatal("http.ListenAndServeTLS failed:", err)
		}
		log.Fatal("http.ListenAndServeTLS ended prematurely.", nil)
	} else {
		// Listen and serve (HTTP)
		if err := http.ListenAndServe(
			":"+strconv.Itoa(port), // Nothing before the colon implies 0.0.0.0
			httpRouter,
		); err != nil {
			log.Fatal("http.ListenAndServe failed:", err)
		}
		log.Fatal("http.ListenAndServe ended prematurely.", nil)
	}
}

/*
	HTTP miscellaneous subroutines
*/

func httpServeTemplate(w http.ResponseWriter, templateName string, data interface{}) {
	lp := path.Join("views", "layout.tmpl")
	fp := path.Join("views", templateName+".tmpl")

	// Return a 404 if the template doesn't exist
	info, err := os.Stat(fp)
	if err != nil {
		if os.IsNotExist(err) {
			http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
			return
		}
	}

	// Return a 404 if the request is for a directory
	if info.IsDir() {
		http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
		return
	}

	// Create the template
	tmpl, err := template.ParseFiles(lp, fp)
	if err != nil {
		log.Error("Failed to create the template: " + err.Error())
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}

	// Execute the template and send it to the user
	if err := tmpl.ExecuteTemplate(w, "layout", data); err != nil {
		if strings.HasSuffix(err.Error(), ": write: broken pipe") {
			// Broken pipe errors can occur when the user presses the "Stop" button while the template is executing
			// We don't want to reporting these errors to Sentry
			// https://stackoverflow.com/questions/26853200/filter-out-broken-pipe-errors-from-template-execution
			log.Info("Failed to execute the template: " + err.Error())
		} else {
			log.Error("Failed to execute the template: " + err.Error())
		}
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"time"

	"os"
	"path/filepath"

	"github.com/kardianos/osext"
	"github.com/spring1843/chat-server/src/config"
	"github.com/spring1843/chat-server/src/drivers/bootstrap"
	"github.com/spring1843/chat-server/src/shared/logs"
)

const usageDoc = `Chat Server
Usage:
        chat-server -config config.json
Flags:
        -config S r equired .json config file, look at config.json for default settings
`

func main() {
	var configFile string
	flag.StringVar(&configFile, "config", "", "path to .json config file")
	flag.Parse()

	if configFile == "" {
		logs.Fatalf(usageDoc)
	}
	config := config.FromFile(configFile)
	config = setCWD(config)
	checkStaticDirExists(config)

	// Start all services e.g. Telnet, WebSocket, REST
	bootstrap.NewBootstrap(config)

	// Never end
	neverDie()
}

func checkStaticDirExists(config config.Config) {
	absolutePath, err := filepath.Abs(filepath.Join(config.CWD, config.StaticWeb))
	if err != nil {
		logs.Fatalf("Error finding absolutepath of %q + %q", config.CWD, config.StaticWeb)
	}
	_, err = os.Stat(absolutePath)
	if os.IsNotExist(err) {
		logs.Fatalf("Directory for StaticWeb defined in config does not exist. CWD %s Absolute Path %s", config.CWD, absolutePath)
		return
	}
}

// TODO change to os.Executable() when upgrading to Go 1.8
func setCWD(config config.Config) config.Config {
	if config.CWD == "" {
		var err error
		if config.CWD, err = osext.ExecutableFolder(); err != nil {
			logs.FatalIfErrf(err, "Error finding out CWD, current working directory")
		}
		config.CWD += "/"
	}
	return config
}

func neverDie() {
	for true {
		time.Sleep(24 * time.Hour)
	}
}
<commit_msg>Use Go 1.8 os.Executable() to find CWD<commit_after>package main

import (
	"flag"
	"time"

	"os"
	"path/filepath"

	"github.com/spring1843/chat-server/src/config"
	"github.com/spring1843/chat-server/src/drivers/bootstrap"
	"github.com/spring1843/chat-server/src/shared/logs"
)

const usageDoc = `Chat Server
Usage:
        chat-server -config config.json
Flags:
        -config S r equired .json config file, look at config.json for default settings
`

func main() {
	var configFile string
	flag.StringVar(&configFile, "config", "", "path to .json config file")
	flag.Parse()

	if configFile == "" {
		logs.Fatalf(usageDoc)
	}
	config := config.FromFile(configFile)
	config = setCWD(config)
	checkStaticDirExists(config)

	// Start all services e.g. Telnet, WebSocket, REST
	bootstrap.NewBootstrap(config)

	// Never end
	neverDie()
}

func checkStaticDirExists(config config.Config) {
	absolutePath, err := filepath.Abs(filepath.Join(config.CWD, config.StaticWeb))
	if err != nil {
		logs.Fatalf("Error finding absolutepath of %q + %q", config.CWD, config.StaticWeb)
	}
	_, err = os.Stat(absolutePath)
	if os.IsNotExist(err) {
		logs.Fatalf("Directory for StaticWeb defined in config does not exist. CWD %s Absolute Path %s", config.CWD, absolutePath)
		return
	}
}

func setCWD(config config.Config) config.Config {
	if config.CWD == "" {
		var err error
		if config.CWD, err = os.Executable(); err != nil {
			logs.FatalIfErrf(err, "Error finding out CWD, current working directory")
		}

		config.CWD += "/"
	}
	return config
}

func neverDie() {
	for true {
		time.Sleep(24 * time.Hour)
	}
}
<|endoftext|>


<commit_before>package main

import (
    "fmt"
    "net/http"
    "database/sql"
    _ "github.com/go-sql-driver/mysql"
)

var sqlString string = "root:root@/soc"

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, "Stevilo ucencev: ", stevilo("gender", ""), "\n")
	fmt.Fprint(w, "Stevilo moskih: ", stevilo("gender", "gender = 'M'"), "\n")
	fmt.Fprint(w, "Stevilo zensk: ", stevilo("gender", "gender = 'Z'"), "\n")
	fmt.Fprint(w, "Povprecni uspeh: ", povprecna("final", ""), "\n")
	fmt.Fprint(w, "Povprecni uspeh moskih: ", povprecna("final", "gender = 'M'"), "\n")
	fmt.Fprint(w, "Povprecni uspeh zensk: ", povprecna("final", "gender = 'Z'"), "\n")
	fmt.Fprint(w, "Povprecna ocena: ", povprecna("average", ""), "\n")
	fmt.Fprint(w, "Povprecna ocena moskih: ", povprecna("average", "gender = 'M'"), "\n")
	fmt.Fprint(w, "Povprecna ocena zensk: ", povprecna("average", "gender = 'Z'"), "\n")
	fmt.Fprint(w, "Povprecno stevilo opravicenih ur: ", povprecna("opravicene", ""), "\n")
	fmt.Fprint(w, "Povprecno stevilo opravicenih ur pri moskih: ", povprecna("opravicene", "gender = 'M'"), "\n")
	fmt.Fprint(w, "Povprecno stevilo opravicenih ur pri zenskah: ", povprecna("opravicene", "gender = 'Z'"), "\n")
	fmt.Fprint(w, "Povprecno stevilo opravicenih ur v 1. letniku: ", povprecna("opravicene", "class = 1"), "\n")
	fmt.Fprint(w, "Povprecno stevilo opravicenih ur v 2. letniku: ", povprecna("opravicene", "class = 2"), "\n")
	fmt.Fprint(w, "Povprecno stevilo opravicenih ur v 3. letniku: ", povprecna("opravicene", "class = 3"), "\n")
	fmt.Fprint(w, "Povprecno stevilo opravicenih ur v 4. letniku: ", povprecna("opravicene", "class = 4"), "\n")
	fmt.Fprint(w, "Povprecno stevilo neopravicenih ur: ", povprecna("neopravicene", ""), "\n")
	fmt.Fprint(w, "Povprecno stevilo neopravicenih ur pri moskih: ", povprecna("neopravicene", "gender = 'M'"), "\n")
	fmt.Fprint(w, "Povprecno stevilo neopravicenih ur pri zenskah: ", povprecna("neopravicene", "gender = 'Z'"), "\n")
	fmt.Fprint(w, "Povprecno stevilo neopravicenih ur v 1. letniku: ", povprecna("neopravicene", "class = '1'"), "\n")
	fmt.Fprint(w, "Povprecno stevilo neopravicenih ur v 2. letniku: ", povprecna("neopravicene", "class = '2'"), "\n")
	fmt.Fprint(w, "Povprecno stevilo neopravicenih ur v 3. letniku: ", povprecna("neopravicene", "class = '3'"), "\n")
	fmt.Fprint(w, "Povprecno stevilo neopravicenih ur v 4. letniku: ", povprecna("neopravicene", "class = '4'"), "\n")
	fmt.Fprint(w, "Stevilo dijakov z neopravicenimi urami: ", stevilo("neopravicene", "neopravicene != 0"), "\n")
	fmt.Fprint(w, "Stevilo moskih z neopravicenimi urami: ", stevilo("neopravicene", "neopravicene != 0 AND gender='M'"), "\n")
	fmt.Fprint(w, "Stevilo zensk z neopravicenimi urami: ", stevilo("neopravicene", "neopravicene != 0 AND gender='Z'"), "\n")
	fmt.Fprint(w, "\n")
	fmt.Fprint(w, "Povprecno stevlilo opravicenih ur dijakov (5): ", povprecna("opravicene", "final = 5"), "\n")
	fmt.Fprint(w, "Povprecno stevlilo opravicenih ur dijakov (4): ", povprecna("opravicene", "final = 4"), "\n")
	fmt.Fprint(w, "Povprecno stevlilo opravicenih ur dijakov (3): ", povprecna("opravicene", "final = 3"), "\n")
	fmt.Fprint(w, "Povprecno stevlilo opravicenih ur dijakov (2): ", povprecna("opravicene", "final = 2"), "\n")
	fmt.Fprint(w, "Povprecno stevlilo opravicenih ur dijakov (1): ", povprecna("opravicene", "final = 1"), "\n")
	fmt.Fprint(w, "Povprecno stevlilo opravicenih ur dijakov (0): ", povprecna("opravicene", "final = 0"), "\n")
	fmt.Fprint(w, "\n")
	fmt.Fprint(w, "Povprecno stevlilo neopravicenih ur dijakov (5): ", povprecna("neopravicene", "final = 5"), "\n")
	fmt.Fprint(w, "Povprecno stevlilo neopravicenih ur dijakov (4): ", povprecna("neopravicene", "final = 4"), "\n")
	fmt.Fprint(w, "Povprecno stevlilo neopravicenih ur dijakov (3): ", povprecna("neopravicene", "final = 3"), "\n")
	fmt.Fprint(w, "Povprecno stevlilo neopravicenih ur dijakov (2): ", povprecna("neopravicene", "final = 2"), "\n")
	fmt.Fprint(w, "Povprecno stevlilo neopravicenih ur dijakov (1): ", povprecna("neopravicene", "final = 1"), "\n")
	fmt.Fprint(w, "Povprecno stevlilo neopravicenih ur dijakov (0): ", povprecna("neopravicene", "final = 0"), "\n")
}

func main() {
    http.HandleFunc("/", handler)
    http.ListenAndServe(":8080", nil)
}

func stevilo(what string, where string) int {
	var query string
	if where == "" {
		query = "select " + what + " from soc;"
	} else {
		query = "select " + what + " from soc where " + where + ";"
	}

	con, err := sql.Open("mysql", sqlString)
	check(err)
	defer con.Close()

	rows, err := con.Query(query)
	check(err)
	var i int = 0

	for rows.Next() {
		i++
	}
	return i
}

func povprecna(what, where string) float64 {
	var query string
	if where == "" {
		query = "select " + what + " from soc;"
	} else {
		query = "select " + what + " from soc where " + where + ";"
	}

	con, err := sql.Open("mysql", sqlString)
	check(err)
	defer con.Close()

	rows, err := con.Query(query)
	check(err)

	var sum float64 = 0
	var i int = 0

	for rows.Next() {
		i++
		var temp float64
		rows.Scan(&temp)
		sum += temp
	}

	if i == 0 {
		return -1
	}

	return float64(sum) / float64(i)
}

func check(err error) {
	if err != nil {
		panic(err)
	}
}<commit_msg>translated method names<commit_after>package main

import (
    "fmt"
    "net/http"
    "database/sql"
    _ "github.com/go-sql-driver/mysql"
)

var sqlString string = "root:root@/soc"

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, "numberOf ucencev: ", numberOf("gender", ""), "\n")
	fmt.Fprint(w, "numberOf moskih: ", numberOf("gender", "gender = 'M'"), "\n")
	fmt.Fprint(w, "numberOf zensk: ", numberOf("gender", "gender = 'Z'"), "\n")
	fmt.Fprint(w, "Povprecni uspeh: ", average("final", ""), "\n")
	fmt.Fprint(w, "Povprecni uspeh moskih: ", average("final", "gender = 'M'"), "\n")
	fmt.Fprint(w, "Povprecni uspeh zensk: ", average("final", "gender = 'Z'"), "\n")
	fmt.Fprint(w, "average ocena: ", average("average", ""), "\n")
	fmt.Fprint(w, "average ocena moskih: ", average("average", "gender = 'M'"), "\n")
	fmt.Fprint(w, "average ocena zensk: ", average("average", "gender = 'Z'"), "\n")
	fmt.Fprint(w, "Povprecno numberOf opravicenih ur: ", average("opravicene", ""), "\n")
	fmt.Fprint(w, "Povprecno numberOf opravicenih ur pri moskih: ", average("opravicene", "gender = 'M'"), "\n")
	fmt.Fprint(w, "Povprecno numberOf opravicenih ur pri zenskah: ", average("opravicene", "gender = 'Z'"), "\n")
	fmt.Fprint(w, "Povprecno numberOf opravicenih ur v 1. letniku: ", average("opravicene", "class = 1"), "\n")
	fmt.Fprint(w, "Povprecno numberOf opravicenih ur v 2. letniku: ", average("opravicene", "class = 2"), "\n")
	fmt.Fprint(w, "Povprecno numberOf opravicenih ur v 3. letniku: ", average("opravicene", "class = 3"), "\n")
	fmt.Fprint(w, "Povprecno numberOf opravicenih ur v 4. letniku: ", average("opravicene", "class = 4"), "\n")
	fmt.Fprint(w, "Povprecno numberOf neopravicenih ur: ", average("neopravicene", ""), "\n")
	fmt.Fprint(w, "Povprecno numberOf neopravicenih ur pri moskih: ", average("neopravicene", "gender = 'M'"), "\n")
	fmt.Fprint(w, "Povprecno numberOf neopravicenih ur pri zenskah: ", average("neopravicene", "gender = 'Z'"), "\n")
	fmt.Fprint(w, "Povprecno numberOf neopravicenih ur v 1. letniku: ", average("neopravicene", "class = '1'"), "\n")
	fmt.Fprint(w, "Povprecno numberOf neopravicenih ur v 2. letniku: ", average("neopravicene", "class = '2'"), "\n")
	fmt.Fprint(w, "Povprecno numberOf neopravicenih ur v 3. letniku: ", average("neopravicene", "class = '3'"), "\n")
	fmt.Fprint(w, "Povprecno numberOf neopravicenih ur v 4. letniku: ", average("neopravicene", "class = '4'"), "\n")
	fmt.Fprint(w, "numberOf dijakov z neopravicenimi urami: ", numberOf("neopravicene", "neopravicene != 0"), "\n")
	fmt.Fprint(w, "numberOf moskih z neopravicenimi urami: ", numberOf("neopravicene", "neopravicene != 0 AND gender='M'"), "\n")
	fmt.Fprint(w, "numberOf zensk z neopravicenimi urami: ", numberOf("neopravicene", "neopravicene != 0 AND gender='Z'"), "\n")
	fmt.Fprint(w, "\n")
	fmt.Fprint(w, "Povprecno stevlilo opravicenih ur dijakov (5): ", average("opravicene", "final = 5"), "\n")
	fmt.Fprint(w, "Povprecno stevlilo opravicenih ur dijakov (4): ", average("opravicene", "final = 4"), "\n")
	fmt.Fprint(w, "Povprecno stevlilo opravicenih ur dijakov (3): ", average("opravicene", "final = 3"), "\n")
	fmt.Fprint(w, "Povprecno stevlilo opravicenih ur dijakov (2): ", average("opravicene", "final = 2"), "\n")
	fmt.Fprint(w, "Povprecno stevlilo opravicenih ur dijakov (1): ", average("opravicene", "final = 1"), "\n")
	fmt.Fprint(w, "Povprecno stevlilo opravicenih ur dijakov (0): ", average("opravicene", "final = 0"), "\n")
	fmt.Fprint(w, "\n")
	fmt.Fprint(w, "Povprecno stevlilo neopravicenih ur dijakov (5): ", average("neopravicene", "final = 5"), "\n")
	fmt.Fprint(w, "Povprecno stevlilo neopravicenih ur dijakov (4): ", average("neopravicene", "final = 4"), "\n")
	fmt.Fprint(w, "Povprecno stevlilo neopravicenih ur dijakov (3): ", average("neopravicene", "final = 3"), "\n")
	fmt.Fprint(w, "Povprecno stevlilo neopravicenih ur dijakov (2): ", average("neopravicene", "final = 2"), "\n")
	fmt.Fprint(w, "Povprecno stevlilo neopravicenih ur dijakov (1): ", average("neopravicene", "final = 1"), "\n")
	fmt.Fprint(w, "Povprecno stevlilo neopravicenih ur dijakov (0): ", average("neopravicene", "final = 0"), "\n")
}

func main() {
    http.HandleFunc("/", handler)
    http.ListenAndServe(":8080", nil)
}

func numberOf(what string, where string) int {
	var query string
	if where == "" {
		query = "select " + what + " from soc;"
	} else {
		query = "select " + what + " from soc where " + where + ";"
	}

	con, err := sql.Open("mysql", sqlString)
	check(err)
	defer con.Close()

	rows, err := con.Query(query)
	check(err)
	var i int = 0

	for rows.Next() {
		i++
	}
	return i
}

func average(what, where string) float64 {
	var query string
	if where == "" {
		query = "select " + what + " from soc;"
	} else {
		query = "select " + what + " from soc where " + where + ";"
	}

	con, err := sql.Open("mysql", sqlString)
	check(err)
	defer con.Close()

	rows, err := con.Query(query)
	check(err)

	var sum float64 = 0
	var i int = 0

	for rows.Next() {
		i++
		var temp float64
		rows.Scan(&temp)
		sum += temp
	}

	if i == 0 {
		return -1
	}

	return float64(sum) / float64(i)
}

func check(err error) {
	if err != nil {
		panic(err)
	}
}<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"github.com/btcsuite/btcrpcclient"
	"io/ioutil"
	"log"
	"os/exec"
)

type Config struct {
	User     string `json:"user"`
	Password string `json:"password"`
	Host     string `json:"host"`
	Account  string `json:"account"`
}

//Missing: capabilities, transactions, mutable
type ResultTemplate struct {
	PreviousBlockHash string `json:"previousblockhash"`
	Target            string `json:"target"`
	NonceRange        string `json:"noncerange"`
	MinTime           uint   `json:"mintime"`
	SigOpLimit        uint   `json:"sigoplimit"`
	CurTime           uint   `json:"curtime"`
	Height            uint   `json:"height"`
	Version           uint   `json:"version"`
	Bits              string `json:"bits"`
	CoinBaseValue     uint   `json:"coinbasevalue"`
	SizeLimit         uint   `json:"sizelimit"`
	LongPollId        string `json:"longpollid"`
}

type BlockTemplate struct {
	Error  string         `json:"error"`
	Result ResultTemplate `json:"result"`
}

func VerifyAccount(client *btcrpcclient.Client, name string) bool {
	adr, err := client.GetAccountAddress(name)
	if err != nil {
		log.Printf("Error getting account address %s", name)
		return false
	} else {
		wal, err := client.ValidateAddress(adr)
		if err != nil {
			log.Printf("Error validating account address")
			return false
		} else if !wal.IsValid {
			log.Printf("Invalid account address")
			return false
		}
		log.Printf("Account: %s, Address: %s, PubKey: %s\n", name, adr, wal.PubKey)
	}
	return true
}
func ListAccounts(client *btcrpcclient.Client) {
	accounts, err := client.ListAccounts()
	if err != nil {
		log.Fatalf("Error listing accounts: %v", err)
	}
	for label, amount := range accounts {
		log.Println("Account %s with %s", label, amount)
	}
	log.Fatalf("Indicates the right account in config.json then try again.")
}

func readconf() (conf Config) {
	content, err := ioutil.ReadFile("config.json")
	if err != nil {
		log.Fatalf("Error:", err)
	}
	err = json.Unmarshal(content, &conf)
	if err != nil {
		log.Fatalf("Error:", err)
	}
	return
}

// VERY Temporary work-around for GetBlockTemplate ;)
func GetBlockTemplate(user, password, host string) ResultTemplate {
	command := "curl -u " + user + ":" + password + ` --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "getblocktemplate", "params": [] }'   -H 'content-type: text/plain;' http://` + host + "/"
	out, err := exec.Command("sh", "-c", command).Output()
	if err != nil {
		log.Fatal(err)
	}
	var btp BlockTemplate
	err = json.Unmarshal(out, &btp)
	if err != nil {
		log.Fatalf("Error:", err)
	}
	return btp.Result
}

func main() {
	// Read and parse the configuration file
	conf := readconf()
	// Create new client instance
	client, err := btcrpcclient.New(&btcrpcclient.ConnConfig{
		HTTPPostMode: true,
		DisableTLS:   true,
		Host:         conf.Host,
		User:         conf.User,
		Pass:         conf.Password,
	}, nil)
	if err != nil {
		log.Fatalf("error creating new btc client: %v", err)
	}
	// Verifying Account
	if !VerifyAccount(client, conf.Account) {
		ListAccounts(client)
	}
	// Get and Parse BlockTemplate to begin minning
	GetBlockTemplate(conf.User, conf.Password, conf.Host)
}
<commit_msg>Loaded Transactions data.<commit_after>package main

import (
	"encoding/json"
	"errors"
	"github.com/btcsuite/btcrpcclient"
	"io/ioutil"
	"log"
	"os/exec"
)

type Config struct {
	User     string `json:"user"`
	Password string `json:"password"`
	Host     string `json:"host"`
	Account  string `json:"account"`
}

// Missing: depends[]
type TransactionTemplate struct {
	Hash   string `json:"hash"`
	Fee    uint   `json:"fee"`
	Data   string `json:"data"`
	SigOps uint   `json:"sigops"`
}

//Missing: capabilities, mutable
type ResultTemplate struct {
	PreviousBlockHash string                `json:"previousblockhash"`
	Target            string                `json:"target"`
	NonceRange        string                `json:"noncerange"`
	Bits              string                `json:"bits"`
	LongPollId        string                `json:"longpollid"`
	MinTime           uint                  `json:"mintime"`
	SigOpLimit        uint                  `json:"sigoplimit"`
	CurTime           uint                  `json:"curtime"`
	Height            uint                  `json:"height"`
	Version           uint                  `json:"version"`
	CoinBaseValue     uint                  `json:"coinbasevalue"`
	SizeLimit         uint                  `json:"sizelimit"`
	Transactions      []TransactionTemplate `json:"transactions"`
}

type BlockTemplate struct {
	Error  string         `json:"error"`
	Result ResultTemplate `json:"result"`
}

func VerifyAccount(client *btcrpcclient.Client, name string) (bool, error) {
	adr, err := client.GetAccountAddress(name)
	if err != nil {
		return false, err
	} else {
		wal, err := client.ValidateAddress(adr)
		if err != nil {
			return false, err
		} else if !wal.IsValid {
			return false, err
		}
	}
	return true, nil
}

func ListAccounts(client *btcrpcclient.Client) {
	accounts, err := client.ListAccounts()
	if err != nil {
		log.Fatalf("Error listing accounts: %v", err)
	}
	for label, amount := range accounts {
		log.Println("Account %s with %s", label, amount)
	}
	log.Fatalf("Indicates the right account in config.json then try again.")
}

func readconf() (conf Config) {
	content, err := ioutil.ReadFile("config.json")
	if err != nil {
		log.Fatalf("Error:", err)
	}
	err = json.Unmarshal(content, &conf)
	if err != nil {
		log.Fatalf("Error:", err)
	}
	return
}

// VERY Temporary work-around for GetBlockTemplate() from BP023 ;)
func GetResultTemplate(user, password, host string) (rtp ResultTemplate, err error) {
	var btp BlockTemplate
	command := "curl -u " + user + ":" + password + ` --data-binary '{"jsonrpc": "1.1", "id":"0", "method": "getblocktemplate", "params": [{"capabilities": ["coinbasetxn", "workid", "coinbase/append"]}] }'   -H 'content-type: application/json;' http://` + host + "/"
	log.Printf(command)
	out, err := exec.Command("sh", "-c", command).Output()
	if err != nil {
		return
	}
	err = json.Unmarshal(out, &btp)
	if err != nil {
		return
	}
	if btp.Error == "" {
		return btp.Result, nil
	} else {
		return rtp, errors.New(btp.Error)
	}
	return
}

func main() {
	// Read and parse the configuration file
	conf := readconf()
	// Create new client instance
	client, err := btcrpcclient.New(&btcrpcclient.ConnConfig{
		HTTPPostMode: true,
		DisableTLS:   true,
		Host:         conf.Host,
		User:         conf.User,
		Pass:         conf.Password,
	}, nil)
	if err != nil {
		log.Fatalf("Error creating new btc client: %v", err)
	}
	// Verifying Account
	if val, err := VerifyAccount(client, conf.Account); !val {
		log.Printf("Error: %v ", err)
		ListAccounts(client)
	}
	//Loading and parsing values from Bitcoin API call
	_, err = GetResultTemplate(conf.User, conf.Password, conf.Host)
	if err != nil {
		log.Fatalf("Error getting mining data: %v", err)
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2021 The cert-manager Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package revisionmanager

import (
	"context"
	"reflect"
	"testing"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/types"
	coretesting "k8s.io/client-go/testing"

	cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1"
	cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1"
	controllerpkg "github.com/jetstack/cert-manager/pkg/controller"
	testpkg "github.com/jetstack/cert-manager/pkg/controller/test"
	logtest "github.com/jetstack/cert-manager/pkg/logs/testing"
	"github.com/jetstack/cert-manager/test/unit/gen"
)

func TestProcessItem(t *testing.T) {
	baseCrt := gen.Certificate("test-cert",
		gen.SetCertificateNamespace("testns"),
		gen.SetCertificateUID("uid-1"),
	)
	baseCRNoOwner := gen.CertificateRequest("test-cr",
		gen.SetCertificateRequestNamespace("testns"),
	)
	baseCR := gen.CertificateRequestFrom(baseCRNoOwner,
		gen.AddCertificateRequestOwnerReferences(*metav1.NewControllerRef(
			baseCrt, cmapi.SchemeGroupVersion.WithKind("Certificate")),
		),
	)

	tests := map[string]struct {
		// key that should be passed to ProcessItem.
		// if not set, the 'namespace/name' of the 'Certificate' field will be used.
		// if neither is set, the key will be ""
		key string

		// Certificate to be synced for the test.
		// if not set, the 'key' will be passed to ProcessItem instead.
		certificate *cmapi.Certificate

		// Request, if set, will exist in the apiserver before the test is run.
		requests []runtime.Object

		expectedActions []testpkg.Action

		// err is the expected error text returned by the controller, if any.
		err string
	}{
		"do nothing if an empty 'key' is used": {},
		"do nothing if an invalid 'key' is used": {
			key: "abc/def/ghi",
		},
		"do nothing if a key references a Certificate that does not exist": {
			key: "namespace/name",
		},
		"do nothing if Certificate is not in a Ready=True state": {
			certificate: gen.CertificateFrom(baseCrt,
				gen.SetCertificateStatusCondition(cmapi.CertificateCondition{Type: cmapi.CertificateConditionIssuing, Status: cmmeta.ConditionFalse}),
				gen.SetCertificateRevisionHistoryLimit(1),
			),
			requests: []runtime.Object{
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-1"),
					gen.SetCertificateRequestRevision("1"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("2"),
				),
			},
		},
		"do nothing if no requests exist": {
			certificate: gen.CertificateFrom(baseCrt,
				gen.SetCertificateStatusCondition(cmapi.CertificateCondition{Type: cmapi.CertificateConditionReady, Status: cmmeta.ConditionTrue}),
				gen.SetCertificateRevisionHistoryLimit(1),
			),
		},
		"do nothing if requests don't have or bad revisions set": {
			certificate: gen.CertificateFrom(baseCrt,
				gen.SetCertificateStatusCondition(cmapi.CertificateCondition{Type: cmapi.CertificateConditionReady, Status: cmmeta.ConditionTrue}),
				gen.SetCertificateRevisionHistoryLimit(1),
			),
			requests: []runtime.Object{
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-1"),
					gen.SetCertificateRequestRevision("abc"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-2"),
				),
			},
		},
		"do nothing if requests aren't owned by this Certificate": {
			certificate: gen.CertificateFrom(baseCrt,
				gen.SetCertificateStatusCondition(cmapi.CertificateCondition{Type: cmapi.CertificateConditionReady, Status: cmmeta.ConditionTrue}),
				gen.SetCertificateRevisionHistoryLimit(1),
			),
			requests: []runtime.Object{
				gen.CertificateRequestFrom(baseCRNoOwner,
					gen.SetCertificateRequestName("cr-1"),
					gen.SetCertificateRequestRevision("1"),
				),
				gen.CertificateRequestFrom(baseCRNoOwner,
					gen.SetCertificateRequestName("cr-2"),
					gen.SetCertificateRequestRevision("2"),
				),
			},
		},
		"do nothing if number of revisions matches that of the limit": {
			certificate: gen.CertificateFrom(baseCrt,
				gen.SetCertificateStatusCondition(cmapi.CertificateCondition{Type: cmapi.CertificateConditionReady, Status: cmmeta.ConditionTrue}),
				gen.SetCertificateRevisionHistoryLimit(2),
			),
			requests: []runtime.Object{
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-1"),
					gen.SetCertificateRequestRevision("1"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-2"),
					gen.SetCertificateRequestRevision("2"),
				),
			},
		},
		"do nothing if revision limit is not set": {
			certificate: gen.CertificateFrom(baseCrt,
				gen.SetCertificateStatusCondition(cmapi.CertificateCondition{Type: cmapi.CertificateConditionReady, Status: cmmeta.ConditionTrue}),
			),
			requests: []runtime.Object{
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-1"),
					gen.SetCertificateRequestRevision("1"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-2"),
					gen.SetCertificateRequestRevision("2"),
				),
			},
		},
		"delete 1 request if limit is 1 and 2 requests exist": {
			certificate: gen.CertificateFrom(baseCrt,
				gen.SetCertificateStatusCondition(cmapi.CertificateCondition{Type: cmapi.CertificateConditionReady, Status: cmmeta.ConditionTrue}),
				gen.SetCertificateRevisionHistoryLimit(1),
			),
			requests: []runtime.Object{
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-2"),
					gen.SetCertificateRequestRevision("2"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-1"),
					gen.SetCertificateRequestRevision("1"),
				),
			},
			expectedActions: []testpkg.Action{
				testpkg.NewAction(coretesting.NewDeleteAction(cmapi.SchemeGroupVersion.WithResource("certificaterequests"), "testns", "cr-1")),
			},
		},
		"delete 3 requests if limit is 3 and 6 requests exist": {
			certificate: gen.CertificateFrom(baseCrt,
				gen.SetCertificateStatusCondition(cmapi.CertificateCondition{Type: cmapi.CertificateConditionReady, Status: cmmeta.ConditionTrue}),
				gen.SetCertificateRevisionHistoryLimit(3),
			),
			requests: []runtime.Object{
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-2"),
					gen.SetCertificateRequestRevision("2"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-3"),
					gen.SetCertificateRequestRevision("3"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-1"),
					gen.SetCertificateRequestRevision("1"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-4"),
					gen.SetCertificateRequestRevision("11"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-5"),
					gen.SetCertificateRequestRevision("11"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-6"),
					gen.SetCertificateRequestRevision("2"),
				),
			},
			expectedActions: []testpkg.Action{
				testpkg.NewAction(coretesting.NewDeleteAction(cmapi.SchemeGroupVersion.WithResource("certificaterequests"), "testns", "cr-1")),
				testpkg.NewAction(coretesting.NewDeleteAction(cmapi.SchemeGroupVersion.WithResource("certificaterequests"), "testns", "cr-2")),
				testpkg.NewAction(coretesting.NewDeleteAction(cmapi.SchemeGroupVersion.WithResource("certificaterequests"), "testns", "cr-6")),
			},
		},
	}
	for name, test := range tests {
		t.Run(name, func(t *testing.T) {
			// Create and initialise a new unit test builder
			builder := &testpkg.Builder{
				T:               t,
				ExpectedEvents:  nil,
				ExpectedActions: test.expectedActions,
				StringGenerator: func(i int) string { return "notrandom" },
			}
			if test.certificate != nil {
				builder.CertManagerObjects = append(builder.CertManagerObjects, test.certificate)
			}
			for _, req := range test.requests {
				builder.CertManagerObjects = append(builder.CertManagerObjects, req)
			}
			builder.Init()

			// Register informers used by the controller using the registration wrapper
			w := &controllerWrapper{}
			_, _, err := w.Register(builder.Context)
			if err != nil {
				t.Fatal(err)
			}
			// Start the informers and begin processing updates
			builder.Start()
			defer builder.Stop()

			key := test.key
			if key == "" && test.certificate != nil {
				key, err = controllerpkg.KeyFunc(test.certificate)
				if err != nil {
					t.Fatal(err)
				}
			}

			// Call ProcessItem
			err = w.controller.ProcessItem(context.Background(), key)
			switch {
			case err != nil:
				if test.err != err.Error() {
					t.Errorf("error text did not match, got=%s, exp=%s", err.Error(), test.err)
				}
			default:
				if test.err != "" {
					t.Errorf("got no error but expected: %s", test.err)
				}
			}

			if err := builder.AllEventsCalled(); err != nil {
				builder.T.Error(err)
			}
			if err := builder.AllActionsExecuted(); err != nil {
				builder.T.Error(err)
			}
			if err := builder.AllReactorsCalled(); err != nil {
				builder.T.Error(err)
			}
		})
	}
}

func TestCertificateRequestsToDelete(t *testing.T) {
	baseCR := gen.CertificateRequest("test")

	tests := map[string]struct {
		input []*cmapi.CertificateRequest
		limit int
		exp   []revision
	}{
		"an empty list of request should return empty": {
			input: nil,
			limit: 3,
			exp:   nil,
		},
		"a single request with no revision set should return empty": {
			input: []*cmapi.CertificateRequest{
				baseCR,
			},
			limit: 3,
			exp:   nil,
		},
		"a single request with revision set but higher limit should return no requests": {
			input: []*cmapi.CertificateRequest{
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestRevision("123"),
				),
			},
			limit: 3,
			exp:   nil,
		},
		"two requests with one badly formed revision but limit set to 1 should return no requests": {
			input: []*cmapi.CertificateRequest{
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-1"),
					gen.SetCertificateRequestRevision("123"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-2"),
					gen.SetCertificateRequestRevision("hello"),
				),
			},
			limit: 1,
			exp:   []revision{},
		},
		"multiple requests with some with good revsions should return list in order": {
			input: []*cmapi.CertificateRequest{
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-1"),
					gen.SetCertificateRequestRevision("123"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-2"),
					gen.SetCertificateRequestRevision("hello"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-3"),
					gen.SetCertificateRequestRevision("3"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-4"),
					gen.SetCertificateRequestRevision("cert-manager"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-5"),
					gen.SetCertificateRequestRevision("900"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-6"),
					gen.SetCertificateRequestRevision("1"),
				),
			},
			limit: 1,
			exp: []revision{
				{
					1,
					types.NamespacedName{
						Namespace: gen.DefaultTestNamespace,
						Name:      "cr-6",
					},
				},
				{
					3,
					types.NamespacedName{
						Namespace: gen.DefaultTestNamespace,
						Name:      "cr-3",
					},
				},
				{
					123,
					types.NamespacedName{
						Namespace: gen.DefaultTestNamespace,
						Name:      "cr-1",
					},
				},
			},
		},
		"multiple requests with some with good revsions but less than the limit, should return list in order under limit": {
			input: []*cmapi.CertificateRequest{
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-1"),
					gen.SetCertificateRequestRevision("123"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-2"),
					gen.SetCertificateRequestRevision("hello"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-3"),
					gen.SetCertificateRequestRevision("3"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-4"),
					gen.SetCertificateRequestRevision("cert-manager"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-5"),
					gen.SetCertificateRequestRevision("900"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-6"),
					gen.SetCertificateRequestRevision("1"),
				),
			},
			limit: 3,
			exp: []revision{
				{
					1,
					types.NamespacedName{
						Namespace: gen.DefaultTestNamespace,
						Name:      "cr-6",
					},
				},
			},
		},
	}

	for name, test := range tests {
		t.Run(name, func(t *testing.T) {
			log := logtest.TestLogger{T: t}
			output := certificateRequestsToDelete(log, test.limit, test.input)
			if !reflect.DeepEqual(test.exp, output) {
				t.Errorf("unexpected prune sort response, exp=%v got=%v",
					test.exp, output)
			}
		})
	}
}
<commit_msg>gosimple: S1011<commit_after>/*
Copyright 2021 The cert-manager Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package revisionmanager

import (
	"context"
	"reflect"
	"testing"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/types"
	coretesting "k8s.io/client-go/testing"

	cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1"
	cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1"
	controllerpkg "github.com/jetstack/cert-manager/pkg/controller"
	testpkg "github.com/jetstack/cert-manager/pkg/controller/test"
	logtest "github.com/jetstack/cert-manager/pkg/logs/testing"
	"github.com/jetstack/cert-manager/test/unit/gen"
)

func TestProcessItem(t *testing.T) {
	baseCrt := gen.Certificate("test-cert",
		gen.SetCertificateNamespace("testns"),
		gen.SetCertificateUID("uid-1"),
	)
	baseCRNoOwner := gen.CertificateRequest("test-cr",
		gen.SetCertificateRequestNamespace("testns"),
	)
	baseCR := gen.CertificateRequestFrom(baseCRNoOwner,
		gen.AddCertificateRequestOwnerReferences(*metav1.NewControllerRef(
			baseCrt, cmapi.SchemeGroupVersion.WithKind("Certificate")),
		),
	)

	tests := map[string]struct {
		// key that should be passed to ProcessItem.
		// if not set, the 'namespace/name' of the 'Certificate' field will be used.
		// if neither is set, the key will be ""
		key string

		// Certificate to be synced for the test.
		// if not set, the 'key' will be passed to ProcessItem instead.
		certificate *cmapi.Certificate

		// Request, if set, will exist in the apiserver before the test is run.
		requests []runtime.Object

		expectedActions []testpkg.Action

		// err is the expected error text returned by the controller, if any.
		err string
	}{
		"do nothing if an empty 'key' is used": {},
		"do nothing if an invalid 'key' is used": {
			key: "abc/def/ghi",
		},
		"do nothing if a key references a Certificate that does not exist": {
			key: "namespace/name",
		},
		"do nothing if Certificate is not in a Ready=True state": {
			certificate: gen.CertificateFrom(baseCrt,
				gen.SetCertificateStatusCondition(cmapi.CertificateCondition{Type: cmapi.CertificateConditionIssuing, Status: cmmeta.ConditionFalse}),
				gen.SetCertificateRevisionHistoryLimit(1),
			),
			requests: []runtime.Object{
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-1"),
					gen.SetCertificateRequestRevision("1"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("2"),
				),
			},
		},
		"do nothing if no requests exist": {
			certificate: gen.CertificateFrom(baseCrt,
				gen.SetCertificateStatusCondition(cmapi.CertificateCondition{Type: cmapi.CertificateConditionReady, Status: cmmeta.ConditionTrue}),
				gen.SetCertificateRevisionHistoryLimit(1),
			),
		},
		"do nothing if requests don't have or bad revisions set": {
			certificate: gen.CertificateFrom(baseCrt,
				gen.SetCertificateStatusCondition(cmapi.CertificateCondition{Type: cmapi.CertificateConditionReady, Status: cmmeta.ConditionTrue}),
				gen.SetCertificateRevisionHistoryLimit(1),
			),
			requests: []runtime.Object{
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-1"),
					gen.SetCertificateRequestRevision("abc"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-2"),
				),
			},
		},
		"do nothing if requests aren't owned by this Certificate": {
			certificate: gen.CertificateFrom(baseCrt,
				gen.SetCertificateStatusCondition(cmapi.CertificateCondition{Type: cmapi.CertificateConditionReady, Status: cmmeta.ConditionTrue}),
				gen.SetCertificateRevisionHistoryLimit(1),
			),
			requests: []runtime.Object{
				gen.CertificateRequestFrom(baseCRNoOwner,
					gen.SetCertificateRequestName("cr-1"),
					gen.SetCertificateRequestRevision("1"),
				),
				gen.CertificateRequestFrom(baseCRNoOwner,
					gen.SetCertificateRequestName("cr-2"),
					gen.SetCertificateRequestRevision("2"),
				),
			},
		},
		"do nothing if number of revisions matches that of the limit": {
			certificate: gen.CertificateFrom(baseCrt,
				gen.SetCertificateStatusCondition(cmapi.CertificateCondition{Type: cmapi.CertificateConditionReady, Status: cmmeta.ConditionTrue}),
				gen.SetCertificateRevisionHistoryLimit(2),
			),
			requests: []runtime.Object{
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-1"),
					gen.SetCertificateRequestRevision("1"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-2"),
					gen.SetCertificateRequestRevision("2"),
				),
			},
		},
		"do nothing if revision limit is not set": {
			certificate: gen.CertificateFrom(baseCrt,
				gen.SetCertificateStatusCondition(cmapi.CertificateCondition{Type: cmapi.CertificateConditionReady, Status: cmmeta.ConditionTrue}),
			),
			requests: []runtime.Object{
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-1"),
					gen.SetCertificateRequestRevision("1"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-2"),
					gen.SetCertificateRequestRevision("2"),
				),
			},
		},
		"delete 1 request if limit is 1 and 2 requests exist": {
			certificate: gen.CertificateFrom(baseCrt,
				gen.SetCertificateStatusCondition(cmapi.CertificateCondition{Type: cmapi.CertificateConditionReady, Status: cmmeta.ConditionTrue}),
				gen.SetCertificateRevisionHistoryLimit(1),
			),
			requests: []runtime.Object{
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-2"),
					gen.SetCertificateRequestRevision("2"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-1"),
					gen.SetCertificateRequestRevision("1"),
				),
			},
			expectedActions: []testpkg.Action{
				testpkg.NewAction(coretesting.NewDeleteAction(cmapi.SchemeGroupVersion.WithResource("certificaterequests"), "testns", "cr-1")),
			},
		},
		"delete 3 requests if limit is 3 and 6 requests exist": {
			certificate: gen.CertificateFrom(baseCrt,
				gen.SetCertificateStatusCondition(cmapi.CertificateCondition{Type: cmapi.CertificateConditionReady, Status: cmmeta.ConditionTrue}),
				gen.SetCertificateRevisionHistoryLimit(3),
			),
			requests: []runtime.Object{
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-2"),
					gen.SetCertificateRequestRevision("2"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-3"),
					gen.SetCertificateRequestRevision("3"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-1"),
					gen.SetCertificateRequestRevision("1"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-4"),
					gen.SetCertificateRequestRevision("11"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-5"),
					gen.SetCertificateRequestRevision("11"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-6"),
					gen.SetCertificateRequestRevision("2"),
				),
			},
			expectedActions: []testpkg.Action{
				testpkg.NewAction(coretesting.NewDeleteAction(cmapi.SchemeGroupVersion.WithResource("certificaterequests"), "testns", "cr-1")),
				testpkg.NewAction(coretesting.NewDeleteAction(cmapi.SchemeGroupVersion.WithResource("certificaterequests"), "testns", "cr-2")),
				testpkg.NewAction(coretesting.NewDeleteAction(cmapi.SchemeGroupVersion.WithResource("certificaterequests"), "testns", "cr-6")),
			},
		},
	}
	for name, test := range tests {
		t.Run(name, func(t *testing.T) {
			// Create and initialise a new unit test builder
			builder := &testpkg.Builder{
				T:               t,
				ExpectedEvents:  nil,
				ExpectedActions: test.expectedActions,
				StringGenerator: func(i int) string { return "notrandom" },
			}
			if test.certificate != nil {
				builder.CertManagerObjects = append(builder.CertManagerObjects, test.certificate)
			}
			builder.CertManagerObjects = append(builder.CertManagerObjects, test.requests...)
			builder.Init()

			// Register informers used by the controller using the registration wrapper
			w := &controllerWrapper{}
			_, _, err := w.Register(builder.Context)
			if err != nil {
				t.Fatal(err)
			}
			// Start the informers and begin processing updates
			builder.Start()
			defer builder.Stop()

			key := test.key
			if key == "" && test.certificate != nil {
				key, err = controllerpkg.KeyFunc(test.certificate)
				if err != nil {
					t.Fatal(err)
				}
			}

			// Call ProcessItem
			err = w.controller.ProcessItem(context.Background(), key)
			switch {
			case err != nil:
				if test.err != err.Error() {
					t.Errorf("error text did not match, got=%s, exp=%s", err.Error(), test.err)
				}
			default:
				if test.err != "" {
					t.Errorf("got no error but expected: %s", test.err)
				}
			}

			if err := builder.AllEventsCalled(); err != nil {
				builder.T.Error(err)
			}
			if err := builder.AllActionsExecuted(); err != nil {
				builder.T.Error(err)
			}
			if err := builder.AllReactorsCalled(); err != nil {
				builder.T.Error(err)
			}
		})
	}
}

func TestCertificateRequestsToDelete(t *testing.T) {
	baseCR := gen.CertificateRequest("test")

	tests := map[string]struct {
		input []*cmapi.CertificateRequest
		limit int
		exp   []revision
	}{
		"an empty list of request should return empty": {
			input: nil,
			limit: 3,
			exp:   nil,
		},
		"a single request with no revision set should return empty": {
			input: []*cmapi.CertificateRequest{
				baseCR,
			},
			limit: 3,
			exp:   nil,
		},
		"a single request with revision set but higher limit should return no requests": {
			input: []*cmapi.CertificateRequest{
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestRevision("123"),
				),
			},
			limit: 3,
			exp:   nil,
		},
		"two requests with one badly formed revision but limit set to 1 should return no requests": {
			input: []*cmapi.CertificateRequest{
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-1"),
					gen.SetCertificateRequestRevision("123"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-2"),
					gen.SetCertificateRequestRevision("hello"),
				),
			},
			limit: 1,
			exp:   []revision{},
		},
		"multiple requests with some with good revsions should return list in order": {
			input: []*cmapi.CertificateRequest{
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-1"),
					gen.SetCertificateRequestRevision("123"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-2"),
					gen.SetCertificateRequestRevision("hello"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-3"),
					gen.SetCertificateRequestRevision("3"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-4"),
					gen.SetCertificateRequestRevision("cert-manager"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-5"),
					gen.SetCertificateRequestRevision("900"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-6"),
					gen.SetCertificateRequestRevision("1"),
				),
			},
			limit: 1,
			exp: []revision{
				{
					1,
					types.NamespacedName{
						Namespace: gen.DefaultTestNamespace,
						Name:      "cr-6",
					},
				},
				{
					3,
					types.NamespacedName{
						Namespace: gen.DefaultTestNamespace,
						Name:      "cr-3",
					},
				},
				{
					123,
					types.NamespacedName{
						Namespace: gen.DefaultTestNamespace,
						Name:      "cr-1",
					},
				},
			},
		},
		"multiple requests with some with good revsions but less than the limit, should return list in order under limit": {
			input: []*cmapi.CertificateRequest{
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-1"),
					gen.SetCertificateRequestRevision("123"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-2"),
					gen.SetCertificateRequestRevision("hello"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-3"),
					gen.SetCertificateRequestRevision("3"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-4"),
					gen.SetCertificateRequestRevision("cert-manager"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-5"),
					gen.SetCertificateRequestRevision("900"),
				),
				gen.CertificateRequestFrom(baseCR,
					gen.SetCertificateRequestName("cr-6"),
					gen.SetCertificateRequestRevision("1"),
				),
			},
			limit: 3,
			exp: []revision{
				{
					1,
					types.NamespacedName{
						Namespace: gen.DefaultTestNamespace,
						Name:      "cr-6",
					},
				},
			},
		},
	}

	for name, test := range tests {
		t.Run(name, func(t *testing.T) {
			log := logtest.TestLogger{T: t}
			output := certificateRequestsToDelete(log, test.limit, test.input)
			if !reflect.DeepEqual(test.exp, output) {
				t.Errorf("unexpected prune sort response, exp=%v got=%v",
					test.exp, output)
			}
		})
	}
}
<|endoftext|>


<commit_before>package git_test

import (
	"bytes"
	"fmt"
	"os"
	"path"
	"path/filepath"
	"runtime"
	"strconv"

	"github.com/alessio/shellescape"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/ginkgo/extensions/table"
	. "github.com/onsi/gomega"

	"github.com/werf/werf/integration/utils"
	"github.com/werf/werf/integration/utils/docker"
)

var _ = Describe("file lifecycle", func() {
	var fixturesPathParts []string
	gitToPath := "/app"

	fileDataToAdd := []byte("test")
	fileDataToModify := []byte("test2")

	gitExecutableFilePerm := os.FileMode(0755)
	gitOrdinaryFilePerm := os.FileMode(0644)

	type fileLifecycleEntry struct {
		relPath       string
		data          []byte
		perm          os.FileMode
		delete        bool
		devMode       bool
		skipOnWindows bool
	}

	createFileFunc := func(fileName string, fileData []byte, filePerm os.FileMode) {
		filePath := filepath.Join(testDirPath, fileName)
		utils.CreateFile(filePath, fileData)

		if runtime.GOOS == "windows" {
			gitArgs := []string{"add"}
			if filePerm == gitExecutableFilePerm {
				gitArgs = append(gitArgs, "--chmod=+x")
			} else {
				gitArgs = append(gitArgs, "--chmod=-x")
			}
			gitArgs = append(gitArgs, fileName)

			utils.RunSucceedCommand(
				testDirPath,
				"git",
				gitArgs...,
			)
		} else {
			Ω(os.Chmod(filePath, filePerm)).Should(Succeed())
		}
	}

	fileLifecycleEntryItBody := func(entry fileLifecycleEntry) {
		if entry.skipOnWindows {
			Skip("skip on windows")
		}

		var commitMsg string
		filePath := filepath.Join(testDirPath, entry.relPath)
		if entry.delete {
			Ω(os.Remove(filePath)).Should(Succeed())
			commitMsg = "Delete file " + entry.relPath
		} else {
			createFileFunc(entry.relPath, entry.data, entry.perm)
			commitMsg = "Add/Modify file " + entry.relPath
		}

		if entry.devMode {
			stubs.SetEnv("WERF_DEV", "1")
			addFile(testDirPath, entry.relPath)
		} else {
			addAndCommitFile(testDirPath, entry.relPath, commitMsg)
		}

		utils.RunSucceedCommand(
			testDirPath,
			werfBinPath,
			"build",
		)

		var cmd []string
		var extraDockerOptions []string
		if entry.delete {
			cmd = append(cmd, docker.CheckContainerFileCommand(path.Join(gitToPath, entry.relPath), false, false))
		} else {
			cmd = append(cmd, docker.CheckContainerFileCommand(path.Join(gitToPath, entry.relPath), false, true))
			cmd = append(cmd, fmt.Sprintf("diff <(stat -c %%a %s) <(echo %s)", shellescape.Quote(path.Join(gitToPath, entry.relPath)), strconv.FormatUint(uint64(entry.perm), 8)))
			cmd = append(cmd, fmt.Sprintf("diff %s %s", shellescape.Quote(path.Join(gitToPath, entry.relPath)), shellescape.Quote(path.Join("/host", entry.relPath))))

			extraDockerOptions = append(extraDockerOptions, fmt.Sprintf("-v %s:%s", testDirPath, "/host"))
		}

		docker.RunSucceedContainerCommandWithStapel(
			werfBinPath,
			testDirPath,
			extraDockerOptions,
			cmd,
		)
	}

	BeforeEach(func() {
		fixturesPathParts = []string{"file_lifecycle"}
		commonBeforeEach(testDirPath, utils.FixturePath(fixturesPathParts...))
	})

	type test struct {
		relPathToAdd          string
		relPathToAddAndModify string
	}

	tests := []test{
		{
			"test",
			"test2",
		},
		{
			"dir/test",
			"dir/test2",
		},
	}

	if runtime.GOOS == "windows" {
		tests = append(tests, []test{
			{
				"普 通 话",
				"华语",
			},
			{
				"普 通 话/华语",
				"普 通 话/华语 2",
			},
		}...)
	} else {
		tests = append(tests, []test{
			{
				"file with !%s $chars один! два 'три' & ? .",
				"file with !%s $chars один! два 'три' & ? .. 2",
			},
			{
				"d i r/file with !%s $chars один! два 'три' & ? .",
				"d i r/file with !%s $chars один! два 'три' & ? .. 2",
			},
		}...)
	}

	for _, t := range tests {
		relPathToAdd := t.relPathToAdd
		relPathToAddAndModify := t.relPathToAddAndModify

		pathLogFunc := func(path string) string {
			return fmt.Sprintf(" (%s)", path)
		}

		forNormalAndDevMode(func(extraDescription string, devMode bool) {
			DescribeTable("processing file with archive apply"+extraDescription+pathLogFunc(relPathToAdd),
				fileLifecycleEntryItBody,
				Entry("should add file (0755)", fileLifecycleEntry{
					relPath:       relPathToAdd,
					data:          fileDataToAdd,
					perm:          gitExecutableFilePerm,
					devMode:       devMode,
					skipOnWindows: devMode,
				}),
				Entry("should add file (0644)", fileLifecycleEntry{
					relPath: relPathToAdd,
					data:    fileDataToAdd,
					perm:    gitOrdinaryFilePerm,
					devMode: devMode,
				}),
			)

			When("gitArchive stage with file is built"+extraDescription+pathLogFunc(relPathToAdd), func() {
				BeforeEach(func() {
					createFileFunc(relPathToAddAndModify, fileDataToAdd, gitExecutableFilePerm)
					addAndCommitFile(testDirPath, relPathToAddAndModify, "Add file "+relPathToAddAndModify)

					utils.RunSucceedCommand(
						testDirPath,
						werfBinPath,
						"build",
					)
				})

				DescribeTable("processing file with patch apply"+extraDescription,
					fileLifecycleEntryItBody,
					Entry("should add file (0755)", fileLifecycleEntry{
						relPath:       relPathToAdd,
						data:          fileDataToAdd,
						perm:          gitExecutableFilePerm,
						devMode:       devMode,
						skipOnWindows: devMode,
					}),
					Entry("should add file (0644)", fileLifecycleEntry{
						relPath: relPathToAdd,
						data:    fileDataToAdd,
						perm:    gitOrdinaryFilePerm,
						devMode: devMode,
					}),
					Entry("should modify file", fileLifecycleEntry{
						relPath: relPathToAddAndModify,
						data:    fileDataToModify,
						perm:    gitExecutableFilePerm,
						devMode: devMode,
					}),
					Entry("should change file permission (0755->0644)", fileLifecycleEntry{
						relPath:       relPathToAddAndModify,
						data:          fileDataToAdd,
						perm:          gitOrdinaryFilePerm,
						devMode:       devMode,
						skipOnWindows: devMode,
					}),
					Entry("should modify and change file permission (0755->0644)", fileLifecycleEntry{
						relPath:       relPathToAddAndModify,
						data:          fileDataToModify,
						perm:          gitOrdinaryFilePerm,
						devMode:       devMode,
						skipOnWindows: devMode,
					}),
					Entry("should delete file", fileLifecycleEntry{
						relPath: relPathToAddAndModify,
						delete:  true,
						devMode: devMode,
					}),
				)
			})

			When("file is symlink"+extraDescription+pathLogFunc(relPathToAdd), func() {
				linkToAdd := "werf.yaml"
				linkToModify := "none"

				type symlinkFileLifecycleEntry struct {
					relPath       string
					link          string
					delete        bool
					devMode       bool
					skipOnWindows bool
				}

				symlinkFileLifecycleEntryItBody := func(entry symlinkFileLifecycleEntry) {
					if entry.skipOnWindows {
						Skip("skip on windows")
					}

					var commitMsg string
					filePath := filepath.Join(testDirPath, entry.relPath)
					if entry.delete {
						Ω(os.Remove(filePath)).Should(Succeed())
						commitMsg = "Delete file " + entry.relPath
					} else {
						hashBytes, _ := utils.RunCommandWithOptions(
							testDirPath,
							"git",
							[]string{"hash-object", "-w", "--stdin"},
							utils.RunCommandOptions{
								ToStdin:       entry.link,
								ShouldSucceed: true,
							},
						)

						utils.RunSucceedCommand(
							testDirPath,
							"git",
							"update-index", "--add", "--cacheinfo", "120000", string(bytes.TrimSpace(hashBytes)), entry.relPath,
						)

						utils.RunSucceedCommand(
							testDirPath,
							"git",
							"checkout", entry.relPath,
						)

						commitMsg = "Add/Modify file " + entry.relPath
					}

					if entry.devMode {
						stubs.SetEnv("WERF_DEV", "1")
						addFile(testDirPath, entry.relPath)
					} else {
						addAndCommitFile(testDirPath, entry.relPath, commitMsg)
					}

					utils.RunSucceedCommand(
						testDirPath,
						werfBinPath,
						"build",
					)

					var cmd []string
					if entry.delete {
						cmd = append(cmd, checkContainerSymlinkFileCommand(path.Join(gitToPath, entry.relPath), false))
					} else {
						cmd = append(cmd, checkContainerSymlinkFileCommand(path.Join(gitToPath, entry.relPath), true))
						readlinkCmd := fmt.Sprintf("readlink %s", shellescape.Quote(path.Join(gitToPath, entry.relPath)))
						cmd = append(cmd, fmt.Sprintf("diff <(%s) <(echo %s)", readlinkCmd, shellescape.Quote(entry.link)))
					}

					docker.RunSucceedContainerCommandWithStapel(
						werfBinPath,
						testDirPath,
						[]string{},
						cmd,
					)
				}

				DescribeTable("processing symlink file with archive apply"+extraDescription,
					symlinkFileLifecycleEntryItBody,
					Entry("should add symlink", symlinkFileLifecycleEntry{
						relPath:       relPathToAdd,
						link:          linkToAdd,
						devMode:       devMode,
						skipOnWindows: devMode,
					}),
				)

				When("gitArchive stage with file is built"+extraDescription, func() {
					BeforeEach(func() {
						symlinkFileLifecycleEntryItBody(symlinkFileLifecycleEntry{
							relPath: relPathToAddAndModify,
							link:    linkToAdd,
						})
					})

					DescribeTable("processing symlink file with patch apply"+extraDescription,
						symlinkFileLifecycleEntryItBody,
						Entry("should add symlink", symlinkFileLifecycleEntry{
							relPath:       relPathToAdd,
							link:          linkToAdd,
							devMode:       devMode,
							skipOnWindows: devMode,
						}),
						Entry("should modify file", symlinkFileLifecycleEntry{
							relPath:       relPathToAddAndModify,
							link:          linkToModify,
							devMode:       devMode,
							skipOnWindows: devMode,
						}),
						Entry("should delete file", symlinkFileLifecycleEntry{
							relPath:       relPathToAddAndModify,
							delete:        true,
							devMode:       devMode,
							skipOnWindows: devMode,
						}))
				})
			})
		})
	}
})

func forNormalAndDevMode(f func(string, bool)) {
	for _, devMode := range []bool{false, true} {
		var extraDescription string
		if devMode {
			extraDescription = " in developer mode"
		}

		f(extraDescription, devMode)
	}
}

func checkContainerSymlinkFileCommand(containerDirPath string, exist bool) string {
	var cmd string

	if exist {
		cmd = fmt.Sprintf("test -h %s", shellescape.Quote(containerDirPath))
	} else {
		cmd = fmt.Sprintf("! test -h %s", shellescape.Quote(containerDirPath))
	}

	return cmd
}
<commit_msg>[tests] Build/Stapel/Git: active developer mode tests<commit_after>package git_test

import (
	"bytes"
	"fmt"
	"os"
	"path"
	"path/filepath"
	"runtime"
	"strconv"

	"github.com/alessio/shellescape"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/ginkgo/extensions/table"
	. "github.com/onsi/gomega"

	"github.com/werf/werf/integration/utils"
	"github.com/werf/werf/integration/utils/docker"
)

var _ = Describe("file lifecycle", func() {
	var fixturesPathParts []string
	gitToPath := "/app"

	fileDataToAdd := []byte("test")
	fileDataToModify := []byte("test2")

	gitExecutableFilePerm := os.FileMode(0755)
	gitOrdinaryFilePerm := os.FileMode(0644)

	type fileLifecycleEntry struct {
		relPath string
		data    []byte
		perm    os.FileMode
		delete  bool
		devMode bool
	}

	createFileFunc := func(fileName string, fileData []byte, filePerm os.FileMode) {
		filePath := filepath.Join(testDirPath, fileName)
		utils.CreateFile(filePath, fileData)

		if runtime.GOOS == "windows" {
			gitArgs := []string{"add"}
			if filePerm == gitExecutableFilePerm {
				gitArgs = append(gitArgs, "--chmod=+x")
			} else {
				gitArgs = append(gitArgs, "--chmod=-x")
			}
			gitArgs = append(gitArgs, fileName)

			utils.RunSucceedCommand(
				testDirPath,
				"git",
				gitArgs...,
			)
		} else {
			Ω(os.Chmod(filePath, filePerm)).Should(Succeed())
		}
	}

	fileLifecycleEntryItBody := func(entry fileLifecycleEntry) {
		var commitMsg string
		filePath := filepath.Join(testDirPath, entry.relPath)
		if entry.delete {
			Ω(os.Remove(filePath)).Should(Succeed())
			commitMsg = "Delete file " + entry.relPath
		} else {
			createFileFunc(entry.relPath, entry.data, entry.perm)
			commitMsg = "Add/Modify file " + entry.relPath
		}

		if entry.devMode {
			stubs.SetEnv("WERF_DEV", "1")
			addFile(testDirPath, entry.relPath)
		} else {
			addAndCommitFile(testDirPath, entry.relPath, commitMsg)
		}

		utils.RunSucceedCommand(
			testDirPath,
			werfBinPath,
			"build",
		)

		var cmd []string
		var extraDockerOptions []string
		if entry.delete {
			cmd = append(cmd, docker.CheckContainerFileCommand(path.Join(gitToPath, entry.relPath), false, false))
		} else {
			cmd = append(cmd, docker.CheckContainerFileCommand(path.Join(gitToPath, entry.relPath), false, true))
			cmd = append(cmd, fmt.Sprintf("diff <(stat -c %%a %s) <(echo %s)", shellescape.Quote(path.Join(gitToPath, entry.relPath)), strconv.FormatUint(uint64(entry.perm), 8)))
			cmd = append(cmd, fmt.Sprintf("diff %s %s", shellescape.Quote(path.Join(gitToPath, entry.relPath)), shellescape.Quote(path.Join("/host", entry.relPath))))

			extraDockerOptions = append(extraDockerOptions, fmt.Sprintf("-v %s:%s", testDirPath, "/host"))
		}

		docker.RunSucceedContainerCommandWithStapel(
			werfBinPath,
			testDirPath,
			extraDockerOptions,
			cmd,
		)
	}

	BeforeEach(func() {
		fixturesPathParts = []string{"file_lifecycle"}
		commonBeforeEach(testDirPath, utils.FixturePath(fixturesPathParts...))
	})

	type test struct {
		relPathToAdd          string
		relPathToAddAndModify string
	}

	tests := []test{
		{
			"test",
			"test2",
		},
		{
			"dir/test",
			"dir/test2",
		},
	}

	if runtime.GOOS == "windows" {
		tests = append(tests, []test{
			{
				"普 通 话",
				"华语",
			},
			{
				"普 通 话/华语",
				"普 通 话/华语 2",
			},
		}...)
	} else {
		tests = append(tests, []test{
			{
				"file with !%s $chars один! два 'три' & ? .",
				"file with !%s $chars один! два 'три' & ? .. 2",
			},
			{
				"d i r/file with !%s $chars один! два 'три' & ? .",
				"d i r/file with !%s $chars один! два 'три' & ? .. 2",
			},
		}...)
	}

	for _, t := range tests {
		relPathToAdd := t.relPathToAdd
		relPathToAddAndModify := t.relPathToAddAndModify

		pathLogFunc := func(path string) string {
			return fmt.Sprintf(" (%s)", path)
		}

		forNormalAndDevMode(func(extraDescription string, devMode bool) {
			DescribeTable("processing file with archive apply"+extraDescription+pathLogFunc(relPathToAdd),
				fileLifecycleEntryItBody,
				Entry("should add file (0755)", fileLifecycleEntry{
					relPath: relPathToAdd,
					data:    fileDataToAdd,
					perm:    gitExecutableFilePerm,
					devMode: devMode,
				}),
				Entry("should add file (0644)", fileLifecycleEntry{
					relPath: relPathToAdd,
					data:    fileDataToAdd,
					perm:    gitOrdinaryFilePerm,
					devMode: devMode,
				}),
			)

			When("gitArchive stage with file is built"+extraDescription+pathLogFunc(relPathToAdd), func() {
				BeforeEach(func() {
					createFileFunc(relPathToAddAndModify, fileDataToAdd, gitExecutableFilePerm)
					addAndCommitFile(testDirPath, relPathToAddAndModify, "Add file "+relPathToAddAndModify)

					utils.RunSucceedCommand(
						testDirPath,
						werfBinPath,
						"build",
					)
				})

				DescribeTable("processing file with patch apply"+extraDescription,
					fileLifecycleEntryItBody,
					Entry("should add file (0755)", fileLifecycleEntry{
						relPath: relPathToAdd,
						data:    fileDataToAdd,
						perm:    gitExecutableFilePerm,
						devMode: devMode,
					}),
					Entry("should add file (0644)", fileLifecycleEntry{
						relPath: relPathToAdd,
						data:    fileDataToAdd,
						perm:    gitOrdinaryFilePerm,
						devMode: devMode,
					}),
					Entry("should modify file", fileLifecycleEntry{
						relPath: relPathToAddAndModify,
						data:    fileDataToModify,
						perm:    gitExecutableFilePerm,
						devMode: devMode,
					}),
					Entry("should change file permission (0755->0644)", fileLifecycleEntry{
						relPath: relPathToAddAndModify,
						data:    fileDataToAdd,
						perm:    gitOrdinaryFilePerm,
						devMode: devMode,
					}),
					Entry("should modify and change file permission (0755->0644)", fileLifecycleEntry{
						relPath: relPathToAddAndModify,
						data:    fileDataToModify,
						perm:    gitOrdinaryFilePerm,
						devMode: devMode,
					}),
					Entry("should delete file", fileLifecycleEntry{
						relPath: relPathToAddAndModify,
						delete:  true,
						devMode: devMode,
					}),
				)
			})

			When("file is symlink"+extraDescription+pathLogFunc(relPathToAdd), func() {
				linkToAdd := "werf.yaml"
				linkToModify := "none"

				type symlinkFileLifecycleEntry struct {
					relPath string
					link    string
					delete  bool
					devMode bool
				}

				symlinkFileLifecycleEntryItBody := func(entry symlinkFileLifecycleEntry) {
					var commitMsg string
					filePath := filepath.Join(testDirPath, entry.relPath)
					if entry.delete {
						Ω(os.Remove(filePath)).Should(Succeed())
						commitMsg = "Delete file " + entry.relPath
					} else {
						hashBytes, _ := utils.RunCommandWithOptions(
							testDirPath,
							"git",
							[]string{"hash-object", "-w", "--stdin"},
							utils.RunCommandOptions{
								ToStdin:       entry.link,
								ShouldSucceed: true,
							},
						)

						utils.RunSucceedCommand(
							testDirPath,
							"git",
							"update-index", "--add", "--cacheinfo", "120000", string(bytes.TrimSpace(hashBytes)), entry.relPath,
						)

						utils.RunSucceedCommand(
							testDirPath,
							"git",
							"checkout", entry.relPath,
						)

						commitMsg = "Add/Modify file " + entry.relPath
					}

					if entry.devMode {
						stubs.SetEnv("WERF_DEV", "1")
						addFile(testDirPath, entry.relPath)
					} else {
						addAndCommitFile(testDirPath, entry.relPath, commitMsg)
					}

					utils.RunSucceedCommand(
						testDirPath,
						werfBinPath,
						"build",
					)

					var cmd []string
					if entry.delete {
						cmd = append(cmd, checkContainerSymlinkFileCommand(path.Join(gitToPath, entry.relPath), false))
					} else {
						cmd = append(cmd, checkContainerSymlinkFileCommand(path.Join(gitToPath, entry.relPath), true))
						readlinkCmd := fmt.Sprintf("readlink %s", shellescape.Quote(path.Join(gitToPath, entry.relPath)))
						cmd = append(cmd, fmt.Sprintf("diff <(%s) <(echo %s)", readlinkCmd, shellescape.Quote(entry.link)))
					}

					docker.RunSucceedContainerCommandWithStapel(
						werfBinPath,
						testDirPath,
						[]string{},
						cmd,
					)
				}

				DescribeTable("processing symlink file with archive apply"+extraDescription,
					symlinkFileLifecycleEntryItBody,
					Entry("should add symlink", symlinkFileLifecycleEntry{
						relPath: relPathToAdd,
						link:    linkToAdd,
						devMode: devMode,
					}),
				)

				When("gitArchive stage with file is built"+extraDescription, func() {
					BeforeEach(func() {
						symlinkFileLifecycleEntryItBody(symlinkFileLifecycleEntry{
							relPath: relPathToAddAndModify,
							link:    linkToAdd,
						})
					})

					DescribeTable("processing symlink file with patch apply"+extraDescription,
						symlinkFileLifecycleEntryItBody,
						Entry("should add symlink", symlinkFileLifecycleEntry{
							relPath: relPathToAdd,
							link:    linkToAdd,
							devMode: devMode,
						}),
						Entry("should modify file", symlinkFileLifecycleEntry{
							relPath: relPathToAddAndModify,
							link:    linkToModify,
							devMode: devMode,
						}),
						Entry("should delete file", symlinkFileLifecycleEntry{
							relPath: relPathToAddAndModify,
							delete:  true,
							devMode: devMode,
						}))
				})
			})
		})
	}
})

func forNormalAndDevMode(f func(string, bool)) {
	for _, devMode := range []bool{false, true} {
		var extraDescription string
		if devMode {
			extraDescription = " in developer mode"
		}

		f(extraDescription, devMode)
	}
}

func checkContainerSymlinkFileCommand(containerDirPath string, exist bool) string {
	var cmd string

	if exist {
		cmd = fmt.Sprintf("test -h %s", shellescape.Quote(containerDirPath))
	} else {
		cmd = fmt.Sprintf("! test -h %s", shellescape.Quote(containerDirPath))
	}

	return cmd
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Knative Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package metrics

import (
	"os"
	"testing"

	"github.com/google/go-cmp/cmp"
	corev1 "k8s.io/api/core/v1"

	_ "knative.dev/pkg/system/testing"
)

func TestObservabilityConfiguration(t *testing.T) {
	observabilityConfigTests := []struct {
		name       string
		data       map[string]string
		wantErr    bool
		wantConfig *ObservabilityConfig
	}{{
		name: "observability configuration with all inputs",
		wantConfig: &ObservabilityConfig{
			EnableProbeRequestLog:  true,
			EnableProfiling:        true,
			EnableVarLogCollection: true,
			EnableRequestLog:       true,
			LoggingURLTemplate:     "https://logging.io",
			RequestLogTemplate:     `{"requestMethod": "{{.Request.Method}}"}`,
			RequestMetricsBackend:  "stackdriver",
		},
		data: map[string]string{
			EnableProbeReqLogKey:                          "true",
			"logging.enable-var-log-collection":           "true",
			ReqLogTemplateKey:                             `{"requestMethod": "{{.Request.Method}}"}`,
			"logging.revision-url-template":               "https://logging.io",
			EnableReqLogKey:                               "true",
			"metrics.request-metrics-backend-destination": "stackdriver",
			"profiling.enable":                            "true",
		},
	}, {
		name:       "observability config with no map",
		wantConfig: defaultConfig(),
	}, {
		name:    "invalid request log template",
		wantErr: true,
		data: map[string]string{
			ReqLogTemplateKey: `{{ something }}`,
		},
	}, {
		name: "observability configuration with request log set and template default",
		data: map[string]string{
			EnableProbeReqLogKey:                          "true",
			EnableReqLogKey:                               "true",
			"logging.enable-var-log-collection":           "true",
			"logging.revision-url-template":               "https://logging.io",
			"metrics.request-metrics-backend-destination": "stackdriver",
			"profiling.enable":                            "true",
		},
		wantConfig: &ObservabilityConfig{
			EnableProbeRequestLog:  true,
			EnableProfiling:        true,
			EnableRequestLog:       true,
			EnableVarLogCollection: true,
			LoggingURLTemplate:     "https://logging.io",
			RequestLogTemplate:     DefaultRequestLogTemplate,
			RequestMetricsBackend:  "stackdriver",
		},
	}, {
		name: "observability configuration with request log and template not set",
		wantConfig: &ObservabilityConfig{
			EnableProbeRequestLog:  true,
			EnableProfiling:        true,
			EnableVarLogCollection: true,
			LoggingURLTemplate:     "https://logging.io",
			RequestMetricsBackend:  "stackdriver",
		},
		data: map[string]string{
			EnableProbeReqLogKey:                          "true",
			EnableReqLogKey:                               "false",
			"logging.enable-var-log-collection":           "true",
			ReqLogTemplateKey:                             "",
			"logging.revision-url-template":               "https://logging.io",
			"metrics.request-metrics-backend-destination": "stackdriver",
			"profiling.enable":                            "true",
		},
	}, {
		name:    "observability configuration with request log set and template not set",
		wantErr: true,
		data: map[string]string{
			EnableProbeReqLogKey:                          "true",
			EnableReqLogKey:                               "true",
			"logging.enable-var-log-collection":           "true",
			ReqLogTemplateKey:                             "",
			"logging.revision-url-template":               "https://logging.io",
			"metrics.request-metrics-backend-destination": "stackdriver",
			"profiling.enable":                            "true",
		},
	}, {
		name: "observability configuration with request log not set and with template set",
		wantConfig: &ObservabilityConfig{
			EnableProbeRequestLog:  true,
			EnableProfiling:        true,
			EnableVarLogCollection: true,
			LoggingURLTemplate:     "https://logging.io",
			RequestLogTemplate:     `{"requestMethod": "{{.Request.Method}}"}`,
			RequestMetricsBackend:  "stackdriver",
		},
		data: map[string]string{
			EnableProbeReqLogKey:                          "true",
			"logging.enable-var-log-collection":           "true",
			ReqLogTemplateKey:                             `{"requestMethod": "{{.Request.Method}}"}`,
			"logging.revision-url-template":               "https://logging.io",
			"metrics.request-metrics-backend-destination": "stackdriver",
			"profiling.enable":                            "true",
		},
	}, {
		name: "observability configuration with collector address",
		wantConfig: &ObservabilityConfig{
			LoggingURLTemplate:      DefaultLogURLTemplate,
			RequestLogTemplate:      DefaultRequestLogTemplate,
			RequestMetricsBackend:   "opencensus",
			MetricsCollectorAddress: "otel:55678",
		},
		data: map[string]string{
			"metrics.request-metrics-backend-destination": "opencensus",
			"metrics.opencensus-address":                  "otel:55678",
		},
	}}

	for _, tt := range observabilityConfigTests {
		t.Run(tt.name, func(t *testing.T) {
			obsConfig, err := NewObservabilityConfigFromConfigMap(&corev1.ConfigMap{
				Data: tt.data,
			})

			if (err != nil) != tt.wantErr {
				t.Fatalf("NewObservabilityFromConfigMap() error = %v, WantErr %v", err, tt.wantErr)
			}

			if got, want := obsConfig, tt.wantConfig; !cmp.Equal(got, want) {
				t.Errorf("Got = %v, want: %v, diff(-want,+got)\n%s", got, want, cmp.Diff(want, got))
			}
		})
	}
}

func TestConfigMapName(t *testing.T) {
	if got, want := ConfigMapName(), "config-observability"; got != want {
		t.Errorf("ConfigMapName = %q, want: %q", got, want)
	}
	t.Cleanup(func() {
		os.Unsetenv(configMapNameEnv)
	})
	os.Setenv(configMapNameEnv, "")
	if got, want := ConfigMapName(), "config-observability"; got != want {
		t.Errorf("ConfigMapName = %q, want: %q", got, want)
	}
	os.Setenv(configMapNameEnv, "why-is-living-so-hard?")
	if got, want := ConfigMapName(), "why-is-living-so-hard?"; got != want {
		t.Errorf("ConfigMapName = %q, want: %q", got, want)
	}
}
<commit_msg>Retain the UT improvements from #1898 (#1900)<commit_after>/*
Copyright 2019 The Knative Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package metrics

import (
	"os"
	"testing"

	"github.com/google/go-cmp/cmp"
	corev1 "k8s.io/api/core/v1"

	_ "knative.dev/pkg/system/testing"
)

func TestObservabilityConfiguration(t *testing.T) {
	observabilityConfigTests := []struct {
		name       string
		data       map[string]string
		wantErr    bool
		wantConfig *ObservabilityConfig
	}{{
		name: "observability configuration with all inputs",
		wantConfig: &ObservabilityConfig{
			EnableProbeRequestLog:  true,
			EnableProfiling:        true,
			EnableVarLogCollection: true,
			EnableRequestLog:       true,
			LoggingURLTemplate:     "https://logging.io",
			RequestLogTemplate:     `{"requestMethod": "{{.Request.Method}}"}`,
			RequestMetricsBackend:  "stackdriver",
		},
		data: map[string]string{
			EnableProbeReqLogKey:                          "true",
			"logging.enable-var-log-collection":           "true",
			ReqLogTemplateKey:                             `{"requestMethod": "{{.Request.Method}}"}`,
			"logging.revision-url-template":               "https://logging.io",
			EnableReqLogKey:                               "true",
			"metrics.request-metrics-backend-destination": "stackdriver",
			"profiling.enable":                            "true",
		},
	}, {
		name:       "observability config with no map",
		wantConfig: defaultConfig(),
	}, {
		name:    "invalid request log template",
		wantErr: true,
		data: map[string]string{
			ReqLogTemplateKey: `{{ something }}`,
		},
	}, {
		name: "observability configuration with request log set and template default",
		data: map[string]string{
			EnableProbeReqLogKey:            "true",
			EnableReqLogKey:                 "true",
			"logging.revision-url-template": "https://logging.io",
		},
		wantConfig: func() *ObservabilityConfig {
			oc := defaultConfig()
			oc.EnableProbeRequestLog = true
			oc.EnableRequestLog = true
			oc.LoggingURLTemplate = "https://logging.io"
			return oc
		}(),
	}, {
		name: "observability configuration with request log and template not set",
		wantConfig: func() *ObservabilityConfig {
			oc := defaultConfig()
			oc.RequestLogTemplate = ""
			oc.EnableProbeRequestLog = true
			return oc
		}(),
		data: map[string]string{
			EnableProbeReqLogKey: "true",
			EnableReqLogKey:      "false", // Explicit default.
			ReqLogTemplateKey:    "",
		},
	}, {
		name:    "observability configuration with request log set and template not set",
		wantErr: true,
		data: map[string]string{
			EnableProbeReqLogKey:                "true",
			EnableReqLogKey:                     "true",
			"logging.enable-var-log-collection": "true",
			ReqLogTemplateKey:                   "",
		},
	}, {
		name: "observability configuration with request log not set and with template set",
		wantConfig: func() *ObservabilityConfig {
			oc := defaultConfig()
			oc.EnableProbeRequestLog = true
			oc.EnableVarLogCollection = true
			oc.RequestLogTemplate = `{"requestMethod": "{{.Request.Method}}"}`
			return oc
		}(),
		data: map[string]string{
			EnableProbeReqLogKey:                "true",
			"logging.enable-var-log-collection": "true",
			ReqLogTemplateKey:                   `{"requestMethod": "{{.Request.Method}}"}`,
		},
	}, {
		name: "observability configuration with collector address",
		wantConfig: func() *ObservabilityConfig {
			oc := defaultConfig()
			oc.RequestMetricsBackend = "opencensus"
			oc.MetricsCollectorAddress = "otel:55678"
			return oc
		}(),
		data: map[string]string{
			"metrics.request-metrics-backend-destination": "opencensus",
			"metrics.opencensus-address":                  "otel:55678",
		},
	}}

	for _, tt := range observabilityConfigTests {
		t.Run(tt.name, func(t *testing.T) {
			obsConfig, err := NewObservabilityConfigFromConfigMap(&corev1.ConfigMap{
				Data: tt.data,
			})

			if (err != nil) != tt.wantErr {
				t.Fatalf("NewObservabilityFromConfigMap() error = %v, WantErr %v", err, tt.wantErr)
			}

			if got, want := obsConfig, tt.wantConfig; !cmp.Equal(got, want) {
				t.Errorf("Got = %v, want: %v, diff(-want,+got)\n%s", got, want, cmp.Diff(want, got))
			}
		})
	}
}

func TestConfigMapName(t *testing.T) {
	if got, want := ConfigMapName(), "config-observability"; got != want {
		t.Errorf("ConfigMapName = %q, want: %q", got, want)
	}
	t.Cleanup(func() {
		os.Unsetenv(configMapNameEnv)
	})
	os.Setenv(configMapNameEnv, "")
	if got, want := ConfigMapName(), "config-observability"; got != want {
		t.Errorf("ConfigMapName = %q, want: %q", got, want)
	}
	os.Setenv(configMapNameEnv, "why-is-living-so-hard?")
	if got, want := ConfigMapName(), "why-is-living-so-hard?"; got != want {
		t.Errorf("ConfigMapName = %q, want: %q", got, want)
	}
}
<|endoftext|>