<commit_before>/*
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.

    * Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.

    * Neither the name of "The Computer Language Benchmarks Game" nor the
    name of "The Computer Language Shootout Benchmarks" nor the names of
    its contributors may be used to endorse or promote products derived
    from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/

/* The Computer Language Benchmarks Game
 * http://shootout.alioth.debian.org/
 *
 * contributed by The Go Authors.
 */

package main

import (
	"flag";
	"fmt";
	"os";
)

var n = flag.Int("n", 600, "count")

type Color int

const (
	blue Color = iota;
	red;
	yellow;
)

func (c Color) String() string {
	return []string{"blue", "red", "yellow"}[c]
}

func complement(c1, c2 Color) Color {
	 switch c1 << 2 | c2 {
	 case blue << 2 | blue:
	 	return blue
	 case blue << 2 | red:
	 	return yellow
	 case blue << 2 | yellow:
	 	return red
	 case red << 2 | blue:
	 	return yellow
	 case red << 2 | red:
	 	return red
	 case red << 2 | yellow:
	 	return blue
	 case yellow << 2 | blue:
	 	return red
	 case yellow << 2 | red:
	 	return blue
	 case yellow << 2 | yellow:
	 	return yellow
	}
	fmt.Println("invalid colors", c1, c2);
	os.Exit(2);
	return 0
}

func printColors(c1, c2 Color) {
	fmt.Printf("%s + %s -> %s\n", c1, c2, complement(c1, c2));
}

func printColorTable() {
	printColors(blue, blue);
	printColors(blue, red);
	printColors(blue, yellow);
	printColors(red, blue);
	printColors(red, red);
	printColors(red, yellow);
	printColors(yellow, blue);
	printColors(yellow, red);
	printColors(yellow, yellow);
}

type Referee struct {
	rendezCount	int;
	cham	[]*Chameneos;
	rendez	chan *Chameneos;
	done	chan int;
}

func NewReferee() *Referee {
	ref := new(Referee);
	ref.cham = make([]*Chameneos, 0, 100);
	ref.rendez = make(chan *Chameneos);
	ref.done = make(chan int);
	go ref.Serve();
	return ref;
}

func (ref *Referee) Serve() {
	for i := 0; i < *n; i++ {
		c1 := <-ref.rendez;
		c2 := <-ref.rendez;
		c1.col, c2.col = complement(c1.col, c2.col), complement(c2.col, c1.col);
		c1.rendez <- c2;
		c2.rendez <- c1;
	}
	for i := 0; i < len(ref.cham); i++ {
		c := <-ref.rendez;
		c.rendez <- nil;
	}
	ref.done <- 1;
}

func (ref *Referee) Add(ch *Chameneos) {
	n := len(ref.cham);
	ref.cham = ref.cham[0:n+1];
	ref.cham[n] = ch;
}

type Chameneos struct {
	index	int;
	col	Color;
	rendez	chan *Chameneos;
	count	int;
	same	int;
	ref	*Referee;
}

func (c *Chameneos) Init(index int, ref *Referee, col Color) *Chameneos {
	c.index = index;
	c.ref = ref;
	c.col = col;
	c.rendez = make(chan *Chameneos);
	go c.Serve();
	return c;
}

func (c *Chameneos) Serve() {
	for {
		c.ref.rendez <- c;
		c1 := <- c.rendez;
		if c1 == nil {
			break
		}
		if c1.index == c.index {
			c.same++
		}
		c.count++;
	}
}

func play(ref *Referee, color []Color) {
	cham := make([]Chameneos, len(color));
	for i, c := range color {
		fmt.Printf(" %s", c);
		ref.Add(cham[i].Init(i, ref, c));
	}
	fmt.Printf("\n");
	<-ref.done;
	total := 0;
	for _, c := range cham {
		total += c.count;
		fmt.Printf("%d %s\n", c.count, say(c.same));
	}
	fmt.Printf("%s\n", say(total));
}

var words = []string{"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"}

func say(n int) string {
	digits := fmt.Sprint(n);
	s := "";
	for _, c := range digits {
		s += " " + words[c-'0'];
	}
	return s;
}

func main() {
	flag.Parse();
	printColorTable();
	fmt.Print("\n");
	play(NewReferee(), []Color{blue, red, yellow});
	fmt.Print("\n");
	play(NewReferee(), []Color{blue, red, yellow, red, yellow, blue, red, yellow, red, blue});
}
<commit_msg>chameneosredux test modified, bug fixed, faster based on suggestion from arvindht@gmail.com<commit_after>/*
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.

    * Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.

    * Neither the name of "The Computer Language Benchmarks Game" nor the
    name of "The Computer Language Shootout Benchmarks" nor the names of
    its contributors may be used to endorse or promote products derived
    from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/

/* The Computer Language Benchmarks Game
 * http://shootout.alioth.debian.org/
 *
 * contributed by The Go Authors.
 */

package main

import "fmt"
import "flag"

const (
	blue	= iota;
	red;
	yellow;
	ncol;
)

var complement = [...]int{
	red | red<<2: red,
	red | yellow<<2: blue,
	red | blue<<2: yellow,
	yellow | red<<2: blue,
	yellow | yellow<<2: yellow,
	yellow | blue<<2: red,
	blue | red<<2: yellow,
	blue | yellow<<2: red,
	blue | blue<<2: blue,
}

var colname = [...]string{
	blue: "blue",
	red: "red",
	yellow: "yellow",
}

// information about the current state of a creature.
type info struct {
	colour	int;	// creature's current colour.
	name	int;	// creature's name.
}

// exclusive access data-structure kept inside meetingplace.
// if mate is nil, it indicates there's no creature currently waiting;
// otherwise the creature's info is stored in info, and
// it is waiting to receive its mate's information on the mate channel.
type rendez struct {
	n	int;		// current number of encounters.
	mate	chan<- info;	// creature waiting when non-nil.
	info	info;		// info about creature waiting.
}

// result sent by each creature at the end of processing.
type result struct {
	met	int;
	same	int;
}

var np = flag.Int("n", 600, "count")
var N int

func main() {
	flag.Parse();
	N = *np;

	for c0 := 0; c0 < ncol; c0++ {
		for c1 := 0; c1 < ncol; c1++ {
			fmt.Printf("%s + %s -> %s\n", colname[c0], colname[c1], colname[complement[c0|c1<<2]])
		}
	}

	pallmall([]int{blue, red, yellow});
	pallmall([]int{blue, red, yellow, red, yellow, blue, red, yellow, red, blue});
}

func pallmall(cols []int) {
	fmt.Print("\n");

	// invariant: meetingplace always contains a value unless a creature
	// is currently dealing with it (whereupon it must put it back).
	meetingplace := make(chan rendez, 1);
	meetingplace <- rendez{n: 0};

	ended := make(chan result);
	msg := "";
	for i, col := range cols {
		go creature(info{col, i}, meetingplace, ended);
		msg += " " + colname[col];
	}
	fmt.Println(msg);
	tot := 0;
	// wait for all results
	for _ = range (cols) {
		result := <-ended;
		tot += result.met;
		fmt.Println(result.met, spell(result.same, true));
	}
	fmt.Println(spell(tot, true));
}

// in this function, variables ending in 0 refer to the local creature,
// variables ending in 1 to the creature we've met.
func creature(info0 info, meetingplace chan rendez, ended chan result) {
	c0 := make(chan info);
	met := 0;
	same := 0;
	for {
		var othername int;
		// get access to rendez data and decide what to do.
		switch r := <-meetingplace; {
		case r.n >= N:
			// if more than N meetings, then send our result data and exit.
			meetingplace <- rendez{n: r.n};
			ended <- result{met, same};
			return;
		case r.mate == nil:
			// no creature waiting; wait for someone to meet us,
			// get their info and send our info in reply.
			meetingplace <- rendez{n: r.n, info: info0, mate: c0};
			info1 := <-c0;
			othername = info1.name;
			info0.colour = complement[info0.colour|info1.colour<<2];
		default:
			// another creature is waiting for us with its info;
			// increment meeting count,
			// send them our info in reply.
			r.n++;
			meetingplace <- rendez{n: r.n, mate: nil};
			r.mate <- info0;
			othername = r.info.name;
			info0.colour = complement[info0.colour|r.info.colour<<2];
		}
		if othername == info0.name {
			same++
		}
		met++;
	}
}

var digits = [...]string{"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"}

func spell(n int, required bool) string {
	if n == 0 && !required {
		return ""
	}
	return spell(n/10, false) + " " + digits[n%10];
}
<|endoftext|>


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

// Garbage collection benchmark: parse Go packages repeatedly.

package main

import (
	"flag"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"log"
	"net/http"
	_ "net/http/pprof"
	"os"
	"path"
	"runtime"
	"strings"
	"time"
)

var serve = flag.String("serve", "", "serve http on this address at end")

func isGoFile(dir os.FileInfo) bool {
	return !dir.IsDir() &&
		!strings.HasPrefix(dir.Name(), ".") && // ignore .files
		path.Ext(dir.Name()) == ".go"
}

func isPkgFile(dir os.FileInfo) bool {
	return isGoFile(dir) &&
		!strings.HasSuffix(dir.Name(), "_test.go") // ignore test files
}

func pkgName(filename string) string {
	file, err := parser.ParseFile(token.NewFileSet(), filename, nil, parser.PackageClauseOnly)
	if err != nil || file == nil {
		return ""
	}
	return file.Name.Name
}

func parseDir(dirpath string) map[string]*ast.Package {
	// the package name is the directory name within its parent
	// (use dirname instead of path because dirname is clean; i.e. has no trailing '/')
	_, pkgname := path.Split(dirpath)

	// filter function to select the desired .go files
	filter := func(d os.FileInfo) bool {
		if isPkgFile(d) {
			// Some directories contain main packages: Only accept
			// files that belong to the expected package so that
			// parser.ParsePackage doesn't return "multiple packages
			// found" errors.
			// Additionally, accept the special package name
			// fakePkgName if we are looking at cmd documentation.
			name := pkgName(dirpath + "/" + d.Name())
			return name == pkgname
		}
		return false
	}

	// get package AST
	pkgs, err := parser.ParseDir(token.NewFileSet(), dirpath, filter, parser.ParseComments)
	if err != nil {
		println("parse", dirpath, err.Error())
		panic("fail")
	}
	return pkgs
}

func main() {
	st := new(runtime.MemStats)
	packages = append(packages, packages...)
	packages = append(packages, packages...)
	n := flag.Int("n", 4, "iterations")
	p := flag.Int("p", len(packages), "# of packages to keep in memory")
	flag.BoolVar(&st.DebugGC, "d", st.DebugGC, "print GC debugging info (pause times)")
	flag.Parse()

	var lastParsed []map[string]*ast.Package
	var t0 time.Time
	var numGC uint32
	var pauseTotalNs uint64
	pkgroot := runtime.GOROOT() + "/src/pkg/"
	for pass := 0; pass < 2; pass++ {
		// Once the heap is grown to full size, reset counters.
		// This hides the start-up pauses, which are much smaller
		// than the normal pauses and would otherwise make
		// the average look much better than it actually is.
		runtime.ReadMemStats(st)
		numGC = st.NumGC
		pauseTotalNs = st.PauseTotalNs
		t0 = time.Now()

		for i := 0; i < *n; i++ {
			parsed := make([]map[string]*ast.Package, *p)
			for j := range parsed {
				parsed[j] = parseDir(pkgroot + packages[j%len(packages)])
			}
			if i+1 == *n && *serve != "" {
				lastParsed = parsed
			}
		}
		runtime.GC()
		runtime.GC()
	}
	t1 := time.Now()

	runtime.ReadMemStats(st)
	st.NumGC -= numGC
	st.PauseTotalNs -= pauseTotalNs
	fmt.Printf("Alloc=%d/%d Heap=%d Mallocs=%d PauseTime=%.3f/%d = %.3f\n",
		st.Alloc, st.TotalAlloc,
		st.Sys,
		st.Mallocs, float64(st.PauseTotalNs)/1e9,
		st.NumGC, float64(st.PauseTotalNs)/1e9/float64(st.NumGC))

	/*
		fmt.Printf("%10s %10s %10s\n", "size", "#alloc", "#free")
		for _, s := range st.BySize {
			fmt.Printf("%10d %10d %10d\n", s.Size, s.Mallocs, s.Frees)
		}
	*/
	// Standard gotest benchmark output, collected by build dashboard.
	gcstats("BenchmarkParser", *n, t1.Sub(t0))

	if *serve != "" {
		log.Fatal(http.ListenAndServe(*serve, nil))
		println(lastParsed)
	}
}

