<commit_before>package cmd

import (
	"log"
	"net/http"

	"github.com/danesparza/centralconfig/api"
	"github.com/danesparza/centralconfig/datastores"

	"github.com/gorilla/mux"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

var (
	serverInterface   string
	serverPort        int
	serverUIDirectory string
)

// serveCmd represents the serve command
var serveCmd = &cobra.Command{
	Use:   "serve",
	Short: "Start the config server",
	Long: `Centralconfig provides its own webserver which can serve both the
	API and the UI for the app.`,
	Run: serve,
}

func serve(cmd *cobra.Command, args []string) {

	//	If we have a config file, report it:
	if viper.ConfigFileUsed() != "" {
		log.Println("[INFO] Using config file:", viper.ConfigFileUsed())
	}

	//	Log the datastore information we have:
	logDatastoreInfo()

	//	Create a router and setup our REST endpoints...
	var Router = mux.NewRouter()

	//	Setup our routes
	Router.HandleFunc("/", api.ShowUI)
	Router.HandleFunc("/config/get", api.GetConfig)
	Router.HandleFunc("/config/set", api.SetConfig)
	Router.HandleFunc("/config/remove", api.RemoveConfig)
	Router.HandleFunc("/config/getall", api.GetAllConfig)
	Router.HandleFunc("/config/getallforapp", api.GetAllConfigForApp)
	Router.HandleFunc("/config/init", api.InitStore)
	Router.HandleFunc("/applications/getall", api.GetAllApplications)

	//	If we don't have a UI directory specified...
	if viper.GetString("http.ui-dir") == "" {
		//	Use the static assets file generated with
		//	https://github.com/elazarl/go-bindata-assetfs using the centralconfig-ui from
		//	https://github.com/danesparza/centralconfig-ui.
		//
		//	To generate this file, place the 'ui'
		//	directory under the main centralconfig directory and run the commands:
		//	go-bindata-assetfs.exe -pkg cmd ./ui/...
		//	mv bindata_assetfs.go cmd
		//	go install ./...
		Router.PathPrefix("/ui").Handler(http.StripPrefix("/ui", http.FileServer(assetFS())))
	} else {
		//	Use the supplied directory:
		log.Printf("[INFO] Using UI directory: %s", viper.GetString("http.ui-dir"))
		Router.PathPrefix("/ui").Handler(http.StripPrefix("/ui", http.FileServer(http.Dir(viper.GetString("http.ui-dir")))))
	}

	log.Printf("[INFO] Starting HTTP server: %s:%s", viper.GetString("http.bind"), viper.GetString("http.port"))
	http.ListenAndServe(viper.GetString("http.bind")+":"+viper.GetString("http.port"), Router)
}

func init() {
	RootCmd.AddCommand(serveCmd)

	//	Setup our flags
	serveCmd.Flags().IntVarP(&serverPort, "port", "p", 1313, "port on which the server will listen")
	serveCmd.Flags().StringVarP(&serverInterface, "bind", "i", "127.0.0.1", "interface to which the server will bind")
	serveCmd.Flags().StringVarP(&serverUIDirectory, "ui-dir", "u", "", "directory for the UI")

	//	Bind config flags for optional config file override:
	viper.BindPFlag("http.port", serveCmd.Flags().Lookup("port"))
	viper.BindPFlag("http.bind", serveCmd.Flags().Lookup("bind"))
	viper.BindPFlag("http.ui-dir", serveCmd.Flags().Lookup("ui-dir"))
}

func logDatastoreInfo() {
	//	Get configuration information
	ds := datastores.GetConfigDatastore()

	switch t := ds.(type) {
	case datastores.MySqlDB:
		log.Printf("[INFO] Using MySQL server: %s", ds.(datastores.MySqlDB).Address)
		log.Printf("[INFO] Using MySQL database: %s", ds.(datastores.MySqlDB).Database)
	case datastores.BoltDB:
		log.Printf("[INFO] Using BoltDB database: %s", ds.(datastores.BoltDB).Database)
	default:
		_ = t
		log.Println("[ERROR] Can't determine datastore type")
	}
}
<commit_msg>Bugfix: Determining MSSQL datastore type from config<commit_after>package cmd

import (
	"log"
	"net/http"

	"github.com/danesparza/centralconfig/api"
	"github.com/danesparza/centralconfig/datastores"

	"github.com/gorilla/mux"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

var (
	serverInterface   string
	serverPort        int
	serverUIDirectory string
)

// serveCmd represents the serve command
var serveCmd = &cobra.Command{
	Use:   "serve",
	Short: "Start the config server",
	Long: `Centralconfig provides its own webserver which can serve both the
	API and the UI for the app.`,
	Run: serve,
}

func serve(cmd *cobra.Command, args []string) {

	//	If we have a config file, report it:
	if viper.ConfigFileUsed() != "" {
		log.Println("[INFO] Using config file:", viper.ConfigFileUsed())
	}

	//	Log the datastore information we have:
	logDatastoreInfo()

	//	Create a router and setup our REST endpoints...
	var Router = mux.NewRouter()

	//	Setup our routes
	Router.HandleFunc("/", api.ShowUI)
	Router.HandleFunc("/config/get", api.GetConfig)
	Router.HandleFunc("/config/set", api.SetConfig)
	Router.HandleFunc("/config/remove", api.RemoveConfig)
	Router.HandleFunc("/config/getall", api.GetAllConfig)
	Router.HandleFunc("/config/getallforapp", api.GetAllConfigForApp)
	Router.HandleFunc("/config/init", api.InitStore)
	Router.HandleFunc("/applications/getall", api.GetAllApplications)

	//	If we don't have a UI directory specified...
	if viper.GetString("http.ui-dir") == "" {
		//	Use the static assets file generated with
		//	https://github.com/elazarl/go-bindata-assetfs using the centralconfig-ui from
		//	https://github.com/danesparza/centralconfig-ui.
		//
		//	To generate this file, place the 'ui'
		//	directory under the main centralconfig directory and run the commands:
		//	go-bindata-assetfs.exe -pkg cmd ./ui/...
		//	mv bindata_assetfs.go cmd
		//	go install ./...
		Router.PathPrefix("/ui").Handler(http.StripPrefix("/ui", http.FileServer(assetFS())))
	} else {
		//	Use the supplied directory:
		log.Printf("[INFO] Using UI directory: %s", viper.GetString("http.ui-dir"))
		Router.PathPrefix("/ui").Handler(http.StripPrefix("/ui", http.FileServer(http.Dir(viper.GetString("http.ui-dir")))))
	}

	log.Printf("[INFO] Starting HTTP server: %s:%s", viper.GetString("http.bind"), viper.GetString("http.port"))
	http.ListenAndServe(viper.GetString("http.bind")+":"+viper.GetString("http.port"), Router)
}

func init() {
	RootCmd.AddCommand(serveCmd)

	//	Setup our flags
	serveCmd.Flags().IntVarP(&serverPort, "port", "p", 1313, "port on which the server will listen")
	serveCmd.Flags().StringVarP(&serverInterface, "bind", "i", "127.0.0.1", "interface to which the server will bind")
	serveCmd.Flags().StringVarP(&serverUIDirectory, "ui-dir", "u", "", "directory for the UI")

	//	Bind config flags for optional config file override:
	viper.BindPFlag("http.port", serveCmd.Flags().Lookup("port"))
	viper.BindPFlag("http.bind", serveCmd.Flags().Lookup("bind"))
	viper.BindPFlag("http.ui-dir", serveCmd.Flags().Lookup("ui-dir"))
}

func logDatastoreInfo() {
	//	Get configuration information
	ds := datastores.GetConfigDatastore()

	switch t := ds.(type) {
	case datastores.MySqlDB:
		log.Printf("[INFO] Using MySQL server: %s", ds.(datastores.MySqlDB).Address)
		log.Printf("[INFO] Using MySQL database: %s", ds.(datastores.MySqlDB).Database)
	case datastores.MSSqlDB:
		log.Printf("[INFO] Using MSSQL server: %s", ds.(datastores.MSSqlDB).Address)
		log.Printf("[INFO] Using MSSQL database: %s", ds.(datastores.MSSqlDB).Database)
	case datastores.BoltDB:
		log.Printf("[INFO] Using BoltDB database: %s", ds.(datastores.BoltDB).Database)
	default:
		_ = t
		log.Println("[ERROR] Can't determine datastore type")
	}
}
<|endoftext|>


<commit_before>// Copyright 2014 Richard Lehane. All rights reserved.
//
// 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 main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"sync"
	"time"

	"github.com/richardlehane/siegfried"
	"github.com/richardlehane/siegfried/config"
	"github.com/richardlehane/siegfried/pkg/core/siegreader"

	// Uncomment to build with profiler
	//"net/http"
	//_ "net/http/pprof"
)

const PROCS = -1

// flags
var (
	update   = flag.Bool("update", false, "update or install the default signature file")
	version  = flag.Bool("version", false, "display version information")
	debug    = flag.Bool("debug", false, "scan in debug mode")
	slow     = flag.Bool("slow", false, "scan and report slow signatures")
	nr       = flag.Bool("nr", false, "prevent automatic directory recursion")
	csvo     = flag.Bool("csv", false, "CSV output format")
	jsono    = flag.Bool("json", false, "JSON output format")
	droido   = flag.Bool("droid", false, "DROID CSV output format")
	knowno   = flag.Bool("known", false, "Output list of known files")
	unknowno = flag.Bool("unknown", false, "Output list of unknown files")
	sig      = flag.String("sig", config.SignatureBase(), "set the signature file")
	home     = flag.String("home", config.Home(), "override the default home directory")
	serve    = flag.String("serve", "", "start siegfried server e.g. -serve localhost:5138")
	multi    = flag.Int("multi", 1, "set number of file ID processes")
	archive  = flag.Bool("z", false, "scan archive formats (zip, tar, gzip)")
	hashf    = flag.String("hash", "", "calculate file checksum with hash algorithm; options "+hashChoices)
)

type res struct {
	path string
	sz   int64
	mod  string
	c    iterableID
	err  error
}

func printer(w writer, resc chan chan res, wg *sync.WaitGroup) {
	for rr := range resc {
		r := <-rr
		w.writeFile(r.path, r.sz, r.mod, nil, r.err, r.c)
		wg.Done()
	}
}

func multiIdentifyP(w writer, s *siegfried.Siegfried, r string, norecurse bool) {
	wg := &sync.WaitGroup{}
	runtime.GOMAXPROCS(PROCS)
	resc := make(chan chan res, *multi)
	go printer(w, resc, wg)
	wf := func(path string, info os.FileInfo, err error) error {
		if info.IsDir() {
			if norecurse && path != r {
				return filepath.SkipDir
			}
			if *droido {
				wg.Add(1)
				rchan := make(chan res, 1)
				resc <- rchan
				go func() {
					rchan <- res{path, -1, info.ModTime().String(), nil, nil} // write directory with a -1 size for droid output only
				}()
			}
			return nil
		}
		wg.Add(1)
		rchan := make(chan res, 1)
		resc <- rchan
		go func() {
			f, err := os.Open(path)
			if err != nil {
				rchan <- res{"", 0, "", nil, fmt.Errorf("failed to open %v, got: %v", path, err)}
				return
			}
			c, err := s.Identify(path, f)
			if c == nil {
				f.Close()
				rchan <- res{"", 0, "", nil, fmt.Errorf("failed to identify %v, got: %v", path, err)}
				return
			}
			ids := makeIdSlice(idChan(c))
			cerr := f.Close()
			if err == nil {
				err = cerr
			}
			rchan <- res{path, info.Size(), info.ModTime().Format(time.RFC3339), ids, err}
		}()
		return nil
	}
	filepath.Walk(r, wf)
	wg.Wait()
	close(resc)
}

func multiIdentifyS(w writer, s *siegfried.Siegfried, r string, norecurse bool) error {
	wf := func(path string, info os.FileInfo, err error) error {
		if info.IsDir() {
			if norecurse && path != r {
				return filepath.SkipDir
			}
			if *droido {
				w.writeFile(path, -1, info.ModTime().Format(time.RFC3339), nil, nil, nil) // write directory with a -1 size for droid output only
			}
			return nil
		}
		identifyFile(w, s, path, info.Size(), info.ModTime().Format(time.RFC3339))
		return nil
	}
	return filepath.Walk(r, wf)
}

func identifyFile(w writer, s *siegfried.Siegfried, path string, sz int64, mod string) {
	f, err := os.Open(path)
	if err != nil {
		w.writeFile(path, sz, mod, nil, fmt.Errorf("failed to open %s, got: %v", path, err), nil)
		return
	}
	identifyRdr(w, s, f, path, sz, mod)
	f.Close()
}

func identifyRdr(w writer, s *siegfried.Siegfried, r io.Reader, path string, sz int64, mod string) {
	c, err := s.Identify(path, r)
	if c == nil {
		w.writeFile(path, sz, mod, nil, fmt.Errorf("failed to identify %s, got: %v", path, err), nil)
		return
	}
	var b siegreader.Buffer
	var cs []byte
	if checksum != nil {
		b = s.Buffer()
		checksum.Write(siegreader.Bytes(b)) // ignore error returned here
		cs = checksum.Sum(nil)
		checksum.Reset()
	}
	a := w.writeFile(path, sz, mod, cs, err, idChan(c))
	if !*archive || a == config.None {
		return
	}
	var d decompressor
	if b == nil {
		b = s.Buffer()
	}
	switch a {
	case config.Zip:
		d, err = newZip(siegreader.ReaderFrom(b), path, sz)
	case config.Gzip:
		d, err = newGzip(b, path)
	case config.Tar:
		d, err = newTar(siegreader.ReaderFrom(b), path)
	case config.ARC:
		d, err = newARC(siegreader.ReaderFrom(b), path)
	case config.WARC:
		d, err = newWARC(siegreader.ReaderFrom(b), path)
	}
	if err != nil {
		w.writeFile(path, sz, mod, nil, fmt.Errorf("failed to decompress %s, got: %v", path, err), nil)
		return
	}
	for err = d.next(); err == nil; err = d.next() {
		if *droido {
			for _, v := range d.dirs() {
				w.writeFile(v, -1, "", nil, nil, nil)
			}
		}
		identifyRdr(w, s, d.reader(), d.path(), d.size(), d.mod())
	}
}

func main() {

	flag.Parse()

	/*//UNCOMMENT TO RUN PROFILER
	go func() {
		log.Println(http.ListenAndServe("localhost:6060", nil))
	}()*/

	if *version {
		version := config.Version()
		fmt.Printf("siegfried %d.%d.%d\n", version[0], version[1], version[2])
		s, err := siegfried.Load(config.Signature())
		if err != nil {
			fmt.Println(err)
			return
		}
		fmt.Print(s)
		return
	}

	if *home != config.Home() {
		config.SetHome(*home)
	}

	if *sig != config.SignatureBase() {
		config.SetSignature(*sig)
	}

	if *update {
		msg, err := updateSigs()
		if err != nil {
			log.Fatalf("Error: failed to update signature file, %v", err)
		}
		fmt.Println(msg)
		return
	}

	// during parallel scanning or in server mode, unsafe to access the last read buffer - so can't unzip or hash
	if *multi > 1 || *serve != "" {
		if *archive {
			log.Fatalln("Error: cannot scan archive formats when running in parallel mode")
		}
		if *hashf != "" {
			log.Fatalln("Error: cannot calculate file checksum when running in parallel mode")
		}
	}

	if err := setHash(); err != nil {
		log.Fatal(err)
	}

	if *serve != "" || *fprflag {
		s, err := siegfried.Load(config.Signature())
		if err != nil {
			log.Fatalf("Error: error loading signature file, got: %v", err)
		}
		if *serve != "" {
			log.Printf("Starting server at %s. Use CTRL-C to quit.\n", *serve)
			listen(*serve, s)
			return
		}
		log.Printf("FPR server started at %s. Use CTRL-C to quit.\n", config.Fpr())
		serveFpr(config.Fpr(), s)
		return
	}

	if flag.NArg() != 1 {
		log.Fatalln("Error: expecting a single file or directory argument")
	}

	s, err := siegfried.Load(config.Signature())
	if err != nil {
		log.Fatalf("Error: error loading signature file, got: %v", err)
	}

	var w writer
	switch {
	case *debug:
		config.SetDebug()
		w = debugWriter{}
	case *slow:
		config.SetSlow()
		w = &slowWriter{os.Stdout}
	case *csvo:
		w = newCSV(os.Stdout)
	case *jsono:
		w = newJSON(os.Stdout)
	case *droido:
		w = newDroid(os.Stdout)
	case *knowno:
		w = &knownWriter{true, os.Stdout}
	case *unknowno:
		w = &knownWriter{false, os.Stdout}
	default:
		w = newYAML(os.Stdout)
	}

	// support reading list files from stdin
	if flag.Arg(0) == "-" {
		w.writeHead(s)
		scanner := bufio.NewScanner(os.Stdin)
		for scanner.Scan() {
			info, err := os.Stat(scanner.Text())
			if err != nil || info.IsDir() {
				w.writeFile(scanner.Text(), 0, "", nil, fmt.Errorf("failed to identify %s (in scanning mode, inputs must all be files and not directories), got: %v", scanner.Text(), err), nil)
			} else {
				identifyFile(w, s, scanner.Text(), info.Size(), info.ModTime().Format(time.RFC3339))
			}
		}
		w.writeTail()
		os.Exit(0)
	}

	info, err := os.Stat(flag.Arg(0))
	if err != nil {
		log.Fatalf("Error: error getting info for %v, got: %v", flag.Arg(0), err)
	}

	if info.IsDir() {
		if config.Debug() {
			log.Fatalln("Error: when scanning in debug mode, give a file rather than a directory argument")
		}
		w.writeHead(s)
		if *multi > 16 {
			*multi = 16
		}
		if *multi > 1 {
			multiIdentifyP(w, s, flag.Arg(0), *nr)
		} else {
			multiIdentifyS(w, s, flag.Arg(0), *nr)
		}
		w.writeTail()
		os.Exit(0)
	}

	w.writeHead(s)
	identifyFile(w, s, flag.Arg(0), info.Size(), info.ModTime().Format(time.RFC3339))
	w.writeTail()
	os.Exit(0)
}
<commit_msg>update -z help text<commit_after>// Copyright 2014 Richard Lehane. All rights reserved.
//
// 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 main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"sync"
	"time"

	"github.com/richardlehane/siegfried"
	"github.com/richardlehane/siegfried/config"
	"github.com/richardlehane/siegfried/pkg/core/siegreader"

	// Uncomment to build with profiler
	//"net/http"
	//_ "net/http/pprof"
)

