<commit_before>// Package ostype is define OS type of SakuraCloud public archive
package ostype

//go:generate stringer -type=ArchiveOSTypes

// ArchiveOSTypes パブリックアーカイブOS種別
type ArchiveOSTypes int

const (
	// CentOS OS種別:CentOS
	CentOS ArchiveOSTypes = iota
	// CentOS6 OS種別:CentOS6
	CentOS6
	// Ubuntu OS種別:Ubuntu
	Ubuntu
	// Debian OS種別:Debian
	Debian
	// VyOS OS種別:VyOS
	VyOS
	// CoreOS OS種別:CoreOS
	CoreOS
	// RancherOS OS種別:RancherOS
	RancherOS
	// Kusanagi OS種別:Kusanagi(CentOS)
	Kusanagi
	// SophosUTM OS種別:Sophos UTM
	SophosUTM
	// FreeBSD OS種別:FreeBSD
	FreeBSD
	// Windows2012 OS種別:Windows Server 2012 R2 Datacenter Edition
	Windows2012
	// Windows2012RDS OS種別:Windows Server 2012 R2 for RDS
	Windows2012RDS
	// Windows2012RDSOffice OS種別:Windows Server 2012 R2 for RDS(Office)
	Windows2012RDSOffice
	// Windows2016 OS種別:Windows Server 2016 Datacenter Edition
	Windows2016
	// Windows2016RDS OS種別:Windows Server 2016 RDS
	Windows2016RDS
	// Windows2016RDSOffice OS種別:Windows Server 2016 RDS(Office)
	Windows2016RDSOffice
	// Windows2016SQLServerWeb OS種別:Windows Server 2016 SQLServer(Web)
	Windows2016SQLServerWeb
	// Windows2016SQLServerStandard OS種別:Windows Server 2016 SQLServer(Standard)
	Windows2016SQLServerStandard
	// Windows2016SQLServerStandardAll OS種別:Windows Server 2016 SQLServer(Standard) + RDS + Office
	Windows2016SQLServerStandardAll
	// Custom OS種別:カスタム
	Custom
)

// OSTypeShortNames OSTypeとして利用できる文字列のリスト
var OSTypeShortNames = []string{
	"centos", "centos6", "ubuntu", "debian", "vyos", "coreos",
	"rancheros", "kusanagi", "freebsd",
	"windows2012", "windows2012-rds", "windows2012-rds-office",
	"windows2016", "windows2016-rds", "windows2016-rds-office",
	"windows2016-sql-web", "windows2016-sql-standard", "windows2016-sql-standard-all",
}

// IsWindows Windowsか
func (o ArchiveOSTypes) IsWindows() bool {
	switch o {
	case Windows2012, Windows2012RDS, Windows2012RDSOffice,
		Windows2016, Windows2016RDS, Windows2016RDSOffice,
		Windows2016SQLServerWeb, Windows2016SQLServerStandard, Windows2016SQLServerStandardAll:
		return true
	default:
		return false
	}
}

// IsSupportDiskEdit ディスクの修正機能をフルサポートしているか(Windowsは一部サポートのためfalseを返す)
func (o ArchiveOSTypes) IsSupportDiskEdit() bool {
	switch o {
	case CentOS, CentOS6, Ubuntu, Debian, VyOS, CoreOS, RancherOS, Kusanagi, FreeBSD:
		return true
	default:
		return false
	}
}

// StrToOSType 文字列からArchiveOSTypesへの変換
func StrToOSType(osType string) ArchiveOSTypes {
	switch osType {
	case "centos":
		return CentOS
	case "centos6":
		return CentOS6
	case "ubuntu":
		return Ubuntu
	case "debian":
		return Debian
	case "vyos":
		return VyOS
	case "coreos":
		return CoreOS
	case "rancheros":
		return RancherOS
	case "kusanagi":
		return Kusanagi
	case "freebsd":
		return FreeBSD
	case "windows2012":
		return Windows2012
	case "windows2012-rds":
		return Windows2012RDS
	case "windows2012-rds-office":
		return Windows2012RDSOffice
	case "windows2016":
		return Windows2016
	case "windows2016-rds":
		return Windows2016RDS
	case "windows2016-rds-office":
		return Windows2016RDSOffice
	case "windows2016-sql-web":
		return Windows2016SQLServerWeb
	case "windows2016-sql-standard":
		return Windows2016SQLServerStandard
	case "windows2016-sql-standard-all":
		return Windows2016SQLServerStandardAll
	default:
		return Custom
	}
}
<commit_msg>Add SophosUTM to ostype utilities<commit_after>// Package ostype is define OS type of SakuraCloud public archive
package ostype

//go:generate stringer -type=ArchiveOSTypes

// ArchiveOSTypes パブリックアーカイブOS種別
type ArchiveOSTypes int

const (
	// CentOS OS種別:CentOS
	CentOS ArchiveOSTypes = iota
	// CentOS6 OS種別:CentOS6
	CentOS6
	// Ubuntu OS種別:Ubuntu
	Ubuntu
	// Debian OS種別:Debian
	Debian
	// VyOS OS種別:VyOS
	VyOS
	// CoreOS OS種別:CoreOS
	CoreOS
	// RancherOS OS種別:RancherOS
	RancherOS
	// Kusanagi OS種別:Kusanagi(CentOS)
	Kusanagi
	// SophosUTM OS種別:Sophos UTM
	SophosUTM
	// FreeBSD OS種別:FreeBSD
	FreeBSD
	// Windows2012 OS種別:Windows Server 2012 R2 Datacenter Edition
	Windows2012
	// Windows2012RDS OS種別:Windows Server 2012 R2 for RDS
	Windows2012RDS
	// Windows2012RDSOffice OS種別:Windows Server 2012 R2 for RDS(Office)
	Windows2012RDSOffice
	// Windows2016 OS種別:Windows Server 2016 Datacenter Edition
	Windows2016
	// Windows2016RDS OS種別:Windows Server 2016 RDS
	Windows2016RDS
	// Windows2016RDSOffice OS種別:Windows Server 2016 RDS(Office)
	Windows2016RDSOffice
	// Windows2016SQLServerWeb OS種別:Windows Server 2016 SQLServer(Web)
	Windows2016SQLServerWeb
	// Windows2016SQLServerStandard OS種別:Windows Server 2016 SQLServer(Standard)
	Windows2016SQLServerStandard
	// Windows2016SQLServerStandardAll OS種別:Windows Server 2016 SQLServer(Standard) + RDS + Office
	Windows2016SQLServerStandardAll
	// Custom OS種別:カスタム
	Custom
)

// OSTypeShortNames OSTypeとして利用できる文字列のリスト
var OSTypeShortNames = []string{
	"centos", "centos6", "ubuntu", "debian", "vyos", "coreos",
	"rancheros", "kusanagi", "sophos-utm", "freebsd",
	"windows2012", "windows2012-rds", "windows2012-rds-office",
	"windows2016", "windows2016-rds", "windows2016-rds-office",
	"windows2016-sql-web", "windows2016-sql-standard", "windows2016-sql-standard-all",
}

// IsWindows Windowsか
func (o ArchiveOSTypes) IsWindows() bool {
	switch o {
	case Windows2012, Windows2012RDS, Windows2012RDSOffice,
		Windows2016, Windows2016RDS, Windows2016RDSOffice,
		Windows2016SQLServerWeb, Windows2016SQLServerStandard, Windows2016SQLServerStandardAll:
		return true
	default:
		return false
	}
}

// IsSupportDiskEdit ディスクの修正機能をフルサポートしているか(Windowsは一部サポートのためfalseを返す)
func (o ArchiveOSTypes) IsSupportDiskEdit() bool {
	switch o {
	case CentOS, CentOS6, Ubuntu, Debian, VyOS, CoreOS, RancherOS, Kusanagi, FreeBSD:
		return true
	default:
		return false
	}
}

// StrToOSType 文字列からArchiveOSTypesへの変換
func StrToOSType(osType string) ArchiveOSTypes {
	switch osType {
	case "centos":
		return CentOS
	case "centos6":
		return CentOS6
	case "ubuntu":
		return Ubuntu
	case "debian":
		return Debian
	case "vyos":
		return VyOS
	case "coreos":
		return CoreOS
	case "rancheros":
		return RancherOS
	case "kusanagi":
		return Kusanagi
	case "sophos-utm":
		return SophosUTM
	case "freebsd":
		return FreeBSD
	case "windows2012":
		return Windows2012
	case "windows2012-rds":
		return Windows2012RDS
	case "windows2012-rds-office":
		return Windows2012RDSOffice
	case "windows2016":
		return Windows2016
	case "windows2016-rds":
		return Windows2016RDS
	case "windows2016-rds-office":
		return Windows2016RDSOffice
	case "windows2016-sql-web":
		return Windows2016SQLServerWeb
	case "windows2016-sql-standard":
		return Windows2016SQLServerStandard
	case "windows2016-sql-standard-all":
		return Windows2016SQLServerStandardAll
	default:
		return Custom
	}
}
<|endoftext|>


<commit_before>package java

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"testing"

	"github.com/ezbuy/tgen/global"
	"github.com/samuel/go-thrift/parser"
)

func TestGenerate(t *testing.T) {
	// 1 read thrift files from folder 'cases'
	// 2 generate & output
	// 3 read generated files, compared with corresponding files in folder 'test'

	casedir, _ := filepath.Abs("./../../example/java")

	// create output dir
	outdir, _ := filepath.Abs("./output")
	// if err := os.MkdirAll(outdir, 0755); err != nil {
	// 	t.Errorf("failed to create output directory %s", outdir)
	// }

	testdir, _ := filepath.Abs("./../../example/java/ref")

	gen := &JavaGen{}
	p := &parser.Parser{}

	visitfunc := func(path string, info os.FileInfo, err error) error {
		if strings.HasPrefix(filepath.Base(path), ".") || filepath.Ext(path) != ".thrift" {
			return nil
		}

		global.InputFile = path

		parsedThrift, _, err := p.ParseFile(path)
		if err != nil {
			t.Errorf("parse error: %s\n", err.Error())
		}

		gen.Generate(outdir, parsedThrift)

		for f, thrift := range parsedThrift {
			if f != global.InputFile {
				continue
			}

			ns := thrift.Namespaces["java"]
			p := strings.Replace(ns, ".", "/", -1)

			for _, m := range thrift.Structs {
				name := m.Name + ".java"

				// jsonrpc

				outfile := filepath.Join(outdir, global.MODE_JSONRPC, p, name)
				testfile := filepath.Join(testdir, global.MODE_JSONRPC, p, name)

				fileCompare(t, outfile, testfile)

				// rest
				outfile = filepath.Join(outdir, global.MODE_REST, p, name)
				testfile = filepath.Join(testdir, global.MODE_REST, p, name)

				fileCompare(t, outfile, testfile)
			}

			for _, s := range thrift.Services {
				name := s.Name + "Service.java"

				// jsonrpc
				outfile := filepath.Join(outdir, global.MODE_JSONRPC, p, name)
				testfile := filepath.Join(testdir, global.MODE_JSONRPC, p, name)

				fileCompare(t, outfile, testfile)

				// rest
				outfile = filepath.Join(outdir, global.MODE_REST, p, name)
				testfile = filepath.Join(testdir, global.MODE_REST, p, name)

				fileCompare(t, outfile, testfile)
			}
		}

		return nil
	}

	if err := filepath.Walk(casedir, visitfunc); err != nil {
		t.Errorf("walk error: %s\n", err.Error())
	}

	// do some clean
	os.RemoveAll(outdir)
}

func fileCompare(t *testing.T, src string, dest string) {
	if !pathexists(src) {
		t.Error("generate error\n")
	} else if !pathexists(dest) {
		t.Errorf("no test file found [%s]\n", dest)
	} else {
		// compare the output file with the case
		srcdata, srcerr := ioutil.ReadFile(src)
		destdata, desterr := ioutil.ReadFile(dest)

		if srcerr != nil || desterr != nil {
			t.Error("compare error [reading]")
		} else if string(srcdata) != string(destdata) {
			t.Errorf("mismatch: [%s, %s]", src, dest)
		} else {
			t.Log("PASS")
		}
	}
}

func pathexists(path string) bool {
	_, err := os.Stat(path)
	if err == nil {
		return true
	}

	if os.IsNotExist(err) {
		return false
	}

	return false
}
<commit_msg>modify go test<commit_after>package java

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"testing"

	"github.com/ezbuy/tgen/global"
	"github.com/samuel/go-thrift/parser"
)

func TestGenerate(t *testing.T) {
	// 1 read thrift files from folder 'cases'
	// 2 generate & output
	// 3 read generated files, compared with corresponding files in folder 'test'

	casedir, _ := filepath.Abs("./../../example/java")

	// create output dir
	outdir, _ := filepath.Abs("./output")
	// if err := os.MkdirAll(outdir, 0755); err != nil {
	// 	t.Errorf("failed to create output directory %s", outdir)
	// }

	testdir, _ := filepath.Abs("./../../example/java/ref")

	gen := &JavaGen{}
	p := &parser.Parser{}

	visitfunc := func(path string, info os.FileInfo, err error) error {
		if strings.HasPrefix(filepath.Base(path), ".") || filepath.Ext(path) != ".thrift" {
			return nil
		}

		if !strings.HasSuffix(path, "ShipForMe.thrift") {
			return nil
		}

		global.InputFile = path

		parsedThrift, _, err := p.ParseFile(path)
		if err != nil {
			t.Errorf("parse error: %s\n", err.Error())
		}

		gen.Generate(outdir, parsedThrift)

		for f, thrift := range parsedThrift {
			if f != global.InputFile {
				continue
			}

			ns := thrift.Namespaces["java"]
			p := strings.Replace(ns, ".", "/", -1)

			for _, m := range thrift.Structs {
				name := m.Name + ".java"

				// jsonrpc

				outfile := filepath.Join(outdir, global.MODE_JSONRPC, p, name)
				testfile := filepath.Join(testdir, global.MODE_JSONRPC, p, name)

				fileCompare(t, outfile, testfile)

				// rest
				outfile = filepath.Join(outdir, global.MODE_REST, p, name)
				testfile = filepath.Join(testdir, global.MODE_REST, p, name)

				fileCompare(t, outfile, testfile)
			}

			for _, s := range thrift.Services {
				name := s.Name + "Service.java"

				// jsonrpc
				outfile := filepath.Join(outdir, global.MODE_JSONRPC, p, name)
				testfile := filepath.Join(testdir, global.MODE_JSONRPC, p, name)

				fileCompare(t, outfile, testfile)

				// rest
				outfile = filepath.Join(outdir, global.MODE_REST, p, name)
				testfile = filepath.Join(testdir, global.MODE_REST, p, name)

				fileCompare(t, outfile, testfile)
			}
		}

		return nil
	}

	if err := filepath.Walk(casedir, visitfunc); err != nil {
		t.Errorf("walk error: %s\n", err.Error())
	}

	// do some clean
	os.RemoveAll(outdir)
}

func fileCompare(t *testing.T, src string, dest string) {
	if !pathexists(src) {
		t.Error("generate error\n")
	} else if !pathexists(dest) {
		t.Errorf("no test file found [%s]\n", dest)
	} else {
		// compare the output file with the case
		srcdata, srcerr := ioutil.ReadFile(src)
		destdata, desterr := ioutil.ReadFile(dest)

		if srcerr != nil || desterr != nil {
			t.Error("compare error [reading]")
		} else if string(srcdata) != string(destdata) {
			t.Errorf("mismatch: [%s, %s]", src, dest)
		} else {
			t.Log("PASS")
		}
	}
}

func pathexists(path string) bool {
	_, err := os.Stat(path)
	if err == nil {
		return true
	}

	if os.IsNotExist(err) {
		return false
	}

	return false
}
<|endoftext|>


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