var packages = []string{
	"archive/tar",
	"encoding/asn1",
	"math/big",
	"bufio",
	"bytes",
	"math/cmplx",
	"compress/flate",
	"compress/gzip",
	"compress/zlib",
	"container/heap",
	"container/list",
	"container/ring",
	"crypto/aes",
	"crypto/hmac",
	"crypto/md5",
	"crypto/rand",
	"crypto/rc4",
	"crypto/rsa",
	"crypto/sha1",
	"crypto/sha256",
	"crypto/sha512",
	"crypto/subtle",
	"crypto/tls",
	"crypto/x509",
	"debug/dwarf",
	"debug/macho",
	"debug/elf",
	"debug/gosym",
	"exp/ebnf",
	"encoding/ascii85",
	"encoding/base64",
	"encoding/binary",
	"encoding/hex",
	"encoding/pem",
	"os/exec",
	"flag",
	"fmt",
	"go/ast",
	"go/doc",
	"go/parser",
	"go/printer",
	"go/scanner",
	"go/token",
	"encoding/gob",
	"hash",
	"hash/adler32",
	"hash/crc32",
	"hash/crc64",
	"net/http",
	"image",
	"image/jpeg",
	"image/png",
	"io",
	"io/ioutil",
	"encoding/json",
	"log",
	"math",
	"mime",
	"net",
	"os",
	"path",
	"math/rand",
	"reflect",
	"regexp",
	"net/rpc",
	"runtime",
	"text/scanner",
	"sort",
	"net/smtp",
	"strconv",
	"strings",
	"sync",
	"syscall",
	"log/syslog",
	"text/tabwriter",
	"text/template",
	"testing",
	"testing/iotest",
	"testing/quick",
	"time",
	"unicode",
	"unicode/utf8",
	"unicode/utf16",
	"encoding/xml",
}
<commit_msg>test/bench/garbage: fix parser benchmark<commit_after>// Copyright 2010 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Garbage collection benchmark: parse Go packages repeatedly.

package main

import (
	"flag"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"log"
	"net/http"
	_ "net/http/pprof"
	"os"
	"path"
	"runtime"
	"strings"
	"time"
)

var serve = flag.String("serve", "", "serve http on this address at end")

func isGoFile(dir os.FileInfo) bool {
	return !dir.IsDir() &&
		!strings.HasPrefix(dir.Name(), ".") && // ignore .files
		path.Ext(dir.Name()) == ".go"
}

func isPkgFile(dir os.FileInfo) bool {
	return isGoFile(dir) &&
		!strings.HasSuffix(dir.Name(), "_test.go") // ignore test files
}

func pkgName(filename string) string {
	file, err := parser.ParseFile(token.NewFileSet(), filename, nil, parser.PackageClauseOnly)
	if err != nil || file == nil {
		return ""
	}
	return file.Name.Name
}

func parseDir(dirpath string) map[string]*ast.Package {
	// the package name is the directory name within its parent
	// (use dirname instead of path because dirname is clean; i.e. has no trailing '/')
	_, pkgname := path.Split(dirpath)

	// filter function to select the desired .go files
	filter := func(d os.FileInfo) bool {
		if isPkgFile(d) {
			// Some directories contain main packages: Only accept
			// files that belong to the expected package so that
			// parser.ParsePackage doesn't return "multiple packages
			// found" errors.
			// Additionally, accept the special package name
			// fakePkgName if we are looking at cmd documentation.
			name := pkgName(dirpath + "/" + d.Name())
			return name == pkgname
		}
		return false
	}

	// get package AST
	pkgs, err := parser.ParseDir(token.NewFileSet(), dirpath, filter, parser.ParseComments)
	if err != nil {
		println("parse", dirpath, err.Error())
		panic("fail")
	}
	return pkgs
}

func main() {
	st := new(runtime.MemStats)
	packages = append(packages, packages...)
	packages = append(packages, packages...)
	n := flag.Int("n", 4, "iterations")
	p := flag.Int("p", len(packages), "# of packages to keep in memory")
	flag.BoolVar(&st.DebugGC, "d", st.DebugGC, "print GC debugging info (pause times)")
	flag.Parse()

	var lastParsed []map[string]*ast.Package
	var t0 time.Time
	var numGC uint32
	var pauseTotalNs uint64
	pkgroot := runtime.GOROOT() + "/src/pkg/"
	for pass := 0; pass < 2; pass++ {
		// Once the heap is grown to full size, reset counters.
		// This hides the start-up pauses, which are much smaller
		// than the normal pauses and would otherwise make
		// the average look much better than it actually is.
		runtime.ReadMemStats(st)
		numGC = st.NumGC
		pauseTotalNs = st.PauseTotalNs
		t0 = time.Now()

		for i := 0; i < *n; i++ {
			parsed := make([]map[string]*ast.Package, *p)
			for j := range parsed {
				parsed[j] = parseDir(pkgroot + packages[j%len(packages)])
			}
			if i+1 == *n && *serve != "" {
				lastParsed = parsed
			}
		}
		runtime.GC()
		runtime.GC()
	}
	t1 := time.Now()

	runtime.ReadMemStats(st)
	st.NumGC -= numGC
	st.PauseTotalNs -= pauseTotalNs
	fmt.Printf("Alloc=%d/%d Heap=%d Mallocs=%d PauseTime=%.3f/%d = %.3f\n",
		st.Alloc, st.TotalAlloc,
		st.Sys,
		st.Mallocs, float64(st.PauseTotalNs)/1e9,
		st.NumGC, float64(st.PauseTotalNs)/1e9/float64(st.NumGC))

	/*
		fmt.Printf("%10s %10s %10s\n", "size", "#alloc", "#free")
		for _, s := range st.BySize {
			fmt.Printf("%10d %10d %10d\n", s.Size, s.Mallocs, s.Frees)
		}
	*/
	// Standard gotest benchmark output, collected by build dashboard.
	gcstats("BenchmarkParser", *n, t1.Sub(t0))

	if *serve != "" {
		log.Fatal(http.ListenAndServe(*serve, nil))
		println(lastParsed)
	}
}

// find . -type d -not -path "./exp" -not -path "./exp/*" -printf "\t\"%p\",\n" | sort | sed "s/\.\///" | grep -v testdata
var packages = []string{
	"archive",
	"archive/tar",
	"archive/zip",
	"bufio",
	"builtin",
	"bytes",
	"compress",
	"compress/bzip2",
	"compress/flate",
	"compress/gzip",
	"compress/lzw",
	"compress/zlib",
	"container",
	"container/heap",
	"container/list",
	"container/ring",
	"crypto",
	"crypto/aes",
	"crypto/cipher",
	"crypto/des",
	"crypto/dsa",
	"crypto/ecdsa",
	"crypto/elliptic",
	"crypto/hmac",
	"crypto/md5",
	"crypto/rand",
	"crypto/rc4",
	"crypto/rsa",
	"crypto/sha1",
	"crypto/sha256",
	"crypto/sha512",
	"crypto/subtle",
	"crypto/tls",
	"crypto/x509",
	"crypto/x509/pkix",
	"database",
	"database/sql",
	"database/sql/driver",
	"debug",
	"debug/dwarf",
	"debug/elf",
	"debug/gosym",
	"debug/macho",
	"debug/pe",
	"encoding",
	"encoding/ascii85",
	"encoding/asn1",
	"encoding/base32",
	"encoding/base64",
	"encoding/binary",
	"encoding/csv",
	"encoding/gob",
	"encoding/hex",
	"encoding/json",
	"encoding/pem",
	"encoding/xml",
	"errors",
	"expvar",
	"flag",
	"fmt",
	"go",
	"go/ast",
	"go/build",
	"go/doc",
	"go/format",
	"go/parser",
	"go/printer",
	"go/scanner",
	"go/token",
	"go/types",
	"hash",
	"hash/adler32",
	"hash/crc32",
	"hash/crc64",
	"hash/fnv",
	"html",
	"html/template",
	"image",
	"image/color",
	"image/draw",
	"image/gif",
	"image/jpeg",
	"image/png",
	"index",
	"index/suffixarray",
	"io",
	"io/ioutil",
	"log",
	"log/syslog",
	"math",
	"math/big",
	"math/cmplx",
	"math/rand",
	"mime",
	"mime/multipart",
	"net",
	"net/http",
	"net/http/cgi",
	"net/http/cookiejar",
	"net/http/fcgi",
	"net/http/httptest",
	"net/http/httputil",
	"net/http/pprof",
	"net/mail",
	"net/rpc",
	"net/rpc/jsonrpc",
	"net/smtp",
	"net/textproto",
	"net/url",
	"os",
	"os/exec",
	"os/signal",
	"os/user",
	"path",
	"path/filepath",
	"reflect",
	"regexp",
	"regexp/syntax",
	"runtime",
	"runtime/cgo",
	"runtime/debug",
	"runtime/pprof",
	"runtime/race",
	"sort",
	"strconv",
	"strings",
	"sync",
	"sync/atomic",
	"syscall",
	"testing",
	"testing/iotest",
	"testing/quick",
	"text",
	"text/scanner",
	"text/tabwriter",
	"text/template",
	"text/template/parse",
	"time",
	"unicode",
	"unicode/utf16",
	"unicode/utf8",
	"unsafe",
}
<|endoftext|>


<commit_before>package phraseapp

import (
	"fmt"
	"net/http"

	"github.com/bgentry/speakeasy"
)

type DefaultParams Action
type Action map[string]map[string]interface{}

type AuthCredentials struct {
	Username string `cli:"opt --username desc='username used for authentication'"`
	Token    string `cli:"opt --token desc='token used for authentication'"`
	TFA      bool   `cli:"opt --tfa desc='use Two-Factor Authentication'"`
	Host     string `cli:"opt --host default='https://api.phraseapp.com' desc='Host to send Request to'"`
}

var authC *AuthCredentials

func RegisterAuthCredentials(cmdAuth *AuthCredentials, defaultCredentials *AuthCredentials) {
	authC = new(AuthCredentials)

	if cmdAuth.Token != "" && authC.Token == "" && authC.Username == "" {
		authC.Token = cmdAuth.Token
	} else if cmdAuth.Username != "" && authC.Username == "" {
		authC.Username = cmdAuth.Username
	}

	if cmdAuth.TFA && authC.Username == "" {
		authC.TFA = cmdAuth.TFA || defaultCredentials.TFA
	}

	if cmdAuth.Host != "" {
		authC.Host = cmdAuth.Host
	}

	notSet := authC.Token == "" && authC.Username == ""
	if notSet && defaultCredentials.Token != "" {
		authC.Token = defaultCredentials.Token
	}
	if notSet && defaultCredentials.Username != "" {
		authC.Username = defaultCredentials.Username
	}
}

func authenticate(req *http.Request) error {
	if authC == nil {
		return fmt.Errorf("no auth handler registered")
	}

	if err := authC.validate(); err != nil {
		return err
	}

	switch {
	case authC.Token != "":
		req.Header.Set("Authorization", "token "+authC.Token)
	case authC.Username != "":
		pwd, err := speakeasy.Ask("Password: ")
		if err != nil {
			return err
		}
		req.SetBasicAuth(authC.Username, pwd)

		if authC.TFA { // TFA only required for username+password based login.
			token, err := speakeasy.Ask("TFA-Token: ")
			if err != nil {
				return err
			}
			req.Header.Set("X-PhraseApp-OTP", token)
		}
	}

	return nil
}

func (ah *AuthCredentials) validate() error {
	switch {
	case ah.Username == "" && ah.Token == "":
		return fmt.Errorf("either username or token must be given")
	default:
		return nil
	}
}
<commit_msg>solves default behavior for Host<commit_after>package phraseapp

import (
	"fmt"
	"net/http"

	"github.com/bgentry/speakeasy"
)

type DefaultParams Action
type Action map[string]map[string]interface{}

type AuthCredentials struct {
	Username string `cli:"opt --username desc='username used for authentication'"`
	Token    string `cli:"opt --token desc='token used for authentication'"`
	TFA      bool   `cli:"opt --tfa desc='use Two-Factor Authentication'"`
	Host     string `cli:"opt --host desc='Host to send Request to'"`
}

var authC *AuthCredentials

func RegisterAuthCredentials(cmdAuth *AuthCredentials, defaultCredentials *AuthCredentials) {
	authC = new(AuthCredentials)

	if cmdAuth.Token != "" && authC.Token == "" && authC.Username == "" {
		authC.Token = cmdAuth.Token
	} else if cmdAuth.Username != "" && authC.Username == "" {
		authC.Username = cmdAuth.Username
	}

	if cmdAuth.TFA && authC.Username == "" {
		authC.TFA = cmdAuth.TFA || defaultCredentials.TFA
	}

	if cmdAuth.Host != "" {
		authC.Host = cmdAuth.Host
	} else {
		if defaultCredentials.Host != "" {
			authC.Host = defaultCredentials.Host
		}
	}

	if authC.Host == "" {
		authC.Host = "https://api.phraseapp.com"
	}

	notSet := authC.Token == "" && authC.Username == ""
	if notSet && defaultCredentials.Token != "" {
		authC.Token = defaultCredentials.Token
	}
	if notSet && defaultCredentials.Username != "" {
		authC.Username = defaultCredentials.Username
	}
}