const PROCS = -1

// flags
var (
	update   = flag.Bool("update", false, "update or install the default signature file")
	version  = flag.Bool("version", false, "display version information")
	debug    = flag.Bool("debug", false, "scan in debug mode")
	slow     = flag.Bool("slow", false, "scan and report slow signatures")
	nr       = flag.Bool("nr", false, "prevent automatic directory recursion")
	csvo     = flag.Bool("csv", false, "CSV output format")
	jsono    = flag.Bool("json", false, "JSON output format")
	droido   = flag.Bool("droid", false, "DROID CSV output format")
	knowno   = flag.Bool("known", false, "Output list of known files")
	unknowno = flag.Bool("unknown", false, "Output list of unknown files")
	sig      = flag.String("sig", config.SignatureBase(), "set the signature file")
	home     = flag.String("home", config.Home(), "override the default home directory")
	serve    = flag.String("serve", "", "start siegfried server e.g. -serve localhost:5138")
	multi    = flag.Int("multi", 1, "set number of file ID processes")
	archive  = flag.Bool("z", false, "scan archive formats (zip, tar, gzip, warc, arc)")
	hashf    = flag.String("hash", "", "calculate file checksum with hash algorithm; options "+hashChoices)
)

type res struct {
	path string
	sz   int64
	mod  string
	c    iterableID
	err  error
}

func printer(w writer, resc chan chan res, wg *sync.WaitGroup) {
	for rr := range resc {
		r := <-rr
		w.writeFile(r.path, r.sz, r.mod, nil, r.err, r.c)
		wg.Done()
	}
}

func multiIdentifyP(w writer, s *siegfried.Siegfried, r string, norecurse bool) {
	wg := &sync.WaitGroup{}
	runtime.GOMAXPROCS(PROCS)
	resc := make(chan chan res, *multi)
	go printer(w, resc, wg)
	wf := func(path string, info os.FileInfo, err error) error {
		if info.IsDir() {
			if norecurse && path != r {
				return filepath.SkipDir
			}
			if *droido {
				wg.Add(1)
				rchan := make(chan res, 1)
				resc <- rchan
				go func() {
					rchan <- res{path, -1, info.ModTime().String(), nil, nil} // write directory with a -1 size for droid output only
				}()
			}
			return nil
		}
		wg.Add(1)
		rchan := make(chan res, 1)
		resc <- rchan
		go func() {
			f, err := os.Open(path)
			if err != nil {
				rchan <- res{"", 0, "", nil, fmt.Errorf("failed to open %v, got: %v", path, err)}
				return
			}
			c, err := s.Identify(path, f)
			if c == nil {
				f.Close()
				rchan <- res{"", 0, "", nil, fmt.Errorf("failed to identify %v, got: %v", path, err)}
				return
			}
			ids := makeIdSlice(idChan(c))
			cerr := f.Close()
			if err == nil {
				err = cerr
			}
			rchan <- res{path, info.Size(), info.ModTime().Format(time.RFC3339), ids, err}
		}()
		return nil
	}
	filepath.Walk(r, wf)
	wg.Wait()
	close(resc)
}

func multiIdentifyS(w writer, s *siegfried.Siegfried, r string, norecurse bool) error {
	wf := func(path string, info os.FileInfo, err error) error {
		if info.IsDir() {
			if norecurse && path != r {
				return filepath.SkipDir
			}
			if *droido {
				w.writeFile(path, -1, info.ModTime().Format(time.RFC3339), nil, nil, nil) // write directory with a -1 size for droid output only
			}
			return nil
		}
		identifyFile(w, s, path, info.Size(), info.ModTime().Format(time.RFC3339))
		return nil
	}
	return filepath.Walk(r, wf)
}

func identifyFile(w writer, s *siegfried.Siegfried, path string, sz int64, mod string) {
	f, err := os.Open(path)
	if err != nil {
		w.writeFile(path, sz, mod, nil, fmt.Errorf("failed to open %s, got: %v", path, err), nil)
		return
	}
	identifyRdr(w, s, f, path, sz, mod)
	f.Close()
}

func identifyRdr(w writer, s *siegfried.Siegfried, r io.Reader, path string, sz int64, mod string) {
	c, err := s.Identify(path, r)
	if c == nil {
		w.writeFile(path, sz, mod, nil, fmt.Errorf("failed to identify %s, got: %v", path, err), nil)
		return
	}
	var b siegreader.Buffer
	var cs []byte
	if checksum != nil {
		b = s.Buffer()
		checksum.Write(siegreader.Bytes(b)) // ignore error returned here
		cs = checksum.Sum(nil)
		checksum.Reset()
	}
	a := w.writeFile(path, sz, mod, cs, err, idChan(c))
	if !*archive || a == config.None {
		return
	}
	var d decompressor
	if b == nil {
		b = s.Buffer()
	}
	switch a {
	case config.Zip:
		d, err = newZip(siegreader.ReaderFrom(b), path, sz)
	case config.Gzip:
		d, err = newGzip(b, path)
	case config.Tar:
		d, err = newTar(siegreader.ReaderFrom(b), path)
	case config.ARC:
		d, err = newARC(siegreader.ReaderFrom(b), path)
	case config.WARC:
		d, err = newWARC(siegreader.ReaderFrom(b), path)
	}
	if err != nil {
		w.writeFile(path, sz, mod, nil, fmt.Errorf("failed to decompress %s, got: %v", path, err), nil)
		return
	}
	for err = d.next(); err == nil; err = d.next() {
		if *droido {
			for _, v := range d.dirs() {
				w.writeFile(v, -1, "", nil, nil, nil)
			}
		}
		identifyRdr(w, s, d.reader(), d.path(), d.size(), d.mod())
	}
}