package testlapack

import (
	"testing"

	"golang.org/x/exp/rand"

	"gonum.org/v1/gonum/blas"
	"gonum.org/v1/gonum/blas/blas64"
	"gonum.org/v1/gonum/floats"
)

type Dgeqr2er interface {
	Dgeqr2(m, n int, a []float64, lda int, tau []float64, work []float64)
}

func Dgeqr2Test(t *testing.T, impl Dgeqr2er) {
	rnd := rand.New(rand.NewSource(1))
	for c, test := range []struct {
		m, n, lda int
	}{
		{1, 1, 0},
		{2, 2, 0},
		{3, 2, 0},
		{2, 3, 0},
		{1, 12, 0},
		{2, 6, 0},
		{3, 4, 0},
		{4, 3, 0},
		{6, 2, 0},
		{12, 1, 0},
		{1, 1, 20},
		{2, 2, 20},
		{3, 2, 20},
		{2, 3, 20},
		{1, 12, 20},
		{2, 6, 20},
		{3, 4, 20},
		{4, 3, 20},
		{6, 2, 20},
		{12, 1, 20},
	} {
		n := test.n
		m := test.m
		lda := test.lda
		if lda == 0 {
			lda = test.n
		}
		a := make([]float64, m*lda)
		for i := range a {
			a[i] = rnd.Float64()
		}
		aCopy := make([]float64, len(a))
		k := min(m, n)
		tau := make([]float64, k)
		for i := range tau {
			tau[i] = rnd.Float64()
		}
		work := make([]float64, n)
		for i := range work {
			work[i] = rnd.Float64()
		}
		copy(aCopy, a)
		impl.Dgeqr2(m, n, a, lda, tau, work)

		// Test that the QR factorization has completed successfully. Compute
		// Q based on the vectors.
		q := constructQ("QR", m, n, a, lda, tau)

		// Check that Q is orthogonal.
		if !isOrthogonal(q) {
			t.Errorf("Case %v, Q not orthogonal", c)
		}
		// Check that A = Q * R
		r := blas64.General{
			Rows:   m,
			Cols:   n,
			Stride: n,
			Data:   make([]float64, m*n),
		}
		for i := 0; i < m; i++ {
			for j := i; j < n; j++ {
				r.Data[i*n+j] = a[i*lda+j]
			}
		}
		atmp := blas64.General{
			Rows:   m,
			Cols:   n,
			Stride: lda,
			Data:   make([]float64, m*lda),
		}
		copy(atmp.Data, a)
		blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, q, r, 0, atmp)
		if !floats.EqualApprox(atmp.Data, aCopy, 1e-14) {
			t.Errorf("Q*R != a")
		}
	}
}
<commit_msg>testlapack: rework Dgeqr2Test<commit_after>// Copyright ©2015 The Gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package testlapack

import (
	"fmt"
	"testing"

	"golang.org/x/exp/rand"

	"gonum.org/v1/gonum/blas"
	"gonum.org/v1/gonum/blas/blas64"
	"gonum.org/v1/gonum/lapack"
)

type Dgeqr2er interface {
	Dgeqr2(m, n int, a []float64, lda int, tau []float64, work []float64)
}

func Dgeqr2Test(t *testing.T, impl Dgeqr2er) {
	rnd := rand.New(rand.NewSource(1))
	for _, m := range []int{0, 1, 2, 3, 4, 5, 6, 12, 23} {
		for _, n := range []int{0, 1, 2, 3, 4, 5, 6, 12, 23} {
			for _, lda := range []int{max(1, n), n + 4} {
				dgeqr2Test(t, impl, rnd, m, n, lda)
			}
		}
	}
}

func dgeqr2Test(t *testing.T, impl Dgeqr2er, rnd *rand.Rand, m, n, lda int) {
	const tol = 1e-14

	name := fmt.Sprintf("m=%d,n=%d,lda=%d", m, n, lda)

	a := randomGeneral(m, n, lda, rnd)
	aCopy := cloneGeneral(a)

	k := min(m, n)
	tau := make([]float64, k)
	for i := range tau {
		tau[i] = rnd.Float64()
	}

	work := make([]float64, n)
	for i := range work {
		work[i] = rnd.Float64()
	}

	impl.Dgeqr2(m, n, a.Data, a.Stride, tau, work)

	// Test that the QR factorization has completed successfully. Compute
	// Q based on the vectors.
	q := constructQ("QR", m, n, a.Data, a.Stride, tau)

	// Check that Q is orthogonal.
	if resid := residualOrthogonal(q, false); resid > tol {
		t.Errorf("Case %v: Q not orthogonal; resid=%v, want<=%v", name, resid, tol)
	}

	// Check that |Q*R - A| is small.
	r := zeros(m, n, n)
	for i := 0; i < m; i++ {
		for j := i; j < n; j++ {
			r.Data[i*r.Stride+j] = a.Data[i*a.Stride+j]
		}
	}
	qra := cloneGeneral(aCopy)
	blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, q, r, -1, qra)
	resid := dlange(lapack.MaxColumnSum, qra.Rows, qra.Cols, qra.Data, qra.Stride)
	if resid > tol*float64(m) {
		t.Errorf("Case %v: |Q*R - A|=%v, want<=%v", name, resid, tol*float64(m))
	}
}
<|endoftext|>


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

package testlapack

import (
	"fmt"
	"math"
	"testing"

	"golang.org/x/exp/rand"

	"gonum.org/v1/gonum/blas"
	"gonum.org/v1/gonum/floats"
	"gonum.org/v1/gonum/lapack"
)

type Dlantber interface {
	Dlantb(norm lapack.MatrixNorm, uplo blas.Uplo, diag blas.Diag, n, k int, a []float64, lda int, work []float64) float64
}

func DlantbTest(t *testing.T, impl Dlantber) {
	rnd := rand.New(rand.NewSource(1))
	for _, norm := range []lapack.MatrixNorm{lapack.MaxAbs, lapack.MaxRowSum, lapack.MaxColumnSum, lapack.Frobenius} {
		for _, uplo := range []blas.Uplo{blas.Lower, blas.Upper} {
			for _, diag := range []blas.Diag{blas.NonUnit, blas.Unit} {
				name := normToString(norm) + uploToString(uplo) + diagToString(diag)
				t.Run(name, func(t *testing.T) {
					for _, n := range []int{0, 1, 2, 3, 4, 5, 10} {
						for _, k := range []int{0, 1, 2, 3, n, n + 2} {
							for _, lda := range []int{k + 1, k + 3} {
								for iter := 0; iter < 10; iter++ {
									dlantbTest(t, impl, rnd, norm, uplo, diag, n, k, lda)
								}
							}
						}
					}
				})
			}
		}
	}
}

func dlantbTest(t *testing.T, impl Dlantber, rnd *rand.Rand, norm lapack.MatrixNorm, uplo blas.Uplo, diag blas.Diag, n, k, lda int) {
	const tol = 1e-14

	name := fmt.Sprintf("n=%v,k=%v,lda=%v", n, k, lda)

	// Deal with zero-sized matrices early.
	if n == 0 {
		got := impl.Dlantb(norm, uplo, diag, n, k, nil, lda, nil)
		if got != 0 {
			t.Errorf("%v: unexpected result for zero-sized matrix", name)
		}
		return
	}

	a := make([]float64, max(0, (n-1)*lda+k+1))
	if rnd.Float64() < 0.5 {
		// Sometimes fill A with elements between -0.5 and 0.5 so that for
		// blas.Unit matrices the largest element is the 1 on the main diagonal.
		for i := range a {
			// Between -0.5 and 0.5.
			a[i] = rnd.Float64() - 0.5
		}
	} else {
		for i := range a {
			// Between -2 and 2.
			a[i] = 4*rnd.Float64() - 2
		}
	}
	// Sometimes put a NaN into A.
	if rnd.Float64() < 0.5 {
		a[rnd.Intn(len(a))] = math.NaN()
	}
	// Make a copy of A for later comparison.
	aCopy := make([]float64, len(a))
	copy(aCopy, a)

	var work []float64
	if norm == lapack.MaxColumnSum {
		work = make([]float64, n)
	}
	// Fill work with random garbage.
	for i := range work {
		work[i] = rnd.NormFloat64()
	}

	got := impl.Dlantb(norm, uplo, diag, n, k, a, lda, work)

	if !floats.Same(a, aCopy) {
		t.Fatalf("%v: unexpected modification of a", name)
	}

	// Generate a dense representation of A and compute the wanted result.
	ldaGen := n
	aGen := make([]float64, n*ldaGen)
	if uplo == blas.Upper {
		for i := 0; i < n; i++ {
			for j := 0; j < min(n-i, k+1); j++ {
				aGen[i*ldaGen+i+j] = a[i*lda+j]
			}
		}
	} else {
		for i := 0; i < n; i++ {
			for j := max(0, k-i); j < k+1; j++ {
				aGen[i*ldaGen+i-(k-j)] = a[i*lda+j]
			}
		}
	}
	if diag == blas.Unit {
		for i := 0; i < n; i++ {
			aGen[i*ldaGen+i] = 1
		}
	}
	want := dlange(norm, n, n, aGen, ldaGen)

	if math.IsNaN(want) {
		if !math.IsNaN(got) {
			t.Errorf("%v: unexpected result with NaN element; got %v, want %v\n%v\n%v", name, got, want, a, aGen)
		}
		return
	}

	if norm == lapack.MaxAbs {
		if got != want {
			t.Errorf("%v: unexpected result; got %v, want %v", name, got, want)
		}
		return
	}
	diff := math.Abs(got - want)
	if diff > tol {
		t.Errorf("%v: unexpected result; got %v, want %v, diff=%v", name, got, want, diff)
	}
}
<commit_msg>testlapack: don't output matrix contents in DlantbTest<commit_after>// Copyright ©2020 The Gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package testlapack

import (
	"fmt"
	"math"
	"testing"

	"golang.org/x/exp/rand"

	"gonum.org/v1/gonum/blas"
	"gonum.org/v1/gonum/floats"
	"gonum.org/v1/gonum/lapack"
)

type Dlantber interface {
	Dlantb(norm lapack.MatrixNorm, uplo blas.Uplo, diag blas.Diag, n, k int, a []float64, lda int, work []float64) float64
}

func DlantbTest(t *testing.T, impl Dlantber) {
	rnd := rand.New(rand.NewSource(1))
	for _, norm := range []lapack.MatrixNorm{lapack.MaxAbs, lapack.MaxRowSum, lapack.MaxColumnSum, lapack.Frobenius} {
		for _, uplo := range []blas.Uplo{blas.Lower, blas.Upper} {
			for _, diag := range []blas.Diag{blas.NonUnit, blas.Unit} {
				name := normToString(norm) + uploToString(uplo) + diagToString(diag)
				t.Run(name, func(t *testing.T) {
					for _, n := range []int{0, 1, 2, 3, 4, 5, 10} {
						for _, k := range []int{0, 1, 2, 3, n, n + 2} {
							for _, lda := range []int{k + 1, k + 3} {
								for iter := 0; iter < 10; iter++ {
									dlantbTest(t, impl, rnd, norm, uplo, diag, n, k, lda)
								}
							}
						}
					}
				})
			}
		}
	}
}

func dlantbTest(t *testing.T, impl Dlantber, rnd *rand.Rand, norm lapack.MatrixNorm, uplo blas.Uplo, diag blas.Diag, n, k, lda int) {
	const tol = 1e-14

	name := fmt.Sprintf("n=%v,k=%v,lda=%v", n, k, lda)

	// Deal with zero-sized matrices early.
	if n == 0 {
		got := impl.Dlantb(norm, uplo, diag, n, k, nil, lda, nil)
		if got != 0 {
			t.Errorf("%v: unexpected result for zero-sized matrix", name)
		}
		return
	}

	a := make([]float64, max(0, (n-1)*lda+k+1))
	if rnd.Float64() < 0.5 {
		// Sometimes fill A with elements between -0.5 and 0.5 so that for
		// blas.Unit matrices the largest element is the 1 on the main diagonal.
		for i := range a {
			// Between -0.5 and 0.5.
			a[i] = rnd.Float64() - 0.5
		}
	} else {
		for i := range a {
			// Between -2 and 2.
			a[i] = 4*rnd.Float64() - 2
		}
	}
	// Sometimes put a NaN into A.
	if rnd.Float64() < 0.5 {
		a[rnd.Intn(len(a))] = math.NaN()
	}
	// Make a copy of A for later comparison.
	aCopy := make([]float64, len(a))
	copy(aCopy, a)

	var work []float64
	if norm == lapack.MaxColumnSum {
		work = make([]float64, n)
	}
	// Fill work with random garbage.
	for i := range work {
		work[i] = rnd.NormFloat64()
	}

	got := impl.Dlantb(norm, uplo, diag, n, k, a, lda, work)

	if !floats.Same(a, aCopy) {
		t.Fatalf("%v: unexpected modification of a", name)
	}

	// Generate a dense representation of A and compute the wanted result.
	ldaGen := n
	aGen := make([]float64, n*ldaGen)
	if uplo == blas.Upper {
		for i := 0; i < n; i++ {
			for j := 0; j < min(n-i, k+1); j++ {
				aGen[i*ldaGen+i+j] = a[i*lda+j]
			}
		}
	} else {
		for i := 0; i < n; i++ {
			for j := max(0, k-i); j < k+1; j++ {
				aGen[i*ldaGen+i-(k-j)] = a[i*lda+j]
			}
		}
	}
	if diag == blas.Unit {
		for i := 0; i < n; i++ {
			aGen[i*ldaGen+i] = 1
		}
	}
	want := dlange(norm, n, n, aGen, ldaGen)

	if math.IsNaN(want) {
		if !math.IsNaN(got) {
			t.Errorf("%v: unexpected result with NaN element; got %v, want %v", name, got, want)
		}
		return
	}

	if norm == lapack.MaxAbs {
		if got != want {
			t.Errorf("%v: unexpected result; got %v, want %v", name, got, want)
		}
		return
	}
	diff := math.Abs(got - want)
	if diff > tol {
		t.Errorf("%v: unexpected result; got %v, want %v, diff=%v", name, got, want, diff)
	}
}
<|endoftext|>


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

package testlapack

import (
	"math"
	"testing"

	"golang.org/x/exp/rand"

	"gonum.org/v1/gonum/blas"
	"gonum.org/v1/gonum/blas/blas64"
)

type Dlasq1er interface {
	Dlasq1(n int, d, e, work []float64) int
	Dgetrfer
}

func Dlasq1Test(t *testing.T, impl Dlasq1er) {
	rnd := rand.New(rand.NewSource(1))
	bi := blas64.Implementation()
	// TODO(btracey): Increase the size of this test when we have a more numerically
	// stable way to test the singular values.
	for _, n := range []int{1, 2, 5, 8} {
		work := make([]float64, 4*n)
		d := make([]float64, n)
		e := make([]float64, n-1)
		for cas := 0; cas < 1; cas++ {
			for i := range work {
				work[i] = rnd.Float64()
			}
			for i := range d {
				d[i] = rnd.NormFloat64() + 10
			}
			for i := range e {
				e[i] = rnd.NormFloat64()
			}
			ldm := n
			m := make([]float64, n*ldm)
			// Set up the matrix
			for i := 0; i < n; i++ {
				m[i*ldm+i] = d[i]
				if i != n-1 {
					m[(i+1)*ldm+i] = e[i]
				}
			}

			ldmm := n
			mm := make([]float64, n*ldmm)
			bi.Dgemm(blas.Trans, blas.NoTrans, n, n, n, 1, m, ldm, m, ldm, 0, mm, ldmm)

			impl.Dlasq1(n, d, e, work)

			// Check that they are singular values. The
			// singular values are the square roots of the
			// eigenvalues of Xᵀ * X
			mmCopy := make([]float64, len(mm))
			copy(mmCopy, mm)
			ipiv := make([]int, n)
			for elem, sv := range d[0:n] {
				copy(mm, mmCopy)
				lambda := sv * sv
				for i := 0; i < n; i++ {
					mm[i*ldm+i] -= lambda
				}

				// Compute LU.
				ok := impl.Dgetrf(n, n, mm, ldmm, ipiv)
				if !ok {
					// Definitely singular.
					continue
				}
				// Compute determinant
				var logdet float64
				for i := 0; i < n; i++ {
					v := mm[i*ldm+i]
					logdet += math.Log(math.Abs(v))
				}
				if math.Exp(logdet) > 2 {
					t.Errorf("Incorrect singular value. n = %d, cas = %d, elem = %d, det = %v", n, cas, elem, math.Exp(logdet))
				}
			}
		}
	}
}
<commit_msg>lapack/testlapack: rework Dlasq1Test<commit_after>// Copyright ©2015 The Gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package testlapack