func authenticate(req *http.Request) error {
	if authC == nil {
		return fmt.Errorf("no auth handler registered")
	}

	if err := authC.validate(); err != nil {
		return err
	}

	switch {
	case authC.Token != "":
		req.Header.Set("Authorization", "token "+authC.Token)
	case authC.Username != "":
		pwd, err := speakeasy.Ask("Password: ")
		if err != nil {
			return err
		}
		req.SetBasicAuth(authC.Username, pwd)

		if authC.TFA { // TFA only required for username+password based login.
			token, err := speakeasy.Ask("TFA-Token: ")
			if err != nil {
				return err
			}
			req.Header.Set("X-PhraseApp-OTP", token)
		}
	}

	return nil
}

func (ah *AuthCredentials) validate() error {
	switch {
	case ah.Username == "" && ah.Token == "":
		return fmt.Errorf("either username or token must be given")
	default:
		return nil
	}
}
<|endoftext|>


<commit_before>/*§
  ===========================================================================
  MoonDeploy
  ===========================================================================
  Copyright (C) 2015-2016 Gianluca Costa
  ===========================================================================
  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 descriptors

import (
	"fmt"
	"path"
	"path/filepath"
	"strings"
)

func validate(descriptor AppDescriptor) (err error) {
	if descriptor.GetDescriptorVersion() == nil {
		return fmt.Errorf("Descriptor Version field is missing")
	}

	if descriptor.GetDeclaredBaseURL() == nil {
		return fmt.Errorf("Declared Base URL field is missing")
	}

	if descriptor.GetActualBaseURL() == nil {
		return fmt.Errorf("Actual Base URL field is missing")
	}

	descriptorFileName := descriptor.GetDescriptorFileName()
	if strings.TrimSpace(descriptorFileName) == "" {
		return fmt.Errorf("Descriptor File Name field is missing")
	}

	if path.Base(descriptorFileName) != descriptorFileName {
		return fmt.Errorf("Descriptor File Name cannot be a path")
	}

	if strings.TrimSpace(descriptor.GetName()) == "" {
		return fmt.Errorf("Name field is missing")
	}

	if descriptor.GetAppVersion() == nil {
		return fmt.Errorf("App version field is missing")
	}

	if strings.TrimSpace(descriptor.GetPublisher()) == "" {
		return fmt.Errorf("Publisher field is missing")
	}

	if strings.TrimSpace(descriptor.GetDescription()) == "" {
		return fmt.Errorf("Description field is missing")
	}

	if descriptor.GetPackageVersions() == nil {
		return fmt.Errorf("Package versions field is missing")
	}

	iconPath := descriptor.GetIconPath()
	if iconPath != "" {
		if filepath.IsAbs(iconPath) {
			return fmt.Errorf("The Icon Path must be relative")
		}
	}

	commandLine := descriptor.GetCommandLine()
	if commandLine == nil || len(commandLine) == 0 {
		return fmt.Errorf("Command Line field is missing")
	}

	if descriptor.GetSkipPackageLevels() < 0 {
		return fmt.Errorf("SkipPackageLevels field must be >= 0")
	}

	if strings.TrimSpace(descriptor.GetTitle()) == "" {
		return fmt.Errorf("Title is missing")
	}

	return nil
}

func CheckDescriptorMatch(descriptor AppDescriptor, otherDescriptor AppDescriptor) (err error) {
	if descriptor.GetDeclaredBaseURL().String() != otherDescriptor.GetDeclaredBaseURL().String() {
		return fmt.Errorf("The descriptors have different BaseURL's:\n\t'%v'\n\t'%v'",
			descriptor.GetDeclaredBaseURL(),
			otherDescriptor.GetDeclaredBaseURL())
	}

	if descriptor.GetDescriptorFileName() != otherDescriptor.GetDescriptorFileName() {
		return fmt.Errorf("The descriptors have different Descriptor File Name values:\n\t'%v'\n\t'%v",
			descriptor.GetDescriptorFileName(),
			otherDescriptor.GetDescriptorFileName())
	}

	if descriptor.GetName() != otherDescriptor.GetName() {
		return fmt.Errorf("The descriptors have different Name values:\n\t'%v'\n\t'%v",
			descriptor.GetName(),
			otherDescriptor.GetName())
	}

	return nil
}
<commit_msg>Enforce .moondeploy extension for app descriptors<commit_after>/*§
  ===========================================================================
  MoonDeploy
  ===========================================================================
  Copyright (C) 2015-2016 Gianluca Costa
  ===========================================================================
  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 descriptors

import (
	"fmt"
	"path"
	"path/filepath"
	"strings"
)

func validate(descriptor AppDescriptor) (err error) {
	if descriptor.GetDescriptorVersion() == nil {
		return fmt.Errorf("Descriptor Version field is missing")
	}

	if descriptor.GetDeclaredBaseURL() == nil {
		return fmt.Errorf("Declared Base URL field is missing")
	}

	if descriptor.GetActualBaseURL() == nil {
		return fmt.Errorf("Actual Base URL field is missing")
	}

	descriptorFileName := descriptor.GetDescriptorFileName()
	if strings.TrimSpace(descriptorFileName) == "" {
		return fmt.Errorf("Descriptor File Name field is missing")
	}

	if !strings.HasSuffix(descriptorFileName, ".moondeploy") {
		return fmt.Errorf("The descriptor filename must end with .moondeploy")
	}

	if path.Base(descriptorFileName) != descriptorFileName {
		return fmt.Errorf("Descriptor File Name cannot be a path")
	}

	if strings.TrimSpace(descriptor.GetName()) == "" {
		return fmt.Errorf("Name field is missing")
	}

	if descriptor.GetAppVersion() == nil {
		return fmt.Errorf("App version field is missing")
	}

	if strings.TrimSpace(descriptor.GetPublisher()) == "" {
		return fmt.Errorf("Publisher field is missing")
	}

	if strings.TrimSpace(descriptor.GetDescription()) == "" {
		return fmt.Errorf("Description field is missing")
	}

	if descriptor.GetPackageVersions() == nil {
		return fmt.Errorf("Package versions field is missing")
	}

	iconPath := descriptor.GetIconPath()
	if iconPath != "" {
		if filepath.IsAbs(iconPath) {
			return fmt.Errorf("The Icon Path must be relative")
		}
	}

	commandLine := descriptor.GetCommandLine()
	if commandLine == nil || len(commandLine) == 0 {
		return fmt.Errorf("Command Line field is missing")
	}

	if descriptor.GetSkipPackageLevels() < 0 {
		return fmt.Errorf("SkipPackageLevels field must be >= 0")
	}

	if strings.TrimSpace(descriptor.GetTitle()) == "" {
		return fmt.Errorf("Title is missing")
	}

	return nil
}

func CheckDescriptorMatch(descriptor AppDescriptor, otherDescriptor AppDescriptor) (err error) {
	if descriptor.GetDeclaredBaseURL().String() != otherDescriptor.GetDeclaredBaseURL().String() {
		return fmt.Errorf("The descriptors have different BaseURL's:\n\t'%v'\n\t'%v'",
			descriptor.GetDeclaredBaseURL(),
			otherDescriptor.GetDeclaredBaseURL())
	}

	if descriptor.GetDescriptorFileName() != otherDescriptor.GetDescriptorFileName() {
		return fmt.Errorf("The descriptors have different Descriptor File Name values:\n\t'%v'\n\t'%v",
			descriptor.GetDescriptorFileName(),
			otherDescriptor.GetDescriptorFileName())
	}

	if descriptor.GetName() != otherDescriptor.GetName() {
		return fmt.Errorf("The descriptors have different Name values:\n\t'%v'\n\t'%v",
			descriptor.GetName(),
			otherDescriptor.GetName())
	}

	return nil
}
<|endoftext|>


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

package v1alpha3_test

import (
	"testing"

	"github.com/google/go-cmp/cmp"

	"istio.io/istio/pilot/pkg/model"
	"istio.io/istio/pilot/pkg/networking/core"
	nds "istio.io/istio/pilot/pkg/proto"
	"istio.io/istio/pilot/pkg/serviceregistry"
	"istio.io/istio/pkg/cluster"
	"istio.io/istio/pkg/config/constants"
	"istio.io/istio/pkg/config/host"
	"istio.io/istio/pkg/config/protocol"
)

func makeServiceInstances(proxy *model.Proxy, service *model.Service, hostname, subdomain string) map[int][]*model.ServiceInstance {
	instances := make(map[int][]*model.ServiceInstance)
	for _, port := range service.Ports {
		instances[port.Port] = makeInstances(proxy, service, port.Port, port.Port)
		instances[port.Port][0].Endpoint.HostName = hostname
		instances[port.Port][0].Endpoint.SubDomain = subdomain

	}
	return instances
}

func TestNameTable(t *testing.T) {
	proxy := &model.Proxy{
		IPAddresses: []string{"9.9.9.9"},
		Metadata:    &model.NodeMetadata{},
		Type:        model.SidecarProxy,
		DNSDomain:   "testns.svc.cluster.local",
	}

	pod1 := &model.Proxy{
		IPAddresses: []string{"1.2.3.4"},
		Metadata:    &model.NodeMetadata{},
		Type:        model.SidecarProxy,
		DNSDomain:   "testns.svc.cluster.local",
	}
	pod2 := &model.Proxy{
		IPAddresses: []string{"9.6.7.8"},
		Metadata:    &model.NodeMetadata{},
		Type:        model.SidecarProxy,
		DNSDomain:   "testns.svc.cluster.local",
	}

	headlessService := &model.Service{
		Hostname:    host.Name("headless-svc.testns.svc.cluster.local"),
		Address:     constants.UnspecifiedIP,
		ClusterVIPs: make(map[cluster.ID]string),
		Ports: model.PortList{&model.Port{
			Name:     "tcp-port",
			Port:     9000,
			Protocol: protocol.TCP,
		}},
		Resolution: model.Passthrough,
		Attributes: model.ServiceAttributes{
			Name:            "headless-svc",
			Namespace:       "testns",
			ServiceRegistry: string(serviceregistry.Kubernetes),
		},
	}

	wildcardService := &model.Service{
		Hostname:    host.Name("*.testns.svc.cluster.local"),
		Address:     "172.10.10.10",
		ClusterVIPs: make(map[cluster.ID]string),
		Ports: model.PortList{
			&model.Port{
				Name:     "tcp-port",
				Port:     9000,
				Protocol: protocol.TCP,
			},
			&model.Port{
				Name:     "http-port",
				Port:     8000,
				Protocol: protocol.HTTP,
			},
		},
		Resolution: model.ClientSideLB,
		Attributes: model.ServiceAttributes{
			Name:            "wildcard-svc",
			Namespace:       "testns",
			ServiceRegistry: string(serviceregistry.Kubernetes),
		},
	}

	cidrService := &model.Service{
		Hostname:    host.Name("*.testns.svc.cluster.local"),
		Address:     "172.217.0.0/16",
		ClusterVIPs: make(map[cluster.ID]string),
		Ports: model.PortList{
			&model.Port{
				Name:     "tcp-port",
				Port:     9000,
				Protocol: protocol.TCP,
			},
			&model.Port{
				Name:     "http-port",
				Port:     8000,
				Protocol: protocol.HTTP,
			},
		},
		Resolution: model.ClientSideLB,
		Attributes: model.ServiceAttributes{
			Name:            "cidr-svc",
			Namespace:       "testns",
			ServiceRegistry: string(serviceregistry.Kubernetes),
		},
	}

	push := model.NewPushContext()
	push.AddPublicServices([]*model.Service{headlessService})
	push.AddServiceInstances(headlessService,
		makeServiceInstances(pod1, headlessService, "pod1", "headless-svc"))
	push.AddServiceInstances(headlessService,
		makeServiceInstances(pod2, headlessService, "pod2", "headless-svc"))

	wpush := model.NewPushContext()
	wpush.AddPublicServices([]*model.Service{wildcardService})

	cpush := model.NewPushContext()
	wpush.AddPublicServices([]*model.Service{cidrService})

	cases := []struct {
		name              string
		proxy             *model.Proxy
		push              *model.PushContext
		expectedNameTable *nds.NameTable
	}{
		{
			name:  "headless service pods",
			proxy: proxy,
			push:  push,
			expectedNameTable: &nds.NameTable{
				Table: map[string]*nds.NameTable_NameInfo{
					"pod1.headless-svc.testns.svc.cluster.local": {
						Ips:       []string{"1.2.3.4"},
						Registry:  "Kubernetes",
						Shortname: "pod1.headless-svc",
						Namespace: "testns",
					},
					"pod2.headless-svc.testns.svc.cluster.local": {
						Ips:       []string{"9.6.7.8"},
						Registry:  "Kubernetes",
						Shortname: "pod2.headless-svc",
						Namespace: "testns",
					},
					"headless-svc.testns.svc.cluster.local": {
						Ips:       []string{"1.2.3.4", "9.6.7.8"},
						Registry:  "Kubernetes",
						Shortname: "headless-svc",
						Namespace: "testns",
					},
				},
			},
		},
		{
			name:  "wildcard service pods",
			proxy: proxy,
			push:  wpush,
			expectedNameTable: &nds.NameTable{
				Table: map[string]*nds.NameTable_NameInfo{
					"*.testns.svc.cluster.local": {
						Ips:       []string{"172.10.10.10"},
						Registry:  "Kubernetes",
						Shortname: "wildcard-svc",
						Namespace: "testns",
					},
				},
			},
		},
		{
			name:  "cidr service",
			proxy: proxy,
			push:  cpush,
			expectedNameTable: &nds.NameTable{
				Table: map[string]*nds.NameTable_NameInfo{},
			},
		},
	}
	for _, tt := range cases {
		t.Run(tt.name, func(t *testing.T) {
			configgen := core.NewConfigGenerator(nil, model.DisabledCache{})
			if diff := cmp.Diff(configgen.BuildNameTable(tt.proxy, tt.push), tt.expectedNameTable); diff != "" {
				t.Fatalf("got diff: %v", diff)
			}
		})
	}
}
<commit_msg>dns: add multi cluster and multi network cases (#33655)<commit_after>// Copyright Istio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package v1alpha3_test

import (
	"testing"

	"github.com/google/go-cmp/cmp"

	"istio.io/istio/pilot/pkg/features"
	"istio.io/istio/pilot/pkg/model"
	"istio.io/istio/pilot/pkg/networking/core"
	nds "istio.io/istio/pilot/pkg/proto"
	"istio.io/istio/pilot/pkg/serviceregistry"
	"istio.io/istio/pkg/cluster"
	"istio.io/istio/pkg/config/constants"
	"istio.io/istio/pkg/config/host"
	"istio.io/istio/pkg/config/protocol"
)

// nolint
func makeServiceInstances(proxy *model.Proxy, service *model.Service, hostname, subdomain string) map[int][]*model.ServiceInstance {
	instances := make(map[int][]*model.ServiceInstance)
	for _, port := range service.Ports {
		instances[port.Port] = makeInstances(proxy, service, port.Port, port.Port)
		instances[port.Port][0].Endpoint.HostName = hostname
		instances[port.Port][0].Endpoint.SubDomain = subdomain
		instances[port.Port][0].Endpoint.Network = proxy.Metadata.Network
		instances[port.Port][0].Endpoint.Locality.ClusterID = proxy.Metadata.ClusterID
	}
	return instances
}

func TestNameTable(t *testing.T) {
	proxy := &model.Proxy{
		IPAddresses: []string{"9.9.9.9"},
		Metadata:    &model.NodeMetadata{},
		Type:        model.SidecarProxy,
		DNSDomain:   "testns.svc.cluster.local",
	}
	nw1proxy := &model.Proxy{
		IPAddresses: []string{"9.9.9.9"},
		Metadata:    &model.NodeMetadata{Network: "nw1"},
		Type:        model.SidecarProxy,
		DNSDomain:   "testns.svc.cluster.local",
	}
	cl1proxy := &model.Proxy{
		IPAddresses: []string{"9.9.9.9"},
		Metadata:    &model.NodeMetadata{ClusterID: "cl1"},
		Type:        model.SidecarProxy,
		DNSDomain:   "testns.svc.cluster.local",
	}

	pod1 := &model.Proxy{
		IPAddresses: []string{"1.2.3.4"},
		Metadata:    &model.NodeMetadata{},
		Type:        model.SidecarProxy,
		DNSDomain:   "testns.svc.cluster.local",
	}
	pod2 := &model.Proxy{
		IPAddresses: []string{"9.6.7.8"},
		Metadata:    &model.NodeMetadata{Network: "nw2", ClusterID: "cl2"},
		Type:        model.SidecarProxy,
		DNSDomain:   "testns.svc.cluster.local",
	}
	pod3 := &model.Proxy{
		IPAddresses: []string{"19.6.7.8"},
		Metadata:    &model.NodeMetadata{Network: "nw1"},
		Type:        model.SidecarProxy,
		DNSDomain:   "testns.svc.cluster.local",
	}
	pod4 := &model.Proxy{
		IPAddresses: []string{"9.16.7.8"},
		Metadata:    &model.NodeMetadata{ClusterID: "cl1"},
		Type:        model.SidecarProxy,
		DNSDomain:   "testns.svc.cluster.local",
	}

	headlessService := &model.Service{
		Hostname:    host.Name("headless-svc.testns.svc.cluster.local"),
		Address:     constants.UnspecifiedIP,
		ClusterVIPs: make(map[cluster.ID]string),
		Ports: model.PortList{&model.Port{
			Name:     "tcp-port",
			Port:     9000,
			Protocol: protocol.TCP,
		}},
		Resolution: model.Passthrough,
		Attributes: model.ServiceAttributes{
			Name:            "headless-svc",
			Namespace:       "testns",
			ServiceRegistry: string(serviceregistry.Kubernetes),
		},
	}

	wildcardService := &model.Service{
		Hostname:    host.Name("*.testns.svc.cluster.local"),
		Address:     "172.10.10.10",
		ClusterVIPs: make(map[cluster.ID]string),
		Ports: model.PortList{
			&model.Port{
				Name:     "tcp-port",
				Port:     9000,
				Protocol: protocol.TCP,
			},
			&model.Port{
				Name:     "http-port",
				Port:     8000,
				Protocol: protocol.HTTP,
			},
		},
		Resolution: model.ClientSideLB,
		Attributes: model.ServiceAttributes{
			Name:            "wildcard-svc",
			Namespace:       "testns",
			ServiceRegistry: string(serviceregistry.Kubernetes),
		},
	}

	cidrService := &model.Service{
		Hostname:    host.Name("*.testns.svc.cluster.local"),
		Address:     "172.217.0.0/16",
		ClusterVIPs: make(map[cluster.ID]string),
		Ports: model.PortList{
			&model.Port{
				Name:     "tcp-port",
				Port:     9000,
				Protocol: protocol.TCP,
			},
			&model.Port{
				Name:     "http-port",
				Port:     8000,
				Protocol: protocol.HTTP,
			},
		},
		Resolution: model.ClientSideLB,
		Attributes: model.ServiceAttributes{
			Name:            "cidr-svc",
			Namespace:       "testns",
			ServiceRegistry: string(serviceregistry.Kubernetes),
		},
	}

	push := model.NewPushContext()
	push.AddPublicServices([]*model.Service{headlessService})
	push.AddServiceInstances(headlessService,
		makeServiceInstances(pod1, headlessService, "pod1", "headless-svc"))
	push.AddServiceInstances(headlessService,
		makeServiceInstances(pod2, headlessService, "pod2", "headless-svc"))
	push.AddServiceInstances(headlessService,
		makeServiceInstances(pod3, headlessService, "pod3", "headless-svc"))
	push.AddServiceInstances(headlessService,
		makeServiceInstances(pod4, headlessService, "pod4", "headless-svc"))

	wpush := model.NewPushContext()
	wpush.AddPublicServices([]*model.Service{wildcardService})

	cpush := model.NewPushContext()
	wpush.AddPublicServices([]*model.Service{cidrService})

	cases := []struct {
		name                       string
		proxy                      *model.Proxy
		push                       *model.PushContext
		enableMultiClusterHeadless bool
		expectedNameTable          *nds.NameTable
	}{
		{
			name:  "headless service pods",
			proxy: proxy,
			push:  push,
			expectedNameTable: &nds.NameTable{
				Table: map[string]*nds.NameTable_NameInfo{
					"pod1.headless-svc.testns.svc.cluster.local": {
						Ips:       []string{"1.2.3.4"},
						Registry:  "Kubernetes",
						Shortname: "pod1.headless-svc",
						Namespace: "testns",
					},
					"pod2.headless-svc.testns.svc.cluster.local": {
						Ips:       []string{"9.6.7.8"},
						Registry:  "Kubernetes",
						Shortname: "pod2.headless-svc",
						Namespace: "testns",
					},
					"pod3.headless-svc.testns.svc.cluster.local": {
						Ips:       []string{"19.6.7.8"},
						Registry:  "Kubernetes",
						Shortname: "pod3.headless-svc",
						Namespace: "testns",
					},
					"pod4.headless-svc.testns.svc.cluster.local": {
						Ips:       []string{"9.16.7.8"},
						Registry:  "Kubernetes",
						Shortname: "pod4.headless-svc",
						Namespace: "testns",
					},
					"headless-svc.testns.svc.cluster.local": {
						Ips:       []string{"1.2.3.4", "9.6.7.8", "19.6.7.8", "9.16.7.8"},
						Registry:  "Kubernetes",
						Shortname: "headless-svc",
						Namespace: "testns",
					},
				},
			},
		},
		{
			name:  "headless service pods with network isolation",
			proxy: nw1proxy,
			push:  push,
			expectedNameTable: &nds.NameTable{
				Table: map[string]*nds.NameTable_NameInfo{
					"pod1.headless-svc.testns.svc.cluster.local": {
						Ips:       []string{"1.2.3.4"},
						Registry:  "Kubernetes",
						Shortname: "pod1.headless-svc",
						Namespace: "testns",
					},
					"pod3.headless-svc.testns.svc.cluster.local": {
						Ips:       []string{"19.6.7.8"},
						Registry:  "Kubernetes",
						Shortname: "pod3.headless-svc",
						Namespace: "testns",
					},
					"pod4.headless-svc.testns.svc.cluster.local": {
						Ips:       []string{"9.16.7.8"},
						Registry:  "Kubernetes",
						Shortname: "pod4.headless-svc",
						Namespace: "testns",
					},
					"headless-svc.testns.svc.cluster.local": {
						Ips:       []string{"1.2.3.4", "19.6.7.8", "9.16.7.8"},
						Registry:  "Kubernetes",
						Shortname: "headless-svc",
						Namespace: "testns",
					},
				},
			},
		},
		{
			name:  "multi cluster headless service pods",
			proxy: cl1proxy,
			push:  push,
			expectedNameTable: &nds.NameTable{
				Table: map[string]*nds.NameTable_NameInfo{
					"pod1.headless-svc.testns.svc.cluster.local": {
						Ips:       []string{"1.2.3.4"},
						Registry:  "Kubernetes",
						Shortname: "pod1.headless-svc",
						Namespace: "testns",
					},
					"pod2.headless-svc.testns.svc.cluster.local": {
						Ips:       []string{"9.6.7.8"},
						Registry:  "Kubernetes",
						Shortname: "pod2.headless-svc",
						Namespace: "testns",
					},
					"pod3.headless-svc.testns.svc.cluster.local": {
						Ips:       []string{"19.6.7.8"},
						Registry:  "Kubernetes",
						Shortname: "pod3.headless-svc",
						Namespace: "testns",
					},
					"pod4.headless-svc.testns.svc.cluster.local": {
						Ips:       []string{"9.16.7.8"},
						Registry:  "Kubernetes",
						Shortname: "pod4.headless-svc",
						Namespace: "testns",
					},
					"headless-svc.testns.svc.cluster.local": {
						Ips:       []string{"1.2.3.4", "19.6.7.8", "9.16.7.8"},
						Registry:  "Kubernetes",
						Shortname: "headless-svc",
						Namespace: "testns",
					},
				},
			},
		},
		{
			name:                       "multi cluster headless service pods with multi cluster enabled",
			proxy:                      cl1proxy,
			push:                       push,
			enableMultiClusterHeadless: true,
			expectedNameTable: &nds.NameTable{
				Table: map[string]*nds.NameTable_NameInfo{
					"pod1.headless-svc.testns.svc.cluster.local": {
						Ips:       []string{"1.2.3.4"},
						Registry:  "Kubernetes",
						Shortname: "pod1.headless-svc",
						Namespace: "testns",
					},
					"pod2.headless-svc.testns.svc.cluster.local": {
						Ips:       []string{"9.6.7.8"},
						Registry:  "Kubernetes",
						Shortname: "pod2.headless-svc",
						Namespace: "testns",
					},
					"pod3.headless-svc.testns.svc.cluster.local": {
						Ips:       []string{"19.6.7.8"},
						Registry:  "Kubernetes",
						Shortname: "pod3.headless-svc",
						Namespace: "testns",
					},
					"pod4.headless-svc.testns.svc.cluster.local": {
						Ips:       []string{"9.16.7.8"},
						Registry:  "Kubernetes",
						Shortname: "pod4.headless-svc",
						Namespace: "testns",
					},
					"headless-svc.testns.svc.cluster.local": {
						Ips:       []string{"1.2.3.4", "9.6.7.8", "19.6.7.8", "9.16.7.8"},
						Registry:  "Kubernetes",
						Shortname: "headless-svc",
						Namespace: "testns",
					},
				},
			},
		},
		{
			name:  "wildcard service pods",
			proxy: proxy,
			push:  wpush,
			expectedNameTable: &nds.NameTable{
				Table: map[string]*nds.NameTable_NameInfo{
					"*.testns.svc.cluster.local": {
						Ips:       []string{"172.10.10.10"},
						Registry:  "Kubernetes",
						Shortname: "wildcard-svc",
						Namespace: "testns",
					},
				},
			},
		},
		{
			name:  "cidr service",
			proxy: proxy,
			push:  cpush,
			expectedNameTable: &nds.NameTable{
				Table: map[string]*nds.NameTable_NameInfo{},
			},
		},
	}
	for _, tt := range cases {
		t.Run(tt.name, func(t *testing.T) {
			dvalue := features.MulticlusterHeadlessEnabled
			features.MulticlusterHeadlessEnabled = tt.enableMultiClusterHeadless
			defer func() { features.MulticlusterHeadlessEnabled = dvalue }()
			configgen := core.NewConfigGenerator(nil, model.DisabledCache{})
			if diff := cmp.Diff(configgen.BuildNameTable(tt.proxy, tt.push), tt.expectedNameTable); diff != "" {
				t.Fatalf("got diff: %v", diff)
			}
		})
	}
}
<|endoftext|>


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

//go:build !race
// +build !race

package integration

import (
	"os"
	"os/exec"
	"strings"
	"testing"
	"time"

	"github.com/u-root/u-root/pkg/qemu"
	"github.com/u-root/u-root/pkg/uroot"
	"github.com/u-root/u-root/pkg/vmtest"
)

// testPkgs returns a slice of tests to run.
func testPkgs(t *testing.T) []string {
	// Packages which do not contain tests (or do not contain tests for the
	// build target) will still compile a test binary which vacuously pass.
	cmd := exec.Command("go", "list",
		"github.com/u-root/u-root/cmds/boot/...",
		"github.com/u-root/u-root/cmds/core/...",
		"github.com/u-root/u-root/cmds/exp/...",
		"github.com/u-root/u-root/pkg/...",
	)
	cmd.Env = append(os.Environ(), "GOARCH="+vmtest.TestArch())
	out, err := cmd.CombinedOutput()
	if err != nil {
		t.Fatal(err)
	}
	pkgs := strings.Fields(strings.TrimSpace(string(out)))

	// TODO: Some tests do not run properly in QEMU at the moment. They are
	// blocklisted. These tests fail for mostly two reasons:
	// 1. either it requires networking (not enabled in the kernel)
	// 2. or it depends on some test files (for example /bin/sleep)
	blocklist := []string{
		"github.com/u-root/u-root/cmds/core/cmp",
		"github.com/u-root/u-root/cmds/core/dd",
		"github.com/u-root/u-root/cmds/core/fusermount",
		"github.com/u-root/u-root/cmds/core/wget",
		"github.com/u-root/u-root/cmds/core/which",
		"github.com/u-root/u-root/cmds/exp/gosh",
		"github.com/u-root/u-root/cmds/exp/pox",
		"github.com/u-root/u-root/pkg/crypto",
		"github.com/u-root/u-root/pkg/tarutil",
		"github.com/u-root/u-root/pkg/ldd",

		// These have special configuration.
		"github.com/u-root/u-root/pkg/gpio",
		"github.com/u-root/u-root/pkg/mount",
		"github.com/u-root/u-root/pkg/mount/loop",

		// Missing xzcat in VM.
		"github.com/u-root/u-root/cmds/exp/bzimage",
		"github.com/u-root/u-root/pkg/boot/bzimage",

		// No Go compiler in VM.
		"github.com/u-root/u-root/pkg/bb",
		"github.com/u-root/u-root/pkg/uroot",
		"github.com/u-root/u-root/pkg/uroot/builder",

		// ??
		"github.com/u-root/u-root/pkg/tss",
	}
	if vmtest.TestArch() == "arm64" {
		blocklist = append(
			blocklist,
			"github.com/u-root/u-root/pkg/strace",
		)
	}
	for i := 0; i < len(pkgs); i++ {
		for _, b := range blocklist {
			if pkgs[i] == b {
				pkgs = append(pkgs[:i], pkgs[i+1:]...)
			}
		}
	}

	return pkgs
}

// TestGoTest effectively runs "go test ./..." inside a QEMU instance. The
// tests run as root and can do all sorts of things not possible otherwise.
func TestGoTest(t *testing.T) {
	pkgs := testPkgs(t)

	o := &vmtest.Options{
		QEMUOpts: qemu.Options{
			Timeout: 120 * time.Second,
			Devices: []qemu.Device{
				// Bump this up so that some unit tests can happily
				// and questionably pre-claim large bytes slices.
				//
				// e.g. pkg/mount/gpt/gpt_test.go need to claim 4.29G
				//
				//     disk = make([]byte, 0x100000000)
				qemu.ArbitraryArgs{"-m", "6G"},
			},
		},
		BuildOpts: uroot.Opts{
			ExtraFiles: []string{
				"/etc/group",
			},
		},
	}
	vmtest.GolangTest(t, pkgs, o)
}
<commit_msg>Add /etc/passwd file to integration tests. This will be used for testing of id cmd<commit_after>// Copyright 2018 the u-root Authors. All rights reserved
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build !race
// +build !race

package integration

import (
	"os"
	"os/exec"
	"strings"
	"testing"
	"time"

	"github.com/u-root/u-root/pkg/qemu"
	"github.com/u-root/u-root/pkg/uroot"
	"github.com/u-root/u-root/pkg/vmtest"
)

// testPkgs returns a slice of tests to run.
func testPkgs(t *testing.T) []string {
	// Packages which do not contain tests (or do not contain tests for the
	// build target) will still compile a test binary which vacuously pass.
	cmd := exec.Command("go", "list",
		"github.com/u-root/u-root/cmds/boot/...",
		"github.com/u-root/u-root/cmds/core/...",
		"github.com/u-root/u-root/cmds/exp/...",
		"github.com/u-root/u-root/pkg/...",
	)
	cmd.Env = append(os.Environ(), "GOARCH="+vmtest.TestArch())
	out, err := cmd.CombinedOutput()
	if err != nil {
		t.Fatal(err)
	}
	pkgs := strings.Fields(strings.TrimSpace(string(out)))

	// TODO: Some tests do not run properly in QEMU at the moment. They are
	// blocklisted. These tests fail for mostly two reasons:
	// 1. either it requires networking (not enabled in the kernel)
	// 2. or it depends on some test files (for example /bin/sleep)
	blocklist := []string{
		"github.com/u-root/u-root/cmds/core/cmp",
		"github.com/u-root/u-root/cmds/core/dd",
		"github.com/u-root/u-root/cmds/core/fusermount",
		"github.com/u-root/u-root/cmds/core/wget",
		"github.com/u-root/u-root/cmds/core/which",
		"github.com/u-root/u-root/cmds/exp/gosh",
		"github.com/u-root/u-root/cmds/exp/pox",
		"github.com/u-root/u-root/pkg/crypto",
		"github.com/u-root/u-root/pkg/tarutil",
		"github.com/u-root/u-root/pkg/ldd",

		// These have special configuration.
		"github.com/u-root/u-root/pkg/gpio",
		"github.com/u-root/u-root/pkg/mount",
		"github.com/u-root/u-root/pkg/mount/loop",

		// Missing xzcat in VM.
		"github.com/u-root/u-root/cmds/exp/bzimage",
		"github.com/u-root/u-root/pkg/boot/bzimage",

		// No Go compiler in VM.
		"github.com/u-root/u-root/pkg/bb",
		"github.com/u-root/u-root/pkg/uroot",
		"github.com/u-root/u-root/pkg/uroot/builder",

		// ??
		"github.com/u-root/u-root/pkg/tss",
	}
	if vmtest.TestArch() == "arm64" {
		blocklist = append(
			blocklist,
			"github.com/u-root/u-root/pkg/strace",
		)
	}
	for i := 0; i < len(pkgs); i++ {
		for _, b := range blocklist {
			if pkgs[i] == b {
				pkgs = append(pkgs[:i], pkgs[i+1:]...)
			}
		}
	}

	return pkgs
}

// TestGoTest effectively runs "go test ./..." inside a QEMU instance. The
// tests run as root and can do all sorts of things not possible otherwise.
func TestGoTest(t *testing.T) {
	pkgs := testPkgs(t)

	o := &vmtest.Options{
		QEMUOpts: qemu.Options{
			Timeout: 120 * time.Second,
			Devices: []qemu.Device{
				// Bump this up so that some unit tests can happily
				// and questionably pre-claim large bytes slices.
				//
				// e.g. pkg/mount/gpt/gpt_test.go need to claim 4.29G
				//
				//     disk = make([]byte, 0x100000000)
				qemu.ArbitraryArgs{"-m", "6G"},
			},
		},
		BuildOpts: uroot.Opts{
			ExtraFiles: []string{
				"/etc/group",
				"/etc/passwd",
			},
		},
	}
	vmtest.GolangTest(t, pkgs, o)
}
<|endoftext|>


<commit_before>package sftp_test

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
	"path"
	"strings"

	"github.com/pkg/sftp"
	"golang.org/x/crypto/ssh"
)

func Example() {
	var conn *ssh.Client

	// open an SFTP session over an existing ssh connection.
	sftp, err := sftp.NewClient(conn)
	if err != nil {
		log.Fatal(err)
	}
	defer sftp.Close()

	// walk a directory
	w := sftp.Walk("/home/user")
	for w.Step() {
		if w.Err() != nil {
			continue
		}
		log.Println(w.Path())
	}

	// leave your mark
	f, err := sftp.Create("hello.txt")
	if err != nil {
		log.Fatal(err)
	}
	if _, err := f.Write([]byte("Hello world!")); err != nil {
		log.Fatal(err)
	}

	// check it's there
	fi, err := sftp.Lstat("hello.txt")
	if err != nil {
		log.Fatal(err)
	}
	log.Println(fi)
}

func ExampleNewClientPipe() {
	// Connect to a remote host and request the sftp subsystem via the 'ssh'
	// command.  This assumes that passwordless login is correctly configured.
	cmd := exec.Command("ssh", "example.com", "-s", "sftp")

	// send errors from ssh to stderr
	cmd.Stderr = os.Stderr

	// get stdin and stdout
	wr, err := cmd.StdinPipe()
	if err != nil {
		log.Fatal(err)
	}
	rd, err := cmd.StdoutPipe()
	if err != nil {
		log.Fatal(err)
	}

	// start the process
	if err := cmd.Start(); err != nil {
		log.Fatal(err)
	}
	defer cmd.Wait()

	// open the SFTP session
	client, err := sftp.NewClientPipe(rd, wr)
	if err != nil {
		log.Fatal(err)
	}

	// read a directory
	list, err := client.ReadDir("/")
	if err != nil {
		log.Fatal(err)
	}

	// print contents
	for _, item := range list {
		fmt.Println(item.Name())
	}

	// close the connection
	client.Close()
}

func ExampleClient_Mkdir_parents() {
	// Example of mimicing 'mkdir --parents'; I.E. recursively create
	// directoryies and don't error if any directories already exists.
	var conn *ssh.Client

	client, err := sftp.NewClient(conn)
	if err != nil {
		log.Fatal(err)
	}
	defer client.Close()

	sshFxFailure := uint32(4)
	mkdirParents := func(client *sftp.Client, dir string) (err error) {
		var parents string

		if path.IsAbs(dir) {
			// Otherwise, an absolute path given below would be turned in to a relative one
			// by splitting on "/"
			parents = "/"
		}

		for _, name := range strings.Split(dir, "/") {
			if name == "" {
				// Paths with double-/ in them should just move along
				// this will also catch the case of the first character being a "/", i.e. an absolute path
				continue
			}
			parents = path.Join(parents, name)
			err = client.Mkdir(parents)
			if status, ok := err.(*sftp.StatusError); ok {
				if status.Code == sshFxFailure {
					var fi os.FileInfo
					fi, err = client.Stat(parents)
					if err == nil {
						if !fi.IsDir() {
							return fmt.Errorf("File exists: %s", parents)
						}
					}
				}
			}
			if err != nil {
				break
			}
		}
		return err
	}

	err = mkdirParents(client, "/tmp/foo/bar")
	if err != nil {
		log.Fatal(err)
	}
}

func ExampleFile_ReadFrom_bufio() {
	// Using Bufio to buffer writes going to an sftp.File won't buffer as it
	// skips buffering if the underlying writer support ReadFrom. The
	// workaround is to wrap your writer in a struct that only implements
	// io.Writer.
	//
	// For background see github.com/pkg/sftp/issues/125

	var data_source io.Reader
	var f *sftp.File
	type writerOnly struct{ io.Writer }
	bw := bufio.NewWriter(writerOnly{f}) // no ReadFrom()
	bw.ReadFrom(data_source)
}
<commit_msg>Update example_test.go<commit_after>package sftp_test

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
	"path"
	"strings"

	"github.com/pkg/sftp"
	"golang.org/x/crypto/ssh"
)

func Example() {
	var conn *ssh.Client

	// open an SFTP session over an existing ssh connection.
	client, err := sftp.NewClient(conn)
	if err != nil {
		log.Fatal(err)
	}
	defer sftp.Close()

	// walk a directory
	w := client.Walk("/home/user")
	for w.Step() {
		if w.Err() != nil {
			continue
		}
		log.Println(w.Path())
	}

	// leave your mark
	f, err := client.Create("hello.txt")
	if err != nil {
		log.Fatal(err)
	}
	if _, err := f.Write([]byte("Hello world!")); err != nil {
		log.Fatal(err)
	}

	// check it's there
	fi, err := client.Lstat("hello.txt")
	if err != nil {
		log.Fatal(err)
	}
	log.Println(fi)
}

func ExampleNewClientPipe() {
	// Connect to a remote host and request the sftp subsystem via the 'ssh'
	// command.  This assumes that passwordless login is correctly configured.
	cmd := exec.Command("ssh", "example.com", "-s", "sftp")

	// send errors from ssh to stderr
	cmd.Stderr = os.Stderr

	// get stdin and stdout
	wr, err := cmd.StdinPipe()
	if err != nil {
		log.Fatal(err)
	}
	rd, err := cmd.StdoutPipe()
	if err != nil {
		log.Fatal(err)
	}

	// start the process
	if err := cmd.Start(); err != nil {
		log.Fatal(err)
	}
	defer cmd.Wait()

	// open the SFTP session
	client, err := sftp.NewClientPipe(rd, wr)
	if err != nil {
		log.Fatal(err)
	}

	// read a directory
	list, err := client.ReadDir("/")
	if err != nil {
		log.Fatal(err)
	}

	// print contents
	for _, item := range list {
		fmt.Println(item.Name())
	}

	// close the connection
	client.Close()
}

func ExampleClient_Mkdir_parents() {
	// Example of mimicing 'mkdir --parents'; I.E. recursively create
	// directoryies and don't error if any directories already exists.
	var conn *ssh.Client

	client, err := sftp.NewClient(conn)
	if err != nil {
		log.Fatal(err)
	}
	defer client.Close()

	sshFxFailure := uint32(4)
	mkdirParents := func(client *sftp.Client, dir string) (err error) {
		var parents string

		if path.IsAbs(dir) {
			// Otherwise, an absolute path given below would be turned in to a relative one
			// by splitting on "/"
			parents = "/"
		}

		for _, name := range strings.Split(dir, "/") {
			if name == "" {
				// Paths with double-/ in them should just move along
				// this will also catch the case of the first character being a "/", i.e. an absolute path
				continue
			}
			parents = path.Join(parents, name)
			err = client.Mkdir(parents)
			if status, ok := err.(*sftp.StatusError); ok {
				if status.Code == sshFxFailure {
					var fi os.FileInfo
					fi, err = client.Stat(parents)
					if err == nil {
						if !fi.IsDir() {
							return fmt.Errorf("File exists: %s", parents)
						}
					}
				}
			}
			if err != nil {
				break
			}
		}
		return err
	}

	err = mkdirParents(client, "/tmp/foo/bar")
	if err != nil {
		log.Fatal(err)
	}
}

func ExampleFile_ReadFrom_bufio() {
	// Using Bufio to buffer writes going to an sftp.File won't buffer as it
	// skips buffering if the underlying writer support ReadFrom. The
	// workaround is to wrap your writer in a struct that only implements
	// io.Writer.
	//
	// For background see github.com/pkg/sftp/issues/125

	var data_source io.Reader
	var f *sftp.File
	type writerOnly struct{ io.Writer }
	bw := bufio.NewWriter(writerOnly{f}) // no ReadFrom()
	bw.ReadFrom(data_source)
}
<|endoftext|>


<commit_before>// +build !windows

package cmd_test

import (
	"context"
	"errors"
	"flag"
	"net/http"
	"syscall"

	"github.com/BurntSushi/toml"
	"github.com/cybozu-go/cmd"
	"github.com/cybozu-go/log"
)

// The most basic usage of the framework.
func Example_basic() {
	flag.Parse()
	cmd.LogConfig{}.Apply()

	cmd.Go(func(ctx context.Context) error {
		// do something

		return errors.New("...")
	})

	// some more Go
	//cmd.Go(func(ctx context.Context) error {})

	// Stop declares no Go calls will be made from this point.
	cmd.Stop()

	// Wait waits for all goroutines started by Go to complete,
	// or one of such goroutine returns non-nil error.
	err := cmd.Wait()
	if err != nil {
		log.ErrorExit(err)
	}
}

// HTTP server that stops gracefully.
func Example_http() {
	flag.Parse() // must precedes LogConfig.Apply
	cmd.LogConfig{}.Apply()

	// log accesses to another file in JSON Lines format.
	w, err := log.NewFileReopener("/path/to/access.log", syscall.SIGUSR1)
	if err != nil {
		log.ErrorExit(err)
	}
	accessLog := log.NewLogger()
	accessLog.SetFormatter(log.JSONFormat{})
	accessLog.SetOutput(w)

	// HTTP server.
	serv := &cmd.HTTPServer{
		Server: &http.Server{
			Handler: http.FileServer(http.Dir("/path/to/directory")),
		},
		AccessLog: accessLog,
	}

	// ListenAndServe is overridden to start a goroutine by cmd.Go.
	err = serv.ListenAndServe()
	if err != nil {
		log.ErrorExit(err)
	}

	// Wait waits for SIGINT or SIGTERM.
	// In this case, cmd.Stop can be omitted.
	err = cmd.Wait()

	// Use IsSignaled to determine err is the result of a signal.
	if err != nil && !cmd.IsSignaled(err) {
		log.ErrorExit(err)
	}
}

// Load logging configurations from TOML file.
func ExampleLogConfig() {
	// compile-time defaults
	config := &cmd.LogConfig{
		Level:  "error",
		Format: "json",
	}

	// load from TOML
	_, err := toml.DecodeFile("/path/to/config.toml", config)
	if err != nil {
		log.ErrorExit(err)
	}

	// Apply gives priority to command-line flags, if any.
	flag.Parse()
	err = config.Apply()
	if err != nil {
		log.ErrorExit(err)
	}
}

// Barrier wait for gorutines.
func ExampleNewEnvironment() {
	// An independent environment.
	env := cmd.NewEnvironment(context.Background())

	env.Go(func(ctx context.Context) error {
		// do something
		return nil
	})
	// some more env.Go()

	// wait all goroutines started by env.Go().
	// These goroutines may also be canceled when the global
	// environment is canceled.
	env.Stop()
	err := env.Wait()
	if err != nil {
		log.ErrorExit(err)
	}

	// another environment for another barrier.
	env = cmd.NewEnvironment(context.Background())

	// env.Go, env.Stop, and env.Wait again.
}
<commit_msg>Re-enable examples on Windows.<commit_after>package cmd_test

import (
	"context"
	"errors"
	"flag"
	"net/http"

	"github.com/BurntSushi/toml"
	"github.com/cybozu-go/cmd"
	"github.com/cybozu-go/log"
)

// The most basic usage of the framework.
func Example_basic() {
	flag.Parse()
	cmd.LogConfig{}.Apply()

	cmd.Go(func(ctx context.Context) error {
		// do something

		return errors.New("...")
	})

	// some more Go
	//cmd.Go(func(ctx context.Context) error {})

	// Stop declares no Go calls will be made from this point.
	cmd.Stop()

	// Wait waits for all goroutines started by Go to complete,
	// or one of such goroutine returns non-nil error.
	err := cmd.Wait()
	if err != nil {
		log.ErrorExit(err)
	}
}

// HTTP server that stops gracefully.
func Example_http() {
	flag.Parse() // must precedes LogConfig.Apply
	cmd.LogConfig{}.Apply()

	// log accesses in JSON Lines format.
	accessLog := log.NewLogger()
	accessLog.SetFormatter(log.JSONFormat{})

	// HTTP server.
	serv := &cmd.HTTPServer{
		Server: &http.Server{
			Handler: http.FileServer(http.Dir("/path/to/directory")),
		},
		AccessLog: accessLog,
	}

	// ListenAndServe is overridden to start a goroutine by cmd.Go.
	err := serv.ListenAndServe()
	if err != nil {
		log.ErrorExit(err)
	}

	// Wait waits for SIGINT or SIGTERM.
	// In this case, cmd.Stop can be omitted.
	err = cmd.Wait()

	// Use IsSignaled to determine err is the result of a signal.
	if err != nil && !cmd.IsSignaled(err) {
		log.ErrorExit(err)
	}
}

// Load logging configurations from TOML file.
func ExampleLogConfig() {
	// compile-time defaults
	config := &cmd.LogConfig{
		Level:  "error",
		Format: "json",
	}

	// load from TOML
	_, err := toml.DecodeFile("/path/to/config.toml", config)
	if err != nil {
		log.ErrorExit(err)
	}

	// Apply gives priority to command-line flags, if any.
	flag.Parse()
	err = config.Apply()
	if err != nil {
		log.ErrorExit(err)
	}
}

// Barrier wait for gorutines.
func ExampleNewEnvironment() {
	// An independent environment.
	env := cmd.NewEnvironment(context.Background())

	env.Go(func(ctx context.Context) error {
		// do something
		return nil
	})
	// some more env.Go()

	// wait all goroutines started by env.Go().
	// These goroutines may also be canceled when the global
	// environment is canceled.
	env.Stop()
	err := env.Wait()
	if err != nil {
		log.ErrorExit(err)
	}

	// another environment for another barrier.
	env = cmd.NewEnvironment(context.Background())

	// env.Go, env.Stop, and env.Wait again.
}
<|endoftext|>


<commit_before>package sessiontest

import (
	"encoding/json"
	"fmt"
	"github.com/alicebob/miniredis"
	irma "github.com/privacybydesign/irmago"
	"github.com/privacybydesign/irmago/internal/test"
	"github.com/privacybydesign/irmago/server"
	"github.com/privacybydesign/irmago/server/requestorserver"
	"github.com/stretchr/testify/require"
	"io"
	"net/http"
	"strings"
	"sync"
	"testing"
)

func startRedis(t *testing.T) *miniredis.Miniredis {
	mr, err := miniredis.Run()
	require.NoError(t, err)
	return mr
}

func redisConfigDecorator(mr *miniredis.Miniredis, fn func() *requestorserver.Configuration) func() *requestorserver.Configuration {
	return func() *requestorserver.Configuration {
		mr.FlushAll() // Flush Redis memory between different runs of the IRMA server to prevent side effects.
		c := fn()
		c.StoreType = "redis"
		c.RedisSettings = &server.RedisSettings{}
		c.RedisSettings.Addr = mr.Host() + ":" + mr.Port()
		return c
	}
}

type DummyLoadBalancer struct {
	sync.Mutex
	t           *testing.T
	irmaServers []int
	index       int
}

func (lb *DummyLoadBalancer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	lb.Lock()

	// Replace URL with URL of IRMA server
	port := lb.irmaServers[lb.index]
	relayURL := fmt.Sprintf("http://localhost:%d%s", port, r.URL.Path)

	// Send the request to the IRMA server
	relayReq, err := http.NewRequest(r.Method, relayURL, r.Body)
	require.NoError(lb.t, err)
	relayReq.Header = r.Header.Clone()
	relayResp, err := http.DefaultClient.Do(relayReq)
	require.NoError(lb.t, err)

	// Write the IRMA server response to our response writer
	w.WriteHeader(relayResp.StatusCode)
	_, err = io.Copy(w, relayResp.Body)
	require.NoError(lb.t, err)
	for key, values := range relayResp.Header {
		for _, value := range values {
			w.Header().Add(key, value)
		}
	}

	err = relayResp.Body.Close()
	require.NoError(lb.t, err)

	// Make sure next IRMA server receives the next request
	lb.index = (lb.index + 1) % len(lb.irmaServers)
	lb.Unlock()
}

func startLoadBalancer(t *testing.T, irmaServers []int) *http.Server {
	lb := &http.Server{
		Addr:    "localhost:48682",
		Handler: &DummyLoadBalancer{t: t, irmaServers: irmaServers, index: 0},
	}
	go func() {
		_ = lb.ListenAndServe()
	}()
	return lb
}

func TestRedis(t *testing.T) {
	defaultIrmaServerConfiguration := IrmaServerConfiguration
	defaultJwtServerConfiguration := JwtServerConfiguration

	mr := startRedis(t)
	IrmaServerConfiguration = redisConfigDecorator(mr, IrmaServerConfiguration)
	JwtServerConfiguration = redisConfigDecorator(mr, JwtServerConfiguration)
	defer func() {
		mr.Close()
		IrmaServerConfiguration = defaultIrmaServerConfiguration
		JwtServerConfiguration = defaultJwtServerConfiguration
	}()

	t.Run("TestSigningSession", TestSigningSession)
	t.Run("TestDisclosureSession", TestDisclosureSession)
	t.Run("TestIssuanceSession", TestIssuanceSession)
	t.Run("TestIssuedCredentialIsStored", TestIssuedCredentialIsStored)
	t.Run("TestChainedSessions", TestChainedSessions)
	t.Run("TestUnknownRequestorToken", TestUnknownRequestorToken)
}

func TestRedisRedundancy(t *testing.T) {
	mr := startRedis(t)
	defer mr.Close()

	ports := []int{48690, 48691, 48692}
	servers := make([]*requestorserver.Server, len(ports))

	for i, port := range ports {
		c := redisConfigDecorator(mr, IrmaServerConfiguration)()
		c.Configuration.URL = fmt.Sprintf("http://localhost:%d/irma", port)
		c.Port = port
		rs := StartRequestorServer(t, c)
		servers[i] = rs
	}
	lb := startLoadBalancer(t, ports)
	defer func() {
		err := lb.Close()
		require.NoError(t, err)
		for _, s := range servers {
			s.Stop()
		}
	}()

	id := irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.studentID")
	request := getDisclosureRequest(id)

	sessionHelperWithFrontendOptionsAndConfig(t, request, "verification", nil, nil, nil, nil)
}

// Tests whether the right error is returned by the client's Failure handler
func TestRedisSessionFailure(t *testing.T) {
	mr := startRedis(t)

	id := irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.studentID")
	request := getDisclosureRequest(id)

	// Make sure Redis is used in the IrmaServerConfiguration
	defaultIrmaServerConfiguration := IrmaServerConfiguration
	IrmaServerConfiguration = redisConfigDecorator(mr, IrmaServerConfiguration)
	defer func() {
		IrmaServerConfiguration = defaultIrmaServerConfiguration
	}()

	StartIrmaServer(t, false, "")
	defer StopIrmaServer()
	client, handler := parseStorage(t)
	defer test.ClearTestStorage(t, handler.storage)

	qr, _, _, err := irmaServer.StartSession(request, nil)
	require.NoError(t, err)
	qrjson, err := json.Marshal(qr)
	require.NoError(t, err)

	// Stop the Redis server early to check whether the IRMA client fails correctly
	mr.Close()

	clientChan := make(chan *SessionResult)
	h := &TestHandler{t, clientChan, client, nil, 0, "", nil, nil, nil}
	client.NewSession(string(qrjson), h)
	clientResult := <-h.c

	require.Error(t, clientResult.Err)
	serr, ok := clientResult.Err.(*irma.SessionError)
	require.True(t, ok)
	require.Equal(t, server.ErrorInternal.Status, serr.RemoteError.Status)
	require.Equal(t, string(server.ErrorInternal.Type), serr.RemoteError.ErrorName)
}

func TestRedisLibraryErrors(t *testing.T) {
	mr := startRedis(t)

	id := irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.studentID")
	request := getDisclosureRequest(id)

	// Make sure Redis is used in the IrmaServerConfiguration
	defaultIrmaServerConfiguration := IrmaServerConfiguration
	IrmaServerConfiguration = redisConfigDecorator(mr, IrmaServerConfiguration)
	defer func() {
		IrmaServerConfiguration = defaultIrmaServerConfiguration
	}()

	StartIrmaServer(t, false, "")
	defer StopIrmaServer()

	// Stop the Redis server early to check whether the IRMA server fails correctly
	mr.Close()

	token := irma.RequestorToken("Sxqcpng37mAdBKgoAJXl")

	_, _, _, err := irmaServer.StartSession(request, nil)
	require.Error(t, err)
	_, err = irmaServer.GetSessionResult(token)
	require.Error(t, err)
	err = irmaServer.CancelSession(token)
	require.Error(t, err)
	_, err = irmaServer.GetRequest(token)
	require.Error(t, err)
}

func TestRedisHTTPErrors(t *testing.T) {
	mr := startRedis(t)

	config := redisConfigDecorator(mr, JwtServerConfiguration)()
	rs := StartRequestorServer(t, config)
	defer rs.Stop()

	// Stop the Redis server early to check whether the IRMA client fails correctly
	mr.Close()

	checkErrorSessionUnknown := func(err error) {
		serr, ok := err.(*irma.SessionError)
		require.True(t, ok)
		require.NotNil(t, serr.RemoteError)
		require.Equal(t, server.ErrorSessionUnknown.Status, serr.RemoteError.Status)
		require.Equal(t, string(server.ErrorSessionUnknown.Type), serr.RemoteError.ErrorName)
	}

	checkErrorInternal := func(err error) {
		serr, ok := err.(*irma.SessionError)
		require.True(t, ok)
		require.NotNil(t, serr.RemoteError)
		require.Equal(t, server.ErrorInternal.Status, serr.RemoteError.Status)
		require.Equal(t, string(server.ErrorInternal.Type), serr.RemoteError.ErrorName)
	}

	url := fmt.Sprintf("http://localhost:%d", config.Port)
	transport := irma.NewHTTPTransport(url, false)
	transport.SetHeader("Authorization", TokenAuthenticationKey)

	// Check error response of POST /session requestor endpoint
	id := irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.studentID")
	request := getDisclosureRequest(id)
	err := transport.Post("session", nil, request)
	checkErrorInternal(err)

	// Check error response of requestor endpoints for sessions
	transport.Server += "session/Sxqcpng37mAdBKgoAJXl/"
	err = transport.Get("result", nil)
	checkErrorSessionUnknown(err)
	err = transport.Get("result-jwt", nil)
	checkErrorSessionUnknown(err)
	err = transport.Get("getproof", nil)
	checkErrorSessionUnknown(err)
	err = transport.Get("status", nil)
	checkErrorSessionUnknown(err)
	// TODO: Check for sse endpoint. We don't know yet whether this will be implemented for Redis.

	// Check error response of irma endpoints
	transport.Server = strings.Replace(transport.Server, "/session/", "/irma/session/", 1)
	err = transport.Post("", nil, struct{}{})
	checkErrorInternal(err)
	err = transport.Delete()
	checkErrorInternal(err)
	err = transport.Post("commitments", nil, struct{}{})
	checkErrorInternal(err)
	err = transport.Post("proofs", nil, struct{}{})
	checkErrorInternal(err)
	err = transport.Get("status", nil)
	checkErrorInternal(err)
	// TODO: Check for sse endpoint. We don't know yet whether this will be implemented for Redis.
}
<commit_msg>Add test to validate correct Redis update trigger in sessionMiddleware.<commit_after>package sessiontest

import (
	"encoding/json"
	"fmt"
	"github.com/alicebob/miniredis"
	irma "github.com/privacybydesign/irmago"
	"github.com/privacybydesign/irmago/internal/test"
	"github.com/privacybydesign/irmago/server"
	"github.com/privacybydesign/irmago/server/requestorserver"
	"github.com/stretchr/testify/require"
	"io"
	"net/http"
	"strings"
	"sync"
	"testing"
)

func startRedis(t *testing.T) *miniredis.Miniredis {
	mr, err := miniredis.Run()
	require.NoError(t, err)
	return mr
}

func redisConfigDecorator(mr *miniredis.Miniredis, fn func() *requestorserver.Configuration) func() *requestorserver.Configuration {
	return func() *requestorserver.Configuration {
		mr.FlushAll() // Flush Redis memory between different runs of the IRMA server to prevent side effects.
		c := fn()
		c.StoreType = "redis"
		c.RedisSettings = &server.RedisSettings{}
		c.RedisSettings.Addr = mr.Host() + ":" + mr.Port()
		return c
	}
}

type DummyLoadBalancer struct {
	sync.Mutex
	t           *testing.T
	irmaServers []int
	index       int
}

func (lb *DummyLoadBalancer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	lb.Lock()

	// Replace URL with URL of IRMA server
	port := lb.irmaServers[lb.index]
	relayURL := fmt.Sprintf("http://localhost:%d%s", port, r.URL.Path)

	// Send the request to the IRMA server
	relayReq, err := http.NewRequest(r.Method, relayURL, r.Body)
	require.NoError(lb.t, err)
	relayReq.Header = r.Header.Clone()
	relayResp, err := http.DefaultClient.Do(relayReq)
	require.NoError(lb.t, err)

	// Write the IRMA server response to our response writer
	w.WriteHeader(relayResp.StatusCode)
	_, err = io.Copy(w, relayResp.Body)
	require.NoError(lb.t, err)
	for key, values := range relayResp.Header {
		for _, value := range values {
			w.Header().Add(key, value)
		}
	}

	err = relayResp.Body.Close()
	require.NoError(lb.t, err)

	// Make sure next IRMA server receives the next request
	lb.index = (lb.index + 1) % len(lb.irmaServers)
	lb.Unlock()
}

func startLoadBalancer(t *testing.T, irmaServers []int) *http.Server {
	lb := &http.Server{
		Addr:    "localhost:48682",
		Handler: &DummyLoadBalancer{t: t, irmaServers: irmaServers, index: 0},
	}
	go func() {
		_ = lb.ListenAndServe()
	}()
	return lb
}

func TestRedis(t *testing.T) {
	defaultIrmaServerConfiguration := IrmaServerConfiguration
	defaultJwtServerConfiguration := JwtServerConfiguration

	mr := startRedis(t)
	IrmaServerConfiguration = redisConfigDecorator(mr, IrmaServerConfiguration)
	JwtServerConfiguration = redisConfigDecorator(mr, JwtServerConfiguration)
	defer func() {
		mr.Close()
		IrmaServerConfiguration = defaultIrmaServerConfiguration
		JwtServerConfiguration = defaultJwtServerConfiguration
	}()

	t.Run("TestSigningSession", TestSigningSession)
	t.Run("TestDisclosureSession", TestDisclosureSession)
	t.Run("TestIssuanceSession", TestIssuanceSession)
	t.Run("TestIssuedCredentialIsStored", TestIssuedCredentialIsStored)
	t.Run("TestChainedSessions", TestChainedSessions)
	t.Run("TestUnknownRequestorToken", TestUnknownRequestorToken)
}

func TestRedisUpdates(t *testing.T) {
	mr := startRedis(t)
	defaultIrmaServerConfiguration := IrmaServerConfiguration
	IrmaServerConfiguration = redisConfigDecorator(mr, IrmaServerConfiguration)
	defer func() {
		mr.Close()
		IrmaServerConfiguration = defaultIrmaServerConfiguration
	}()

	StartIrmaServer(t, false, "")
	defer StopIrmaServer()
	qr, token, _, err := irmaServer.StartSession(irma.NewDisclosureRequest(
		irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.studentID"),
	), nil)
	require.NoError(t, err)

	var o interface{}
	transport := irma.NewHTTPTransport(qr.URL, false)
	transport.SetHeader(irma.MinVersionHeader, "2.5")
	transport.SetHeader(irma.MaxVersionHeader, "2.5")
	clientToken, err := mr.Get("token:" + string(token))
	require.NoError(t, err)

	initialData, _ := mr.Get("session:" + clientToken)
	require.NoError(t, transport.Get("", &o))
	updatedData, _ := mr.Get("session:" + clientToken)
	require.NoError(t, transport.Get("", &o))
	latestData, _ := mr.Get("session:" + clientToken)

	// First Get should update the data stored in Redis
	require.NotEqual(t, updatedData, initialData)
	// Second Get should not update the data stored in Redis
	require.Equal(t, updatedData, latestData)
}

func TestRedisRedundancy(t *testing.T) {
	mr := startRedis(t)
	defer mr.Close()

	ports := []int{48690, 48691, 48692}
	servers := make([]*requestorserver.Server, len(ports))

	for i, port := range ports {
		c := redisConfigDecorator(mr, IrmaServerConfiguration)()
		c.Configuration.URL = fmt.Sprintf("http://localhost:%d/irma", port)
		c.Port = port
		rs := StartRequestorServer(t, c)
		servers[i] = rs
	}
	lb := startLoadBalancer(t, ports)
	defer func() {
		err := lb.Close()
		require.NoError(t, err)
		for _, s := range servers {
			s.Stop()
		}
	}()

	id := irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.studentID")
	request := getDisclosureRequest(id)

	sessionHelperWithFrontendOptionsAndConfig(t, request, "verification", nil, nil, nil, nil)
}

// Tests whether the right error is returned by the client's Failure handler
func TestRedisSessionFailure(t *testing.T) {
	mr := startRedis(t)

	id := irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.studentID")
	request := getDisclosureRequest(id)

	// Make sure Redis is used in the IrmaServerConfiguration
	defaultIrmaServerConfiguration := IrmaServerConfiguration
	IrmaServerConfiguration = redisConfigDecorator(mr, IrmaServerConfiguration)
	defer func() {
		IrmaServerConfiguration = defaultIrmaServerConfiguration
	}()

	StartIrmaServer(t, false, "")
	defer StopIrmaServer()
	client, handler := parseStorage(t)
	defer test.ClearTestStorage(t, handler.storage)

	qr, _, _, err := irmaServer.StartSession(request, nil)
	require.NoError(t, err)
	qrjson, err := json.Marshal(qr)
	require.NoError(t, err)

	// Stop the Redis server early to check whether the IRMA client fails correctly
	mr.Close()

	clientChan := make(chan *SessionResult)
	h := &TestHandler{t, clientChan, client, nil, 0, "", nil, nil, nil}
	client.NewSession(string(qrjson), h)
	clientResult := <-h.c

	require.Error(t, clientResult.Err)
	serr, ok := clientResult.Err.(*irma.SessionError)
	require.True(t, ok)
	require.Equal(t, server.ErrorInternal.Status, serr.RemoteError.Status)
	require.Equal(t, string(server.ErrorInternal.Type), serr.RemoteError.ErrorName)
}

func TestRedisLibraryErrors(t *testing.T) {
	mr := startRedis(t)

	id := irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.studentID")
	request := getDisclosureRequest(id)

	// Make sure Redis is used in the IrmaServerConfiguration
	defaultIrmaServerConfiguration := IrmaServerConfiguration
	IrmaServerConfiguration = redisConfigDecorator(mr, IrmaServerConfiguration)
	defer func() {
		IrmaServerConfiguration = defaultIrmaServerConfiguration
	}()

	StartIrmaServer(t, false, "")
	defer StopIrmaServer()

	// Stop the Redis server early to check whether the IRMA server fails correctly
	mr.Close()

	token := irma.RequestorToken("Sxqcpng37mAdBKgoAJXl")

	_, _, _, err := irmaServer.StartSession(request, nil)
	require.Error(t, err)
	_, err = irmaServer.GetSessionResult(token)
	require.Error(t, err)
	err = irmaServer.CancelSession(token)
	require.Error(t, err)
	_, err = irmaServer.GetRequest(token)
	require.Error(t, err)
}

func TestRedisHTTPErrors(t *testing.T) {
	mr := startRedis(t)

	config := redisConfigDecorator(mr, JwtServerConfiguration)()
	rs := StartRequestorServer(t, config)
	defer rs.Stop()

	// Stop the Redis server early to check whether the IRMA client fails correctly
	mr.Close()

	checkErrorSessionUnknown := func(err error) {
		serr, ok := err.(*irma.SessionError)
		require.True(t, ok)
		require.NotNil(t, serr.RemoteError)
		require.Equal(t, server.ErrorSessionUnknown.Status, serr.RemoteError.Status)
		require.Equal(t, string(server.ErrorSessionUnknown.Type), serr.RemoteError.ErrorName)
	}

	checkErrorInternal := func(err error) {
		serr, ok := err.(*irma.SessionError)
		require.True(t, ok)
		require.NotNil(t, serr.RemoteError)
		require.Equal(t, server.ErrorInternal.Status, serr.RemoteError.Status)
		require.Equal(t, string(server.ErrorInternal.Type), serr.RemoteError.ErrorName)
	}

	url := fmt.Sprintf("http://localhost:%d", config.Port)
	transport := irma.NewHTTPTransport(url, false)
	transport.SetHeader("Authorization", TokenAuthenticationKey)

	// Check error response of POST /session requestor endpoint
	id := irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.studentID")
	request := getDisclosureRequest(id)
	err := transport.Post("session", nil, request)
	checkErrorInternal(err)

	// Check error response of requestor endpoints for sessions
	transport.Server += "session/Sxqcpng37mAdBKgoAJXl/"
	err = transport.Get("result", nil)
	checkErrorSessionUnknown(err)
	err = transport.Get("result-jwt", nil)
	checkErrorSessionUnknown(err)
	err = transport.Get("getproof", nil)
	checkErrorSessionUnknown(err)
	err = transport.Get("status", nil)
	checkErrorSessionUnknown(err)
	// TODO: Check for sse endpoint. We don't know yet whether this will be implemented for Redis.

	// Check error response of irma endpoints
	transport.Server = strings.Replace(transport.Server, "/session/", "/irma/session/", 1)
	err = transport.Post("", nil, struct{}{})
	checkErrorInternal(err)
	err = transport.Delete()
	checkErrorInternal(err)
	err = transport.Post("commitments", nil, struct{}{})
	checkErrorInternal(err)
	err = transport.Post("proofs", nil, struct{}{})
	checkErrorInternal(err)
	err = transport.Get("status", nil)
	checkErrorInternal(err)
	// TODO: Check for sse endpoint. We don't know yet whether this will be implemented for Redis.
}
<|endoftext|>


<commit_before>package storagetesting

import (
	"bytes"
	"context"
	"reflect"
	"sort"
	"testing"

	"github.com/kopia/repo/storage"
)

// AssertGetBlock asserts that the specified storage block has correct content.
func AssertGetBlock(ctx context.Context, t *testing.T, s storage.Storage, block string, expected []byte) {
	t.Helper()

	b, err := s.GetBlock(ctx, block, 0, -1)
	if err != nil {
		t.Errorf("GetBlock(%v) returned error %v, expected data: %v", block, err, expected)
		return
	}

	if !bytes.Equal(b, expected) {
		t.Errorf("GetBlock(%v) returned %x, but expected %x", block, b, expected)
	}

	half := int64(len(expected) / 2)
	if half == 0 {
		return
	}

	b, err = s.GetBlock(ctx, block, 0, 0)
	if err != nil {
		t.Errorf("GetBlock(%v) returned error %v, expected data: %v", block, err, expected)
		return
	}

	b, err = s.GetBlock(ctx, block, 0, half)
	if err != nil {
		t.Errorf("GetBlock(%v) returned error %v, expected data: %v", block, err, expected)
		return
	}

	if !bytes.Equal(b, expected[0:half]) {
		t.Errorf("GetBlock(%v) returned %x, but expected %x", block, b, expected[0:half])
	}

	b, err = s.GetBlock(ctx, block, half, int64(len(expected))-half)
	if err != nil {
		t.Errorf("GetBlock(%v) returned error %v, expected data: %v", block, err, expected)
		return
	}

	if !bytes.Equal(b, expected[len(expected)-int(half):]) {
		t.Errorf("GetBlock(%v) returned %x, but expected %x", block, b, expected[len(expected)-int(half):])
	}

	AssertInvalidOffsetLength(ctx, t, s, block, -3, 1)
	AssertInvalidOffsetLength(ctx, t, s, block, int64(len(expected)), 3)
	AssertInvalidOffsetLength(ctx, t, s, block, int64(len(expected)-1), 3)
	AssertInvalidOffsetLength(ctx, t, s, block, int64(len(expected)+1), 3)
}

func AssertInvalidOffsetLength(ctx context.Context, t *testing.T, s storage.Storage, block string, offset, length int64) {
	if _, err := s.GetBlock(ctx, block, offset, length); err == nil {
		t.Errorf("GetBlock(%v,%v,%v) did not return error for invalid offset/length", block, offset, length)
	}
}

// AssertGetBlockNotFound asserts that GetBlock() for specified storage block returns ErrBlockNotFound.
func AssertGetBlockNotFound(ctx context.Context, t *testing.T, s storage.Storage, block string) {
	t.Helper()

	b, err := s.GetBlock(ctx, block, 0, -1)
	if err != storage.ErrBlockNotFound || b != nil {
		t.Errorf("GetBlock(%v) returned %v, %v but expected ErrBlockNotFound", block, b, err)
	}
}

// AssertListResults asserts that the list results with given prefix return the specified list of names in order.
func AssertListResults(ctx context.Context, t *testing.T, s storage.Storage, prefix string, want ...string) {
	t.Helper()
	var names []string

	if err := s.ListBlocks(ctx, prefix, func(e storage.BlockMetadata) error {
		names = append(names, e.BlockID)
		return nil
	}); err != nil {
		t.Fatalf("err: %v", err)
	}

	names = sorted(names)
	want = sorted(want)

	if !reflect.DeepEqual(names, want) {
		t.Errorf("ListBlocks(%v) returned %v, but wanted %v", prefix, names, want)
	}
}

func sorted(s []string) []string {
	x := append([]string(nil), s...)
	sort.Strings(x)
	return x
}
<commit_msg>storagetesting: added test case for zero length<commit_after>package storagetesting

import (
	"bytes"
	"context"
	"reflect"
	"sort"
	"testing"

	"github.com/kopia/repo/storage"
)

// AssertGetBlock asserts that the specified storage block has correct content.
func AssertGetBlock(ctx context.Context, t *testing.T, s storage.Storage, block string, expected []byte) {
	t.Helper()

	b, err := s.GetBlock(ctx, block, 0, -1)
	if err != nil {
		t.Errorf("GetBlock(%v) returned error %v, expected data: %v", block, err, expected)
		return
	}

	if !bytes.Equal(b, expected) {
		t.Errorf("GetBlock(%v) returned %x, but expected %x", block, b, expected)
	}

	half := int64(len(expected) / 2)
	if half == 0 {
		return
	}

	b, err = s.GetBlock(ctx, block, 0, 0)
	if err != nil {
		t.Errorf("GetBlock(%v) returned error %v, expected data: %v", block, err, expected)
		return
	}

	if len(b) != 0 {
		t.Errorf("GetBlock(%v) returned non-zero length: %v", block, len(b))
		return
	}

	b, err = s.GetBlock(ctx, block, 0, half)
	if err != nil {
		t.Errorf("GetBlock(%v) returned error %v, expected data: %v", block, err, expected)
		return
	}

	if !bytes.Equal(b, expected[0:half]) {
		t.Errorf("GetBlock(%v) returned %x, but expected %x", block, b, expected[0:half])
	}

	b, err = s.GetBlock(ctx, block, half, int64(len(expected))-half)
	if err != nil {
		t.Errorf("GetBlock(%v) returned error %v, expected data: %v", block, err, expected)
		return
	}

	if !bytes.Equal(b, expected[len(expected)-int(half):]) {
		t.Errorf("GetBlock(%v) returned %x, but expected %x", block, b, expected[len(expected)-int(half):])
	}

	AssertInvalidOffsetLength(ctx, t, s, block, -3, 1)
	AssertInvalidOffsetLength(ctx, t, s, block, int64(len(expected)), 3)
	AssertInvalidOffsetLength(ctx, t, s, block, int64(len(expected)-1), 3)
	AssertInvalidOffsetLength(ctx, t, s, block, int64(len(expected)+1), 3)
}

// AssertInvalidOffsetLength verifies that the given combination of (offset,length) fails on GetBlock()
func AssertInvalidOffsetLength(ctx context.Context, t *testing.T, s storage.Storage, block string, offset, length int64) {
	if _, err := s.GetBlock(ctx, block, offset, length); err == nil {
		t.Errorf("GetBlock(%v,%v,%v) did not return error for invalid offset/length", block, offset, length)
	}
}

// AssertGetBlockNotFound asserts that GetBlock() for specified storage block returns ErrBlockNotFound.
func AssertGetBlockNotFound(ctx context.Context, t *testing.T, s storage.Storage, block string) {
	t.Helper()

	b, err := s.GetBlock(ctx, block, 0, -1)
	if err != storage.ErrBlockNotFound || b != nil {
		t.Errorf("GetBlock(%v) returned %v, %v but expected ErrBlockNotFound", block, b, err)
	}
}

// AssertListResults asserts that the list results with given prefix return the specified list of names in order.
func AssertListResults(ctx context.Context, t *testing.T, s storage.Storage, prefix string, want ...string) {
	t.Helper()
	var names []string

	if err := s.ListBlocks(ctx, prefix, func(e storage.BlockMetadata) error {
		names = append(names, e.BlockID)
		return nil
	}); err != nil {
		t.Fatalf("err: %v", err)
	}

	names = sorted(names)
	want = sorted(want)

	if !reflect.DeepEqual(names, want) {
		t.Errorf("ListBlocks(%v) returned %v, but wanted %v", prefix, names, want)
	}
}

func sorted(s []string) []string {
	x := append([]string(nil), s...)
	sort.Strings(x)
	return x
}
<|endoftext|>