func main() {

	flag.Parse()

	/*//UNCOMMENT TO RUN PROFILER
	go func() {
		log.Println(http.ListenAndServe("localhost:6060", nil))
	}()*/

	if *version {
		version := config.Version()
		fmt.Printf("siegfried %d.%d.%d\n", version[0], version[1], version[2])
		s, err := siegfried.Load(config.Signature())
		if err != nil {
			fmt.Println(err)
			return
		}
		fmt.Print(s)
		return
	}

	if *home != config.Home() {
		config.SetHome(*home)
	}

	if *sig != config.SignatureBase() {
		config.SetSignature(*sig)
	}

	if *update {
		msg, err := updateSigs()
		if err != nil {
			log.Fatalf("Error: failed to update signature file, %v", err)
		}
		fmt.Println(msg)
		return
	}

	// during parallel scanning or in server mode, unsafe to access the last read buffer - so can't unzip or hash
	if *multi > 1 || *serve != "" {
		if *archive {
			log.Fatalln("Error: cannot scan archive formats when running in parallel mode")
		}
		if *hashf != "" {
			log.Fatalln("Error: cannot calculate file checksum when running in parallel mode")
		}
	}

	if err := setHash(); err != nil {
		log.Fatal(err)
	}

	if *serve != "" || *fprflag {
		s, err := siegfried.Load(config.Signature())
		if err != nil {
			log.Fatalf("Error: error loading signature file, got: %v", err)
		}
		if *serve != "" {
			log.Printf("Starting server at %s. Use CTRL-C to quit.\n", *serve)
			listen(*serve, s)
			return
		}
		log.Printf("FPR server started at %s. Use CTRL-C to quit.\n", config.Fpr())
		serveFpr(config.Fpr(), s)
		return
	}

	if flag.NArg() != 1 {
		log.Fatalln("Error: expecting a single file or directory argument")
	}

	s, err := siegfried.Load(config.Signature())
	if err != nil {
		log.Fatalf("Error: error loading signature file, got: %v", err)
	}

	var w writer
	switch {
	case *debug:
		config.SetDebug()
		w = debugWriter{}
	case *slow:
		config.SetSlow()
		w = &slowWriter{os.Stdout}
	case *csvo:
		w = newCSV(os.Stdout)
	case *jsono:
		w = newJSON(os.Stdout)
	case *droido:
		w = newDroid(os.Stdout)
	case *knowno:
		w = &knownWriter{true, os.Stdout}
	case *unknowno:
		w = &knownWriter{false, os.Stdout}
	default:
		w = newYAML(os.Stdout)
	}

	// support reading list files from stdin
	if flag.Arg(0) == "-" {
		w.writeHead(s)
		scanner := bufio.NewScanner(os.Stdin)
		for scanner.Scan() {
			info, err := os.Stat(scanner.Text())
			if err != nil || info.IsDir() {
				w.writeFile(scanner.Text(), 0, "", nil, fmt.Errorf("failed to identify %s (in scanning mode, inputs must all be files and not directories), got: %v", scanner.Text(), err), nil)
			} else {
				identifyFile(w, s, scanner.Text(), info.Size(), info.ModTime().Format(time.RFC3339))
			}
		}
		w.writeTail()
		os.Exit(0)
	}

	info, err := os.Stat(flag.Arg(0))
	if err != nil {
		log.Fatalf("Error: error getting info for %v, got: %v", flag.Arg(0), err)
	}

	if info.IsDir() {
		if config.Debug() {
			log.Fatalln("Error: when scanning in debug mode, give a file rather than a directory argument")
		}
		w.writeHead(s)
		if *multi > 16 {
			*multi = 16
		}
		if *multi > 1 {
			multiIdentifyP(w, s, flag.Arg(0), *nr)
		} else {
			multiIdentifyS(w, s, flag.Arg(0), *nr)
		}
		w.writeTail()
		os.Exit(0)
	}

	w.writeHead(s)
	identifyFile(w, s, flag.Arg(0), info.Size(), info.ModTime().Format(time.RFC3339))
	w.writeTail()
	os.Exit(0)
}
<|endoftext|>


<commit_before>package main

import (
	"os"

	"github.com/urfave/cli"
)

const VERSION = "2.0.0-beta8"

func main() {
	app := cli.NewApp()
	app.Version = VERSION
	app.Usage = "the easiest way to use docker on macOS"
	app.HideHelp = true
	app.UsageText = "dlite <command>"

	app.Commands = []cli.Command{
		daemonCommand,
		setupCommand,
		initCommand,
		cleanupCommand,
		uninstallCommand,
		startCommand,
		stopCommand,
		statusCommand,
		ipCommand,
		sshCommand,
		ttyCommand,
	}

	app.Run(os.Args)
}
<commit_msg>bump version<commit_after>package main

import (
	"os"

	"github.com/urfave/cli"
)

const VERSION = "2.0.0-beta9"

func main() {
	app := cli.NewApp()
	app.Version = VERSION
	app.Usage = "the easiest way to use docker on macOS"
	app.HideHelp = true
	app.UsageText = "dlite <command>"

	app.Commands = []cli.Command{
		daemonCommand,
		setupCommand,
		initCommand,
		cleanupCommand,
		uninstallCommand,
		startCommand,
		stopCommand,
		statusCommand,
		ipCommand,
		sshCommand,
		ttyCommand,
	}

	app.Run(os.Args)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"github.com/go-martini/martini"
	"github.com/gorilla/websocket"
	"github.com/martini-contrib/sessions"
	"log"
	"math/rand"
	"net/http"
	"os"
	"strconv"
	"sync"
	"time"
)

const CLEAR string = "\033[H\033[2J"

const MAX_CONSOLE int = 10000

const (
	WSTerm  = 1
	WSClick = 2
)

type Config struct {
	Secret  string
	Address string
}

type LockingWebsockets struct {
	sync.RWMutex
	byId        map[int64]*websocket.Conn
	consoleToId map[int64][]int64
	currentId   int64
}

var consoleBuffers map[int64]string

var websockets *LockingWebsockets

func (c *LockingWebsockets) deleteWebsocket(id int64) {
	c.Lock()
	defer c.Unlock()
	delete(c.byId, id)
}

func (c *LockingWebsockets) addWebsocket(ws *websocket.Conn) int64 {
	c.Lock()
	defer c.Unlock()
	c.currentId += 1
	retid := c.currentId
	c.byId[retid] = ws
	return retid
}

func main() {
	consoleBuffers = make(map[int64]string)
	websockets = &LockingWebsockets{
		byId:        make(map[int64]*websocket.Conn),
		consoleToId: make(map[int64][]int64),
		currentId:   0,
	}
	consoleReadChannel = make(chan ConsoleChunk)
	go consoleDispatch()
	vzcontrol := ConnectVZControl()
	defer vzcontrol.Close()

	file, _ := os.Open("game_server.cfg")
	decoder := json.NewDecoder(file)
	config := Config{}
	decoder.Decode(&config)

	m := martini.Classic()
	store := sessions.NewCookieStore([]byte(config.Secret))
	m.Use(sessions.Sessions("session", store))

	generating := false
	gr := NewGraph()
	m.Get("/reset/:secret", func(w http.ResponseWriter, r *http.Request, params martini.Params, session sessions.Session) string {
		if params["secret"] != config.Secret {
			return ""
		}
		err := vzcontrol.Reset()
		if err != nil {
			return err.Error()
		}
		generating = false
		gr = NewGraph()
		return "Done"
	})

	m.Get("/gen", func(w http.ResponseWriter, r *http.Request, session sessions.Session) string {
		if generating {
			return "Already generating"
		}
		generating = true
		maxNodes := 5
		maxEdges := 5
		startNodeId := 100

		startNode := Node{Id: NodeId(startNodeId)}
		gr.AddNode(startNode)
		err := vzcontrol.ContainerCreate(int64(startNode.Id))
		err = vzcontrol.ConsoleStart(int64(startNode.Id))

		nodes := make([]Node, 0)
		nodes = append(nodes, startNode)

		steps := 1
		for len(nodes) != 0 && steps < maxNodes {
			node, nodes := nodes[len(nodes)-1], nodes[:len(nodes)-1]

			numEdges := random(1, maxEdges)
			for i := 1; i <= numEdges; i++ {
				targetNode := Node{Id: NodeId(i*steps + startNodeId)}
				if gr.AddNode(targetNode) {
					err = vzcontrol.ContainerCreate(int64(targetNode.Id))
					if err != nil {
						return fmt.Sprintf("Container Create: %d, %d, %d\n%s", targetNode.Id, i*steps, numEdges, err.Error())
					}
					err = vzcontrol.ConsoleStart(int64(targetNode.Id))
					if err != nil {
						return fmt.Sprintf("Console Start: %d\n%s", targetNode.Id, err.Error())
					}
					nodes = append(nodes, targetNode)
					edgeid := int64(i * steps)
					if gr.AddEdge(Edge{Id: EdgeId(edgeid), Head: node.Id, Tail: targetNode.Id}) {
						err = vzcontrol.NetworkCreate(edgeid)
						if err != nil {
							return fmt.Sprintf("Network Create: %d\n%s", edgeid, err.Error())
						}
						err = vzcontrol.NetworkAdd(int64(node.Id), edgeid)
						if err != nil {
							return fmt.Sprintf("Network Add Node: %d, %d\n%s", node.Id, edgeid, err.Error())
						}
						err = vzcontrol.NetworkAdd(int64(targetNode.Id), edgeid)
						if err != nil {
							return fmt.Sprintf("Network Add Target: %d, %d\n%s", targetNode.Id, edgeid, err.Error())
						}
					}
				}

			}
			steps += 1
		}
		return gr.String()
	})

	m.Get("/graph", func(w http.ResponseWriter, r *http.Request, session sessions.Session) string {
		output, err := json.Marshal(gr)
		if err != nil {
			return err.Error()
		}
		return string(output)
	})

	m.Get("/ws", func(w http.ResponseWriter, r *http.Request, session sessions.Session) {
		var currentVm int64 = -1
		ws, err := websocket.Upgrade(w, r, nil, 1024, 1024)
		if _, ok := err.(websocket.HandshakeError); ok {
			http.Error(w, "Not a websocket handshake", 400)
			log.Println(err)
			return
		} else if err != nil {
			log.Println(err)
			return
		}
		defer ws.Close()
		websocketId := websockets.addWebsocket(ws)
		defer websockets.deleteWebsocket(websocketId)
		ws.WriteMessage(websocket.TextMessage, []byte("Welcome to ginux!\r\n"))
		for {
			_, message, err := ws.ReadMessage()
			if err != nil {
				log.Println(err)
				return
			} else {
				msgType := message[0]
				msgData := message[1:len(message)]
				switch msgType {
				case WSTerm:
					if currentVm != -1 {
						vzcontrol.ConsoleWrite(currentVm, msgData)
					}
				case WSClick:
					prevVm := currentVm
					tmp, _ := strconv.Atoi(string(msgData))
					currentVm = int64(tmp)
					websockets.Lock()
					if prevVm != -1 {
						for index, wsId := range websockets.consoleToId[prevVm] {
							if wsId == websocketId {
								websockets.consoleToId[prevVm] = append(websockets.consoleToId[prevVm][:index], websockets.consoleToId[prevVm][index+1:]...)
							}
						}
					}
					websockets.consoleToId[currentVm] = append(websockets.consoleToId[currentVm], websocketId)
					websockets.Unlock()
					ws.WriteMessage(websocket.TextMessage, []byte(CLEAR))
					//ws.WriteMessage(websocket.TextMessage, []byte(fmt.Sprintf("Selected Container %d\r\n", currentVm)))
					ws.WriteMessage(websocket.TextMessage, []byte(consoleBuffers[currentVm]))
				}
			}
		}
	})
	log.Println("Game Server started on", config.Address)
	log.Fatal(http.ListenAndServe(config.Address, m))
}

func random(min, max int) int {
	rand.Seed(time.Now().Unix())
	return rand.Intn(max-min) + min
}

func consoleDispatch() {
	for chunk := range consoleReadChannel {
		if len(consoleBuffers[chunk.Id]) > MAX_CONSOLE {
			consoleBuffers[chunk.Id] = consoleBuffers[chunk.Id][len(string(chunk.Data)):] + string(chunk.Data)
		} else {
			consoleBuffers[chunk.Id] += string(chunk.Data)
		}
		websockets.RLock()
		for _, wsId := range websockets.consoleToId[chunk.Id] {
			if socket, ok := websockets.byId[wsId]; ok {
				socket.WriteMessage(websocket.TextMessage, chunk.Data)
			}
		}
		websockets.RUnlock()
	}
}
<commit_msg>Changed to reset command<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"github.com/go-martini/martini"
	"github.com/gorilla/websocket"
	"github.com/martini-contrib/sessions"
	"log"
	"math/rand"
	"net/http"
	"os"
	"strconv"
	"sync"
	"time"
)

const CLEAR string = "\033[H\033[2J"
const RESET string = "\0033\0143"

const MAX_CONSOLE int = 10000

const (
	WSTerm  = 1
	WSClick = 2
)

type Config struct {
	Secret  string
	Address string
}

type LockingWebsockets struct {
	sync.RWMutex
	byId        map[int64]*websocket.Conn
	consoleToId map[int64][]int64
	currentId   int64
}

var consoleBuffers map[int64]string

var websockets *LockingWebsockets

func (c *LockingWebsockets) deleteWebsocket(id int64) {
	c.Lock()
	defer c.Unlock()
	delete(c.byId, id)
}