import (
	"fmt"
	"math"
	"sort"
	"testing"

	"golang.org/x/exp/rand"

	"gonum.org/v1/gonum/floats"
)

type Dlasq1er interface {
	Dlasq1(n int, d, e, work []float64) int

	Dgebrd(m, n int, a []float64, lda int, d, e, tauQ, tauP, work []float64, lwork int)
}

func Dlasq1Test(t *testing.T, impl Dlasq1er) {
	const tol = 1e-14
	rnd := rand.New(rand.NewSource(1))
	for _, n := range []int{0, 1, 2, 3, 4, 5, 8, 10, 30, 50} {
		for typ := 0; typ <= 7; typ++ {
			name := fmt.Sprintf("n=%v,typ=%v", n, typ)

			// Generate a diagonal matrix D with positive entries.
			d := make([]float64, n)
			switch typ {
			case 0:
				// The zero matrix.
			case 1:
				// The identity matrix.
				for i := range d {
					d[i] = 1
				}
			case 2:
				// A diagonal matrix with evenly spaced entries 1, ..., eps.
				for i := 0; i < n; i++ {
					if i == 0 {
						d[0] = 1
					} else {
						d[i] = 1 - (1-dlamchE)*float64(i)/float64(n-1)
					}
				}
			case 3, 4, 5:
				// A diagonal matrix with geometrically spaced entries 1, ..., eps.
				for i := 0; i < n; i++ {
					if i == 0 {
						d[0] = 1
					} else {
						d[i] = math.Pow(dlamchE, float64(i)/float64(n-1))
					}
				}
				switch typ {
				case 4:
					// Multiply by SQRT(overflow threshold).
					floats.Scale(math.Sqrt(1/dlamchS), d)
				case 5:
					// Multiply by SQRT(underflow threshold).
					floats.Scale(math.Sqrt(dlamchS), d)
				}
			case 6:
				// A diagonal matrix with "clustered" entries 1, eps, ..., eps.
				for i := range d {
					if i == 0 {
						d[i] = 1
					} else {
						d[i] = dlamchE
					}
				}
			case 7:
				// Diagonal matrix with random entries.
				for i := range d {
					d[i] = math.Abs(rnd.NormFloat64())
				}
			}

			dWant := make([]float64, n)
			copy(dWant, d)
			sort.Sort(sort.Reverse(sort.Float64Slice(dWant)))

			// Allocate work slice to the maximum length needed below.
			work := make([]float64, max(1, 4*n))

			// Generate an n×n matrix A by pre- and post-multiplying D with
			// random orthogonal matrices:
			//  A = U*D*V.
			lda := max(1, n)
			a := make([]float64, n*lda)
			Dlagge(n, n, 0, 0, d, a, lda, rnd, work)

			// Reduce A to bidiagonal form B represented by the diagonal d and
			// off-diagonal e.
			tauQ := make([]float64, n)
			tauP := make([]float64, n)
			e := make([]float64, max(0, n-1))
			impl.Dgebrd(n, n, a, lda, d, e, tauQ, tauP, work, len(work))

			// Compute the singular values of B.
			for i := range work {
				work[i] = math.NaN()
			}
			info := impl.Dlasq1(n, d, e, work)
			if info != 0 {
				t.Fatalf("%v: Dlasq1 returned non-zero info=%v", name, info)
			}

			if n == 0 {
				continue
			}

			if !sort.IsSorted(sort.Reverse(sort.Float64Slice(d))) {
				t.Errorf("%v: singular values not sorted", name)
			}

			diff := floats.Distance(d, dWant, math.Inf(1))
			if diff > tol*floats.Max(dWant) {
				t.Errorf("%v: unexpected result; diff=%v", name, diff)
			}
		}
	}
}
<|endoftext|>


<commit_before>package container // import "github.com/docker/docker/integration/container"

import (
	"context"
	"testing"
	"time"

	"github.com/docker/docker/api/types"
	containertypes "github.com/docker/docker/api/types/container"
	"github.com/docker/docker/client"
	"github.com/docker/docker/integration/internal/container"
	"gotest.tools/v3/assert"
	"gotest.tools/v3/poll"
	"gotest.tools/v3/skip"
)

// TestHealthCheckWorkdir verifies that health-checks inherit the containers'
// working-dir.
func TestHealthCheckWorkdir(t *testing.T) {
	skip.If(t, testEnv.OSType == "windows", "FIXME")
	defer setupTest(t)()
	ctx := context.Background()
	client := testEnv.APIClient()

	cID := container.Run(ctx, t, client, container.WithTty(true), container.WithWorkingDir("/foo"), func(c *container.TestContainerConfig) {
		c.Config.Healthcheck = &containertypes.HealthConfig{
			Test:     []string{"CMD-SHELL", "if [ \"$PWD\" = \"/foo\" ]; then exit 0; else exit 1; fi;"},
			Interval: 50 * time.Millisecond,
			Retries:  3,
		}
	})

	poll.WaitOn(t, pollForHealthStatus(ctx, client, cID, types.Healthy), poll.WithDelay(100*time.Millisecond))
}

// GitHub #37263
// Do not stop healthchecks just because we sent a signal to the container
func TestHealthKillContainer(t *testing.T) {
	skip.If(t, testEnv.OSType == "windows", "Windows only supports SIGKILL and SIGTERM? See https://github.com/moby/moby/issues/39574")
	defer setupTest(t)()

	ctx := context.Background()
	client := testEnv.APIClient()

	id := container.Run(ctx, t, client, func(c *container.TestContainerConfig) {
		c.Config.Healthcheck = &containertypes.HealthConfig{
			Test:     []string{"CMD-SHELL", "sleep 1"},
			Interval: time.Second,
			Retries:  5,
		}
	})

	ctxPoll, cancel := context.WithTimeout(ctx, 30*time.Second)
	defer cancel()
	poll.WaitOn(t, pollForHealthStatus(ctxPoll, client, id, "healthy"), poll.WithDelay(100*time.Millisecond))

	err := client.ContainerKill(ctx, id, "SIGUSR1")
	assert.NilError(t, err)

	ctxPoll, cancel = context.WithTimeout(ctx, 30*time.Second)
	defer cancel()
	poll.WaitOn(t, pollForHealthStatus(ctxPoll, client, id, "healthy"), poll.WithDelay(100*time.Millisecond))
}

func pollForHealthStatus(ctx context.Context, client client.APIClient, containerID string, healthStatus string) func(log poll.LogT) poll.Result {
	return func(log poll.LogT) poll.Result {
		inspect, err := client.ContainerInspect(ctx, containerID)

		switch {
		case err != nil:
			return poll.Error(err)
		case inspect.State.Health.Status == healthStatus:
			return poll.Success()
		default:
			return poll.Continue("waiting for container to become %s", healthStatus)
		}
	}
}
<commit_msg>Fix racey TestHealthKillContainer<commit_after>package container // import "github.com/docker/docker/integration/container"

import (
	"context"
	"testing"
	"time"

	"github.com/docker/docker/api/types"
	containertypes "github.com/docker/docker/api/types/container"
	"github.com/docker/docker/client"
	"github.com/docker/docker/integration/internal/container"
	"gotest.tools/v3/assert"
	"gotest.tools/v3/poll"
	"gotest.tools/v3/skip"
)

// TestHealthCheckWorkdir verifies that health-checks inherit the containers'
// working-dir.
func TestHealthCheckWorkdir(t *testing.T) {
	skip.If(t, testEnv.OSType == "windows", "FIXME")
	defer setupTest(t)()
	ctx := context.Background()
	client := testEnv.APIClient()

	cID := container.Run(ctx, t, client, container.WithTty(true), container.WithWorkingDir("/foo"), func(c *container.TestContainerConfig) {
		c.Config.Healthcheck = &containertypes.HealthConfig{
			Test:     []string{"CMD-SHELL", "if [ \"$PWD\" = \"/foo\" ]; then exit 0; else exit 1; fi;"},
			Interval: 50 * time.Millisecond,
			Retries:  3,
		}
	})

	poll.WaitOn(t, pollForHealthStatus(ctx, client, cID, types.Healthy), poll.WithDelay(100*time.Millisecond))
}

// GitHub #37263
// Do not stop healthchecks just because we sent a signal to the container
func TestHealthKillContainer(t *testing.T) {
	skip.If(t, testEnv.OSType == "windows", "Windows only supports SIGKILL and SIGTERM? See https://github.com/moby/moby/issues/39574")
	defer setupTest(t)()

	ctx := context.Background()
	client := testEnv.APIClient()

	id := container.Run(ctx, t, client, func(c *container.TestContainerConfig) {
		cmd := `
# Set the initial HEALTH value so the healthcheck passes
HEALTH="1"
echo $HEALTH > /health

# Any time doHealth is run we flip the value
# This lets us use kill signals to determine when healtchecks have run.
doHealth() {
	case "$HEALTH" in
		"0")
			HEALTH="1"
			;;
		"1")
			HEALTH="0"
			;;
	esac
	echo $HEALTH > /health
}

trap 'doHealth' USR1

while true; do sleep 1; done
`
		c.Config.Cmd = []string{"/bin/sh", "-c", cmd}
		c.Config.Healthcheck = &containertypes.HealthConfig{
			Test:     []string{"CMD-SHELL", `[ "$(cat /health)" = "1" ]`},
			Interval: time.Second,
			Retries:  5,
		}
	})

	ctxPoll, cancel := context.WithTimeout(ctx, 30*time.Second)
	defer cancel()
	poll.WaitOn(t, pollForHealthStatus(ctxPoll, client, id, "healthy"), poll.WithDelay(100*time.Millisecond))

	err := client.ContainerKill(ctx, id, "SIGUSR1")
	assert.NilError(t, err)

	ctxPoll, cancel = context.WithTimeout(ctx, 30*time.Second)
	defer cancel()
	poll.WaitOn(t, pollForHealthStatus(ctxPoll, client, id, "unhealthy"), poll.WithDelay(100*time.Millisecond))

	err = client.ContainerKill(ctx, id, "SIGUSR1")
	assert.NilError(t, err)

	ctxPoll, cancel = context.WithTimeout(ctx, 30*time.Second)
	defer cancel()
	poll.WaitOn(t, pollForHealthStatus(ctxPoll, client, id, "healthy"), poll.WithDelay(100*time.Millisecond))
}

func pollForHealthStatus(ctx context.Context, client client.APIClient, containerID string, healthStatus string) func(log poll.LogT) poll.Result {
	return func(log poll.LogT) poll.Result {
		inspect, err := client.ContainerInspect(ctx, containerID)

		switch {
		case err != nil:
			return poll.Error(err)
		case inspect.State.Health.Status == healthStatus:
			return poll.Success()
		default:
			return poll.Continue("waiting for container to become %s", healthStatus)
		}
	}
}
<|endoftext|>


<commit_before>package seccomp

import (
	"fmt"
	"syscall"
)

var domainflags = map[uint]string{
	syscall.AF_UNIX:      "AF_UNIX",
	syscall.AF_INET:      "AF_INET",
	syscall.AF_INET6:     "AF_INET6",
	syscall.AF_IPX:       "AF_IPX",
	syscall.AF_NETLINK:   "AF_NETLINK",
	syscall.AF_X25:       "AF_X25",
	syscall.AF_AX25:      "AF_AX25",
	syscall.AF_ATMPVC:    "AF_ATMPVC",
	syscall.AF_APPLETALK: "AF_APPLETALK",
	syscall.AF_PACKET:    "AF_PACKET",
	//	syscall.ALG: "AF_ALG",
}

var socktypes = map[uint]string{
	syscall.SOCK_STREAM:    "SOCK_STREAM",
	syscall.SOCK_DGRAM:     "SOCK_DGRAM",
	syscall.SOCK_SEQPACKET: "SOCK_SEQPACKET",
	syscall.SOCK_RAW:       "SOCK_RAW",
	syscall.SOCK_RDM:       "SOCK_RDM",
	syscall.SOCK_PACKET:    "SOCK_PACKET",
}

var socktypeflags = map[uint]string{
	syscall.SOCK_NONBLOCK: "SOCK_NONBLOCK",
	syscall.SOCK_CLOEXEC:  "SOCK_CLOEXEC",
}

func render_socket(pid int, args RegisterArgs) (string, error) {

	domain := domainflags[uint(args[0])]
	socktype := socktypes[uint(args[1]&0xFF)]

	socktypestr := socktype
	tmp := renderFlags(socktypeflags, uint(args[1]))

	if tmp != "" {
		socktypestr += "|"
	}

	socktypestr += tmp

	callrep := fmt.Sprintf("socket(%s, %s, %d)", domain, socktypestr, args[2])
	return callrep, nil
}
<commit_msg>Make the socket(2) renderer a little bit better<commit_after>package seccomp

import (
	"fmt"
	"syscall"
)

var protocols = map[uint]string{
	syscall.IPPROTO_IP:   "IPPROTO_IP",
	syscall.IPPROTO_ICMP: "IPPROTO_ICMP",
	syscall.IPPROTO_IGMP: "IPPROTO_IGMP",
	syscall.IPPROTO_IPIP: "IPPROTO_IPIP",
	syscall.IPPROTO_TCP:  "IPPROTO_TCP",
	syscall.IPPROTO_EGP:  "IPPROTO_EGP",
	syscall.IPPROTO_PUP:  "IPPROTO_PUP",
	syscall.IPPROTO_UDP:  "IPPROTO_UDP",
	syscall.IPPROTO_IDP:  "IPPROTO_IDP",
	syscall.IPPROTO_TP:   "IPPROTO_TP",
	syscall.IPPROTO_DCCP: "IPPROTO_DCCP",
	syscall.IPPROTO_IPV6: "IPPROTO_IPV6",
	syscall.IPPROTO_RSVP: "IPPROTO_RSVP",
	syscall.IPPROTO_GRE:  "IPPROTO_GRE",
	syscall.IPPROTO_ESP:  "IPPROTO_ESP",
	syscall.IPPROTO_AH:   "IPPROTO_AH",
	syscall.IPPROTO_MTP:  "IPPROTO_MTP",
	//syscall.IPPROTO_BEETPH: "IPPROTO_BEETPH",
	syscall.IPPROTO_ENCAP:   "IPPROTO_ENCAP",
	syscall.IPPROTO_PIM:     "IPPROTO_PIM",
	syscall.IPPROTO_COMP:    "IPPROTO_COMP",
	syscall.IPPROTO_SCTP:    "IPPROTO_SCTP",
	syscall.IPPROTO_UDPLITE: "IPPROTO_UDPLITE",
	syscall.IPPROTO_RAW:     "IPPROTO_RAW",
}