func (c *LockingWebsockets) addWebsocket(ws *websocket.Conn) int64 {
	c.Lock()
	defer c.Unlock()
	c.currentId += 1
	retid := c.currentId
	c.byId[retid] = ws
	return retid
}

func main() {
	consoleBuffers = make(map[int64]string)
	websockets = &LockingWebsockets{
		byId:        make(map[int64]*websocket.Conn),
		consoleToId: make(map[int64][]int64),
		currentId:   0,
	}
	consoleReadChannel = make(chan ConsoleChunk)
	go consoleDispatch()
	vzcontrol := ConnectVZControl()
	defer vzcontrol.Close()

	file, _ := os.Open("game_server.cfg")
	decoder := json.NewDecoder(file)
	config := Config{}
	decoder.Decode(&config)

	m := martini.Classic()
	store := sessions.NewCookieStore([]byte(config.Secret))
	m.Use(sessions.Sessions("session", store))

	generating := false
	gr := NewGraph()
	m.Get("/reset/:secret", func(w http.ResponseWriter, r *http.Request, params martini.Params, session sessions.Session) string {
		if params["secret"] != config.Secret {
			return ""
		}
		err := vzcontrol.Reset()
		if err != nil {
			return err.Error()
		}
		generating = false
		gr = NewGraph()
		return "Done"
	})

	m.Get("/gen", func(w http.ResponseWriter, r *http.Request, session sessions.Session) string {
		if generating {
			return "Already generating"
		}
		generating = true
		maxNodes := 5
		maxEdges := 5
		startNodeId := 100

		startNode := Node{Id: NodeId(startNodeId)}
		gr.AddNode(startNode)
		err := vzcontrol.ContainerCreate(int64(startNode.Id))
		err = vzcontrol.ConsoleStart(int64(startNode.Id))

		nodes := make([]Node, 0)
		nodes = append(nodes, startNode)

		steps := 1
		for len(nodes) != 0 && steps < maxNodes {
			node, nodes := nodes[len(nodes)-1], nodes[:len(nodes)-1]

			numEdges := random(1, maxEdges)
			for i := 1; i <= numEdges; i++ {
				targetNode := Node{Id: NodeId(i*steps + startNodeId)}
				if gr.AddNode(targetNode) {
					err = vzcontrol.ContainerCreate(int64(targetNode.Id))
					if err != nil {
						return fmt.Sprintf("Container Create: %d, %d, %d\n%s", targetNode.Id, i*steps, numEdges, err.Error())
					}
					err = vzcontrol.ConsoleStart(int64(targetNode.Id))
					if err != nil {
						return fmt.Sprintf("Console Start: %d\n%s", targetNode.Id, err.Error())
					}
					nodes = append(nodes, targetNode)
					edgeid := int64(i * steps)
					if gr.AddEdge(Edge{Id: EdgeId(edgeid), Head: node.Id, Tail: targetNode.Id}) {
						err = vzcontrol.NetworkCreate(edgeid)
						if err != nil {
							return fmt.Sprintf("Network Create: %d\n%s", edgeid, err.Error())
						}
						err = vzcontrol.NetworkAdd(int64(node.Id), edgeid)
						if err != nil {
							return fmt.Sprintf("Network Add Node: %d, %d\n%s", node.Id, edgeid, err.Error())
						}
						err = vzcontrol.NetworkAdd(int64(targetNode.Id), edgeid)
						if err != nil {
							return fmt.Sprintf("Network Add Target: %d, %d\n%s", targetNode.Id, edgeid, err.Error())
						}
					}
				}

			}
			steps += 1
		}
		return gr.String()
	})

	m.Get("/graph", func(w http.ResponseWriter, r *http.Request, session sessions.Session) string {
		output, err := json.Marshal(gr)
		if err != nil {
			return err.Error()
		}
		return string(output)
	})

	m.Get("/ws", func(w http.ResponseWriter, r *http.Request, session sessions.Session) {
		var currentVm int64 = -1
		ws, err := websocket.Upgrade(w, r, nil, 1024, 1024)
		if _, ok := err.(websocket.HandshakeError); ok {
			http.Error(w, "Not a websocket handshake", 400)
			log.Println(err)
			return
		} else if err != nil {
			log.Println(err)
			return
		}
		defer ws.Close()
		websocketId := websockets.addWebsocket(ws)
		defer websockets.deleteWebsocket(websocketId)
		ws.WriteMessage(websocket.TextMessage, []byte("Welcome to ginux!\r\n"))
		for {
			_, message, err := ws.ReadMessage()
			if err != nil {
				log.Println(err)
				return
			} else {
				msgType := message[0]
				msgData := message[1:len(message)]
				switch msgType {
				case WSTerm:
					if currentVm != -1 {
						vzcontrol.ConsoleWrite(currentVm, msgData)
					}
				case WSClick:
					prevVm := currentVm
					tmp, _ := strconv.Atoi(string(msgData))
					currentVm = int64(tmp)
					websockets.Lock()
					if prevVm != -1 {
						for index, wsId := range websockets.consoleToId[prevVm] {
							if wsId == websocketId {
								websockets.consoleToId[prevVm] = append(websockets.consoleToId[prevVm][:index], websockets.consoleToId[prevVm][index+1:]...)
							}
						}
					}
					websockets.consoleToId[currentVm] = append(websockets.consoleToId[currentVm], websocketId)
					websockets.Unlock()
					ws.WriteMessage(websocket.TextMessage, []byte(RESET))
					//ws.WriteMessage(websocket.TextMessage, []byte(fmt.Sprintf("Selected Container %d\r\n", currentVm)))
					ws.WriteMessage(websocket.TextMessage, []byte(consoleBuffers[currentVm]))
				}
			}
		}
	})
	log.Println("Game Server started on", config.Address)
	log.Fatal(http.ListenAndServe(config.Address, m))
}

func random(min, max int) int {
	rand.Seed(time.Now().Unix())
	return rand.Intn(max-min) + min
}

func consoleDispatch() {
	for chunk := range consoleReadChannel {
		if len(consoleBuffers[chunk.Id]) > MAX_CONSOLE {
			consoleBuffers[chunk.Id] = consoleBuffers[chunk.Id][len(string(chunk.Data)):] + string(chunk.Data)
		} else {
			consoleBuffers[chunk.Id] += string(chunk.Data)
		}
		websockets.RLock()
		for _, wsId := range websockets.consoleToId[chunk.Id] {
			if socket, ok := websockets.byId[wsId]; ok {
				socket.WriteMessage(websocket.TextMessage, chunk.Data)
			}
		}
		websockets.RUnlock()
	}
}
<|endoftext|>


<commit_before>package githook

import (
	"bytes"
	"encoding/json"
	"fmt"
	"strconv"
	"strings"

	"github.com/pachyderm/pachyderm/src/client"
	"github.com/pachyderm/pachyderm/src/client/pps"

	"gopkg.in/go-playground/webhooks.v3"
	"gopkg.in/go-playground/webhooks.v3/github"
)

// GitHookPort specifies the port the server will listen on
const GitHookPort = 999
const apiVersion = "v1"

// gitHookServer serves GetFile requests over HTTP
type gitHookServer struct {
	hook   *github.Webhook
	client *client.APIClient
}

func RunGitHookServer(address string) error {
	fmt.Printf("new in cluster\n")
	c, err := client.NewFromAddress(address)
	fmt.Printf("new in cluster err %v\n", err)
	if err != nil {
		return err
	}
	fmt.Printf("new github hook\n")
	hook := github.New(&github.Config{})
	s := &gitHookServer{
		hook,
		c,
	}
	hook.RegisterEvents(s.HandlePush, github.PushEvent)
	fmt.Printf("running github webhook\n")
	return webhooks.Run(hook, ":"+strconv.Itoa(GitHookPort), fmt.Sprintf("/%v/handle/push", apiVersion))
}

func (s *gitHookServer) findMatchingPipelineInputs(payload github.PushPayload) (inputs []*pps.GithubInput, err error) {
	urls := []string{
		payload.Repository.SSHURL,
		payload.Repository.GitURL,
		payload.Repository.CloneURL,
		payload.Repository.SvnURL,
	}
	var walkInput func(*pps.Input)
	payloadBranch := getBranch(payload.Ref)
	// TODO use this instead:
	//pps.VisitInput(pipelineInfo.Input, func(input *pps.Input) {
	walkInput = func(input *pps.Input) {
		if input.Github != nil {
			for _, url := range urls {
				fmt.Printf("compariny input url (%v) to push event (%v)\n", input.Github.URL, url)
				if input.Github.URL == url && input.Github.Branch == payloadBranch {
					//			repoName = pps.RepoNameFromGithubInfo(input.Github.URL, input.Github.Name)
					inputs = append(inputs, input.Github)
				}
			}
		}
		var inputs []*pps.Input
		if input.Cross != nil {
			inputs = input.Cross
		}
		if input.Union != nil {
			inputs = input.Union
		}
		for _, input := range inputs {
			walkInput(input)
		}
	}
	pipelines, err := s.client.ListPipeline()
	if err != nil {
		return nil, err
	}
	for _, pipelineInfo := range pipelines {
		walkInput(pipelineInfo.Input)
	}
	if len(inputs) == 0 {
		return nil, fmt.Errorf("no pipeline inputs corresponding to github URL (%v) on branch (%v) found, perhaps the github input is not set yet on a pipeline", urls[0], payloadBranch)
	}
	return inputs, nil
}

func (s *gitHookServer) HandlePush(payload interface{}, header webhooks.Header) {
	var err error
	defer func() {
		// Handle any return error
		if err != nil {
			//TODO: This should probably be a logger of some sort
			// so that we emit the error in the right format for a log parser
			fmt.Printf("Github Webhook failed to handle push with error: %v\n", err)
		}
	}()

	pl := payload.(github.PushPayload)
	fmt.Printf("push payload: %v\n", pl)

	raw, err := json.Marshal(pl)
	if err != nil {
		err = fmt.Errorf("error marshalling payload (%v): %v", pl, err)
		return
	}
	githubInputs, err := s.findMatchingPipelineInputs(pl)
	if err != nil {
		return
	}
	for _, input := range githubInputs {
		repoName := pps.RepoNameFromGithubInfo(input.URL, input.Name)
		fmt.Printf("got repo: %v\n", repoName)
		commit, err := s.client.StartCommit(repoName, input.Branch)
		if err != nil {
			fmt.Printf("error starting commit on repo %v: %v\n", repoName, err)
			return
		}
		func() {
			defer func() {
				// Handle any return error
				if err != nil {
					//TODO: This should probably be a logger of some sort
					// so that we emit the error in the right format for a log parser
					fmt.Printf("Github Webhook failed to handle push with error: %v\n", err)
				}
			}()
			defer func() {
				if err != nil {
					err = s.client.DeleteCommit(repoName, commit.ID)
					return
				}
				err = s.client.FinishCommit(repoName, commit.ID)
				//Final deferred function deals w non nil error
			}()
			_, err = s.client.PutFile(repoName, commit.ID, "commit.json", bytes.NewReader(raw))
			if err != nil {
				return
			}
		}()
	}
}

func getBranch(fullRef string) string {
	// e.g. 'refs/heads/master'
	tokens := strings.Split(fullRef, "/")
	return tokens[len(tokens)-1]
}
<commit_msg>Fix githook master case<commit_after>package githook

import (
	"bytes"
	"encoding/json"
	"fmt"
	"strconv"
	"strings"

	"github.com/pachyderm/pachyderm/src/client"
	"github.com/pachyderm/pachyderm/src/client/pps"

	"gopkg.in/go-playground/webhooks.v3"
	"gopkg.in/go-playground/webhooks.v3/github"
)

// GitHookPort specifies the port the server will listen on
const GitHookPort = 999
const apiVersion = "v1"

// gitHookServer serves GetFile requests over HTTP
type gitHookServer struct {
	hook   *github.Webhook
	client *client.APIClient
}

func RunGitHookServer(address string) error {
	fmt.Printf("new in cluster\n")
	c, err := client.NewFromAddress(address)
	fmt.Printf("new in cluster err %v\n", err)
	if err != nil {
		return err
	}
	fmt.Printf("new github hook\n")
	hook := github.New(&github.Config{})
	s := &gitHookServer{
		hook,
		c,
	}
	hook.RegisterEvents(s.HandlePush, github.PushEvent)
	fmt.Printf("running github webhook\n")
	return webhooks.Run(hook, ":"+strconv.Itoa(GitHookPort), fmt.Sprintf("/%v/handle/push", apiVersion))
}
func matchingBranch(inputBranch string, payloadBranch string) bool {
	if inputBranch == payloadBranch {
		return true
	}
	if inputBranch == "" && payloadBranch == "master" {
		return true
	}
	return false
}

func (s *gitHookServer) findMatchingPipelineInputs(payload github.PushPayload) (inputs []*pps.GithubInput, err error) {
	urls := []string{
		payload.Repository.SSHURL,
		payload.Repository.GitURL,
		payload.Repository.CloneURL,
		payload.Repository.SvnURL,
	}
	var walkInput func(*pps.Input)
	payloadBranch := getBranch(payload.Ref)
	// TODO use this instead:
	//pps.VisitInput(pipelineInfo.Input, func(input *pps.Input) {
	walkInput = func(input *pps.Input) {
		if input.Github != nil {
			for _, url := range urls {
				fmt.Printf("compariny input url (%v) to push event (%v)\n", input.Github.URL, url)
				fmt.Printf("pipeline branch (%v), payload branch (%v), match? (%v)\n", input.Github.Branch, payloadBranch, matchingBranch(input.Github.Branch, payloadBranch))
				if input.Github.URL == url && matchingBranch(input.Github.Branch, payloadBranch) {
					//			repoName = pps.RepoNameFromGithubInfo(input.Github.URL, input.Github.Name)
					inputs = append(inputs, input.Github)
				}
			}
		}
		var inputs []*pps.Input
		if input.Cross != nil {
			inputs = input.Cross
		}
		if input.Union != nil {
			inputs = input.Union
		}
		for _, input := range inputs {
			walkInput(input)
		}
	}
	pipelines, err := s.client.ListPipeline()
	if err != nil {
		return nil, err
	}
	for _, pipelineInfo := range pipelines {
		walkInput(pipelineInfo.Input)
	}
	if len(inputs) == 0 {
		return nil, fmt.Errorf("no pipeline inputs corresponding to github URL (%v) on branch (%v) found, perhaps the github input is not set yet on a pipeline", urls[0], payloadBranch)
	}
	return inputs, nil
}

func (s *gitHookServer) HandlePush(payload interface{}, header webhooks.Header) {
	var err error
	defer func() {
		// Handle any return error
		if err != nil {
			//TODO: This should probably be a logger of some sort
			// so that we emit the error in the right format for a log parser
			fmt.Printf("Github Webhook failed to handle push with error: %v\n", err)
		}
	}()

	pl := payload.(github.PushPayload)
	fmt.Printf("push payload: %v\n", pl)

	raw, err := json.Marshal(pl)
	if err != nil {
		err = fmt.Errorf("error marshalling payload (%v): %v", pl, err)
		return
	}
	githubInputs, err := s.findMatchingPipelineInputs(pl)
	if err != nil {
		return
	}
	for _, input := range githubInputs {
		repoName := pps.RepoNameFromGithubInfo(input.URL, input.Name)
		fmt.Printf("got repo: %v\n", repoName)
		branchName := "master"
		if input.Branch != "" {
			branchName = input.Branch
		}
		commit, err := s.client.StartCommit(repoName, branchName)
		if err != nil {
			fmt.Printf("error starting commit on repo %v: %v\n", repoName, err)
			return
		}
		func() {
			defer func() {
				// Handle any return error
				if err != nil {
					//TODO: This should probably be a logger of some sort
					// so that we emit the error in the right format for a log parser
					fmt.Printf("Github Webhook failed to handle push with error: %v\n", err)
				}
			}()
			defer func() {
				if err != nil {
					err = s.client.DeleteCommit(repoName, commit.ID)
					return
				}
				err = s.client.FinishCommit(repoName, commit.ID)
				//Final deferred function deals w non nil error
			}()
			_, err = s.client.PutFile(repoName, commit.ID, "commit.json", bytes.NewReader(raw))
			if err != nil {
				return
			}
		}()
	}
}

func getBranch(fullRef string) string {
	// e.g. 'refs/heads/master'
	tokens := strings.Split(fullRef, "/")
	return tokens[len(tokens)-1]
}
<|endoftext|>


<commit_before>package loopback2

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"strconv"
	"strings"

	"github.com/AutoRoute/l2"
)

type settings struct {
	Connections []ConnectionType
	Devices     []DeviceType
}

type ConnectionType struct {
	Source      string
	Destination string
	Bandwidth   string
}

type DeviceType struct {
	Name      string
	Bandwidth string
}

// Creates a new tap device with the appropriate parameters.
// Args:
//	name: Name of the device.
//	bandwidth: The max bandwidth for the device.
// Returns:
//	The new tap device.
func makeTap(name string, bandwidth int) l2.FrameReadWriteCloser {
	var err error
	var tap l2.FrameReadWriteCloser
	if bandwidth == 0 {
		// For some reason, some of the integration tests don't like it when we set
		// our own address.
		tap, err = l2.NewTapDevice("", name)
	} else {
		log.Printf("Setting bandwidth on %s to %d.\n", name, bandwidth)
		tap, err = l2.NewTapDeviceWithLatency("", name, bandwidth,
			bandwidth)
	}
	if err != nil {
		log.Fatal("Error opening tap device:", err)
	}

	return tap
}

// A fake network made out of tap devices.
type TapNetwork struct {
	// Suffix to append to the names of tap devices. This is in case we wish to
	// use multiple networks and want to make sure they don't conflict.
	suffix string
	// Channel we use to notify it when we want to quit.
	quitChannel chan bool
	// Path to the configuration file we're using.
	config string
}

// Builds a map of all the connections between tap devices based on an input
// configuration file.
// Returns:
//  * A map that maps a device name to submap which itself maps the name of the
//  device paired with that first device to a string containing the actual names
//  of the tap interfaces that will be used separated by a colon.
//  * A map that maps each device to the bandwidth for that device.
//  * An error if appropriate.
func (t *TapNetwork) ReadConfigFile() (map[string]map[string]string,
	map[string]int, error) {
	file, err := ioutil.ReadFile(t.config)
	if err != nil {
		log.Print("Error opening the configuration file:", err)
		return nil, nil, err
	}

	var s settings
	err = json.Unmarshal(file, &s)
	if err != nil {
		log.Print("Error retrieving JSON from configuration file:", err)
		return nil, nil, err
	}

	// various data structures for holding relationships between structures
	// interfaces
	tap_interfaces := make(map[string]map[string]string)
	// Contains bandwidths for each device.
	tap_bandwidths := make(map[string]int)

	// generate connection pairs
	// goes through each pair of connections
	i := 0
	for _, v := range s.Connections {
		src := v.Source
		dst := v.Destination

		_, ok_src := tap_interfaces[src]
		_, ok_dst := tap_interfaces[dst][src]
		// source-destination mapping is not in map at all
		if !ok_src && !ok_dst {
			tap_interfaces[src] = make(map[string]string)
		}

		_, ok_src = tap_interfaces[src][dst]

		if !ok_src && !ok_dst {
			i1 := "i" + strconv.Itoa(i) + t.suffix
			i++
			i2 := "i" + strconv.Itoa(i) + t.suffix
			i++
			tap_interfaces[src][dst] = i1 + ":" + i2
		}
	}

	// Set bandwidths.
	for _, device := range s.Devices {
		name := device.Name
		bandwidth, err := strconv.Atoi(device.Bandwidth)
		if err != nil {
			log.Printf("Invalid bandwidth parameter '%s'.\n", device.Bandwidth)
			return nil, nil, err
		}

		_, ok_name := tap_interfaces[name]
		if !ok_name {
			log.Printf("Unknown device '%s'.\n", name)
			return nil, nil, err
		}

		tap_bandwidths[name] = bandwidth
	}

	return tap_interfaces, tap_bandwidths, nil
}

// Actually creates the network.
func (t *TapNetwork) doCreateNetwork() {
	log.Printf("Loopback2: Starting...\n")

	devices := []l2.FrameReadWriteCloser{}
	if len(t.config) > 0 {
		tap_interfaces, tap_bandwidths, err := t.ReadConfigFile()
		if err != nil {
			log.Fatal("Error reading the configuration file.")
		}

		// Actually make all the tap devices.
		var device_number int64 = 0
		for src, dsts := range tap_interfaces {
			for _, ifaces := range dsts {
				looptaps := strings.Split(ifaces, ":")
				name1 := fmt.Sprintf(looptaps[0])
				device_number += 1
				name2 := fmt.Sprintf(looptaps[1])
				device_number += 1

				bandwidth := tap_bandwidths[src]

				log.Print(fmt.Sprintf("Creating device pair: %s:%s\n", name1, name2))
				lo0 := makeTap(name1, bandwidth)
				lo1 := makeTap(name2, bandwidth)
				devices = append(devices, lo0, lo1)

				go l2.SendFrames(lo0, lo1)
				go l2.SendFrames(lo1, lo0)
			}
		}

	} else { // set up the testing as normal
		device_number := int64(0)
		name1 := fmt.Sprintf("looptap0-%d", device_number)
		device_number += 1
		name2 := fmt.Sprintf("looptap0-%d", device_number)
		device_number += 1

		lo0 := makeTap(name1, 0)
		lo1 := makeTap(name2, 0)
		devices = append(devices, lo0, lo1)

		go l2.SendFrames(lo0, lo1)
		go l2.SendFrames(lo1, lo0)
	}

	// Wait for someone to tell us to quit.
	<-t.quitChannel
	log.Print("Loopback2: Exiting...\n")
}

// Stops a running network simulation.
func (t *TapNetwork) Stop() {
	t.quitChannel <- true
}

// Creates a network of tap devices that can be used for testing autoroute code.
// Args:
//  config: The location of the config file to use when creating the network. An
//  empty string means use the default network configuration.
//  suffix: Suffix to add to devices created for this network.
// Returns:
//  The TapNetwork object.
func NewTapNetwork(config, suffix string) *TapNetwork {
	network := TapNetwork{
		suffix,
		make(chan bool, 1),
		config,
	}

	go network.doCreateNetwork()

	return &network
}
<commit_msg>Fix more loopback2 issues.<commit_after>package loopback2

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/AutoRoute/l2"
)

type settings struct {
	Connections []ConnectionType
	Devices     []DeviceType
}

type ConnectionType struct {
	Source      string
	Destination string
	Bandwidth   string
}

type DeviceType struct {
	Name      string
	Bandwidth string
}

// Creates a new tap device with the appropriate parameters.
// Args:
//	name: Name of the device.
//	bandwidth: The max bandwidth for the device.
// Returns:
//	The new tap device.
func makeTap(name string, bandwidth int) l2.FrameReadWriteCloser {
	var err error
	var tap l2.FrameReadWriteCloser
	if bandwidth == 0 {
		// For some reason, some of the integration tests don't like it when we set
		// our own address.
		tap, err = l2.NewTapDevice("", name)
	} else {
		log.Printf("Setting bandwidth on %s to %d.\n", name, bandwidth)
		tap, err = l2.NewTapDeviceWithLatency("", name, bandwidth,
			bandwidth)
	}
	if err != nil {
		log.Fatal("Error opening tap device:", err)
	}

	return tap
}

// Waits for a set of devices to go offline.
// Args:
//  devices: The devices that we want to wait for.
func waitForOffline(devices map[string]l2.FrameReadWriteCloser) {
	// Spin until the devices actually appear. We're not really in a hurry here,
	// so we can rate-limit to reduce CPU usage.
	timeout := time.After(10 * time.Second)
	for range time.Tick(10 * time.Millisecond) {
		interfaces, err := net.Interfaces()
		if err != nil {
			log.Printf("Warning: Checking interfaces failed: %s\n", err)
			// Skip this check.
			break
		}

		found := false
		for _, iface := range interfaces {
			_, name_found := devices[iface.Name]
			if name_found {
				found = true
			}
		}
		if !found {
			break
		}

		// Check for timeout.
		select {
		  case <-timeout:
		    log.Fatal("Waiting for devices to go offline took too long.\n")
		  default:
		    continue
		}
	}
}

// A fake network made out of tap devices.
type TapNetwork struct {
	// Suffix to append to the names of tap devices. This is in case we wish to
	// use multiple networks and want to make sure they don't conflict.
	suffix string
	// Channel we use to notify it when we want to quit.
	quitChannel chan bool
	// Channel we use to notify the main goroutine when we are done initializing.
	readyChannel chan bool
	// This is so we can wait for the internal goroutine to finish cleaning
	// everything up when we want to exit.
	waiter sync.WaitGroup
	// Path to the configuration file we're using.
	config string
}