var domainflags = map[uint]string{
	syscall.AF_UNIX:      "AF_UNIX",
	syscall.AF_INET:      "AF_INET",
	syscall.AF_INET6:     "AF_INET6",
	syscall.AF_IPX:       "AF_IPX",
	syscall.AF_NETLINK:   "AF_NETLINK",
	syscall.AF_X25:       "AF_X25",
	syscall.AF_AX25:      "AF_AX25",
	syscall.AF_ATMPVC:    "AF_ATMPVC",
	syscall.AF_APPLETALK: "AF_APPLETALK",
	syscall.AF_PACKET:    "AF_PACKET",
	//	syscall.ALG: "AF_ALG",
}

var socktypes = map[uint]string{
	syscall.SOCK_STREAM:    "SOCK_STREAM",
	syscall.SOCK_DGRAM:     "SOCK_DGRAM",
	syscall.SOCK_SEQPACKET: "SOCK_SEQPACKET",
	syscall.SOCK_RAW:       "SOCK_RAW",
	syscall.SOCK_RDM:       "SOCK_RDM",
	syscall.SOCK_PACKET:    "SOCK_PACKET",
}

var socktypeflags = map[uint]string{
	syscall.SOCK_NONBLOCK: "SOCK_NONBLOCK",
	syscall.SOCK_CLOEXEC:  "SOCK_CLOEXEC",
}

func render_socket(pid int, args RegisterArgs) (string, error) {

	domain := ""
	socktype := ""

	prot := fmt.Sprintf("%d", uint(args[2]))

	if uint(args[0]) == syscall.AF_INET || uint(args[0]) == syscall.AF_INET6 {
		if _, y := protocols[uint(args[2])]; y {
			prot = protocols[uint(args[2])]
		}
	}
	if _, y := domainflags[uint(args[0])]; y {
		domain = domainflags[uint(args[0])]
	} else {
		domain = fmt.Sprintf("%d", args[0])
	}

	socktype = socktypes[uint(args[1]&0xFF)]
	socktypestr := socktype

	tmp := renderFlags(socktypeflags, uint(args[1]))

	if tmp != "" {
		socktypestr += "|"
	}

	socktypestr += tmp

	callrep := fmt.Sprintf("socket(%s, %s, %s)", domain, socktypestr, prot)
	return callrep, nil
}

<|endoftext|>


<commit_before>package ploop

// A test suite, also serving as an example of how to use the package

import (
	"bufio"
	"fmt"
	"github.com/dustin/go-humanize"
	"io/ioutil"
	"os"
	"os/exec"
	"testing"
)

var (
	old_pwd  string
	test_dir string
	d        Ploop
	snap     string
)

const baseDelta = "root.hdd"

// abort is used when the tests after the current one
// can't be run as one of their prerequisite(s) failed
func abort(format string, args ...interface{}) {
	s := fmt.Sprintf("ABORT: "+format+"\n", args...)
	f := bufio.NewWriter(os.Stderr)
	f.Write([]byte(s))
	f.Flush()
	cleanup()
	os.Exit(1)
}

// Check for a fatal error, call abort() if it is
func chk(err error) {
	if err != nil {
		abort("%s", err)
	}
}

func prepare(dir string) {
	var err error

	old_pwd, err = os.Getwd()
	chk(err)

	test_dir, err = ioutil.TempDir(old_pwd, dir)
	chk(err)

	err = os.Chdir(test_dir)
	chk(err)

	SetVerboseLevel(NoStdout)
	SetLogLevel(1)
	SetLogFile("ploop.log")
}

func TestPrepare(t *testing.T) {
	prepare("tmp-test")
}

func TestUUID(t *testing.T) {
	uuid, e := UUID()
	if e != nil {
		t.Errorf("UUID: %s", e)
	}

	t.Logf("Got uuid %s", uuid)
}

func create() {
	size := "384M"
	var p CreateParam

	s, e := humanize.ParseBytes(size)
	if e != nil {
		abort("humanize.ParseBytes: can't parse %s: %s", size, e)
	}
	p.Size = s / 1024
	p.File = baseDelta

	e = Create(&p)
	if e != nil {
		abort("Create: %s", e)
	}
}

func TestCreate(t *testing.T) {
	create()
}

func open() {
	var e error

	d, e = Open("DiskDescriptor.xml")
	if e != nil {
		abort("Open: %s", e)
	}
}

func TestOpen(t *testing.T) {
	open()
}

func TestMount(t *testing.T) {
	mnt := "mnt"

	e := os.Mkdir(mnt, 0755)
	chk(e)

	p := MountParam{Target: mnt}
	dev, e := d.Mount(&p)
	if e != nil {
		abort("Mount: %s", e)
	}

	t.Logf("Mounted; ploop device %s", dev)
}

func resize(t *testing.T, size string, offline bool) {
	if offline && testing.Short() {
		t.Skip("skipping offline resize test in short mode.")
	}
	s, e := humanize.ParseBytes(size)
	if e != nil {
		t.Fatalf("humanize.ParseBytes: can't parse %s: %s", size, e)
	}
	s = s / 1024

	e = d.Resize(s, offline)
	if e != nil {
		t.Fatalf("Resize to %s (%d bytes) failed: %s", size, s, e)
	}
}

func TestResizeOnlineShrink(t *testing.T) {
	resize(t, "256MB", false)
}

func TestResizeOnlineGrow(t *testing.T) {
	resize(t, "512MB", false)
}

func TestSnapshot(t *testing.T) {
	uuid, e := d.Snapshot()
	if e != nil {
		abort("Snapshot: %s", e)
	}

	t.Logf("Created online snapshot; uuid %s", uuid)
	snap = uuid
}

func TestTopDeltaFile(t *testing.T) {
	f, e := d.TopDeltaFile()
	if e != nil {
		t.Fatalf("TopDeltaFile: %s", e)
	}
	t.Logf("Got TopDeltaFile %s", f)
}

func copyFile(src, dst string) error {
	return exec.Command("cp", "-a", src, dst).Run()
}

func testReplace(t *testing.T) {
	var p ReplaceParam
	newDelta := baseDelta + ".new"
	e := copyFile(baseDelta, newDelta)
	if e != nil {
		t.Fatalf("copyFile: %s", e)
	}

	p.File = newDelta
	p.CurFile = baseDelta
	p.Flags = KeepName
	e = d.Replace(&p)
	if e != nil {
		t.Fatalf("Replace: %s", e)
	}
}

func TestReplaceOnline(t *testing.T) {
	testReplace(t)
}

func TestSwitchSnapshotOnline(t *testing.T) {
	e := d.SwitchSnapshot(snap)
	// should fail with E_PARAM
	if IsError(e, E_PARAM) {
		t.Logf("SwitchSnapshot: (online) good, expected error")
	} else {
		t.Fatalf("SwitchSnapshot: (should fail): %s", e)
	}
}

func TestDeleteSnapshot(t *testing.T) {
	e := d.DeleteSnapshot(snap)
	if e != nil {
		t.Fatalf("DeleteSnapshot: %s", e)
	} else {
		t.Logf("Deleted snapshot %s", snap)
	}
}

func TestIsMounted1(t *testing.T) {
	m, e := d.IsMounted()
	if e != nil {
		t.Fatalf("IsMounted: %s", e)
	}
	if !m {
		t.Fatalf("IsMounted: unexpectedly returned false")
	}
}

func TestUmount(t *testing.T) {
	e := d.Umount()
	if e != nil {
		t.Fatalf("Umount: %s", e)
	}
}

func TestIsMounted2(t *testing.T) {
	m, e := d.IsMounted()
	if e != nil {
		t.Fatalf("IsMounted: %s", e)
	}
	if m {
		t.Fatalf("IsMounted: unexpectedly returned true")
	}
}

func TestUmountAgain(t *testing.T) {
	e := d.Umount()
	if IsNotMounted(e) {
		t.Logf("Umount: (not mounted) good, expected error")
	} else {
		t.Fatalf("Umount: %s", e)
	}
}

func TestResizeOfflineShrink(t *testing.T) {
	resize(t, "256MB", true)
}

func TestResizeOfflineGrow(t *testing.T) {
	resize(t, "512MB", true)
}

func TestResizeOfflineShrinkAgain(t *testing.T) {
	resize(t, "256MB", true)
}

func TestSnapshotOffline(t *testing.T) {
	uuid, e := d.Snapshot()
	if e != nil {
		t.Fatalf("Snapshot: %s", e)
	} else {
		t.Logf("Created offline snapshot; uuid %s", uuid)
	}

	snap = uuid
}

func TestReplaceOffline(t *testing.T) {
	testReplace(t)
}

func TestSwitchSnapshot(t *testing.T) {
	e := d.SwitchSnapshot(snap)
	if e != nil {
		t.Fatalf("SwitchSnapshot: %s", e)
	} else {
		t.Logf("Switched to snapshot %s", snap)
	}
}

func TestFSInfo(t *testing.T) {
	i, e := FSInfo("DiskDescriptor.xml")

	if e != nil {
		t.Errorf("FSInfo: %v", e)
	} else {
		bTotal := i.Blocks * i.BlockSize
		bAvail := i.BlocksFree * i.BlockSize
		bUsed := bTotal - bAvail

		iTotal := i.Inodes
		iAvail := i.InodesFree
		iUsed := iTotal - iAvail

		t.Logf("\n             Size       Used      Avail Use%%\n%7s %9s %10s %10s %3d%%\n%7s %9d %10d %10d %3d%%",
			"Blocks",
			humanize.Bytes(bTotal),
			humanize.Bytes(bUsed),
			humanize.Bytes(bAvail),
			100*bUsed/bTotal,
			"Inodes",
			iTotal,
			iUsed,
			iAvail,
			100*iUsed/iTotal)
		t.Logf("\nInode ratio: 1 inode per %s of disk space",
			humanize.Bytes(bTotal/iTotal))
	}
}

func TestImageInfo(t *testing.T) {
	i, e := d.ImageInfo()
	if e != nil {
		t.Errorf("ImageInfo: %v", e)
	} else {
		t.Logf("\n              Blocks  Blocksize       Size  Ver\n%20d %10d %10s %4d",
			i.Blocks, i.BlockSize,
			humanize.Bytes(512*i.Blocks),
			i.Version)
	}

}

func cleanup() {
	if d.d != nil {
		if m, _ := d.IsMounted(); m {
			d.Umount()
		}
		d.Close()
	}
	if old_pwd != "" {
		os.Chdir(old_pwd)
	}
	if test_dir != "" {
		os.RemoveAll(test_dir)
	}
}

// TestCleanup is the last test, removing files created by previous tests
func TestCleanup(t *testing.T) {
	cleanup()
}

func BenchmarkMountUmount(b *testing.B) {
	b.StopTimer()
	prepare("tmp-bench")
	SetVerboseLevel(NoStdout)
	create()
	open()
	mnt := "mnt"
	e := os.Mkdir(mnt, 0755)
	chk(e)
	p := MountParam{Target: mnt, Readonly: true}

	b.StartTimer()
	for n := 0; n < b.N; n++ {
		_, e := d.Mount(&p)
		if e != nil {
			b.Fatalf("Mount: %s", e)
		}
		e = d.Umount()
		if e != nil {
			b.Fatalf("Umount: %s", e)
		}
	}
	b.StopTimer()
	cleanup()
}

func BenchmarkIsMounted(b *testing.B) {
	b.StopTimer()
	prepare("tmp-bench")
	SetVerboseLevel(NoStdout)
	create()
	open()
	mnt := "mnt"
	e := os.Mkdir(mnt, 0755)
	chk(e)
	p := MountParam{Target: mnt, Readonly: true}
	_, e = d.Mount(&p)
	if e != nil {
		b.Fatalf("Mount: %s", e)
	}

	b.StartTimer()
	for n := 0; n < b.N; n++ {
		_, e := d.IsMounted()
		if e != nil {
			b.Fatalf("IsMounted: %s", e)
		}
	}
	b.StopTimer()
	cleanup()
}

func BenchmarkFSInfo(b *testing.B) {
	b.StopTimer()
	prepare("tmp-bench")
	SetVerboseLevel(NoStdout)
	create()
	open()
	mnt := "mnt"
	e := os.Mkdir(mnt, 0755)
	chk(e)
	p := MountParam{Target: mnt, Readonly: true}
	_, e = d.Mount(&p)
	if e != nil {
		b.Fatalf("Mount: %s", e)
	}

	b.StartTimer()
	for n := 0; n < b.N; n++ {
		_, e := FSInfo("DiskDescriptor.xml")
		if e != nil {
			b.Fatalf("FSInfo: %s", e)
		}
	}
	b.StopTimer()
	cleanup()
}

func BenchmarkImageInfo(b *testing.B) {
	b.StopTimer()
	prepare("tmp-bench")
	SetVerboseLevel(NoStdout)
	create()
	open()
	mnt := "mnt"
	e := os.Mkdir(mnt, 0755)
	chk(e)
	p := MountParam{Target: mnt, Readonly: true}
	_, e = d.Mount(&p)
	if e != nil {
		b.Fatalf("Mount: %s", e)
	}

	b.StartTimer()
	for n := 0; n < b.N; n++ {
		_, e := d.ImageInfo()
		if e != nil {
			b.Fatalf("ImageInfo: %s", e)
		}
	}
	b.StopTimer()
	cleanup()
}
<commit_msg>ploop_test.go: minor formatting<commit_after>package ploop

// A test suite, also serving as an example of how to use the package

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"testing"

	"github.com/dustin/go-humanize"
)

var (
	oldPwd  string
	testDir string
	d       Ploop
	snap    string
)

const baseDelta = "root.hdd"

// abort is used when the tests after the current one
// can't be run as one of their prerequisite(s) failed
func abort(format string, args ...interface{}) {
	s := fmt.Sprintf("ABORT: "+format+"\n", args...)
	f := bufio.NewWriter(os.Stderr)
	f.Write([]byte(s))
	f.Flush()
	cleanup()
	os.Exit(1)
}

// Check for a fatal error, call abort() if it is
func chk(err error) {
	if err != nil {
		abort("%s", err)
	}
}

func prepare(dir string) {
	var err error

	oldPwd, err = os.Getwd()
	chk(err)

	testDir, err = ioutil.TempDir(oldPwd, dir)
	chk(err)

	err = os.Chdir(testDir)
	chk(err)

	SetVerboseLevel(NoStdout)
	SetLogLevel(1)
	SetLogFile("ploop.log")
}

func TestPrepare(t *testing.T) {
	prepare("tmp-test")
}

func TestUUID(t *testing.T) {
	uuid, e := UUID()
	if e != nil {
		t.Errorf("UUID: %s", e)
	}

	t.Logf("Got uuid %s", uuid)
}

func create() {
	size := "384M"
	var p CreateParam

	s, e := humanize.ParseBytes(size)
	if e != nil {
		abort("humanize.ParseBytes: can't parse %s: %s", size, e)
	}
	p.Size = s / 1024
	p.File = baseDelta

	e = Create(&p)
	if e != nil {
		abort("Create: %s", e)
	}
}

func TestCreate(t *testing.T) {
	create()
}

func open() {
	var e error

	d, e = Open("DiskDescriptor.xml")
	if e != nil {
		abort("Open: %s", e)
	}
}

func TestOpen(t *testing.T) {
	open()
}

func TestMount(t *testing.T) {
	mnt := "mnt"

	e := os.Mkdir(mnt, 0755)
	chk(e)

	p := MountParam{Target: mnt}
	dev, e := d.Mount(&p)
	if e != nil {
		abort("Mount: %s", e)
	}

	t.Logf("Mounted; ploop device %s", dev)
}

func resize(t *testing.T, size string, offline bool) {
	if offline && testing.Short() {
		t.Skip("skipping offline resize test in short mode.")
	}
	s, e := humanize.ParseBytes(size)
	if e != nil {
		t.Fatalf("humanize.ParseBytes: can't parse %s: %s", size, e)
	}
	s = s / 1024

	e = d.Resize(s, offline)
	if e != nil {
		t.Fatalf("Resize to %s (%d bytes) failed: %s", size, s, e)
	}
}