// Builds a map of all the connections between tap devices based on an input
// configuration file.
// Returns:
//  * A map that maps a device name to submap which itself maps the name of the
//  device paired with that first device to a string containing the actual names
//  of the tap interfaces that will be used separated by a colon.
//  * A map that maps each device to the bandwidth for that device.
//  * An error if appropriate.
func (t *TapNetwork) ReadConfigFile() (map[string]map[string]string,
	map[string]int, error) {
	file, err := ioutil.ReadFile(t.config)
	if err != nil {
		log.Print("Error opening the configuration file:", err)
		return nil, nil, err
	}

	var s settings
	err = json.Unmarshal(file, &s)
	if err != nil {
		log.Print("Error retrieving JSON from configuration file:", err)
		return nil, nil, err
	}

	// various data structures for holding relationships between structures
	// interfaces
	tap_interfaces := make(map[string]map[string]string)
	// Contains bandwidths for each device.
	tap_bandwidths := make(map[string]int)

	// generate connection pairs
	// goes through each pair of connections
	i := 0
	for _, v := range s.Connections {
		src := v.Source
		dst := v.Destination

		_, ok_src := tap_interfaces[src]
		_, ok_dst := tap_interfaces[dst][src]
		// source-destination mapping is not in map at all
		if !ok_src && !ok_dst {
			tap_interfaces[src] = make(map[string]string)
		}

		_, ok_src = tap_interfaces[src][dst]

		if !ok_src && !ok_dst {
			i1 := "i" + strconv.Itoa(i) + t.suffix
			i++
			i2 := "i" + strconv.Itoa(i) + t.suffix
			i++
			tap_interfaces[src][dst] = i1 + ":" + i2
		}
	}

	// Set bandwidths.
	for _, device := range s.Devices {
		name := device.Name
		bandwidth, err := strconv.Atoi(device.Bandwidth)
		if err != nil {
			log.Printf("Invalid bandwidth parameter '%s'.\n", device.Bandwidth)
			return nil, nil, err
		}

		_, ok_name := tap_interfaces[name]
		if !ok_name {
			log.Printf("Unknown device '%s'.\n", name)
			return nil, nil, err
		}

		tap_bandwidths[name] = bandwidth
	}

	return tap_interfaces, tap_bandwidths, nil
}

// Actually creates the network.
func (t *TapNetwork) doCreateNetwork() {
	log.Printf("Loopback2: Starting...\n")

	devices := make(map[string]l2.FrameReadWriteCloser)
	if len(t.config) > 0 {
		tap_interfaces, tap_bandwidths, err := t.ReadConfigFile()
		if err != nil {
			log.Fatal("Error reading the configuration file.")
		}

		// Actually make all the tap devices.
		var device_number int64 = 0
		for src, dsts := range tap_interfaces {
			for _, ifaces := range dsts {
				looptaps := strings.Split(ifaces, ":")
				name1 := fmt.Sprintf(looptaps[0])
				device_number += 1
				name2 := fmt.Sprintf(looptaps[1])
				device_number += 1

				bandwidth := tap_bandwidths[src]

				log.Print(fmt.Sprintf("Creating device pair: %s:%s\n", name1, name2))
				lo0 := makeTap(name1, bandwidth)
				lo1 := makeTap(name2, bandwidth)
				devices[name1] = lo0
				devices[name2] = lo1

				go l2.SendFrames(lo0, lo1)
				go l2.SendFrames(lo1, lo0)
			}
		}

	} else { // set up the testing as normal
		device_number := int64(0)
		name1 := fmt.Sprintf("looptap0-%d", device_number)
		device_number += 1
		name2 := fmt.Sprintf("looptap0-%d", device_number)
		device_number += 1

		lo0 := makeTap(name1, 0)
		lo1 := makeTap(name2, 0)
		devices[name1] = lo0
		devices[name2] = lo1

		go l2.SendFrames(lo0, lo1)
		go l2.SendFrames(lo1, lo0)
	}

	// We're done initializing.
	t.readyChannel <- true
	log.Print("Loopback2: Ready.\n")

	// Wait for someone to tell us to quit.
	<-t.quitChannel
	// Close devices.
	for _, device := range devices {
		device.Close()
	}
	waitForOffline(devices)

	t.waiter.Done()
	log.Print("Loopback2: Exiting...\n")
}

// Stops a running network simulation.
func (t *TapNetwork) Stop() {
	t.quitChannel <- true
	// Wait for it to clean up.
	log.Printf("Waiting for cleanup...\n")
	t.waiter.Wait()
}

// Creates a network of tap devices that can be used for testing autoroute code.
// Args:
//  config: The location of the config file to use when creating the network. An
//  empty string means use the default network configuration.
//  suffix: Suffix to add to devices created for this network.
// Returns:
//  The TapNetwork object.
func NewTapNetwork(config, suffix string) *TapNetwork {
	network := TapNetwork{
		suffix,
		make(chan bool, 1),
		make(chan bool, 1),
		sync.WaitGroup{},
		config,
	}

	go network.doCreateNetwork()

	network.waiter.Add(1)
	<-network.readyChannel
	return &network
}
<|endoftext|>


<commit_before>package proxy