func TestResizeOnlineShrink(t *testing.T) {
	resize(t, "256MB", false)
}

func TestResizeOnlineGrow(t *testing.T) {
	resize(t, "512MB", false)
}

func TestSnapshot(t *testing.T) {
	uuid, e := d.Snapshot()
	if e != nil {
		abort("Snapshot: %s", e)
	}

	t.Logf("Created online snapshot; uuid %s", uuid)
	snap = uuid
}

func TestTopDeltaFile(t *testing.T) {
	f, e := d.TopDeltaFile()
	if e != nil {
		t.Fatalf("TopDeltaFile: %s", e)
	}
	t.Logf("Got TopDeltaFile %s", f)
}

func copyFile(src, dst string) error {
	return exec.Command("cp", "-a", src, dst).Run()
}

func testReplace(t *testing.T) {
	var p ReplaceParam
	newDelta := baseDelta + ".new"
	e := copyFile(baseDelta, newDelta)
	if e != nil {
		t.Fatalf("copyFile: %s", e)
	}

	p.File = newDelta
	p.CurFile = baseDelta
	p.Flags = KeepName
	e = d.Replace(&p)
	if e != nil {
		t.Fatalf("Replace: %s", e)
	}
}

func TestReplaceOnline(t *testing.T) {
	testReplace(t)
}

func TestSwitchSnapshotOnline(t *testing.T) {
	e := d.SwitchSnapshot(snap)
	// should fail with E_PARAM
	if IsError(e, E_PARAM) {
		t.Logf("SwitchSnapshot: (online) good, expected error")
	} else {
		t.Fatalf("SwitchSnapshot: (should fail): %s", e)
	}
}

func TestDeleteSnapshot(t *testing.T) {
	e := d.DeleteSnapshot(snap)
	if e != nil {
		t.Fatalf("DeleteSnapshot: %s", e)
	} else {
		t.Logf("Deleted snapshot %s", snap)
	}
}

func TestIsMounted1(t *testing.T) {
	m, e := d.IsMounted()
	if e != nil {
		t.Fatalf("IsMounted: %s", e)
	}
	if !m {
		t.Fatalf("IsMounted: unexpectedly returned false")
	}
}

func TestUmount(t *testing.T) {
	e := d.Umount()
	if e != nil {
		t.Fatalf("Umount: %s", e)
	}
}

func TestIsMounted2(t *testing.T) {
	m, e := d.IsMounted()
	if e != nil {
		t.Fatalf("IsMounted: %s", e)
	}
	if m {
		t.Fatalf("IsMounted: unexpectedly returned true")
	}
}

func TestUmountAgain(t *testing.T) {
	e := d.Umount()
	if IsNotMounted(e) {
		t.Logf("Umount: (not mounted) good, expected error")
	} else {
		t.Fatalf("Umount: %s", e)
	}
}

func TestResizeOfflineShrink(t *testing.T) {
	resize(t, "256MB", true)
}

func TestResizeOfflineGrow(t *testing.T) {
	resize(t, "512MB", true)
}

func TestResizeOfflineShrinkAgain(t *testing.T) {
	resize(t, "256MB", true)
}

func TestSnapshotOffline(t *testing.T) {
	uuid, e := d.Snapshot()
	if e != nil {
		t.Fatalf("Snapshot: %s", e)
	} else {
		t.Logf("Created offline snapshot; uuid %s", uuid)
	}

	snap = uuid
}

func TestReplaceOffline(t *testing.T) {
	testReplace(t)
}

func TestSwitchSnapshot(t *testing.T) {
	e := d.SwitchSnapshot(snap)
	if e != nil {
		t.Fatalf("SwitchSnapshot: %s", e)
	} else {
		t.Logf("Switched to snapshot %s", snap)
	}
}

func TestFSInfo(t *testing.T) {
	i, e := FSInfo("DiskDescriptor.xml")

	if e != nil {
		t.Errorf("FSInfo: %v", e)
	} else {
		bTotal := i.Blocks * i.BlockSize
		bAvail := i.BlocksFree * i.BlockSize
		bUsed := bTotal - bAvail

		iTotal := i.Inodes
		iAvail := i.InodesFree
		iUsed := iTotal - iAvail

		t.Logf("\n             Size       Used      Avail Use%%\n%7s %9s %10s %10s %3d%%\n%7s %9d %10d %10d %3d%%",
			"Blocks",
			humanize.Bytes(bTotal),
			humanize.Bytes(bUsed),
			humanize.Bytes(bAvail),
			100*bUsed/bTotal,
			"Inodes",
			iTotal,
			iUsed,
			iAvail,
			100*iUsed/iTotal)
		t.Logf("\nInode ratio: 1 inode per %s of disk space",
			humanize.Bytes(bTotal/iTotal))
	}
}

func TestImageInfo(t *testing.T) {
	i, e := d.ImageInfo()
	if e != nil {
		t.Errorf("ImageInfo: %v", e)
	} else {
		t.Logf("\n              Blocks  Blocksize       Size  Ver\n%20d %10d %10s %4d",
			i.Blocks, i.BlockSize,
			humanize.Bytes(512*i.Blocks),
			i.Version)
	}

}

func cleanup() {
	if d.d != nil {
		if m, _ := d.IsMounted(); m {
			d.Umount()
		}
		d.Close()
	}
	if oldPwd != "" {
		os.Chdir(oldPwd)
	}
	if testDir != "" {
		os.RemoveAll(testDir)
	}
}

// TestCleanup is the last test, removing files created by previous tests
func TestCleanup(t *testing.T) {
	cleanup()
}

func BenchmarkMountUmount(b *testing.B) {
	b.StopTimer()
	prepare("tmp-bench")
	SetVerboseLevel(NoStdout)
	create()
	open()
	mnt := "mnt"
	e := os.Mkdir(mnt, 0755)
	chk(e)
	p := MountParam{Target: mnt, Readonly: true}

	b.StartTimer()
	for n := 0; n < b.N; n++ {
		_, e := d.Mount(&p)
		if e != nil {
			b.Fatalf("Mount: %s", e)
		}
		e = d.Umount()
		if e != nil {
			b.Fatalf("Umount: %s", e)
		}
	}
	b.StopTimer()
	cleanup()
}

func BenchmarkIsMounted(b *testing.B) {
	b.StopTimer()
	prepare("tmp-bench")
	SetVerboseLevel(NoStdout)
	create()
	open()
	mnt := "mnt"
	e := os.Mkdir(mnt, 0755)
	chk(e)
	p := MountParam{Target: mnt, Readonly: true}
	_, e = d.Mount(&p)
	if e != nil {
		b.Fatalf("Mount: %s", e)
	}

	b.StartTimer()
	for n := 0; n < b.N; n++ {
		_, e := d.IsMounted()
		if e != nil {
			b.Fatalf("IsMounted: %s", e)
		}
	}
	b.StopTimer()
	cleanup()
}

func BenchmarkFSInfo(b *testing.B) {
	b.StopTimer()
	prepare("tmp-bench")
	SetVerboseLevel(NoStdout)
	create()
	open()
	mnt := "mnt"
	e := os.Mkdir(mnt, 0755)
	chk(e)
	p := MountParam{Target: mnt, Readonly: true}
	_, e = d.Mount(&p)
	if e != nil {
		b.Fatalf("Mount: %s", e)
	}

	b.StartTimer()
	for n := 0; n < b.N; n++ {
		_, e := FSInfo("DiskDescriptor.xml")
		if e != nil {
			b.Fatalf("FSInfo: %s", e)
		}
	}
	b.StopTimer()
	cleanup()
}

func BenchmarkImageInfo(b *testing.B) {
	b.StopTimer()
	prepare("tmp-bench")
	SetVerboseLevel(NoStdout)
	create()
	open()
	mnt := "mnt"
	e := os.Mkdir(mnt, 0755)
	chk(e)
	p := MountParam{Target: mnt, Readonly: true}
	_, e = d.Mount(&p)
	if e != nil {
		b.Fatalf("Mount: %s", e)
	}

	b.StartTimer()
	for n := 0; n < b.N; n++ {
		_, e := d.ImageInfo()
		if e != nil {
			b.Fatalf("ImageInfo: %s", e)
		}
	}
	b.StopTimer()
	cleanup()
}
<|endoftext|>


<commit_before>package autonat

import (
	"context"
	"errors"
	"math/rand"
	"sync"
	"time"

	host "github.com/libp2p/go-libp2p-host"
	inet "github.com/libp2p/go-libp2p-net"
	peer "github.com/libp2p/go-libp2p-peer"
	pstore "github.com/libp2p/go-libp2p-peerstore"
	ma "github.com/multiformats/go-multiaddr"
)

// NATStatus is the state of NAT as detected by the ambient service.
type NATStatus int

const (
	// NAT status is unknown; this means that the ambient service has not been
	// able to decide the presence of NAT in the most recent attempt to test
	// dial through known autonat peers.  initial state.
	NATStatusUnknown NATStatus = iota
	// NAT status is publicly dialable
	NATStatusPublic
	// NAT status is private network
	NATStatusPrivate
)

var (
	AutoNATBootDelay       = 15 * time.Second
	AutoNATRetryInterval   = 90 * time.Second
	AutoNATRefreshInterval = 15 * time.Minute
	AutoNATRequestTimeout  = 60 * time.Second
)

// AutoNAT is the interface for ambient NAT autodiscovery
type AutoNAT interface {
	// Status returns the current NAT status
	Status() NATStatus
	// PublicAddr returns the public dial address when NAT status is public and an
	// error otherwise
	PublicAddr() (ma.Multiaddr, error)
}

// AmbientAutoNAT is the implementation of ambient NAT autodiscovery
type AmbientAutoNAT struct {
	ctx  context.Context
	host host.Host

	getAddrs GetAddrs

	mx     sync.Mutex
	peers  map[peer.ID][]ma.Multiaddr
	status NATStatus
	addr   ma.Multiaddr
	// Reflects the confidence on of the NATStatus being private, as a single
	// dialback may fail for reasons unrelated to NAT.
	// If it is <3, then multiple autoNAT peers may be contacted for dialback
	// If only a single autoNAT peer is known, then the confidence increases
	// for each failure until it reaches 3.
	confidence int
}

// NewAutoNAT creates a new ambient NAT autodiscovery instance attached to a host
// If getAddrs is nil, h.Addrs will be used
func NewAutoNAT(ctx context.Context, h host.Host, getAddrs GetAddrs) AutoNAT {
	if getAddrs == nil {
		getAddrs = h.Addrs
	}

	as := &AmbientAutoNAT{
		ctx:      ctx,
		host:     h,
		getAddrs: getAddrs,
		peers:    make(map[peer.ID][]ma.Multiaddr),
		status:   NATStatusUnknown,
	}

	h.Network().Notify(as)
	go as.background()

	return as
}

func (as *AmbientAutoNAT) Status() NATStatus {
	as.mx.Lock()
	defer as.mx.Unlock()
	return as.status
}

func (as *AmbientAutoNAT) PublicAddr() (ma.Multiaddr, error) {
	as.mx.Lock()
	defer as.mx.Unlock()

	if as.status != NATStatusPublic {
		return nil, errors.New("NAT Status is not public")
	}

	return as.addr, nil
}

func (as *AmbientAutoNAT) background() {
	// wait a bit for the node to come online and establish some connections
	// before starting autodetection
	select {
	case <-time.After(AutoNATBootDelay):
	case <-as.ctx.Done():
		return
	}

	for {
		as.autodetect()

		delay := AutoNATRefreshInterval
		if as.status == NATStatusUnknown {
			delay = AutoNATRetryInterval
		}

		select {
		case <-time.After(delay):
		case <-as.ctx.Done():
			return
		}
	}
}

func (as *AmbientAutoNAT) autodetect() {
	peers := as.getPeers()

	if len(peers) == 0 {
		log.Debugf("skipping NAT auto detection; no autonat peers")
		return
	}

	cli := NewAutoNATClient(as.host, as.getAddrs)
	failures := 0

	for _, pi := range peers {
		ctx, cancel := context.WithTimeout(as.ctx, AutoNATRequestTimeout)
		as.host.Peerstore().AddAddrs(pi.ID, pi.Addrs, pstore.TempAddrTTL)
		a, err := cli.DialBack(ctx, pi.ID)
		cancel()

		switch {
		case err == nil:
			log.Debugf("NAT status is public; address through %s: %s", pi.ID.Pretty(), a.String())
			as.mx.Lock()
			as.addr = a
			as.status = NATStatusPublic
			as.confidence = 0
			as.mx.Unlock()
			return

		case IsDialError(err):
			log.Debugf("dial error through %s: %s", pi.ID.Pretty(), err.Error())
			failures++
			if failures >= 3 || as.confidence >= 3 { // 3 times is enemy action
				log.Debugf("NAT status is private")
				as.mx.Lock()
				as.status = NATStatusPrivate
				as.confidence = 3
				as.mx.Unlock()
				return
			}

		default:
			log.Debugf("Error dialing through %s: %s", pi.ID.Pretty(), err.Error())
		}
	}

	as.mx.Lock()
	if failures > 0 {
		as.status = NATStatusPrivate
		as.confidence++
		log.Debugf("NAT status is private")
	} else {
		as.status = NATStatusUnknown
		as.confidence = 0
		log.Debugf("NAT status is unknown")
	}
	as.mx.Unlock()
}

func (as *AmbientAutoNAT) getPeers() []pstore.PeerInfo {
	as.mx.Lock()
	defer as.mx.Unlock()

	if len(as.peers) == 0 {
		return nil
	}

	var connected, others []pstore.PeerInfo

	for p, addrs := range as.peers {
		if as.host.Network().Connectedness(p) == inet.Connected {
			connected = append(connected, pstore.PeerInfo{ID: p, Addrs: addrs})
		} else {
			others = append(others, pstore.PeerInfo{ID: p, Addrs: addrs})
		}
	}

	shufflePeers(connected)

	if len(connected) < 3 {
		shufflePeers(others)
		return append(connected, others...)
	} else {
		return connected
	}
}

func shufflePeers(peers []pstore.PeerInfo) {
	for i := range peers {
		j := rand.Intn(i + 1)
		peers[i], peers[j] = peers[j], peers[i]
	}
}
<commit_msg>parallelize dialbacks<commit_after>package autonat

import (
	"context"
	"errors"
	"math/rand"
	"sync"
	"time"

	host "github.com/libp2p/go-libp2p-host"
	inet "github.com/libp2p/go-libp2p-net"
	peer "github.com/libp2p/go-libp2p-peer"
	pstore "github.com/libp2p/go-libp2p-peerstore"
	ma "github.com/multiformats/go-multiaddr"
)

// NATStatus is the state of NAT as detected by the ambient service.
type NATStatus int

const (
	// NAT status is unknown; this means that the ambient service has not been
	// able to decide the presence of NAT in the most recent attempt to test
	// dial through known autonat peers.  initial state.
	NATStatusUnknown NATStatus = iota
	// NAT status is publicly dialable
	NATStatusPublic
	// NAT status is private network
	NATStatusPrivate
)

var (
	AutoNATBootDelay       = 15 * time.Second
	AutoNATRetryInterval   = 90 * time.Second
	AutoNATRefreshInterval = 15 * time.Minute
	AutoNATRequestTimeout  = 30 * time.Second
)

// AutoNAT is the interface for ambient NAT autodiscovery
type AutoNAT interface {
	// Status returns the current NAT status
	Status() NATStatus
	// PublicAddr returns the public dial address when NAT status is public and an
	// error otherwise
	PublicAddr() (ma.Multiaddr, error)
}

// AmbientAutoNAT is the implementation of ambient NAT autodiscovery
type AmbientAutoNAT struct {
	ctx  context.Context
	host host.Host

	getAddrs GetAddrs

	mx     sync.Mutex
	peers  map[peer.ID][]ma.Multiaddr
	status NATStatus
	addr   ma.Multiaddr
	// Reflects the confidence on of the NATStatus being private, as a single
	// dialback may fail for reasons unrelated to NAT.
	// If it is <3, then multiple autoNAT peers may be contacted for dialback
	// If only a single autoNAT peer is known, then the confidence increases
	// for each failure until it reaches 3.
	confidence int
}

// NewAutoNAT creates a new ambient NAT autodiscovery instance attached to a host
// If getAddrs is nil, h.Addrs will be used
func NewAutoNAT(ctx context.Context, h host.Host, getAddrs GetAddrs) AutoNAT {
	if getAddrs == nil {
		getAddrs = h.Addrs
	}

	as := &AmbientAutoNAT{
		ctx:      ctx,
		host:     h,
		getAddrs: getAddrs,
		peers:    make(map[peer.ID][]ma.Multiaddr),
		status:   NATStatusUnknown,
	}

	h.Network().Notify(as)
	go as.background()

	return as
}

func (as *AmbientAutoNAT) Status() NATStatus {
	as.mx.Lock()
	defer as.mx.Unlock()
	return as.status
}

func (as *AmbientAutoNAT) PublicAddr() (ma.Multiaddr, error) {
	as.mx.Lock()
	defer as.mx.Unlock()

	if as.status != NATStatusPublic {
		return nil, errors.New("NAT Status is not public")
	}

	return as.addr, nil
}

func (as *AmbientAutoNAT) background() {
	// wait a bit for the node to come online and establish some connections
	// before starting autodetection
	select {
	case <-time.After(AutoNATBootDelay):
	case <-as.ctx.Done():
		return
	}

	for {
		as.autodetect()

		delay := AutoNATRefreshInterval
		if as.status == NATStatusUnknown {
			delay = AutoNATRetryInterval
		}

		select {
		case <-time.After(delay):
		case <-as.ctx.Done():
			return
		}
	}
}

func (as *AmbientAutoNAT) autodetect() {
	peers := as.getPeers()

	if len(peers) == 0 {
		log.Debugf("skipping NAT auto detection; no autonat peers")
		return
	}

	cli := NewAutoNATClient(as.host, as.getAddrs)
	ctx, cancel := context.WithTimeout(as.ctx, AutoNATRequestTimeout)
	defer cancel()

	var mx sync.Mutex
	var pubaddr ma.Multiaddr
	private := 0
	public := 0

	probe := 3 - as.confidence
	if probe == 0 {
		probe = 1
	}
	if probe > len(peers) {
		probe = len(peers)
	}

	var wg sync.WaitGroup

	for _, pi := range peers[:probe] {
		wg.Add(1)
		go func(pi pstore.PeerInfo) {
			as.host.Peerstore().AddAddrs(pi.ID, pi.Addrs, pstore.TempAddrTTL)
			a, err := cli.DialBack(ctx, pi.ID)

			switch {
			case err == nil:
				log.Debugf("Dialback through %s successful; public address is %s", pi.ID.Pretty(), a.String())
				mx.Lock()
				public++
				pubaddr = a
				mx.Unlock()

			case IsDialError(err):
				log.Debugf("Dialback through %s failed", pi.ID.Pretty())
				mx.Lock()
				private++
				mx.Unlock()

			default:
				log.Debugf("Dialback error through %s: %s", pi.ID.Pretty(), err)
			}

			wg.Done()
		}(pi)
	}

	wg.Wait()

	as.mx.Lock()
	if public > 0 {
		log.Debugf("NAT status is public")
		as.status = NATStatusPublic
		as.addr = pubaddr
		if as.confidence < 3 {
			as.confidence++
		}
	} else if private > 0 {
		log.Debugf("NAT status is private")
		as.status = NATStatusPrivate
		as.addr = nil
		if as.confidence < 3 {
			as.confidence++
		}
	} else {
		log.Debugf("NAT status is unknown")
		as.status = NATStatusUnknown
		as.addr = nil
		as.confidence = 0
	}
	as.mx.Unlock()
}

func (as *AmbientAutoNAT) getPeers() []pstore.PeerInfo {
	as.mx.Lock()
	defer as.mx.Unlock()

	if len(as.peers) == 0 {
		return nil
	}

	var connected, others []pstore.PeerInfo

	for p, addrs := range as.peers {
		if as.host.Network().Connectedness(p) == inet.Connected {
			connected = append(connected, pstore.PeerInfo{ID: p, Addrs: addrs})
		} else {
			others = append(others, pstore.PeerInfo{ID: p, Addrs: addrs})
		}
	}

	shufflePeers(connected)

	if len(connected) < 3 {
		shufflePeers(others)
		return append(connected, others...)
	} else {
		return connected
	}
}

func shufflePeers(peers []pstore.PeerInfo) {
	for i := range peers {
		j := rand.Intn(i + 1)
		peers[i], peers[j] = peers[j], peers[i]
	}
}
<|endoftext|>


<commit_before>package relay

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

	basic "github.com/libp2p/go-libp2p/p2p/host/basic"

	autonat "github.com/libp2p/go-libp2p-autonat"
	_ "github.com/libp2p/go-libp2p-circuit"
	discovery "github.com/libp2p/go-libp2p-discovery"
	inet "github.com/libp2p/go-libp2p-net"
	peer "github.com/libp2p/go-libp2p-peer"
	pstore "github.com/libp2p/go-libp2p-peerstore"
	routing "github.com/libp2p/go-libp2p-routing"
	ma "github.com/multiformats/go-multiaddr"
	manet "github.com/multiformats/go-multiaddr-net"
)

const (
	RelayRendezvous = "/libp2p/relay"
)

var (
	DesiredRelays = 3

	BootDelay = 20 * time.Second
)

// AutoRelay is a Host that uses relays for connectivity when a NAT is detected.
type AutoRelay struct {
	host     *basic.BasicHost
	discover discovery.Discoverer
	router   routing.PeerRouting
	autonat  autonat.AutoNAT
	addrsF   basic.AddrsFactory

	disconnect chan struct{}

	mx     sync.Mutex
	relays map[peer.ID]struct{}
	status autonat.NATStatus
}

func NewAutoRelay(ctx context.Context, bhost *basic.BasicHost, discover discovery.Discoverer, router routing.PeerRouting) *AutoRelay {
	ar := &AutoRelay{
		host:       bhost,
		discover:   discover,
		router:     router,
		addrsF:     bhost.AddrsFactory,
		relays:     make(map[peer.ID]struct{}),
		disconnect: make(chan struct{}, 1),
		status:     autonat.NATStatusUnknown,
	}
	ar.autonat = autonat.NewAutoNAT(ctx, bhost, ar.baseAddrs)
	bhost.AddrsFactory = ar.hostAddrs
	bhost.Network().Notify(ar)
	go ar.background(ctx)
	return ar
}

func (ar *AutoRelay) baseAddrs() []ma.Multiaddr {
	return ar.addrsF(ar.host.AllAddrs())
}

func (ar *AutoRelay) hostAddrs(addrs []ma.Multiaddr) []ma.Multiaddr {
	return ar.relayAddrs(ar.addrsF(addrs))
}

func (ar *AutoRelay) background(ctx context.Context) {
	select {
	case <-time.After(autonat.AutoNATBootDelay + BootDelay):
	case <-ctx.Done():
		return
	}

	// when true, we need to identify push
	push := false

	for {
		wait := autonat.AutoNATRefreshInterval
		switch ar.autonat.Status() {
		case autonat.NATStatusUnknown:
			ar.mx.Lock()
			ar.status = autonat.NATStatusUnknown
			ar.mx.Unlock()
			wait = autonat.AutoNATRetryInterval

		case autonat.NATStatusPublic:
			ar.mx.Lock()
			if ar.status != autonat.NATStatusPublic {
				push = true
			}
			ar.status = autonat.NATStatusPublic
			ar.mx.Unlock()

		case autonat.NATStatusPrivate:
			update := ar.findRelays(ctx)
			ar.mx.Lock()
			if update || ar.status != autonat.NATStatusPrivate {
				push = true
			}
			ar.status = autonat.NATStatusPrivate
			ar.mx.Unlock()
		}

		if push {
			push = false
			ar.host.PushIdentify()
		}

		select {
		case <-ar.disconnect:
			push = true
		case <-time.After(wait):
		case <-ctx.Done():
			return
		}
	}
}

func (ar *AutoRelay) findRelays(ctx context.Context) bool {
again:
	ar.mx.Lock()
	haveRelays := len(ar.relays)
	if haveRelays >= DesiredRelays {
		ar.mx.Unlock()
		return false
	}
	need := DesiredRelays - len(ar.relays)
	ar.mx.Unlock()

	limit := 1000

	dctx, cancel := context.WithTimeout(ctx, 30*time.Second)
	pis, err := discovery.FindPeers(dctx, ar.discover, RelayRendezvous, limit)
	cancel()
	if err != nil {
		log.Debugf("error discovering relays: %s", err.Error())

		if haveRelays == 0 {
			log.Debug("no relays connected; retrying in 30s")
			select {
			case <-time.After(30 * time.Second):
				goto again
			case <-ctx.Done():
				return false
			}
		}
	}

	log.Debugf("discovered %d relays", len(pis))

	pis = ar.selectRelays(ctx, pis, 20, 50)
	update := 0

	for _, pi := range pis {
		ar.mx.Lock()
		if _, ok := ar.relays[pi.ID]; ok {
			ar.mx.Unlock()
			continue
		}
		ar.mx.Unlock()

		cctx, cancel := context.WithTimeout(ctx, 15*time.Second)
		err = ar.host.Connect(cctx, pi)
		cancel()
		if err != nil {
			log.Debugf("error connecting to relay %s: %s", pi.ID, err.Error())
			continue
		}

		log.Debugf("connected to relay %s", pi.ID)
		ar.mx.Lock()
		ar.relays[pi.ID] = struct{}{}
		haveRelays++
		ar.mx.Unlock()

		// tag the connection as very important
		ar.host.ConnManager().TagPeer(pi.ID, "relay", 42)

		update++
		need--
		if need == 0 {
			break
		}
	}

	if haveRelays == 0 {
		// we failed to find any relays and we are not connected to any!
		// wait a little and try again, the discovery query might have returned only dead peers
		log.Debug("no relays connected; retrying in 30s")
		select {
		case <-time.After(30 * time.Second):
			goto again
		case <-ctx.Done():
			return false
		}
	}

	return update > 0
}

func (ar *AutoRelay) selectRelays(ctx context.Context, pis []pstore.PeerInfo, count, maxq int) []pstore.PeerInfo {
	// TODO better relay selection strategy; this just selects random relays
	//      but we should probably use ping latency as the selection metric

	if len(pis) == 0 {
		return pis
	}

	if len(pis) < count {
		count = len(pis)
	}

	if len(pis) < maxq {
		maxq = len(pis)
	}

	// only select relays that can be found by routing
	type queryResult struct {
		pi  pstore.PeerInfo
		err error
	}
	result := make([]pstore.PeerInfo, 0, count)
	resultCh := make(chan queryResult, maxq)

	qctx, cancel := context.WithTimeout(ctx, 30*time.Second)
	defer cancel()

	// shuffle to randomize the order of queries
	shuffleRelays(pis)
	for _, pi := range pis[:maxq] {
		// first check to see if we already know this peer from a previous query
		addrs := ar.host.Peerstore().Addrs(pi.ID)
		if len(addrs) > 0 {
			resultCh <- queryResult{pi: pstore.PeerInfo{ID: pi.ID, Addrs: addrs}, err: nil}
			continue
		}
		go func(p peer.ID) {
			pi, err := ar.router.FindPeer(qctx, p)
			if err != nil {
				log.Debugf("error finding relay peer %s: %s", p, err.Error())
			}
			resultCh <- queryResult{pi: pi, err: err}
		}(pi.ID)
	}

	rcount := 0
	for len(result) < count && rcount < maxq {
		select {
		case qr := <-resultCh:
			rcount++
			if qr.err == nil {
				result = append(result, qr.pi)
			}

		case <-qctx.Done():
			break
		}
	}

	shuffleRelays(result)
	return result
}

// This function is computes the NATed relay addrs when our status is private:
// - The public addrs are removed from the address set.
// - The non-public addrs are included verbatim so that peers behind the same NAT/firewall
//   can still dial us directly.
// - On top of those, we add the relay-specific addrs for the relays to which we are
//   connected. For each non-private relay addr, we encapsulate the p2p-circuit addr
//   through which we can be dialed.
func (ar *AutoRelay) relayAddrs(addrs []ma.Multiaddr) []ma.Multiaddr {
	ar.mx.Lock()
	defer ar.mx.Unlock()

	if ar.status != autonat.NATStatusPrivate {
		return addrs
	}

	raddrs := make([]ma.Multiaddr, 0, len(addrs)+len(ar.relays))

	// only keep private addrs from the original addr set
	for _, addr := range addrs {
		if manet.IsPrivateAddr(addr) {
			raddrs = append(raddrs, addr)
		}
	}

	// add relay specific addrs to the list
	for p := range ar.relays {
		addrs := cleanupAddressSet(ar.host.Peerstore().Addrs(p))

		circuit, err := ma.NewMultiaddr(fmt.Sprintf("/p2p/%s/p2p-circuit", p.Pretty()))
		if err != nil {
			panic(err)
		}

		for _, addr := range addrs {
			pub := addr.Encapsulate(circuit)
			raddrs = append(raddrs, pub)
		}
	}

	return raddrs
}

func shuffleRelays(pis []pstore.PeerInfo) {
	for i := range pis {
		j := rand.Intn(i + 1)
		pis[i], pis[j] = pis[j], pis[i]
	}
}

// Notifee
func (ar *AutoRelay) Listen(inet.Network, ma.Multiaddr)      {}
func (ar *AutoRelay) ListenClose(inet.Network, ma.Multiaddr) {}
func (ar *AutoRelay) Connected(inet.Network, inet.Conn)      {}

func (ar *AutoRelay) Disconnected(net inet.Network, c inet.Conn) {
	p := c.RemotePeer()

	ar.mx.Lock()
	defer ar.mx.Unlock()

	if ar.host.Network().Connectedness(p) == inet.Connected {
		// We have a second connection.
		return
	}

	if _, ok := ar.relays[p]; ok {
		delete(ar.relays, p)
		select {
		case ar.disconnect <- struct{}{}:
		default:
		}
	}
}

func (ar *AutoRelay) OpenedStream(inet.Network, inet.Stream) {}
func (ar *AutoRelay) ClosedStream(inet.Network, inet.Stream) {}
<commit_msg>don't preallocate result array, we don't know how long it will be<commit_after>package relay

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

	basic "github.com/libp2p/go-libp2p/p2p/host/basic"

	autonat "github.com/libp2p/go-libp2p-autonat"
	_ "github.com/libp2p/go-libp2p-circuit"
	discovery "github.com/libp2p/go-libp2p-discovery"
	inet "github.com/libp2p/go-libp2p-net"
	peer "github.com/libp2p/go-libp2p-peer"
	pstore "github.com/libp2p/go-libp2p-peerstore"
	routing "github.com/libp2p/go-libp2p-routing"
	ma "github.com/multiformats/go-multiaddr"
	manet "github.com/multiformats/go-multiaddr-net"
)

const (
	RelayRendezvous = "/libp2p/relay"
)

var (
	DesiredRelays = 3

	BootDelay = 20 * time.Second
)

// AutoRelay is a Host that uses relays for connectivity when a NAT is detected.
type AutoRelay struct {
	host     *basic.BasicHost
	discover discovery.Discoverer
	router   routing.PeerRouting
	autonat  autonat.AutoNAT
	addrsF   basic.AddrsFactory

	disconnect chan struct{}

	mx     sync.Mutex
	relays map[peer.ID]struct{}
	status autonat.NATStatus
}