import (
	"bytes"
	"net"
	"strconv"
	"time"

	"github.com/lucas-clemente/quic-go"
	"github.com/lucas-clemente/quic-go/protocol"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

type packetData []byte

var _ = Describe("UDP Proxy", func() {
	var serverPort int

	makePacket := func(p protocol.PacketNumber, payload []byte) []byte {
		b := &bytes.Buffer{}
		hdr := quic.PublicHeader{
			PacketNumber:         p,
			PacketNumberLen:      protocol.PacketNumberLen6,
			ConnectionID:         1337,
			TruncateConnectionID: false,
		}
		hdr.WritePublicHeader(b, protocol.Version34)
		raw := b.Bytes()
		raw = append(raw, payload...)
		return raw
	}

	BeforeEach(func() {
		serverPort = 7331
	})

	It("sets up the UDPProxy", func() {
		proxy, err := NewUDPProxy(13370, "localhost", serverPort, nil, nil, 0, 0)
		Expect(err).ToNot(HaveOccurred())
		Expect(proxy.clientDict).To(HaveLen(0))

		// check that port 13370 is in use
		addr, err := net.ResolveUDPAddr("udp", ":13370")
		Expect(err).ToNot(HaveOccurred())
		_, err = net.ListenUDP("udp", addr)
		Expect(err).To(HaveOccurred())
		Expect(err).To(MatchError("listen udp :13370: bind: address already in use"))

		proxy.Stop() // stopping is tested in the next test
	})

	It("stops the UDPProxy", func() {
		proxy, err := NewUDPProxy(13371, "localhost", serverPort, nil, nil, 0, 0)
		Expect(err).ToNot(HaveOccurred())
		proxy.Stop()

		// check that port 13370 is not in use anymore
		addr, err := net.ResolveUDPAddr("udp", ":13371")
		Expect(err).ToNot(HaveOccurred())
		ln, err := net.ListenUDP("udp", addr)
		Expect(err).ToNot(HaveOccurred())
		ln.Close()
	})

	Context("Proxy tests", func() {
		var serverConn *net.UDPConn
		var serverReceivedPackets []packetData
		var serverNumPacketsSent int
		var clientConn *net.UDPConn
		var proxy *UDPProxy

		BeforeEach(func() {
			var err error
			serverReceivedPackets = serverReceivedPackets[:0]
			serverNumPacketsSent = 0

			// setup a UDP server on port 7331
			serverAddr, err := net.ResolveUDPAddr("udp", ":"+strconv.Itoa(serverPort))
			Expect(err).ToNot(HaveOccurred())
			serverConn, err = net.ListenUDP("udp", serverAddr)
			Expect(err).ToNot(HaveOccurred())

			proxyAddr, err := net.ResolveUDPAddr("udp", ":10001")
			Expect(err).ToNot(HaveOccurred())

			go func() {
				defer GinkgoRecover()

				for {
					buf := make([]byte, 1500)
					n, addr, err2 := serverConn.ReadFromUDP(buf)
					if err2 != nil {
						return
					}
					data := buf[0:n]
					serverReceivedPackets = append(serverReceivedPackets, packetData(data))

					// echo each packet received back to the client
					serverConn.WriteToUDP(data, addr)
					serverNumPacketsSent++
				}
			}()

			// setup the client
			localAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
			Expect(err).ToNot(HaveOccurred())
			clientConn, err = net.DialUDP("udp", localAddr, proxyAddr)
			Expect(err).ToNot(HaveOccurred())
		})

		AfterEach(func() {
			proxy.Stop()
			serverConn.Close()
			time.Sleep(time.Millisecond)
		})

		Context("no packet drop", func() {
			BeforeEach(func() {
				// setup the proxy
				var err error
				proxy, err = NewUDPProxy(10001, "localhost", serverPort, nil, nil, 0, 0)
				Expect(err).ToNot(HaveOccurred())
			})

			It("relays packets from the client to the server", func() {
				_, err := clientConn.Write(makePacket(1, []byte("foobar")))
				Expect(err).ToNot(HaveOccurred())

				Eventually(func() map[string]*connection { return proxy.clientDict }).Should(HaveLen(1))
				var conn *connection
				for _, conn = range proxy.clientDict {
					Expect(conn.incomingPacketCounter).To(Equal(uint64(1)))
				}
				_, err = clientConn.Write(makePacket(2, []byte("decafbad")))
				Expect(err).ToNot(HaveOccurred())
				Expect(proxy.clientDict).To(HaveLen(1))
				Eventually(func() []packetData { return serverReceivedPackets }).Should(HaveLen(2))
				Expect(string(serverReceivedPackets[0])).To(ContainSubstring("foobar"))
				Expect(string(serverReceivedPackets[1])).To(ContainSubstring("decafbad"))
			})

			It("relays packets from the server to the client", func() {
				_, err := clientConn.Write(makePacket(1, []byte("foobar")))
				Expect(err).ToNot(HaveOccurred())
				Eventually(func() map[string]*connection { return proxy.clientDict }).Should(HaveLen(1))
				var key string
				var conn *connection
				for key, conn = range proxy.clientDict {
					Eventually(conn.outgoingPacketCounter).Should(Equal(uint64(1)))
				}
				_, err = clientConn.Write(makePacket(2, []byte("decafbad")))
				Expect(err).ToNot(HaveOccurred())

				Expect(proxy.clientDict).To(HaveLen(1))
				Eventually(func() uint64 { return proxy.clientDict[key].outgoingPacketCounter }).Should(Equal(uint64(2)))

				var clientReceivedPackets []packetData

				// receive the packets echoed by the server on client side
				go func() {
					defer GinkgoRecover()

					for {
						buf := make([]byte, 1500)
						n, _, err2 := clientConn.ReadFromUDP(buf)
						if err2 != nil {
							return
						}
						data := buf[0:n]
						clientReceivedPackets = append(clientReceivedPackets, packetData(data))
					}
				}()

				Eventually(func() []packetData { return serverReceivedPackets }).Should(HaveLen(2))
				Expect(serverReceivedPackets).To(HaveLen(2))
				Expect(serverNumPacketsSent).To(Equal(2))
				Eventually(func() []packetData { return clientReceivedPackets }).Should(HaveLen(2))
				Expect(string(clientReceivedPackets[0])).To(ContainSubstring("foobar"))
				Expect(string(clientReceivedPackets[1])).To(ContainSubstring("decafbad"))
			})
		})

		Context("Drop Callbacks", func() {
			It("drops incoming packets", func() {
				dropper := func(p protocol.PacketNumber) bool {
					return p%2 == 0
				}

				var err error
				proxy, err = NewUDPProxy(10001, "localhost", serverPort, dropper, nil, 0, 0)
				Expect(err).ToNot(HaveOccurred())

				for i := 1; i <= 6; i++ {
					_, err := clientConn.Write(makePacket(protocol.PacketNumber(i), []byte("foobar"+strconv.Itoa(i))))
					Expect(err).ToNot(HaveOccurred())
				}
				Eventually(func() []packetData { return serverReceivedPackets }).Should(HaveLen(3))
				Consistently(func() []packetData { return serverReceivedPackets }).Should(HaveLen(3))
			})

			It("drops outgoing packets", func() {
				dropper := func(p protocol.PacketNumber) bool {
					return p%2 == 0
				}

				var err error
				proxy, err = NewUDPProxy(10001, "localhost", serverPort, nil, dropper, 0, 0)
				Expect(err).ToNot(HaveOccurred())

				for i := 1; i <= 6; i++ {
					_, err := clientConn.Write(makePacket(protocol.PacketNumber(i), []byte("foobar"+strconv.Itoa(i))))
					Expect(err).ToNot(HaveOccurred())
				}

				var clientReceivedPackets []packetData

				// receive the packets echoed by the server on client side
				go func() {
					defer GinkgoRecover()

					for {
						buf := make([]byte, 1500)
						n, _, err2 := clientConn.ReadFromUDP(buf)
						if err2 != nil {
							return
						}
						data := buf[0:n]
						clientReceivedPackets = append(clientReceivedPackets, packetData(data))
					}
				}()

				Eventually(func() []packetData { return clientReceivedPackets }).Should(HaveLen(3))
				Consistently(func() []packetData { return clientReceivedPackets }).Should(HaveLen(3))
			})
		})
	})
})
<commit_msg>fix flaky proxy tests<commit_after>package proxy

import (
	"bytes"
	"net"
	"strconv"
	"sync/atomic"
	"time"

	"github.com/lucas-clemente/quic-go"
	"github.com/lucas-clemente/quic-go/protocol"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

type packetData []byte

var _ = Describe("UDP Proxy", func() {
	var serverPort int

	makePacket := func(p protocol.PacketNumber, payload []byte) []byte {
		b := &bytes.Buffer{}
		hdr := quic.PublicHeader{
			PacketNumber:         p,
			PacketNumberLen:      protocol.PacketNumberLen6,
			ConnectionID:         1337,
			TruncateConnectionID: false,
		}
		hdr.WritePublicHeader(b, protocol.Version34)
		raw := b.Bytes()
		raw = append(raw, payload...)
		return raw
	}

	BeforeEach(func() {
		serverPort = 7331
	})

	It("sets up the UDPProxy", func() {
		proxy, err := NewUDPProxy(13370, "localhost", serverPort, nil, nil, 0, 0)
		Expect(err).ToNot(HaveOccurred())
		Expect(proxy.clientDict).To(HaveLen(0))

		// check that port 13370 is in use
		addr, err := net.ResolveUDPAddr("udp", ":13370")
		Expect(err).ToNot(HaveOccurred())
		_, err = net.ListenUDP("udp", addr)
		Expect(err).To(HaveOccurred())
		Expect(err).To(MatchError("listen udp :13370: bind: address already in use"))

		proxy.Stop() // stopping is tested in the next test
	})

	It("stops the UDPProxy", func() {
		proxy, err := NewUDPProxy(13371, "localhost", serverPort, nil, nil, 0, 0)
		Expect(err).ToNot(HaveOccurred())
		proxy.Stop()

		// check that port 13370 is not in use anymore
		addr, err := net.ResolveUDPAddr("udp", ":13371")
		Expect(err).ToNot(HaveOccurred())
		ln, err := net.ListenUDP("udp", addr)
		Expect(err).ToNot(HaveOccurred())
		ln.Close()
	})

	Context("Proxy tests", func() {
		var serverConn *net.UDPConn
		var serverReceivedPackets []packetData
		var serverNumPacketsSent int
		var clientConn *net.UDPConn
		var proxy *UDPProxy

		BeforeEach(func() {
			var err error
			serverReceivedPackets = serverReceivedPackets[:0]
			serverNumPacketsSent = 0

			// setup a UDP server on port 7331
			serverAddr, err := net.ResolveUDPAddr("udp", ":"+strconv.Itoa(serverPort))
			Expect(err).ToNot(HaveOccurred())
			serverConn, err = net.ListenUDP("udp", serverAddr)
			Expect(err).ToNot(HaveOccurred())

			proxyAddr, err := net.ResolveUDPAddr("udp", ":10001")
			Expect(err).ToNot(HaveOccurred())

			go func() {
				defer GinkgoRecover()

				for {
					buf := make([]byte, 1500)
					n, addr, err2 := serverConn.ReadFromUDP(buf)
					if err2 != nil {
						return
					}
					data := buf[0:n]
					serverReceivedPackets = append(serverReceivedPackets, packetData(data))

					// echo each packet received back to the client
					serverConn.WriteToUDP(data, addr)
					serverNumPacketsSent++
				}
			}()

			// setup the client
			localAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
			Expect(err).ToNot(HaveOccurred())
			clientConn, err = net.DialUDP("udp", localAddr, proxyAddr)
			Expect(err).ToNot(HaveOccurred())
		})

		AfterEach(func() {
			proxy.Stop()
			serverConn.Close()
			time.Sleep(time.Millisecond)
		})

		Context("no packet drop", func() {
			BeforeEach(func() {
				// setup the proxy
				var err error
				proxy, err = NewUDPProxy(10001, "localhost", serverPort, nil, nil, 0, 0)
				Expect(err).ToNot(HaveOccurred())
			})

			It("relays packets from the client to the server", func() {
				_, err := clientConn.Write(makePacket(1, []byte("foobar")))
				Expect(err).ToNot(HaveOccurred())

				Eventually(func() map[string]*connection { return proxy.clientDict }).Should(HaveLen(1))
				var conn *connection
				for _, conn = range proxy.clientDict {
					Expect(atomic.LoadUint64(&conn.incomingPacketCounter)).To(Equal(uint64(1)))
				}
				_, err = clientConn.Write(makePacket(2, []byte("decafbad")))
				Expect(err).ToNot(HaveOccurred())
				Expect(proxy.clientDict).To(HaveLen(1))
				Eventually(func() []packetData { return serverReceivedPackets }).Should(HaveLen(2))
				Expect(string(serverReceivedPackets[0])).To(ContainSubstring("foobar"))
				Expect(string(serverReceivedPackets[1])).To(ContainSubstring("decafbad"))
			})

			It("relays packets from the server to the client", func() {
				_, err := clientConn.Write(makePacket(1, []byte("foobar")))
				Expect(err).ToNot(HaveOccurred())
				Eventually(func() map[string]*connection { return proxy.clientDict }).Should(HaveLen(1))
				var key string
				var conn *connection
				for key, conn = range proxy.clientDict {
					Eventually(func() uint64 { return atomic.LoadUint64(&conn.outgoingPacketCounter) }).Should(Equal(uint64(1)))
				}
				_, err = clientConn.Write(makePacket(2, []byte("decafbad")))
				Expect(err).ToNot(HaveOccurred())

				Expect(proxy.clientDict).To(HaveLen(1))
				Eventually(func() uint64 { return proxy.clientDict[key].outgoingPacketCounter }).Should(Equal(uint64(2)))

				var clientReceivedPackets []packetData

				// receive the packets echoed by the server on client side
				go func() {
					defer GinkgoRecover()

					for {
						buf := make([]byte, 1500)
						n, _, err2 := clientConn.ReadFromUDP(buf)
						if err2 != nil {
							return
						}
						data := buf[0:n]
						clientReceivedPackets = append(clientReceivedPackets, packetData(data))
					}
				}()

				Eventually(func() []packetData { return serverReceivedPackets }).Should(HaveLen(2))
				Expect(serverReceivedPackets).To(HaveLen(2))
				Expect(serverNumPacketsSent).To(Equal(2))
				Eventually(func() []packetData { return clientReceivedPackets }).Should(HaveLen(2))
				Expect(string(clientReceivedPackets[0])).To(ContainSubstring("foobar"))
				Expect(string(clientReceivedPackets[1])).To(ContainSubstring("decafbad"))
			})
		})

		Context("Drop Callbacks", func() {
			It("drops incoming packets", func() {
				dropper := func(p protocol.PacketNumber) bool {
					return p%2 == 0
				}

				var err error
				proxy, err = NewUDPProxy(10001, "localhost", serverPort, dropper, nil, 0, 0)
				Expect(err).ToNot(HaveOccurred())

				for i := 1; i <= 6; i++ {
					_, err := clientConn.Write(makePacket(protocol.PacketNumber(i), []byte("foobar"+strconv.Itoa(i))))
					Expect(err).ToNot(HaveOccurred())
				}
				Eventually(func() []packetData { return serverReceivedPackets }).Should(HaveLen(3))
				Consistently(func() []packetData { return serverReceivedPackets }).Should(HaveLen(3))
			})

			It("drops outgoing packets", func() {
				dropper := func(p protocol.PacketNumber) bool {
					return p%2 == 0
				}

				var err error
				proxy, err = NewUDPProxy(10001, "localhost", serverPort, nil, dropper, 0, 0)
				Expect(err).ToNot(HaveOccurred())

				for i := 1; i <= 6; i++ {
					_, err := clientConn.Write(makePacket(protocol.PacketNumber(i), []byte("foobar"+strconv.Itoa(i))))
					Expect(err).ToNot(HaveOccurred())
				}

				var clientReceivedPackets []packetData

				// receive the packets echoed by the server on client side
				go func() {
					defer GinkgoRecover()

					for {
						buf := make([]byte, 1500)
						n, _, err2 := clientConn.ReadFromUDP(buf)
						if err2 != nil {
							return
						}
						data := buf[0:n]
						clientReceivedPackets = append(clientReceivedPackets, packetData(data))
					}
				}()

				Eventually(func() []packetData { return clientReceivedPackets }).Should(HaveLen(3))
				Consistently(func() []packetData { return clientReceivedPackets }).Should(HaveLen(3))
			})
		})
	})
})
<|endoftext|>


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

// Code generated by "mdtogo"; DO NOT EDIT.
package overview

var READMEShort = `<link rel="stylesheet" type="text/css" href="/kpt/gifs/asciinema-player.css" />`
var READMELong = `
kpt is a toolkit to help you manage, examine, manipulate, customize, validate, and apply Kubernetes resource
configuration files, both manually and programmatically.  (And has a name short enough that you don't have to alias it to ` + "`" + `k` + "`" + `).

A primary goal of kpt is to facilitate configuration reuse. The two primary sets of capabilities that are required to enable reuse are:
1. The ability to distribute/publish/share, compose, and update groups of configuration artifacts, commonly known as packages.
2. The ability to adapt them to your use cases, which we call customization.

In order to facilitate programmatic operations, kpt:
1. Relies upon git as the source of truth
2. Represents configuration as data, specifically Kubernetes resources serialized as YAML or JSON.

For compatibility with other arbitrary formats, kpt supports generating resource configuration data from templates,
configuration DSLs, and programs.

kpt functionality is subdivided into command groups, each of which operates on a particular set of entities, with a consistent command syntax and pattern of inputs and outputs.

| Command Group | Description                                                                     |
|---------------|---------------------------------------------------------------------------------|
| [pkg]         | fetch, update, and sync configuration files using git                           |
| [cfg]         | examine and modify configuration files                                          |
| [fn]          | generate, transform, validate configuration files using containerized functions |
| [live]        | reconcile the live state with configuration files                               |

---

#### [pkg] Package Management

Fetch, update, and sync configuration files using git.

- Fetch and customize blueprints published by others.
- Fetch the standard scaffolding for your new service.
- Update your customized package by merging changes from upstream.

**Data Flow**: git repo -> kpt [pkg] -> local files or stdout

| Configuration Read From | Configuration Written To |
|-------------------------|--------------------------|
| git repository          | local files              |

---

#### [cfg] Configuration Management

Examine and modify configuration files.

- Display structured and condensed views of your resources
- Filter and display resources by constraints
- Set high-level knobs published by the package
- Define and expose new knobs to simplify routine modifications

**Data Flow**: local configuration or stdin -> kpt [cfg] -> local configuration or stdout

| Configuration Read From | Configuration Written To |
|-------------------------|--------------------------|
| local files or stdin    | local files or stdout    |

---

#### [fn] Configuration Functions

Generate, transform, validate configuration files using containerized functions.

- Generate resources from code, DSLs, templates, etc.
- Apply cross-cutting transformations to resources
- Validate resources

*` + "`" + `fn` + "`" + ` is different from ` + "`" + `cfg` + "`" + ` in that it executes programs published as container images, rather
than statically compiled into kpt.*

**Data Flow**:  local configuration or stdin -> kpt [fn] (runs a container) -> local configuration or stdout

| Configuration Read From | Configuration Written To |
|-------------------------|--------------------------|
| local files or stdin    | local files or stdout    |

---

#### [live] Live-state Management

Reconcile configuration files with the live state.

- Apply package resources to cluster
- Preview changes before applying them
- Wait until a package has been fully reconciled with the live state
- Delete package resources from cluster

**Data Flow**: local configuration or stdin -> kpt live -> apiserver (Kubernetes cluster)

| Configuration Read From | Configuration Written To |
|-------------------------|--------------------------|
| local files or stdin    | apiserver                |
| apiserver               | stdout                   |

---
`
var READMEExamples = `
    # get a package
    $ kpt pkg get https://github.com/GoogleContainerTools/kpt.git/package-examples/helloworld-set@v0.5.0 helloworld
    fetching package /package-examples/helloworld-set from \
      https://github.com/GoogleContainerTools/kpt to helloworld

    # list setters and set a value
    $ kpt cfg list-setters helloworld
    NAME            DESCRIPTION         VALUE    TYPE     COUNT   SETBY
    http-port   'helloworld port'         80      integer   3
    image-tag   'hello-world image tag'   v0.3.0  string    1
    replicas    'helloworld replicas'     5       integer   1

    $ kpt cfg set helloworld replicas 3 --set-by pwittrock  --description 'reason'
    set 1 fields

	# add grouping object
	cat << EOF > helloworld/grouping_object.yaml
	apiVersion: v1
	kind: ConfigMap
	metadata:
	  name: test-inventory
	  labels:
	    cli-utils.sigs.k8s.io/inventory-id: helloworld
	EOF

    # preview what will happen when running apply
    $ kpt live preview helloworld
    configmap/test-inventory-2911da3b created
    deployment.apps/helloworld-gke created
    service/helloworld-gke created

    # run apply
    $ kpt live apply --wait-for-reconcile helloworld
    configmap/test-inventory-2911da3b created
    deployment.apps/helloworld-gke created
    service/helloworld-gke created
    configmap/test-inventory-2911da3b is Current: Resource is always ready
    deployment.apps/helloworld-gke is InProgress: Available: 0/3
    service/helloworld-gke is Current: Service is ready
    deployment.apps/helloworld-gke is Current: Deployment is available. Replicas: 3
    all resources has reached the Current status

    # remove the resources
    $ kpt live destroy helloworld
    service/helloworld-gke pruned
    deployment.apps/helloworld-gke pruned
    configmap/test-inventory-2911da3b pruned

    # learn about kpt
    $ kpt help
`
<commit_msg>regenerate docs<commit_after>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Code generated by "mdtogo"; DO NOT EDIT.
package overview

var READMEShort = `<img src="https://storage.googleapis.com/kpt-dev/docs/logo.png" width="50" height="50" />`
var READMELong = `
kpt is a toolkit to help you manage, examine, manipulate, customize, validate, and apply Kubernetes resource
configuration files, both manually and programmatically.  (And has a name short enough that you don't have to alias it to ` + "`" + `k` + "`" + `).

A primary goal of kpt is to facilitate configuration reuse. The two primary sets of capabilities that are required to enable reuse are:
1. The ability to distribute/publish/share, compose, and update groups of configuration artifacts, commonly known as packages.
2. The ability to adapt them to your use cases, which we call customization.

In order to facilitate programmatic operations, kpt:
1. Relies upon git as the source of truth
2. Represents configuration as data, specifically Kubernetes resources serialized as YAML or JSON.

For compatibility with other arbitrary formats, kpt supports generating resource configuration data from templates,
configuration DSLs, and programs.

kpt functionality is subdivided into command groups, each of which operates on a particular set of entities, with a consistent command syntax and pattern of inputs and outputs.

| Command Group | Description                                                                     |
|---------------|---------------------------------------------------------------------------------|
| [pkg]         | fetch, update, and sync configuration files using git                           |
| [cfg]         | examine and modify configuration files                                          |
| [fn]          | generate, transform, validate configuration files using containerized functions |
| [live]        | reconcile the live state with configuration files                               |

---

#### [pkg] Package Management

Fetch, update, and sync configuration files using git.

- Fetch and customize blueprints published by others.
- Fetch the standard scaffolding for your new service.
- Update your customized package by merging changes from upstream.

**Data Flow**: git repo -> kpt [pkg] -> local files or stdout

| Configuration Read From | Configuration Written To |
|-------------------------|--------------------------|
| git repository          | local files              |

---

#### [cfg] Configuration Management

Examine and modify configuration files.

- Display structured and condensed views of your resources
- Filter and display resources by constraints
- Set high-level knobs published by the package
- Define and expose new knobs to simplify routine modifications

**Data Flow**: local configuration or stdin -> kpt [cfg] -> local configuration or stdout

| Configuration Read From | Configuration Written To |
|-------------------------|--------------------------|
| local files or stdin    | local files or stdout    |

---

#### [fn] Configuration Functions

Generate, transform, validate configuration files using containerized functions.

- Generate resources from code, DSLs, templates, etc.
- Apply cross-cutting transformations to resources
- Validate resources

*` + "`" + `fn` + "`" + ` is different from ` + "`" + `cfg` + "`" + ` in that it executes programs published as container images, rather
than statically compiled into kpt.*

**Data Flow**:  local configuration or stdin -> kpt [fn] (runs a container) -> local configuration or stdout

| Configuration Read From | Configuration Written To |
|-------------------------|--------------------------|
| local files or stdin    | local files or stdout    |

---

#### [live] Live-state Management

Reconcile configuration files with the live state.

- Apply package resources to cluster
- Preview changes before applying them
- Wait until a package has been fully reconciled with the live state
- Delete package resources from cluster

**Data Flow**: local configuration or stdin -> kpt live -> apiserver (Kubernetes cluster)

| Configuration Read From | Configuration Written To |
|-------------------------|--------------------------|
| local files or stdin    | apiserver                |
| apiserver               | stdout                   |

---
`
var READMEExamples = `
    # get a package
    $ kpt pkg get https://github.com/GoogleContainerTools/kpt.git/package-examples/helloworld-set@v0.5.0 helloworld
    fetching package /package-examples/helloworld-set from \
      https://github.com/GoogleContainerTools/kpt to helloworld

    # list setters and set a value
    $ kpt cfg list-setters helloworld
    NAME            DESCRIPTION         VALUE    TYPE     COUNT   SETBY
    http-port   'helloworld port'         80      integer   3
    image-tag   'hello-world image tag'   v0.3.0  string    1
    replicas    'helloworld replicas'     5       integer   1

    $ kpt cfg set helloworld replicas 3 --set-by pwittrock  --description 'reason'
    set 1 fields

	# add grouping object
	cat << EOF > helloworld/grouping_object.yaml
	apiVersion: v1
	kind: ConfigMap
	metadata:
	  name: test-inventory
	  labels:
	    cli-utils.sigs.k8s.io/inventory-id: helloworld
	EOF

    # preview what will happen when running apply
    $ kpt live preview helloworld
    configmap/test-inventory-2911da3b created
    deployment.apps/helloworld-gke created
    service/helloworld-gke created

    # run apply
    $ kpt live apply --wait-for-reconcile helloworld
    configmap/test-inventory-2911da3b created
    deployment.apps/helloworld-gke created
    service/helloworld-gke created
    configmap/test-inventory-2911da3b is Current: Resource is always ready
    deployment.apps/helloworld-gke is InProgress: Available: 0/3
    service/helloworld-gke is Current: Service is ready
    deployment.apps/helloworld-gke is Current: Deployment is available. Replicas: 3
    all resources has reached the Current status

    # remove the resources
    $ kpt live destroy helloworld
    service/helloworld-gke pruned
    deployment.apps/helloworld-gke pruned
    configmap/test-inventory-2911da3b pruned

    # learn about kpt
    $ kpt help
`
<|endoftext|>


<commit_before>package ics

import (
	"bytes"
	"io"
	"reflect"
	"testing"
	"time"
)

type typeTest struct {
	Params map[string]string
	Data   string
	Input  interface {
		Decode(map[string]string, string) error
	}
	Match interface {
		Encode(io.Writer)
	}
	Output string
	Error  error
}

func testType(t *testing.T, tests []typeTest) {
	var buf bytes.Buffer
	for n, test := range tests {
		err := test.Input.Decode(test.Params, test.Data)
		if err != test.Error {
			if !reflect.DeepEqual(err, test.Error) {
				t.Errorf("test %d: expecting error %s, got %s", n+1, test.Error, err)
				continue
			}
		}
		if !reflect.DeepEqual(test.Input, test.Match) {
			t.Errorf("test %d: input does not match expected", n+1)
			continue
		}
		test.Match.Encode(&buf)
		if str := buf.String(); str != test.Output {
			t.Errorf("test %d: expecting output string %q, got %q", n+1, test.Output, str)
		}
		buf.Reset()
	}
}

func TestBinary(t *testing.T) {
	testType(t, []typeTest{
		{
			Input: &Binary{},
			Match: &Binary{},
			Error: ErrInvalidEncoding,
		},
		{
			Params: map[string]string{"ENCODING": "BASE64"},
			Data:   "MTIzNDU=",
			Input:  &Binary{},
			Match:  &Binary{'1', '2', '3', '4', '5'},
			Output: "MTIzNDU=",
		},
	})
}

func TestBoolean(t *testing.T) {
	tr := new(Boolean)
	fa := new(Boolean)
	*tr = true
	testType(t, []typeTest{
		{
			Data:   "False",
			Input:  fa,
			Match:  fa,
			Output: "FALSE",
		},
		{
			Data:   "true",
			Input:  tr,
			Match:  tr,
			Output: "TRUE",
		},
		{
			Data:   "HotDog",
			Input:  fa,
			Match:  fa,
			Output: "FALSE",
			Error:  ErrInvalidBoolean,
		},
	})
}

func TestDate(t *testing.T) {
	testType(t, []typeTest{
		{
			Data:   "20011225",
			Input:  &Date{},
			Match:  &Date{time.Date(2001, 12, 25, 0, 0, 0, 0, time.UTC)},
			Output: "20011225",
		},
		{
			Data:   "20081111",
			Input:  &Date{},
			Match:  &Date{time.Date(2008, 11, 11, 0, 0, 0, 0, time.UTC)},
			Output: "20081111",
		},
	})
}
<commit_msg>added tests for DateTime<commit_after>package ics

import (
	"bytes"
	"io"
	"reflect"
	"testing"
	"time"
)

type typeTest struct {
	Params map[string]string
	Data   string
	Input  interface {
		Decode(map[string]string, string) error
	}
	Match interface {
		Encode(io.Writer)
	}
	Output string
	Error  error
}

func testType(t *testing.T, tests []typeTest) {
	var buf bytes.Buffer
	for n, test := range tests {
		err := test.Input.Decode(test.Params, test.Data)
		if err != test.Error {
			if !reflect.DeepEqual(err, test.Error) {
				t.Errorf("test %d: expecting error %s, got %s", n+1, test.Error, err)
				continue
			}
		}
		if !reflect.DeepEqual(test.Input, test.Match) {
			t.Errorf("test %d: input does not match expected", n+1)
			continue
		}
		test.Match.Encode(&buf)
		if str := buf.String(); str != test.Output {
			t.Errorf("test %d: expecting output string %q, got %q", n+1, test.Output, str)
		}
		buf.Reset()
	}
}

func TestBinary(t *testing.T) {
	testType(t, []typeTest{
		{
			Input: &Binary{},
			Match: &Binary{},
			Error: ErrInvalidEncoding,
		},
		{
			Params: map[string]string{"ENCODING": "BASE64"},
			Data:   "MTIzNDU=",
			Input:  &Binary{},
			Match:  &Binary{'1', '2', '3', '4', '5'},
			Output: "MTIzNDU=",
		},
	})
}

func TestBoolean(t *testing.T) {
	tr := new(Boolean)
	fa := new(Boolean)
	*tr = true
	testType(t, []typeTest{
		{
			Data:   "False",
			Input:  fa,
			Match:  fa,
			Output: "FALSE",
		},
		{
			Data:   "true",
			Input:  tr,
			Match:  tr,
			Output: "TRUE",
		},
		{
			Data:   "HotDog",
			Input:  fa,
			Match:  fa,
			Output: "FALSE",
			Error:  ErrInvalidBoolean,
		},
	})
}

func TestDate(t *testing.T) {
	testType(t, []typeTest{
		{
			Data:   "20011225",
			Input:  &Date{},
			Match:  &Date{time.Date(2001, 12, 25, 0, 0, 0, 0, time.UTC)},
			Output: "20011225",
		},
		{
			Data:   "20081111",
			Input:  &Date{},
			Match:  &Date{time.Date(2008, 11, 11, 0, 0, 0, 0, time.UTC)},
			Output: "20081111",
		},
	})
}

func TestDateTime(t *testing.T) {
	l, err := time.LoadLocation("America/New_York")
	if err != nil {
		t.Errorf("unexpected error: %s", err)
		return
	}
	testType(t, []typeTest{
		{
			Params: map[string]string{},
			Data:   "20011225T131415",
			Input:  &DateTime{},
			Match:  &DateTime{time.Date(2001, 12, 25, 13, 14, 15, 0, time.Local)},
			Output: "20011225T131415",
		},
		{
			Params: map[string]string{},
			Data:   "20011225T131415Z",
			Input:  &DateTime{},
			Match:  &DateTime{time.Date(2001, 12, 25, 13, 14, 15, 0, time.UTC)},
			Output: "20011225T131415Z",
		},
		{
			Params: map[string]string{"TZID": "America/New_York"},
			Data:   "20011225T131415",
			Input:  &DateTime{},
			Match:  &DateTime{time.Date(2001, 12, 25, 13, 14, 15, 0, l)},
			Output: "20011225T131415",
		},
	})
}
<|endoftext|>