func NewAutoRelay(ctx context.Context, bhost *basic.BasicHost, discover discovery.Discoverer, router routing.PeerRouting) *AutoRelay {
	ar := &AutoRelay{
		host:       bhost,
		discover:   discover,
		router:     router,
		addrsF:     bhost.AddrsFactory,
		relays:     make(map[peer.ID]struct{}),
		disconnect: make(chan struct{}, 1),
		status:     autonat.NATStatusUnknown,
	}
	ar.autonat = autonat.NewAutoNAT(ctx, bhost, ar.baseAddrs)
	bhost.AddrsFactory = ar.hostAddrs
	bhost.Network().Notify(ar)
	go ar.background(ctx)
	return ar
}

func (ar *AutoRelay) baseAddrs() []ma.Multiaddr {
	return ar.addrsF(ar.host.AllAddrs())
}

func (ar *AutoRelay) hostAddrs(addrs []ma.Multiaddr) []ma.Multiaddr {
	return ar.relayAddrs(ar.addrsF(addrs))
}

func (ar *AutoRelay) background(ctx context.Context) {
	select {
	case <-time.After(autonat.AutoNATBootDelay + BootDelay):
	case <-ctx.Done():
		return
	}

	// when true, we need to identify push
	push := false

	for {
		wait := autonat.AutoNATRefreshInterval
		switch ar.autonat.Status() {
		case autonat.NATStatusUnknown:
			ar.mx.Lock()
			ar.status = autonat.NATStatusUnknown
			ar.mx.Unlock()
			wait = autonat.AutoNATRetryInterval

		case autonat.NATStatusPublic:
			ar.mx.Lock()
			if ar.status != autonat.NATStatusPublic {
				push = true
			}
			ar.status = autonat.NATStatusPublic
			ar.mx.Unlock()

		case autonat.NATStatusPrivate:
			update := ar.findRelays(ctx)
			ar.mx.Lock()
			if update || ar.status != autonat.NATStatusPrivate {
				push = true
			}
			ar.status = autonat.NATStatusPrivate
			ar.mx.Unlock()
		}

		if push {
			push = false
			ar.host.PushIdentify()
		}

		select {
		case <-ar.disconnect:
			push = true
		case <-time.After(wait):
		case <-ctx.Done():
			return
		}
	}
}

func (ar *AutoRelay) findRelays(ctx context.Context) bool {
again:
	ar.mx.Lock()
	haveRelays := len(ar.relays)
	if haveRelays >= DesiredRelays {
		ar.mx.Unlock()
		return false
	}
	need := DesiredRelays - len(ar.relays)
	ar.mx.Unlock()

	limit := 1000

	dctx, cancel := context.WithTimeout(ctx, 30*time.Second)
	pis, err := discovery.FindPeers(dctx, ar.discover, RelayRendezvous, limit)
	cancel()
	if err != nil {
		log.Debugf("error discovering relays: %s", err.Error())

		if haveRelays == 0 {
			log.Debug("no relays connected; retrying in 30s")
			select {
			case <-time.After(30 * time.Second):
				goto again
			case <-ctx.Done():
				return false
			}
		}
	}

	log.Debugf("discovered %d relays", len(pis))

	pis = ar.selectRelays(ctx, pis, 20, 50)
	update := 0

	for _, pi := range pis {
		ar.mx.Lock()
		if _, ok := ar.relays[pi.ID]; ok {
			ar.mx.Unlock()
			continue
		}
		ar.mx.Unlock()

		cctx, cancel := context.WithTimeout(ctx, 15*time.Second)
		err = ar.host.Connect(cctx, pi)
		cancel()
		if err != nil {
			log.Debugf("error connecting to relay %s: %s", pi.ID, err.Error())
			continue
		}

		log.Debugf("connected to relay %s", pi.ID)
		ar.mx.Lock()
		ar.relays[pi.ID] = struct{}{}
		haveRelays++
		ar.mx.Unlock()

		// tag the connection as very important
		ar.host.ConnManager().TagPeer(pi.ID, "relay", 42)

		update++
		need--
		if need == 0 {
			break
		}
	}

	if haveRelays == 0 {
		// we failed to find any relays and we are not connected to any!
		// wait a little and try again, the discovery query might have returned only dead peers
		log.Debug("no relays connected; retrying in 30s")
		select {
		case <-time.After(30 * time.Second):
			goto again
		case <-ctx.Done():
			return false
		}
	}

	return update > 0
}

func (ar *AutoRelay) selectRelays(ctx context.Context, pis []pstore.PeerInfo, count, maxq int) []pstore.PeerInfo {
	// TODO better relay selection strategy; this just selects random relays
	//      but we should probably use ping latency as the selection metric

	if len(pis) == 0 {
		return pis
	}

	if len(pis) < count {
		count = len(pis)
	}

	if len(pis) < maxq {
		maxq = len(pis)
	}

	// only select relays that can be found by routing
	type queryResult struct {
		pi  pstore.PeerInfo
		err error
	}
	result := make([]pstore.PeerInfo, 0, count)
	resultCh := make(chan queryResult, maxq)

	qctx, cancel := context.WithTimeout(ctx, 30*time.Second)
	defer cancel()

	// shuffle to randomize the order of queries
	shuffleRelays(pis)
	for _, pi := range pis[:maxq] {
		// first check to see if we already know this peer from a previous query
		addrs := ar.host.Peerstore().Addrs(pi.ID)
		if len(addrs) > 0 {
			resultCh <- queryResult{pi: pstore.PeerInfo{ID: pi.ID, Addrs: addrs}, err: nil}
			continue
		}
		go func(p peer.ID) {
			pi, err := ar.router.FindPeer(qctx, p)
			if err != nil {
				log.Debugf("error finding relay peer %s: %s", p, err.Error())
			}
			resultCh <- queryResult{pi: pi, err: err}
		}(pi.ID)
	}

	rcount := 0
	for len(result) < count && rcount < maxq {
		select {
		case qr := <-resultCh:
			rcount++
			if qr.err == nil {
				result = append(result, qr.pi)
			}

		case <-qctx.Done():
			break
		}
	}

	shuffleRelays(result)
	return result
}

// This function is computes the NATed relay addrs when our status is private:
// - The public addrs are removed from the address set.
// - The non-public addrs are included verbatim so that peers behind the same NAT/firewall
//   can still dial us directly.
// - On top of those, we add the relay-specific addrs for the relays to which we are
//   connected. For each non-private relay addr, we encapsulate the p2p-circuit addr
//   through which we can be dialed.
func (ar *AutoRelay) relayAddrs(addrs []ma.Multiaddr) []ma.Multiaddr {
	ar.mx.Lock()
	defer ar.mx.Unlock()

	if ar.status != autonat.NATStatusPrivate {
		return addrs
	}

	var raddrs []ma.Multiaddr

	// only keep private addrs from the original addr set
	for _, addr := range addrs {
		if manet.IsPrivateAddr(addr) {
			raddrs = append(raddrs, addr)
		}
	}

	// add relay specific addrs to the list
	for p := range ar.relays {
		addrs := cleanupAddressSet(ar.host.Peerstore().Addrs(p))

		circuit, err := ma.NewMultiaddr(fmt.Sprintf("/p2p/%s/p2p-circuit", p.Pretty()))
		if err != nil {
			panic(err)
		}

		for _, addr := range addrs {
			pub := addr.Encapsulate(circuit)
			raddrs = append(raddrs, pub)
		}
	}

	return raddrs
}

func shuffleRelays(pis []pstore.PeerInfo) {
	for i := range pis {
		j := rand.Intn(i + 1)
		pis[i], pis[j] = pis[j], pis[i]
	}
}

// Notifee
func (ar *AutoRelay) Listen(inet.Network, ma.Multiaddr)      {}
func (ar *AutoRelay) ListenClose(inet.Network, ma.Multiaddr) {}
func (ar *AutoRelay) Connected(inet.Network, inet.Conn)      {}

func (ar *AutoRelay) Disconnected(net inet.Network, c inet.Conn) {
	p := c.RemotePeer()

	ar.mx.Lock()
	defer ar.mx.Unlock()

	if ar.host.Network().Connectedness(p) == inet.Connected {
		// We have a second connection.
		return
	}

	if _, ok := ar.relays[p]; ok {
		delete(ar.relays, p)
		select {
		case ar.disconnect <- struct{}{}:
		default:
		}
	}
}

func (ar *AutoRelay) OpenedStream(inet.Network, inet.Stream) {}
func (ar *AutoRelay) ClosedStream(inet.Network, inet.Stream) {}
<|endoftext|>


<commit_before>// (c) Copyright 2015-2017 JONNALAGADDA Srinivas
//
// 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 flow

import (
	"database/sql"
	"fmt"
	"testing"

	_ "github.com/go-sql-driver/mysql"
)

// Driver test function.
func TestDocActions01(t *testing.T) {
	var (
		actions = []string{"CREATE", "APPROVE", "REJECT", "RET_WITH_COMMENTS", "DISCARD"}
	)

	// Connect to the database.
	driver, connStr := "mysql", "travis@/flow"
	db, err := sql.Open(driver, connStr)
	if err != nil {
		t.Errorf("could not connect to database : %v\n", err)
	}
	defer db.Close()
	err = db.Ping()
	if err != nil {
		t.Errorf("could not ping the database : %v\n", err)
	}
	RegisterDB(db)

	// List document actions.
	t.Run("List", func(t *testing.T) {
		das, err := DocActions().List(0, 0)
		if err != nil {
			t.Errorf("error : %v", err)
		}

		for _, da := range das {
			fmt.Printf("%#v\n", da)
		}
	})

	// Register a few new document actions.
	t.Run("New", func(t *testing.T) {
		tx, err := db.Begin()
		if err != nil {
			t.Errorf("error starting transaction : %v\n", err)
		}
		defer tx.Rollback()

		for _, name := range actions {
			_, err = DocActions().New(tx, name)
			if err != nil {
				t.Errorf("error creating document action '%s' : %v\n", name, err)
			}
		}

		if err == nil {
			err = tx.Commit()
			if err != nil {
				t.Errorf("error committing transaction : %v\n", err)
			}
		}
	})

	// Retrieve a specified document action.
	t.Run("GetByID", func(t *testing.T) {
		da, err := DocActions().Get(1)
		if err != nil {
			t.Errorf("error getting document action '1' : %v\n", err)
		}

		fmt.Printf("%#v\n", da)
	})

	// Verify existence of a specified document action.
	t.Run("GetByName", func(t *testing.T) {
		da, err := DocActions().GetByName(actions[1])
		if err != nil {
			t.Errorf("error getting document action '%s' : %v\n", actions[1], err)
		}

		fmt.Printf("%#v\n", da)
	})

	// Rename the given document action to the specified new name.
	t.Run("RenameAction", func(t *testing.T) {
		tx, err := db.Begin()
		if err != nil {
			t.Errorf("error starting transaction : %v\n", err)
		}
		defer tx.Rollback()

		err = DocActions().Rename(tx, 1, "INITIALISE")
		if err != nil {
			t.Errorf("error renaming document action '1' : %v\n", err)
		}

		if err == nil {
			err = tx.Commit()
			if err != nil {
				t.Errorf("error committing transaction : %v\n", err)
			}
		}
	})

	// Rename the given document action to the specified old name.
	t.Run("UndoRename", func(t *testing.T) {
		tx, err := db.Begin()
		if err != nil {
			t.Errorf("error starting transaction : %v\n", err)
		}
		defer tx.Rollback()

		err = DocActions().Rename(tx, 1, "CREATE")
		if err != nil {
			t.Errorf("error renaming document action '1' : %v\n", err)
		}

		if err == nil {
			err = tx.Commit()
			if err != nil {
				t.Errorf("error committing transaction : %v\n", err)
			}
		}
	})
}
<commit_msg>Modify tests for `DocAction` to be self-contained<commit_after>// (c) Copyright 2015-2017 JONNALAGADDA Srinivas
//
// 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 flow

import (
	"database/sql"
	"testing"

	_ "github.com/go-sql-driver/mysql"
)

// Driver test function.
func TestDocActions01(t *testing.T) {
	var (
		actions = []string{"CREATE", "APPROVE", "REJECT", "RET_WITH_COMMENTS", "DISCARD"}
	)

	// Connect to the database.
	driver, connStr := "mysql", "travis@/flow"
	db, err := sql.Open(driver, connStr)
	if err != nil {
		t.Fatalf("could not connect to database : %v\n", err)
	}
	defer db.Close()
	err = db.Ping()
	if err != nil {
		t.Fatalf("could not ping the database : %v\n", err)
	}
	RegisterDB(db)

	// Tear down.
	defer func() {
		tx, err := db.Begin()
		if err != nil {
			t.Fatalf("error starting transaction : %v\n", err)
		}
		defer tx.Rollback()

		_, err = tx.Exec(`DELETE FROM wf_docactions_master`)
		if err != nil {
			t.Fatalf("error running transaction : %v\n", err)
		}

		err = tx.Commit()
		if err != nil {
			t.Fatalf("error committing transaction : %v\n", err)
		}
	}()

	// Test CRUL operations.
	t.Run("CRUL", func(t *testing.T) {
		tx, err := db.Begin()
		if err != nil {
			t.Fatalf("error starting transaction : %v\n", err)
		}
		defer tx.Rollback()

		var da DocActionID
		for _, name := range actions {
			da, err = DocActions().New(tx, name)
			if err != nil {
				t.Fatalf("error creating document action '%s' : %v\n", name, err)
			}
		}

		err = tx.Commit()
		if err != nil {
			t.Fatalf("error committing transaction : %v\n", err)
		}

		// Test read operations.
		_, err = DocActions().Get(da)
		if err != nil {
			t.Fatalf("error getting document action : %v\n", err)
		}

		_, err = DocActions().GetByName(actions[1])
		if err != nil {
			t.Fatalf("error getting document action '%s' : %v\n", actions[1], err)
		}

		_, err = DocActions().List(0, 0)
		if err != nil {
			t.Fatalf("error : %v", err)
		}

		// Test renaming.
		tx, err = db.Begin()
		if err != nil {
			t.Fatalf("error starting transaction : %v\n", err)
		}
		defer tx.Rollback()

		err = DocActions().Rename(tx, da, "INITIALISE")
		if err != nil {
			t.Fatalf("error renaming document action : %v\n", err)
		}

		err = tx.Commit()
		if err != nil {
			t.Fatalf("error committing transaction : %v\n", err)
		}

		tx, err = db.Begin()
		if err != nil {
			t.Fatalf("error starting transaction : %v\n", err)
		}
		defer tx.Rollback()

		err = DocActions().Rename(tx, da, actions[len(actions)-1])
		if err != nil {
			t.Fatalf("error renaming document action : %v\n", err)
		}

		err = tx.Commit()
		if err != nil {
			t.Fatalf("error committing transaction : %v\n", err)
		}
	})
}
<|endoftext|>


<commit_before>/* Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc> */
/* See LICENSE for licensing information */

package xurls

import (
	"regexp"
	"testing"
)

type regexTestCase struct {
	in   string
	want interface{}
}

var constantTestCases = []regexTestCase{
	{``, nil},
	{` `, nil},
	{`:`, nil},
	{`::`, nil},
	{`:::`, nil},
	{`::::`, nil},
	{`.`, nil},
	{`..`, nil},
	{`...`, nil},
	{`1.1`, nil},
	{`.1.`, nil},
	{`1.1.1`, nil},
	{`1:1`, nil},
	{`:1:`, nil},
	{`1:1:1`, nil},
	{`://`, nil},
	{`foo`, nil},
	{`foo:`, nil},
	{`mailto:`, nil},
	{`randomxmpp:foo`, nil},
	{`foo://`, nil},
	{`http://`, nil},
	{`:foo`, nil},
	{`://foo`, nil},
	{`foo:bar`, nil},
	{`zzz.`, nil},
	{`.zzz`, nil},
	{`zzz.zzz`, nil},
	{`/some/path`, nil},
	{`localhost`, nil},
	{`com`, nil},

	{`http://foo`, `http://foo`},
	{`https://localhost`, `https://localhost`},
	{`mailto:foo`, `mailto:foo`},
	{`sms:123`, `sms:123`},
	{`xmpp:foo@bar`, `xmpp:foo@bar`},
	{`bitcoin:Addr23?amount=1&message=foo`, `bitcoin:Addr23?amount=1&message=foo`},
	{`http://foo.com`, `http://foo.com`},
	{`http://foo.random`, `http://foo.random`},
	{` http://foo.com/bar `, `http://foo.com/bar`},
	{` http://foo.com/bar more`, `http://foo.com/bar`},
	{`<http://foo.com/bar>`, `http://foo.com/bar`},
	{`<http://foo.com/bar>more`, `http://foo.com/bar`},
	{`,http://foo.com/bar.`, `http://foo.com/bar`},
	{`,http://foo.com/bar.more`, `http://foo.com/bar.more`},
	{`,http://foo.com/bar,`, `http://foo.com/bar`},
	{`,http://foo.com/bar,more`, `http://foo.com/bar,more`},
	{`(http://foo.com/bar)`, `http://foo.com/bar`},
	{`(http://foo.com/bar)more`, `http://foo.com/bar)more`},
	{`"http://foo.com/bar'`, `http://foo.com/bar`},
	{`"http://foo.com/bar'more`, `http://foo.com/bar'more`},
	{`"http://foo.com/bar"`, `http://foo.com/bar`},
	{`"http://foo.com/bar"more`, `http://foo.com/bar"more`},
	{`http://a.b/a.,:;-+_()?@&=$~!*%'"a`, `http://a.b/a.,:;-+_()?@&=$~!*%'"a`},
	{`http://foo.com/path_(more)`, `http://foo.com/path_(more)`},
	{`http://test.foo.com/`, `http://test.foo.com/`},
	{`http://foo.com/path`, `http://foo.com/path`},
	{`http://foo.com:8080/path`, `http://foo.com:8080/path`},
	{`http://1.1.1.1/path`, `http://1.1.1.1/path`},
	{`http://1080::8:800:200c:417a/path`, `http://1080::8:800:200c:417a/path`},
	{`what is http://foo.com?`, `http://foo.com`},
	{`the http://foo.com!`, `http://foo.com`},
	{`https://test.foo.bar/path?a=b`, `https://test.foo.bar/path?a=b`},
	{`ftp://user@foo.bar`, `ftp://user@foo.bar`},
}

func doTest(t *testing.T, name string, re *regexp.Regexp, cases []regexTestCase) {
	for _, c := range cases {
		got := re.FindString(c.in)
		var want string
		switch x := c.want.(type) {
		case string:
			want = x
		}
		if got != want {
			t.Errorf(`%s.FindString("%s") got "%s", want "%s"`, name, c.in, got, want)
		}
	}
}

func TestRegexes(t *testing.T) {
	doTest(t, "All", All, constantTestCases)
	doTest(t, "AllStrict", AllStrict, constantTestCases)
	doTest(t, "All", All, []regexTestCase{
		{`foo.a`, nil},
		{`foo.com`, `foo.com`},
		{`foo.com bar.com`, `foo.com`},
		{`foo.com-foo`, `foo.com`},
		{`foo.company`, `foo.company`},
		{`foo.comrandom`, nil},
		{`foo.onion`, `foo.onion`},
		{`foo.i2p`, `foo.i2p`},
		{`中国.中国`, `中国.中国`},
		{`中国.中国/foo中国`, `中国.中国/foo中国`},
		{`foo.com/`, `foo.com/`},
		{`1.1.1.1`, `1.1.1.1`},
		{`121.1.1.1`, `121.1.1.1`},
		{`255.1.1.1`, `255.1.1.1`},
		{`300.1.1.1`, nil},
		{`1080:0:0:0:8:800:200C:4171`, `1080:0:0:0:8:800:200C:4171`},
		{`3ffe:2a00:100:7031::1`, `3ffe:2a00:100:7031::1`},
		{`1080::8:800:200c:417a`, `1080::8:800:200c:417a`},
		{`foo.com:8080`, `foo.com:8080`},
		{`foo.com:8080/path`, `foo.com:8080/path`},
		{`test.foo.com`, `test.foo.com`},
		{`test.foo.com/path`, `test.foo.com/path`},
		{`test.foo.com/path/more/`, `test.foo.com/path/more/`},
		{`TEST.FOO.COM/PATH`, `TEST.FOO.COM/PATH`},
		{`foo.com/a.,:;-+_()?@&=$~!*%'"a`, `foo.com/a.,:;-+_()?@&=$~!*%'"a`},
		{`foo.com/path_(more)`, `foo.com/path_(more)`},
		{`foo.com/path_(even)_(more)`, `foo.com/path_(even)_(more)`},
		{`foo.com/path_(more)/more`, `foo.com/path_(more)/more`},
		{`foo.com/path_(more)/end)`, `foo.com/path_(more)/end)`},
		{`www.foo.com`, `www.foo.com`},
		{` foo.com/bar `, `foo.com/bar`},
		{` foo.com/bar more`, `foo.com/bar`},
		{`<foo.com/bar>`, `foo.com/bar`},
		{`<foo.com/bar>more`, `foo.com/bar`},
		{`,foo.com/bar.`, `foo.com/bar`},
		{`,foo.com/bar.more`, `foo.com/bar.more`},
		{`,foo.com/bar,`, `foo.com/bar`},
		{`,foo.com/bar,more`, `foo.com/bar,more`},
		{`(foo.com/bar)`, `foo.com/bar`},
		{`(foo.com/bar)more`, `foo.com/bar)more`},
		{`"foo.com/bar'`, `foo.com/bar`},
		{`"foo.com/bar'more`, `foo.com/bar'more`},
		{`"foo.com/bar"`, `foo.com/bar`},
		{`"foo.com/bar"more`, `foo.com/bar"more`},
		{`what is foo.com?`, `foo.com`},
		{`the foo.com!`, `foo.com`},

		{`foo@bar`, nil},
		{`foo@bar.a`, nil},
		{`foo@bar.com`, `foo@bar.com`},
		{`foo@bar.com bar@bar.com`, `foo@bar.com`},
		{`foo@bar.onion`, `foo@bar.onion`},
		{`foo@中国.中国`, `foo@中国.中国`},
		{`foo@test.bar.com`, `foo@test.bar.com`},
		{`FOO@TEST.BAR.COM`, `FOO@TEST.BAR.COM`},
		{`foo@bar.com/path`, `foo@bar.com`},
		{`foo+test@bar.com`, `foo+test@bar.com`},
		{`foo+._%-@bar.com`, `foo+._%-@bar.com`},
	})
	doTest(t, "AllStrict", AllStrict, []regexTestCase{
		{`foo.a`, nil},
		{`foo.com`, nil},
		{`foo.com/`, nil},
		{`1.1.1.1`, nil},
		{`3ffe:2a00:100:7031::1`, nil},
		{`test.foo.com:8080/path`, nil},
		{`foo@bar.com`, nil},
	})
}
<commit_msg>Add some more tests<commit_after>/* Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc> */
/* See LICENSE for licensing information */

package xurls

import (
	"regexp"
	"testing"
)

type regexTestCase struct {
	in   string
	want interface{}
}

var constantTestCases = []regexTestCase{
	{``, nil},
	{` `, nil},
	{`:`, nil},
	{`::`, nil},
	{`:::`, nil},
	{`::::`, nil},
	{`.`, nil},
	{`..`, nil},
	{`...`, nil},
	{`1.1`, nil},
	{`.1.`, nil},
	{`1.1.1`, nil},
	{`1:1`, nil},
	{`:1:`, nil},
	{`1:1:1`, nil},
	{`://`, nil},
	{`foo`, nil},
	{`foo:`, nil},
	{`mailto:`, nil},
	{`randomxmpp:foo`, nil},
	{`foo://`, nil},
	{`http://`, nil},
	{`:foo`, nil},
	{`://foo`, nil},
	{`foo:bar`, nil},
	{`zzz.`, nil},
	{`.zzz`, nil},
	{`zzz.zzz`, nil},
	{`/some/path`, nil},
	{`localhost`, nil},
	{`com`, nil},
	{`.com`, nil},
	{`http`, nil},

	{`http://foo`, `http://foo`},
	{`http://FOO`, `http://FOO`},
	{`http://FAÀ`, `http://FAÀ`},
	{`https://localhost`, `https://localhost`},
	{`mailto:foo`, `mailto:foo`},
	{`sms:123`, `sms:123`},
	{`xmpp:foo@bar`, `xmpp:foo@bar`},
	{`bitcoin:Addr23?amount=1&message=foo`, `bitcoin:Addr23?amount=1&message=foo`},
	{`http://foo.com`, `http://foo.com`},
	{`http://foo.random`, `http://foo.random`},
	{` http://foo.com/bar `, `http://foo.com/bar`},
	{` http://foo.com/bar more`, `http://foo.com/bar`},
	{`<http://foo.com/bar>`, `http://foo.com/bar`},
	{`<http://foo.com/bar>more`, `http://foo.com/bar`},
	{`,http://foo.com/bar.`, `http://foo.com/bar`},
	{`,http://foo.com/bar.more`, `http://foo.com/bar.more`},
	{`,http://foo.com/bar,`, `http://foo.com/bar`},
	{`,http://foo.com/bar,more`, `http://foo.com/bar,more`},
	{`(http://foo.com/bar)`, `http://foo.com/bar`},
	{`(http://foo.com/bar)more`, `http://foo.com/bar)more`},
	{`"http://foo.com/bar'`, `http://foo.com/bar`},
	{`"http://foo.com/bar'more`, `http://foo.com/bar'more`},
	{`"http://foo.com/bar"`, `http://foo.com/bar`},
	{`"http://foo.com/bar"more`, `http://foo.com/bar"more`},
	{`http://a.b/a.,:;-+_()?@&=$~!*%'"a`, `http://a.b/a.,:;-+_()?@&=$~!*%'"a`},
	{`http://foo.com/path_(more)`, `http://foo.com/path_(more)`},
	{`http://test.foo.com/`, `http://test.foo.com/`},
	{`http://foo.com/path`, `http://foo.com/path`},
	{`http://foo.com:8080/path`, `http://foo.com:8080/path`},
	{`http://1.1.1.1/path`, `http://1.1.1.1/path`},
	{`http://1080::8:800:200c:417a/path`, `http://1080::8:800:200c:417a/path`},
	{`what is http://foo.com?`, `http://foo.com`},
	{`the http://foo.com!`, `http://foo.com`},
	{`https://test.foo.bar/path?a=b`, `https://test.foo.bar/path?a=b`},
	{`ftp://user@foo.bar`, `ftp://user@foo.bar`},
}

func doTest(t *testing.T, name string, re *regexp.Regexp, cases []regexTestCase) {
	for _, c := range cases {
		got := re.FindString(c.in)
		var want string
		switch x := c.want.(type) {
		case string:
			want = x
		}
		if got != want {
			t.Errorf(`%s.FindString("%s") got "%s", want "%s"`, name, c.in, got, want)
		}
	}
}

func TestRegexes(t *testing.T) {
	doTest(t, "All", All, constantTestCases)
	doTest(t, "AllStrict", AllStrict, constantTestCases)
	doTest(t, "All", All, []regexTestCase{
		{`foo.a`, nil},
		{`foo.com`, `foo.com`},
		{`foo.com bar.com`, `foo.com`},
		{`foo.com-foo`, `foo.com`},
		{`foo.company`, `foo.company`},
		{`foo.comrandom`, nil},
		{`foo.onion`, `foo.onion`},
		{`foo.i2p`, `foo.i2p`},
		{`中国.中国`, `中国.中国`},
		{`中国.中国/foo中国`, `中国.中国/foo中国`},
		{`foo.com/`, `foo.com/`},
		{`1.1.1.1`, `1.1.1.1`},
		{`121.1.1.1`, `121.1.1.1`},
		{`255.1.1.1`, `255.1.1.1`},
		{`300.1.1.1`, nil},
		{`1080:0:0:0:8:800:200C:4171`, `1080:0:0:0:8:800:200C:4171`},
		{`3ffe:2a00:100:7031::1`, `3ffe:2a00:100:7031::1`},
		{`1080::8:800:200c:417a`, `1080::8:800:200c:417a`},
		{`foo.com:8080`, `foo.com:8080`},
		{`foo.com:8080/path`, `foo.com:8080/path`},
		{`test.foo.com`, `test.foo.com`},
		{`test.foo.com/path`, `test.foo.com/path`},
		{`test.foo.com/path/more/`, `test.foo.com/path/more/`},
		{`TEST.FOO.COM/PATH`, `TEST.FOO.COM/PATH`},
		{`TEST.FÓO.COM/PÁTH`, `TEST.FÓO.COM/PÁTH`},
		{`foo.com/a.,:;-+_()?@&=$~!*%'"a`, `foo.com/a.,:;-+_()?@&=$~!*%'"a`},
		{`foo.com/path_(more)`, `foo.com/path_(more)`},
		{`foo.com/path_(even)_(more)`, `foo.com/path_(even)_(more)`},
		{`foo.com/path_(more)/more`, `foo.com/path_(more)/more`},
		{`foo.com/path_(more)/end)`, `foo.com/path_(more)/end)`},
		{`www.foo.com`, `www.foo.com`},
		{` foo.com/bar `, `foo.com/bar`},
		{` foo.com/bar more`, `foo.com/bar`},
		{`<foo.com/bar>`, `foo.com/bar`},
		{`<foo.com/bar>more`, `foo.com/bar`},
		{`,foo.com/bar.`, `foo.com/bar`},
		{`,foo.com/bar.more`, `foo.com/bar.more`},
		{`,foo.com/bar,`, `foo.com/bar`},
		{`,foo.com/bar,more`, `foo.com/bar,more`},
		{`(foo.com/bar)`, `foo.com/bar`},
		{`(foo.com/bar)more`, `foo.com/bar)more`},
		{`"foo.com/bar'`, `foo.com/bar`},
		{`"foo.com/bar'more`, `foo.com/bar'more`},
		{`"foo.com/bar"`, `foo.com/bar`},
		{`"foo.com/bar"more`, `foo.com/bar"more`},
		{`what is foo.com?`, `foo.com`},
		{`the foo.com!`, `foo.com`},

		{`foo@bar`, nil},
		{`foo@bar.a`, nil},
		{`foo@bar.com`, `foo@bar.com`},
		{`foo@bar.com bar@bar.com`, `foo@bar.com`},
		{`foo@bar.onion`, `foo@bar.onion`},
		{`foo@中国.中国`, `foo@中国.中国`},
		{`foo@test.bar.com`, `foo@test.bar.com`},
		{`FOO@TEST.BAR.COM`, `FOO@TEST.BAR.COM`},
		{`foo@bar.com/path`, `foo@bar.com`},
		{`foo+test@bar.com`, `foo+test@bar.com`},
		{`foo+._%-@bar.com`, `foo+._%-@bar.com`},
	})
	doTest(t, "AllStrict", AllStrict, []regexTestCase{
		{`foo.a`, nil},
		{`foo.com`, nil},
		{`foo.com/`, nil},
		{`1.1.1.1`, nil},
		{`3ffe:2a00:100:7031::1`, nil},
		{`test.foo.com:8080/path`, nil},
		{`foo@bar.com`, nil},
	})
}
<|endoftext|>