<commit_before>package testing

import (
	"database/sql"
	"fmt"
	"log"
	"net/url"
	"os"
	"os/exec"
	"syscall"
	"testing"
	"time"

	"github.com/cockroachdb/cockroach-go/v2/testserver"
	"github.com/cockroachdb/examples-orms/version"
	// Import postgres driver.
	_ "github.com/lib/pq"
)

// application represents a single instance of an application running an ORM and
// exposing an HTTP REST API.
type application struct {
	language string
	orm      string
}

func (app application) name() string {
	return fmt.Sprintf("%s/%s", app.language, app.orm)
}

func (app application) dir() string {
	return fmt.Sprintf("../%s", app.name())
}

func (app application) dbName() string {
	return fmt.Sprintf("company_%s", app.orm)
}

// customURLSchemes contains custom schemes for database URLs that are needed
// for test apps that rely on a custom ORM dialect.
var customURLSchemes = map[application]string{
	{language: "python", orm: "sqlalchemy"}: "cockroachdb",
}

type tenantServer interface {
	NewTenantServer(proxy bool) (testserver.TestServer, error)
}

// newServer creates a new cockroachDB server.
func newServer(t *testing.T, insecure bool) testserver.TestServer {
	t.Helper()
	var ts testserver.TestServer
	var err error
	if insecure {
		ts, err = testserver.NewTestServer()
	} else {
		ts, err = testserver.NewTestServer(testserver.SecureOpt())
	}
	if err != nil {
		t.Fatal(err)
	}
	return ts
}

// newTenant creates a new SQL Tenant pointed at the given TestServer. See
// TestServer.NewTenantServer for more information.
func newTenant(t *testing.T, ts testserver.TestServer) testserver.TestServer {
	t.Helper()
	tenant, err := ts.(tenantServer).NewTenantServer(false /* proxy */)
	if err != nil {
		t.Fatal(err)
	}
	return tenant
}

// startServerWithApplication launches a test database as a subprocess.
func startServerWithApplication(
	t *testing.T, ts testserver.TestServer, app application,
) (*sql.DB, *url.URL, func()) {
	t.Helper()
	serverURL := ts.PGURL()
	if serverURL == nil {
		t.Fatal("url not found")
	}
	pgURL := *serverURL
	pgURL.Path = app.dbName()
	db, err := sql.Open("postgres", pgURL.String())
	if err != nil {
		t.Fatal(err)
	}
	if err := ts.WaitForInit(); err != nil {
		t.Fatal(err)
	}
	// Create the database if it does not exist.
	if _, err := db.Exec("CREATE DATABASE IF NOT EXISTS " + app.dbName()); err != nil {
		t.Fatal(err)
	}
	if scheme, ok := customURLSchemes[app]; ok {
		pgURL.Scheme = scheme
	}
	return db, &pgURL, func() {
		_ = db.Close()
		ts.Stop()
	}
}

func getVersionFromDB(t *testing.T, db *sql.DB) *version.Version {
	t.Helper()
	var crdbVersion string
	if err := db.QueryRow(
		`SELECT value FROM crdb_internal.node_build_info where field = 'Version'`,
	).Scan(&crdbVersion); err != nil {
		t.Fatal(err)
	}
	v, err := version.Parse(crdbVersion)
	if err != nil {
		t.Fatal(err)
	}
	return v
}

// initORMApp launches an ORM application as a subprocess and returns a
// function that terminates that process.
func initORMApp(app application, dbURL *url.URL) (func() error, error) {
	cmd := exec.Command("make", "start", "-C", app.dir(), "ADDR="+dbURL.String())
	cmd.Stdout = os.Stderr
	cmd.Stderr = os.Stderr

	// make will launch the application in a child process, and this is the most
	// straightforward way to kill all ancestors.
	cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}

	killCmd := func() error {
		if err := syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL); err != nil {
			return err
		}
		// This error is expected.
		if err := cmd.Wait(); err.Error() != "signal: "+syscall.SIGKILL.String() {
			return err
		}

		// Killing a process is not instant. For example, with the Hibernate server,
		// it often takes ~10 seconds for the listen port to become available after
		// this function is called. This is despite the above code that issues a
		// SIGKILL to the process group for the test server.
		for {
			if !(apiHandler{}).canDial() {
				break
			}
			log.Printf("waiting for app server port to become available")
			time.Sleep(time.Second)
		}

		return nil
	}

	if err := cmd.Start(); err != nil {
		return nil, fmt.Errorf("command %s failed to start: args=%s", cmd.Args, err)
	}

	const maxWait = 3 * time.Minute
	const waitDelay = 250 * time.Millisecond

	for waited := time.Duration(0); ; waited += waitDelay {
		if processState := cmd.ProcessState; processState != nil && processState.Exited() {
			return nil, fmt.Errorf("command %s exited: %v", cmd.Args, cmd.Wait())
		}
		if err := (apiHandler{}).ping(app.name()); err != nil {
			if waited > maxWait {
				if err := killCmd(); err != nil {
					log.Printf("failed to kill command %s with PID %d: %s", cmd.Args, cmd.ProcessState.Pid(), err)
				}
				return nil, err
			}
			time.Sleep(waitDelay)
			continue
		}
		return killCmd, nil
	}
}

var minRequiredVersionsByORMName = map[string]struct {
	v       *version.Version
	skipMsg string
}{
	"django": {
		v:       version.MustParse("v19.1.0-alpha"),
		skipMsg: "TestDjango fails on CRDB <=v2.1 due to missing foreign key support.",
	},
	"activerecord": {
		v:       version.MustParse("v19.2.0-alpha"),
		skipMsg: "TestActiveRecord fails on CRDB <=v19.1 due to missing pg_catalog support.",
	},
}

type testInfo struct {
	language, orm string
	tableNames    testTableNames  // defaults to defaultTestTableNames
	columnNames   testColumnNames // defaults to defaultTestColumnNames
	// insecure is set if ORM does not handle secure servers (client certs).
	// In that case, we start an insecure server (and don't test in tenant
	// mode).
	insecure bool
}

func testORM(t *testing.T, info testInfo) {
	if info.tableNames == (testTableNames{}) {
		info.tableNames = defaultTestTableNames
	}
	if info.columnNames.IsEmpty() {
		info.columnNames = defaultTestColumnNames
	}
	app := application{
		language: info.language,
		orm:      info.orm,
	}

	type testCase struct {
		name  string
		db    *sql.DB
		dbURL *url.URL
	}
	var testCases []testCase
	{
		ts := newServer(t, info.insecure)
		db, dbURL, stopDB := startServerWithApplication(t, ts, app)
		defer stopDB()

		crdbVersion := getVersionFromDB(t, db)
		// Check that this ORM can be run with the given cockroach version.
		if info, ok := minRequiredVersionsByORMName[info.orm]; ok {
			if !crdbVersion.AtLeast(info.v) {
				t.Skip(info.skipMsg)
			}
		}

		testCases = []testCase{
			{
				name:  "SystemTenant",
				db:    db,
				dbURL: dbURL,
			},
		}

		// This cockroach version supports creating tenants, add a test case to
		// run a tenant server. We need at least 20.1-18 for everything to work out
		// as the certificate story was reworked immediately before that version
		// was minted.
		var tenantsSupported bool
		if err := db.QueryRow(`
SELECT
    (major = 20 AND minor = 1 AND (unstable IS NOT NULL AND unstable > 17))
	OR (major = 20 AND minor > 1)
	OR (major > 20)
FROM
	[
		SELECT
			regexp_extract(v, e'^(\\d+)\\.')::INT8 AS major,
			regexp_extract(v, e'^\\d+\\.(\\d+)')::INT8
				AS minor,
			regexp_extract(v, e'^\\d+\\.\\d+-(\\d+)')::INT8
				AS unstable
		FROM
			[SHOW CLUSTER SETTING version] AS t (v)
	];
`,
		).Scan(&tenantsSupported); err != nil {
			t.Fatalf("unable to read cluster version: %s", err)
		}
		if tenantsSupported {
			tenant := newTenant(t, ts)
			db, dbURL, stopDB := startServerWithApplication(t, tenant, app)
			defer stopDB()
			testCases = append(testCases, testCase{
				name:  "RegularTenant",
				db:    db,
				dbURL: dbURL,
			})
		} else {
			t.Logf("not running tenant test case because minimum tenant version check was not satisfied")
		}
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			td := testDriver{
				db:          tc.db,
				dbName:      app.dbName(),
				tableNames:  info.tableNames,
				columnNames: info.columnNames,
			}

			t.Run("FirstRun", func(t *testing.T) {
				stopApp, err := initORMApp(app, tc.dbURL)
				if err != nil {
					t.Fatal(err)
				}
				defer func() {
					if err := stopApp(); err != nil {
						t.Fatal(err)
					}
				}()

				// Test that the correct tables were generated.
				t.Run("GeneratedTables", td.TestGeneratedTables)

				// Test that the correct columns in those tables were generated.
				t.Run("GeneratedColumns", parallelTestGroup{
					"CustomersTable":     td.TestGeneratedCustomersTableColumns,
					"ProductsTable":      td.TestGeneratedProductsTableColumns,
					"OrdersTable":        td.TestGeneratedOrdersTableColumns,
					"OrderProductsTable": td.TestGeneratedOrderProductsTableColumns,
				}.T)

				// Test that the tables begin empty.
				t.Run("EmptyTables", parallelTestGroup{
					"CustomersTable":     td.TestCustomersEmpty,
					"ProductsTable":      td.TestProductsTableEmpty,
					"OrdersTable":        td.TestOrdersTableEmpty,
					"OrderProductsTable": td.TestOrderProductsTableEmpty,
				}.T)

				// Test that the API returns empty sets for each collection.
				t.Run("RetrieveFromAPIBeforeCreation", parallelTestGroup{
					"Customers": td.TestRetrieveCustomersBeforeCreation,
					"Products":  td.TestRetrieveProductsBeforeCreation,
					"Orders":    td.TestRetrieveOrdersBeforeCreation,
				}.T)

				// Test the creation of initial objects.
				t.Run("CreateCustomer", td.TestCreateCustomer)
				t.Run("CreateProduct", td.TestCreateProduct)

				// Test that the API returns what we just created.
				t.Run("RetrieveFromAPIAfterInitialCreation", parallelTestGroup{
					"Customers": td.TestRetrieveCustomerAfterCreation,
					"Products":  td.TestRetrieveProductAfterCreation,
				}.T)

				// Test the creation of dependent objects.
				t.Run("CreateOrder", td.TestCreateOrder)

				// Test that the API returns what we just created.
				t.Run("RetrieveFromAPIAfterDependentCreation", parallelTestGroup{
					"Order": td.TestRetrieveProductAfterCreation,
				}.T)
			})

			t.Run("SecondRun", func(t *testing.T) {
				stopApp, err := initORMApp(app, tc.dbURL)
				if err != nil {
					t.Fatal(err)
				}
				defer func() {
					if err := stopApp(); err != nil {
						t.Fatal(err)
					}
				}()

				// Test that the API still returns all created objects.
				t.Run("RetrieveFromAPIAfterRestart", parallelTestGroup{
					"Customers": td.TestRetrieveCustomerAfterCreation,
					"Products":  td.TestRetrieveProductAfterCreation,
					"Order":     td.TestRetrieveProductAfterCreation,
				}.T)
			})
		})
	}
}

func TestGORM(t *testing.T) {
	testORM(t, testInfo{language: "go", orm: "gorm"})
}

func TestGOPG(t *testing.T) {
	testORM(t, testInfo{
		language: "go",
		orm:      "gopg",
		// GoPG does not support client certs:
		// https://github.com/go-pg/pg/blob/v10/options.go
		// If we set up a secure deployment and went through the proxy, it would work (or should anyway), but only
		// via the 'database' parameter; GoPG also does not support the 'options' parameter.
		insecure: true,
	})
}

func TestHibernate(t *testing.T) {
	testORM(t, testInfo{
		language: "java",
		orm:      "hibernate",
		// Possibly does not unescape the path correctly:
		// Caused by: java.io.FileNotFoundException:
		//	%2Ftmp%2Fcockroach-testserver913095208%2Fcerts%2Fca.crt (No such file or directory)
		insecure: true,
	})
}

func TestSequelize(t *testing.T) {
	testORM(t, testInfo{
		language: "node",
		orm:      "sequelize",
		// Requires bespoke code to actually use SSL, see:
		// https://github.com/sequelize/sequelize/issues/10015
		insecure: true,
	})
}

func TestSQLAlchemy(t *testing.T) {
	testORM(t, testInfo{
		language: "python",
		orm:      "sqlalchemy",
	})
}

func TestDjango(t *testing.T) {
	testORM(t, testInfo{
		language:    "python",
		orm:         "django",
		tableNames:  djangoTestTableNames,
		columnNames: djangoTestColumnNames,
		// No support for client certs (at least not via the query string).
		// psycopg2.OperationalError: fe_sendauth: no password supplied
		insecure: true,
	})
}

func TestActiveRecord(t *testing.T) {
	testORM(t, testInfo{language: "ruby", orm: "activerecord"})
}

func TestActiveRecord4(t *testing.T) {
	testORM(t, testInfo{language: "ruby", orm: "ar4"})
}
<commit_msg>Skip Django tests for v20.1<commit_after>package testing

import (
	"database/sql"
	"fmt"
	"log"
	"net/url"
	"os"
	"os/exec"
	"syscall"
	"testing"
	"time"

	"github.com/cockroachdb/cockroach-go/v2/testserver"
	"github.com/cockroachdb/examples-orms/version"
	// Import postgres driver.
	_ "github.com/lib/pq"
)

// application represents a single instance of an application running an ORM and
// exposing an HTTP REST API.
type application struct {
	language string
	orm      string
}

func (app application) name() string {
	return fmt.Sprintf("%s/%s", app.language, app.orm)
}

func (app application) dir() string {
	return fmt.Sprintf("../%s", app.name())
}

func (app application) dbName() string {
	return fmt.Sprintf("company_%s", app.orm)
}

// customURLSchemes contains custom schemes for database URLs that are needed
// for test apps that rely on a custom ORM dialect.
var customURLSchemes = map[application]string{
	{language: "python", orm: "sqlalchemy"}: "cockroachdb",
}

type tenantServer interface {
	NewTenantServer(proxy bool) (testserver.TestServer, error)
}

// newServer creates a new cockroachDB server.
func newServer(t *testing.T, insecure bool) testserver.TestServer {
	t.Helper()
	var ts testserver.TestServer
	var err error
	if insecure {
		ts, err = testserver.NewTestServer()
	} else {
		ts, err = testserver.NewTestServer(testserver.SecureOpt())
	}
	if err != nil {
		t.Fatal(err)
	}
	return ts
}

// newTenant creates a new SQL Tenant pointed at the given TestServer. See
// TestServer.NewTenantServer for more information.
func newTenant(t *testing.T, ts testserver.TestServer) testserver.TestServer {
	t.Helper()
	tenant, err := ts.(tenantServer).NewTenantServer(false /* proxy */)
	if err != nil {
		t.Fatal(err)
	}
	return tenant
}

// startServerWithApplication launches a test database as a subprocess.
func startServerWithApplication(
	t *testing.T, ts testserver.TestServer, app application,
) (*sql.DB, *url.URL, func()) {
	t.Helper()
	serverURL := ts.PGURL()
	if serverURL == nil {
		t.Fatal("url not found")
	}
	pgURL := *serverURL
	pgURL.Path = app.dbName()
	db, err := sql.Open("postgres", pgURL.String())
	if err != nil {
		t.Fatal(err)
	}
	if err := ts.WaitForInit(); err != nil {
		t.Fatal(err)
	}
	// Create the database if it does not exist.
	if _, err := db.Exec("CREATE DATABASE IF NOT EXISTS " + app.dbName()); err != nil {
		t.Fatal(err)
	}
	if scheme, ok := customURLSchemes[app]; ok {
		pgURL.Scheme = scheme
	}
	return db, &pgURL, func() {
		_ = db.Close()
		ts.Stop()
	}
}

func getVersionFromDB(t *testing.T, db *sql.DB) *version.Version {
	t.Helper()
	var crdbVersion string
	if err := db.QueryRow(
		`SELECT value FROM crdb_internal.node_build_info where field = 'Version'`,
	).Scan(&crdbVersion); err != nil {
		t.Fatal(err)
	}
	v, err := version.Parse(crdbVersion)
	if err != nil {
		t.Fatal(err)
	}
	return v
}

// initORMApp launches an ORM application as a subprocess and returns a
// function that terminates that process.
func initORMApp(app application, dbURL *url.URL) (func() error, error) {
	cmd := exec.Command("make", "start", "-C", app.dir(), "ADDR="+dbURL.String())
	cmd.Stdout = os.Stderr
	cmd.Stderr = os.Stderr

	// make will launch the application in a child process, and this is the most
	// straightforward way to kill all ancestors.
	cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}

	killCmd := func() error {
		if err := syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL); err != nil {
			return err
		}
		// This error is expected.
		if err := cmd.Wait(); err.Error() != "signal: "+syscall.SIGKILL.String() {
			return err
		}

		// Killing a process is not instant. For example, with the Hibernate server,
		// it often takes ~10 seconds for the listen port to become available after
		// this function is called. This is despite the above code that issues a
		// SIGKILL to the process group for the test server.
		for {
			if !(apiHandler{}).canDial() {
				break
			}
			log.Printf("waiting for app server port to become available")
			time.Sleep(time.Second)
		}

		return nil
	}

	if err := cmd.Start(); err != nil {
		return nil, fmt.Errorf("command %s failed to start: args=%s", cmd.Args, err)
	}

	const maxWait = 3 * time.Minute
	const waitDelay = 250 * time.Millisecond

	for waited := time.Duration(0); ; waited += waitDelay {
		if processState := cmd.ProcessState; processState != nil && processState.Exited() {
			return nil, fmt.Errorf("command %s exited: %v", cmd.Args, cmd.Wait())
		}
		if err := (apiHandler{}).ping(app.name()); err != nil {
			if waited > maxWait {
				if err := killCmd(); err != nil {
					log.Printf("failed to kill command %s with PID %d: %s", cmd.Args, cmd.ProcessState.Pid(), err)
				}
				return nil, err
			}
			time.Sleep(waitDelay)
			continue
		}
		return killCmd, nil
	}
}

var minRequiredVersionsByORMName = map[string]struct {
	v       *version.Version
	skipMsg string
}{
	"django": {
		v:       version.MustParse("v20.2.0-alpha"),
		skipMsg: "TestDjango fails on CRDB <=v20.1 due to changes in SHOW TABLES.",
	},
	"activerecord": {
		v:       version.MustParse("v19.2.0-alpha"),
		skipMsg: "TestActiveRecord fails on CRDB <=v19.1 due to missing pg_catalog support.",
	},
}

type testInfo struct {
	language, orm string
	tableNames    testTableNames  // defaults to defaultTestTableNames
	columnNames   testColumnNames // defaults to defaultTestColumnNames
	// insecure is set if ORM does not handle secure servers (client certs).
	// In that case, we start an insecure server (and don't test in tenant
	// mode).
	insecure bool
}

func testORM(t *testing.T, info testInfo) {
	if info.tableNames == (testTableNames{}) {
		info.tableNames = defaultTestTableNames
	}
	if info.columnNames.IsEmpty() {
		info.columnNames = defaultTestColumnNames
	}
	app := application{
		language: info.language,
		orm:      info.orm,
	}

	type testCase struct {
		name  string
		db    *sql.DB
		dbURL *url.URL
	}
	var testCases []testCase
	{
		ts := newServer(t, info.insecure)
		db, dbURL, stopDB := startServerWithApplication(t, ts, app)
		defer stopDB()

		crdbVersion := getVersionFromDB(t, db)
		// Check that this ORM can be run with the given cockroach version.
		if info, ok := minRequiredVersionsByORMName[info.orm]; ok {
			if !crdbVersion.AtLeast(info.v) {
				t.Skip(info.skipMsg)
			}
		}

		testCases = []testCase{
			{
				name:  "SystemTenant",
				db:    db,
				dbURL: dbURL,
			},
		}

		// This cockroach version supports creating tenants, add a test case to
		// run a tenant server. We need at least 20.1-18 for everything to work out
		// as the certificate story was reworked immediately before that version
		// was minted.
		var tenantsSupported bool
		if err := db.QueryRow(`
SELECT
    (major = 20 AND minor = 1 AND (unstable IS NOT NULL AND unstable > 17))
	OR (major = 20 AND minor > 1)
	OR (major > 20)
FROM
	[
		SELECT
			regexp_extract(v, e'^(\\d+)\\.')::INT8 AS major,
			regexp_extract(v, e'^\\d+\\.(\\d+)')::INT8
				AS minor,
			regexp_extract(v, e'^\\d+\\.\\d+-(\\d+)')::INT8
				AS unstable
		FROM
			[SHOW CLUSTER SETTING version] AS t (v)
	];
`,
		).Scan(&tenantsSupported); err != nil {
			t.Fatalf("unable to read cluster version: %s", err)
		}
		if tenantsSupported {
			tenant := newTenant(t, ts)
			db, dbURL, stopDB := startServerWithApplication(t, tenant, app)
			defer stopDB()
			testCases = append(testCases, testCase{
				name:  "RegularTenant",
				db:    db,
				dbURL: dbURL,
			})
		} else {
			t.Logf("not running tenant test case because minimum tenant version check was not satisfied")
		}
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			td := testDriver{
				db:          tc.db,
				dbName:      app.dbName(),
				tableNames:  info.tableNames,
				columnNames: info.columnNames,
			}

			t.Run("FirstRun", func(t *testing.T) {
				stopApp, err := initORMApp(app, tc.dbURL)
				if err != nil {
					t.Fatal(err)
				}
				defer func() {
					if err := stopApp(); err != nil {
						t.Fatal(err)
					}
				}()

				// Test that the correct tables were generated.
				t.Run("GeneratedTables", td.TestGeneratedTables)

				// Test that the correct columns in those tables were generated.
				t.Run("GeneratedColumns", parallelTestGroup{
					"CustomersTable":     td.TestGeneratedCustomersTableColumns,
					"ProductsTable":      td.TestGeneratedProductsTableColumns,
					"OrdersTable":        td.TestGeneratedOrdersTableColumns,
					"OrderProductsTable": td.TestGeneratedOrderProductsTableColumns,
				}.T)

				// Test that the tables begin empty.
				t.Run("EmptyTables", parallelTestGroup{
					"CustomersTable":     td.TestCustomersEmpty,
					"ProductsTable":      td.TestProductsTableEmpty,
					"OrdersTable":        td.TestOrdersTableEmpty,
					"OrderProductsTable": td.TestOrderProductsTableEmpty,
				}.T)

				// Test that the API returns empty sets for each collection.
				t.Run("RetrieveFromAPIBeforeCreation", parallelTestGroup{
					"Customers": td.TestRetrieveCustomersBeforeCreation,
					"Products":  td.TestRetrieveProductsBeforeCreation,
					"Orders":    td.TestRetrieveOrdersBeforeCreation,
				}.T)

				// Test the creation of initial objects.
				t.Run("CreateCustomer", td.TestCreateCustomer)
				t.Run("CreateProduct", td.TestCreateProduct)

				// Test that the API returns what we just created.
				t.Run("RetrieveFromAPIAfterInitialCreation", parallelTestGroup{
					"Customers": td.TestRetrieveCustomerAfterCreation,
					"Products":  td.TestRetrieveProductAfterCreation,
				}.T)

				// Test the creation of dependent objects.
				t.Run("CreateOrder", td.TestCreateOrder)

				// Test that the API returns what we just created.
				t.Run("RetrieveFromAPIAfterDependentCreation", parallelTestGroup{
					"Order": td.TestRetrieveProductAfterCreation,
				}.T)
			})

			t.Run("SecondRun", func(t *testing.T) {
				stopApp, err := initORMApp(app, tc.dbURL)
				if err != nil {
					t.Fatal(err)
				}
				defer func() {
					if err := stopApp(); err != nil {
						t.Fatal(err)
					}
				}()

				// Test that the API still returns all created objects.
				t.Run("RetrieveFromAPIAfterRestart", parallelTestGroup{
					"Customers": td.TestRetrieveCustomerAfterCreation,
					"Products":  td.TestRetrieveProductAfterCreation,
					"Order":     td.TestRetrieveProductAfterCreation,
				}.T)
			})
		})
	}
}

func TestGORM(t *testing.T) {
	testORM(t, testInfo{language: "go", orm: "gorm"})
}

func TestGOPG(t *testing.T) {
	testORM(t, testInfo{
		language: "go",
		orm:      "gopg",
		// GoPG does not support client certs:
		// https://github.com/go-pg/pg/blob/v10/options.go
		// If we set up a secure deployment and went through the proxy, it would work (or should anyway), but only
		// via the 'database' parameter; GoPG also does not support the 'options' parameter.
		insecure: true,
	})
}

func TestHibernate(t *testing.T) {
	testORM(t, testInfo{
		language: "java",
		orm:      "hibernate",
		// Possibly does not unescape the path correctly:
		// Caused by: java.io.FileNotFoundException:
		//	%2Ftmp%2Fcockroach-testserver913095208%2Fcerts%2Fca.crt (No such file or directory)
		insecure: true,
	})
}

func TestSequelize(t *testing.T) {
	testORM(t, testInfo{
		language: "node",
		orm:      "sequelize",
		// Requires bespoke code to actually use SSL, see:
		// https://github.com/sequelize/sequelize/issues/10015
		insecure: true,
	})
}

func TestSQLAlchemy(t *testing.T) {
	testORM(t, testInfo{
		language: "python",
		orm:      "sqlalchemy",
	})
}

func TestDjango(t *testing.T) {
	testORM(t, testInfo{
		language:    "python",
		orm:         "django",
		tableNames:  djangoTestTableNames,
		columnNames: djangoTestColumnNames,
		// No support for client certs (at least not via the query string).
		// psycopg2.OperationalError: fe_sendauth: no password supplied
		insecure: true,
	})
}

func TestActiveRecord(t *testing.T) {
	testORM(t, testInfo{language: "ruby", orm: "activerecord"})
}

func TestActiveRecord4(t *testing.T) {
	testORM(t, testInfo{language: "ruby", orm: "ar4"})
}
<|endoftext|>


<commit_before>/* vim: set sw=4 sts=4 et foldmethod=syntax : */

/*
 * Copyright (c) 2011 Alexander Færøy <ahf@0x90.dk>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package main

import (
    "bufio"
    "flag"
    "fmt"
    "os"
    "strings"
    "websocket"
)

var host = flag.String("host", "", "Host to connect to")
var origin = flag.String("origin", "", "Origin to sent")

func Strip(s string) string {
    return strings.Trim(s, " \r\n")
}

func main() {
    flag.Parse()

    if len(*host) == 0 {
        fmt.Print("Error: Needs -host parameter.\n")
        os.Exit(1)
    }

    ws, err := websocket.Dial(*host, "", *origin)

    if err != nil {
        fmt.Printf("Error: %s\n", err.String())
        os.Exit(1)
    }

    rw := bufio.NewReadWriter(bufio.NewReader(ws), bufio.NewWriter(ws))
    stdin := bufio.NewReader(os.Stdin);

    go func() {
        for {
            s, _ := rw.ReadString('\n')
            s = Strip(s)

            if len(s) == 0 {
                continue
            }

            fmt.Printf("%s\n", s)
        }
    }()

    for {
        input, _ := stdin.ReadString('\n');
        rw.WriteString(input)
        rw.Flush()
    }
}
<commit_msg>Better error handling in wsnc.<commit_after>/* vim: set sw=4 sts=4 et foldmethod=syntax : */

/*
 * Copyright (c) 2011 Alexander Færøy <ahf@0x90.dk>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package main

import (
    "bufio"
    "flag"
    "fmt"
    "os"
    "strings"
    "websocket"
)

var host = flag.String("host", "", "Host to connect to")
var origin = flag.String("origin", "", "Origin to sent")

func Strip(s string) string {
    return strings.Trim(s, " \r\n")
}

func main() {
    flag.Parse()

    if len(*host) == 0 {
        fmt.Print("Error: Needs -host parameter.\n")
        os.Exit(1)
    }

    ws, err := websocket.Dial(*host, "", *origin)

    if err != nil {
        fmt.Printf("Error: %s\n", err.String())
        os.Exit(1)
    }

    rw := bufio.NewReadWriter(bufio.NewReader(ws), bufio.NewWriter(ws))
    stdin := bufio.NewReader(os.Stdin);

    go func() {
        for {
            s, error := rw.ReadString('\n')
            s = Strip(s)

            if error != nil {
                fmt.Printf("Error: %s\n", error.String())
                os.Exit(1)
            }

            if len(s) == 0 {
                continue
            }

            fmt.Printf("%s\n", s)
        }
    }()

    for {
        input, _ := stdin.ReadString('\n');
        rw.WriteString(input)
        rw.Flush()
    }
}
<|endoftext|>


<commit_before>package instance

import (
	"net/http"

	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/metrics"
	"github.com/pkg/errors"

	"github.com/weaveworks/flux"
	"github.com/weaveworks/flux/git"
	"github.com/weaveworks/flux/history"
	"github.com/weaveworks/flux/platform"
	"github.com/weaveworks/flux/registry"
)

type MultitenantInstancer struct {
	DB              DB
	Connecter       platform.Connecter
	Logger          log.Logger
	Histogram       metrics.Histogram
	History         history.DB
	RegistryMetrics registry.Metrics
}

func (m *MultitenantInstancer) Get(instanceID flux.InstanceID) (*Instance, error) {
	c, err := m.DB.GetConfig(instanceID)
	if err != nil {
		return nil, errors.Wrap(err, "getting instance config from DB")
	}

	// Platform interface for this instance
	platform, err := m.Connecter.Connect(instanceID)
	if err != nil {
		return nil, errors.Wrap(err, "connecting to platform")
	}

	// Logger specialised to this instance
	instanceLogger := log.NewContext(m.Logger).With("instanceID", instanceID)

	// Registry client with instance's config
	creds, err := registry.CredentialsFromConfig(c.Settings)
	if err != nil {
		return nil, errors.Wrap(err, "decoding registry credentials")
	}
	regClient := &registry.Client{
		Credentials: creds,
		Logger:      log.NewContext(instanceLogger).With("component", "registry"),
		Metrics:     m.RegistryMetrics.WithInstanceID(instanceID),
	}

	repo := gitRepoFromSettings(c.Settings)

	// Events for this instance
	eventRW := EventReadWriter{instanceID, m.History}
	var eventW history.EventWriter = eventRW
	if c.Settings.Slack.HookURL != "" {
		eventW = history.TeeWriter(eventRW, history.NewSlackEventWriter(
			http.DefaultClient,
			c.Settings.Slack.HookURL,
			c.Settings.Slack.Username,
			`(done|failed)$`, // only catch the final message
		))
	}

	// Configuration for this instance
	config := configurer{instanceID, m.DB}

	return New(
		platform,
		regClient,
		config,
		repo,
		instanceLogger,
		m.Histogram,
		eventRW,
		eventW,
	), nil
}

func gitRepoFromSettings(settings flux.UnsafeInstanceConfig) git.Repo {
	branch := settings.Git.Branch
	if branch == "" {
		branch = "master"
	}
	return git.Repo{
		URL:    settings.Git.URL,
		Branch: branch,
		Key:    settings.Git.Key,
		Path:   settings.Git.Path,
	}
}
<commit_msg>Send async releases to slack<commit_after>package instance

import (
	"net/http"

	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/metrics"
	"github.com/pkg/errors"

	"github.com/weaveworks/flux"
	"github.com/weaveworks/flux/git"
	"github.com/weaveworks/flux/history"
	"github.com/weaveworks/flux/platform"
	"github.com/weaveworks/flux/registry"
)

type MultitenantInstancer struct {
	DB              DB
	Connecter       platform.Connecter
	Logger          log.Logger
	Histogram       metrics.Histogram
	History         history.DB
	RegistryMetrics registry.Metrics
}

func (m *MultitenantInstancer) Get(instanceID flux.InstanceID) (*Instance, error) {
	c, err := m.DB.GetConfig(instanceID)
	if err != nil {
		return nil, errors.Wrap(err, "getting instance config from DB")
	}

	// Platform interface for this instance
	platform, err := m.Connecter.Connect(instanceID)
	if err != nil {
		return nil, errors.Wrap(err, "connecting to platform")
	}

	// Logger specialised to this instance
	instanceLogger := log.NewContext(m.Logger).With("instanceID", instanceID)

	// Registry client with instance's config
	creds, err := registry.CredentialsFromConfig(c.Settings)
	if err != nil {
		return nil, errors.Wrap(err, "decoding registry credentials")
	}
	regClient := &registry.Client{
		Credentials: creds,
		Logger:      log.NewContext(instanceLogger).With("component", "registry"),
		Metrics:     m.RegistryMetrics.WithInstanceID(instanceID),
	}

	repo := gitRepoFromSettings(c.Settings)

	// Events for this instance
	eventRW := EventReadWriter{instanceID, m.History}
	var eventW history.EventWriter = eventRW
	if c.Settings.Slack.HookURL != "" {
		eventW = history.TeeWriter(eventRW, history.NewSlackEventWriter(
			http.DefaultClient,
			c.Settings.Slack.HookURL,
			c.Settings.Slack.Username,
			`(done|failed|\(no result expected\))$`, // only catch the final message, or started msg for async releases
		))
	}

	// Configuration for this instance
	config := configurer{instanceID, m.DB}

	return New(
		platform,
		regClient,
		config,
		repo,
		instanceLogger,
		m.Histogram,
		eventRW,
		eventW,
	), nil
}

func gitRepoFromSettings(settings flux.UnsafeInstanceConfig) git.Repo {
	branch := settings.Git.Branch
	if branch == "" {
		branch = "master"
	}
	return git.Repo{
		URL:    settings.Git.URL,
		Branch: branch,
		Key:    settings.Git.Key,
		Path:   settings.Git.Path,
	}
}
<|endoftext|>


<commit_before>package stun

import (
	"bytes"
	"encoding/hex"
	"testing"
)

func TestMessageIntegrity_AddTo_Simple(t *testing.T) {
	i := NewLongTermIntegrity("user", "realm", "pass")
	expected, err := hex.DecodeString("8493fbc53ba582fb4c044c456bdc40eb")
	if err != nil {
		t.Fatal(err)
	}
	if !bytes.Equal(expected, i) {
		t.Error(ErrIntegrityMismatch)
	}
	t.Run("Check", func(t *testing.T) {
		m := new(Message)
		m.WriteHeader()
		if err := i.AddTo(m); err != nil {
			t.Error(err)
		}
		NewSoftware("software").AddTo(m)
		m.WriteHeader()
		dM := new(Message)
		dM.Raw = m.Raw
		if err := dM.Decode(); err != nil {
			t.Error(err)
		}
		if err := i.Check(dM); err != nil {
			t.Error(err)
		}
		dM.Raw[24] += 12 // HMAC now invalid
		if i.Check(dM) == nil {
			t.Error("should be invalid")
		}
	})
}

func TestMessageIntegrityWithFingerprint(t *testing.T) {
	m := new(Message)
	m.TransactionID = [TransactionIDSize]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}
	m.WriteHeader()
	NewSoftware("software").AddTo(m)
	i := NewShortTermIntegrity("pwd")
	if i.String() != "KEY: 0x707764" {
		t.Error("bad string", i)
	}
	if err := i.Check(m); err == nil {
		t.Error("should error")
	}
	if err := i.AddTo(m); err != nil {
		t.Fatal(err)
	}
	if err := Fingerprint.AddTo(m); err != nil {
		t.Fatal(err)
	}
	if err := i.Check(m); err != nil {
		t.Fatal(err)
	}
	m.Raw[24] = 33
	if err := i.Check(m); err == nil {
		t.Fatal("mismatch expected")
	}
}

func TestMessageIntegrity(t *testing.T) {
	m := new(Message)
	i := NewShortTermIntegrity("password")
	m.WriteHeader()
	if err := i.AddTo(m); err != nil {
		t.Error(err)
	}
	_, err := m.Get(AttrMessageIntegrity)
	if err != nil {
		t.Error(err)
	}
}

func TestMessageIntegrityBeforeFingerprint(t *testing.T) {
	m := new(Message)
	m.WriteHeader()
	Fingerprint.AddTo(m)
	i := NewShortTermIntegrity("password")
	if err := i.AddTo(m); err == nil {
		t.Error("should error")
	}
}

func BenchmarkMessageIntegrity_AddTo(b *testing.B) {
	m := new(Message)
	integrity := NewShortTermIntegrity("password")
	m.WriteHeader()
	b.ReportAllocs()
	b.SetBytes(int64(len(m.Raw)))
	for i := 0; i < b.N; i++ {
		m.WriteHeader()
		if err := integrity.AddTo(m); err != nil {
			b.Error(err)
		}
		m.Reset()
	}
}
func BenchmarkMessageIntegrity_Check(b *testing.B) {
	m := new(Message)
	NewSoftware("software").AddTo(m)
	integrity := NewShortTermIntegrity("password")
	b.ReportAllocs()
	m.WriteHeader()
	b.SetBytes(int64(len(m.Raw)))
	if err := integrity.AddTo(m); err != nil {
		b.Error(err)
	}
	m.WriteLength()
	for i := 0; i < b.N; i++ {
		if err := integrity.Check(m); err != nil {
			b.Fatal(err)
		}
	}
}
<commit_msg>integrity: make test zero-allocation again<commit_after>package stun

import (
	"bytes"
	"encoding/hex"
	"testing"
)

func TestMessageIntegrity_AddTo_Simple(t *testing.T) {
	i := NewLongTermIntegrity("user", "realm", "pass")
	expected, err := hex.DecodeString("8493fbc53ba582fb4c044c456bdc40eb")
	if err != nil {
		t.Fatal(err)
	}
	if !bytes.Equal(expected, i) {
		t.Error(ErrIntegrityMismatch)
	}
	t.Run("Check", func(t *testing.T) {
		m := new(Message)
		m.WriteHeader()
		if err := i.AddTo(m); err != nil {
			t.Error(err)
		}
		NewSoftware("software").AddTo(m)
		m.WriteHeader()
		dM := new(Message)
		dM.Raw = m.Raw
		if err := dM.Decode(); err != nil {
			t.Error(err)
		}
		if err := i.Check(dM); err != nil {
			t.Error(err)
		}
		dM.Raw[24] += 12 // HMAC now invalid
		if i.Check(dM) == nil {
			t.Error("should be invalid")
		}
	})
}

func TestMessageIntegrityWithFingerprint(t *testing.T) {
	m := new(Message)
	m.TransactionID = [TransactionIDSize]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}
	m.WriteHeader()
	NewSoftware("software").AddTo(m)
	i := NewShortTermIntegrity("pwd")
	if i.String() != "KEY: 0x707764" {
		t.Error("bad string", i)
	}
	if err := i.Check(m); err == nil {
		t.Error("should error")
	}
	if err := i.AddTo(m); err != nil {
		t.Fatal(err)
	}
	if err := Fingerprint.AddTo(m); err != nil {
		t.Fatal(err)
	}
	if err := i.Check(m); err != nil {
		t.Fatal(err)
	}
	m.Raw[24] = 33
	if err := i.Check(m); err == nil {
		t.Fatal("mismatch expected")
	}
}

func TestMessageIntegrity(t *testing.T) {
	m := new(Message)
	i := NewShortTermIntegrity("password")
	m.WriteHeader()
	if err := i.AddTo(m); err != nil {
		t.Error(err)
	}
	_, err := m.Get(AttrMessageIntegrity)
	if err != nil {
		t.Error(err)
	}
}

func TestMessageIntegrityBeforeFingerprint(t *testing.T) {
	m := new(Message)
	m.WriteHeader()
	Fingerprint.AddTo(m)
	i := NewShortTermIntegrity("password")
	if err := i.AddTo(m); err == nil {
		t.Error("should error")
	}
}

func BenchmarkMessageIntegrity_AddTo(b *testing.B) {
	m := new(Message)
	integrity := NewShortTermIntegrity("password")
	m.WriteHeader()
	b.ReportAllocs()
	b.SetBytes(int64(len(m.Raw)))
	for i := 0; i < b.N; i++ {
		m.WriteHeader()
		if err := integrity.AddTo(m); err != nil {
			b.Error(err)
		}
		m.Reset()
	}
}
func BenchmarkMessageIntegrity_Check(b *testing.B) {
	m := new(Message)
	// TODO: Find a way to make this test zero-alloc without excessive pre-alloc.
	m.Raw = make([]byte, 0, 1024)
	NewSoftware("software").AddTo(m)
	integrity := NewShortTermIntegrity("password")
	b.ReportAllocs()
	m.WriteHeader()
	b.SetBytes(int64(len(m.Raw)))
	if err := integrity.AddTo(m); err != nil {
		b.Error(err)
	}
	m.WriteLength()
	for i := 0; i < b.N; i++ {
		if err := integrity.Check(m); err != nil {
			b.Fatal(err)
		}
	}
}
<|endoftext|>


<commit_before>package stats

import (
	"testing"
	"time"
)

func TestPrecisionChange(t *testing.T) {
	stat := DefaultStatsReceiver().(*defaultStatsReceiver)
	if stat.precision != time.Nanosecond {
		t.Fatal("Default precision should be nanos.")
	}

	statp := stat.Precision(time.Millisecond).(*defaultStatsReceiver)
	if stat.precision != time.Nanosecond {
		t.Fatal("Default precision should still nanos.")
	}
	if statp.precision != time.Millisecond {
		t.Fatal("New stat precision should be millis.")
	}
}

func TestScopeChange(t *testing.T) {
	stat := DefaultStatsReceiver().(*defaultStatsReceiver)
	if len(stat.scope) != 0 {
		t.Fatal("Default scope should be empty.")
	}

	statp := stat.Scope("a/b", "c").(*defaultStatsReceiver)
	if len(stat.scope) != 0 {
		t.Fatal("Default scope should still empty.")
	}
	if len(statp.scope) != 2 || statp.scope[0] != "a_SLASH_b" || statp.scope[1] != "c" {
		t.Fatal("Invalid scope value: ", statp.scope)
	}
	if statp.scopedName("d") != "a_SLASH_b/c/d" {
		t.Fatal("Invalid scope name: " + statp.scopedName("d"))
	}
}

func TestRegister(t *testing.T) {
	reg := NewFinagleStatsRegistry()
	if reg.GetOrRegister("counter", NewCounter()) == nil {
		t.Fatal("Registry did not save instrument")
	}
	if reg.GetOrRegister("gauge", NewGauge()) == nil {
		t.Fatal("Registry did not save instrument")
	}
	if reg.GetOrRegister("gaugeFloat", NewGaugeFloat()) == nil {
		t.Fatal("Registry did not save instrument")
	}
	if reg.GetOrRegister("histogram", NewHistogram()) == nil {
		t.Fatal("Registry did not save instrument")
	}
	if reg.GetOrRegister("latency", NewLatency()) == nil {
		t.Fatal("Registry did not save instrument")
	}
}

func TestMarshal(t *testing.T) {
	ct := make(chan time.Time)
	Time = NewTestTime(time.Unix(0, 0), time.Nanosecond*5, ct)
	defer close(ct)

	reg := NewFinagleStatsRegistry()
	reg.GetOrRegister("counter", NewCounter()).(Counter).Inc(1)
	reg.GetOrRegister("gauge", NewGauge()).(Gauge).Update(2)

	reg.GetOrRegister("latency", NewLatency()).(Latency).Time().Stop()
	Time = NewTestTime(time.Unix(0, 0), time.Nanosecond*10, ct)
	reg.GetOrRegister("latency", NewLatency()).(Latency).Time().Stop()

	bytes, err := reg.(MarshalerPretty).MarshalJSONPretty()
	expected :=
		`{
  "counter": 1,
  "gauge": 2,
  "latency.avg": 7.5,
  "latency.count": 2,
  "latency.max": 10,
  "latency.min": 5,
  "latency.p50": 7.5,
  "latency.p90": 10,
  "latency.p95": 10,
  "latency.p99": 10,
  "latency.p999": 10,
  "latency.p9999": 10,
  "latency.sum": 15
}`
	if string(bytes) != expected {
		t.Fatal("Wrong json marshal output: ", string(bytes), err)
	}
}

func TestNonLatching(t *testing.T) {
	stat := DefaultStatsReceiver().(*defaultStatsReceiver)
	stat.Counter("counter").Inc(1)

	rendered := string(stat.Render(false))
	if rendered != `{"counter":{"count":1}}` {
		t.Fatal("Expected current stats in render", rendered)
	}

	rendered = string(stat.Render(false))
	if rendered != `{"counter":{"count":0}}` {
		t.Fatal("Expected clearing of stats after render", rendered)
	}
}

func TestLatching(t *testing.T) {
	ct := make(chan time.Time)
	Time = NewTestTime(time.Unix(0, 0), 0, ct)
	statIface, cancelFn := NewLatchedStatsReceiver(time.Second)
	stat := statIface.(*defaultStatsReceiver)
	defer cancelFn()

	// Captured registry should initially be empty even though we added a counter.
	stat.Counter("counter")
	rendered := string(stat.Render(true))
	if rendered != "{}" {
		t.Fatal("Expected empty latch with time=0: ", rendered)
	}

	// Captured registry should still be empty.
	ensureChannelSend(cap(ct), func() { ct <- Time.Now().Add(1) })
	rendered = string(stat.Render(true))
	if rendered != "{}" {
		t.Fatal("Expected empty latch with time=1: ", rendered)
	}

	// Should be captured after enough time has passed.
	ensureChannelSend(cap(ct), func() { ct <- Time.Now().Add(time.Minute) })
	rendered = string(stat.Render(true))
	if rendered == "{}" {
		t.Fatal("Expected non-empty latch with time=0: ", rendered)
	}
}

// Two sends may be required to be sure the first is handled, not just goroutine-queued...
// This function may seem hacky, but it's one way to ensure ordered testing when we're
// receive select'ing on two+ channels: one channel to trigger updates, another accepting
// requests and immediately responding with a cached update.
//
// The Memory Model is light on details regarding select'ing from multiple channels,
// but the following seems possible:
// - a receiver goroutine is blocked on unbuffered ChanA and ChanB.
// - sender goroutine send to ChanA is 'received' but the receiver goroutine isn't scheduled yet.
// - sender goroutine continues executing and sends to ChanB
// - receiver goroutine gets scheduled and randomly handles ChanA or ChanB
//
// Suggestions or further rationale welcomed.
func ensureChannelSend(chanCapacity int, sendFn func()) {
	for i := 0; i < chanCapacity+2; i++ {
		sendFn()
	}
}
<commit_msg>Deleted ensureChannelSend(), I was conflating receiving a message with actually processing it. (#59)<commit_after>package stats

import (
	"testing"
	"time"
)

func TestPrecisionChange(t *testing.T) {
	stat := DefaultStatsReceiver().(*defaultStatsReceiver)
	if stat.precision != time.Nanosecond {
		t.Fatal("Default precision should be nanos.")
	}

	statp := stat.Precision(time.Millisecond).(*defaultStatsReceiver)
	if stat.precision != time.Nanosecond {
		t.Fatal("Default precision should still nanos.")
	}
	if statp.precision != time.Millisecond {
		t.Fatal("New stat precision should be millis.")
	}
}

func TestScopeChange(t *testing.T) {
	stat := DefaultStatsReceiver().(*defaultStatsReceiver)
	if len(stat.scope) != 0 {
		t.Fatal("Default scope should be empty.")
	}

	statp := stat.Scope("a/b", "c").(*defaultStatsReceiver)
	if len(stat.scope) != 0 {
		t.Fatal("Default scope should still empty.")
	}
	if len(statp.scope) != 2 || statp.scope[0] != "a_SLASH_b" || statp.scope[1] != "c" {
		t.Fatal("Invalid scope value: ", statp.scope)
	}
	if statp.scopedName("d") != "a_SLASH_b/c/d" {
		t.Fatal("Invalid scope name: " + statp.scopedName("d"))
	}
}

func TestRegister(t *testing.T) {
	reg := NewFinagleStatsRegistry()
	if reg.GetOrRegister("counter", NewCounter()) == nil {
		t.Fatal("Registry did not save instrument")
	}
	if reg.GetOrRegister("gauge", NewGauge()) == nil {
		t.Fatal("Registry did not save instrument")
	}
	if reg.GetOrRegister("gaugeFloat", NewGaugeFloat()) == nil {
		t.Fatal("Registry did not save instrument")
	}
	if reg.GetOrRegister("histogram", NewHistogram()) == nil {
		t.Fatal("Registry did not save instrument")
	}
	if reg.GetOrRegister("latency", NewLatency()) == nil {
		t.Fatal("Registry did not save instrument")
	}
}

func TestMarshal(t *testing.T) {
	ct := make(chan time.Time)
	Time = NewTestTime(time.Unix(0, 0), time.Nanosecond*5, ct)
	defer close(ct)

	reg := NewFinagleStatsRegistry()
	reg.GetOrRegister("counter", NewCounter()).(Counter).Inc(1)
	reg.GetOrRegister("gauge", NewGauge()).(Gauge).Update(2)

	reg.GetOrRegister("latency", NewLatency()).(Latency).Time().Stop()
	Time = NewTestTime(time.Unix(0, 0), time.Nanosecond*10, ct)
	reg.GetOrRegister("latency", NewLatency()).(Latency).Time().Stop()

	bytes, err := reg.(MarshalerPretty).MarshalJSONPretty()
	expected :=
		`{
  "counter": 1,
  "gauge": 2,
  "latency.avg": 7.5,
  "latency.count": 2,
  "latency.max": 10,
  "latency.min": 5,
  "latency.p50": 7.5,
  "latency.p90": 10,
  "latency.p95": 10,
  "latency.p99": 10,
  "latency.p999": 10,
  "latency.p9999": 10,
  "latency.sum": 15
}`
	if string(bytes) != expected {
		t.Fatal("Wrong json marshal output: ", string(bytes), err)
	}
}

func TestNonLatching(t *testing.T) {
	stat := DefaultStatsReceiver().(*defaultStatsReceiver)
	stat.Counter("counter").Inc(1)

	rendered := string(stat.Render(false))
	if rendered != `{"counter":{"count":1}}` {
		t.Fatal("Expected current stats in render", rendered)
	}

	rendered = string(stat.Render(false))
	if rendered != `{"counter":{"count":0}}` {
		t.Fatal("Expected clearing of stats after render", rendered)
	}
}

func TestLatching(t *testing.T) {
	ct := make(chan time.Time)
	Time = NewTestTime(time.Unix(0, 0), 0, ct)
	statIface, cancelFn := NewLatchedStatsReceiver(time.Second)
	stat := statIface.(*defaultStatsReceiver)
	defer cancelFn()

	// Captured registry should initially be empty even though we added a counter.
	stat.Counter("counter")
	rendered := string(stat.Render(true))
	if rendered != "{}" {
		t.Fatal("Expected empty latch with time=0: ", rendered)
	}

	// Captured registry should still be empty.
	ct <- Time.Now().Add(1)
	rendered = string(stat.Render(true))
	if rendered != "{}" {
		t.Fatal("Expected empty latch with time=1: ", rendered)
	}

	// Should be captured after enough time has passed.
	ct <- Time.Now().Add(time.Minute)
	rendered = string(stat.Render(true))
	if rendered == "{}" {
		t.Fatal("Expected non-empty latch with time=0: ", rendered)
	}
}
<|endoftext|>


<commit_before>package topology

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

	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/storage"
)

// mapping from volume to its locations, inverted from server to volume
type VolumeLayout struct {
	rp               *storage.ReplicaPlacement
	ttl              *storage.TTL
	vid2location     map[storage.VolumeId]*VolumeLocationList
	writables        []storage.VolumeId        // transient array of writable volume id
	readonlyVolumes  map[storage.VolumeId]bool // transient set of readonly volumes
	oversizedVolumes map[storage.VolumeId]bool // set of oversized volumes
	volumeSizeLimit  uint64
	accessLock       sync.RWMutex
}

type VolumeLayoutStats struct {
	TotalSize uint64
	UsedSize  uint64
	FileCount uint64
}

func NewVolumeLayout(rp *storage.ReplicaPlacement, ttl *storage.TTL, volumeSizeLimit uint64) *VolumeLayout {
	return &VolumeLayout{
		rp:               rp,
		ttl:              ttl,
		vid2location:     make(map[storage.VolumeId]*VolumeLocationList),
		writables:        *new([]storage.VolumeId),
		readonlyVolumes:  make(map[storage.VolumeId]bool),
		oversizedVolumes: make(map[storage.VolumeId]bool),
		volumeSizeLimit:  volumeSizeLimit,
	}
}

func (vl *VolumeLayout) String() string {
	return fmt.Sprintf("rp:%v, ttl:%v, vid2location:%v, writables:%v, volumeSizeLimit:%v", vl.rp, vl.ttl, vl.vid2location, vl.writables, vl.volumeSizeLimit)
}

func (vl *VolumeLayout) RegisterVolume(v *storage.VolumeInfo, dn *DataNode) {
	vl.accessLock.Lock()
	defer vl.accessLock.Unlock()

	if _, ok := vl.vid2location[v.Id]; !ok {
		vl.vid2location[v.Id] = NewVolumeLocationList()
	}
	vl.vid2location[v.Id].Set(dn)
	glog.V(4).Infof("volume %d added to %s len %s copy %d", v.Id, dn.Id(), vl.vid2location[v.Id].Length(), v.ReplicaPlacement.GetCopyCount())
	for _, dn := range vl.vid2location[v.Id].list {
		if v_info, err := dn.GetVolumesById(v.Id); err == nil {
			if v_info.ReadOnly {
				glog.V(3).Infof("vid %d removed from writable", v.Id)
				vl.removeFromWritable(v.Id)
				vl.readonlyVolumes[v.Id] = true
				return
			} else {
				delete(vl.readonlyVolumes, v.Id)
			}
		} else {
			glog.V(3).Infof("vid %d removed from writable", v.Id)
			vl.removeFromWritable(v.Id)
			delete(vl.readonlyVolumes, v.Id)
			return
		}
	}
	if vl.vid2location[v.Id].Length() == vl.rp.GetCopyCount() && vl.isWritable(v) {
		if _, ok := vl.oversizedVolumes[v.Id]; !ok {
			vl.addToWritable(v.Id)
		}
	} else {
		vl.rememberOversizedVolumne(v)
		vl.removeFromWritable(v.Id)
	}
}

func (vl *VolumeLayout) rememberOversizedVolumne(v *storage.VolumeInfo) {
	if vl.isOversized(v) {
		vl.oversizedVolumes[v.Id] = true
	}
}

func (vl *VolumeLayout) UnRegisterVolume(v *storage.VolumeInfo, dn *DataNode) {
	vl.accessLock.Lock()
	defer vl.accessLock.Unlock()

	vl.removeFromWritable(v.Id)
	delete(vl.vid2location, v.Id)
}

func (vl *VolumeLayout) addToWritable(vid storage.VolumeId) {
	for _, id := range vl.writables {
		if vid == id {
			return
		}
	}
	vl.writables = append(vl.writables, vid)
}

func (vl *VolumeLayout) isOversized(v *storage.VolumeInfo) bool {
	return uint64(v.Size) >= vl.volumeSizeLimit
}

func (vl *VolumeLayout) isWritable(v *storage.VolumeInfo) bool {
	return !vl.isOversized(v) &&
		v.Version == storage.CurrentVersion &&
		!v.ReadOnly
}

func (vl *VolumeLayout) isEmpty() bool {
	vl.accessLock.RLock()
	defer vl.accessLock.RUnlock()

	return len(vl.vid2location) == 0
}

func (vl *VolumeLayout) Lookup(vid storage.VolumeId) []*DataNode {
	vl.accessLock.RLock()
	defer vl.accessLock.RUnlock()

	if location := vl.vid2location[vid]; location != nil {
		return location.list
	}
	return nil
}

func (vl *VolumeLayout) ListVolumeServers() (nodes []*DataNode) {
	vl.accessLock.RLock()
	defer vl.accessLock.RUnlock()

	for _, location := range vl.vid2location {
		nodes = append(nodes, location.list...)
	}
	return
}

func (vl *VolumeLayout) PickForWrite(count uint64, option *VolumeGrowOption) (*storage.VolumeId, uint64, *VolumeLocationList, error) {
	vl.accessLock.RLock()
	defer vl.accessLock.RUnlock()

	len_writers := len(vl.writables)
	if len_writers <= 0 {
		glog.V(0).Infoln("No more writable volumes!")
		return nil, 0, nil, errors.New("No more writable volumes!")
	}
	if option.DataCenter == "" {
		vid := vl.writables[rand.Intn(len_writers)]
		locationList := vl.vid2location[vid]
		if locationList != nil {
			return &vid, count, locationList, nil
		}
		return nil, 0, nil, errors.New("Strangely vid " + vid.String() + " is on no machine!")
	}
	var vid storage.VolumeId
	var locationList *VolumeLocationList
	counter := 0
	for _, v := range vl.writables {
		volumeLocationList := vl.vid2location[v]
		for _, dn := range volumeLocationList.list {
			if dn.GetDataCenter().Id() == NodeId(option.DataCenter) {
				if option.Rack != "" && dn.GetRack().Id() != NodeId(option.Rack) {
					continue
				}
				if option.DataNode != "" && dn.Id() != NodeId(option.DataNode) {
					continue
				}
				counter++
				if rand.Intn(counter) < 1 {
					vid, locationList = v, volumeLocationList
				}
			}
		}
	}
	return &vid, count, locationList, nil
}

func (vl *VolumeLayout) GetActiveVolumeCount(option *VolumeGrowOption) int {
	vl.accessLock.RLock()
	defer vl.accessLock.RUnlock()

	if option.DataCenter == "" {
		return len(vl.writables)
	}
	counter := 0
	for _, v := range vl.writables {
		for _, dn := range vl.vid2location[v].list {
			if dn.GetDataCenter().Id() == NodeId(option.DataCenter) {
				if option.Rack != "" && dn.GetRack().Id() != NodeId(option.Rack) {
					continue
				}
				if option.DataNode != "" && dn.Id() != NodeId(option.DataNode) {
					continue
				}
				counter++
			}
		}
	}
	return counter
}

func (vl *VolumeLayout) removeFromWritable(vid storage.VolumeId) bool {
	toDeleteIndex := -1
	for k, id := range vl.writables {
		if id == vid {
			toDeleteIndex = k
			break
		}
	}
	if toDeleteIndex >= 0 {
		glog.V(0).Infoln("Volume", vid, "becomes unwritable")
		vl.writables = append(vl.writables[0:toDeleteIndex], vl.writables[toDeleteIndex+1:]...)
		return true
	}
	return false
}
func (vl *VolumeLayout) setVolumeWritable(vid storage.VolumeId) bool {
	for _, v := range vl.writables {
		if v == vid {
			return false
		}
	}
	glog.V(0).Infoln("Volume", vid, "becomes writable")
	vl.writables = append(vl.writables, vid)
	return true
}

func (vl *VolumeLayout) SetVolumeUnavailable(dn *DataNode, vid storage.VolumeId) bool {
	vl.accessLock.Lock()
	defer vl.accessLock.Unlock()

	if location, ok := vl.vid2location[vid]; ok {
		if location.Remove(dn) {
			if location.Length() < vl.rp.GetCopyCount() {
				glog.V(0).Infoln("Volume", vid, "has", location.Length(), "replica, less than required", vl.rp.GetCopyCount())
				return vl.removeFromWritable(vid)
			}
		}
	}
	return false
}
func (vl *VolumeLayout) SetVolumeAvailable(dn *DataNode, vid storage.VolumeId) bool {
	vl.accessLock.Lock()
	defer vl.accessLock.Unlock()

	vl.vid2location[vid].Set(dn)
	if vl.vid2location[vid].Length() >= vl.rp.GetCopyCount() {
		return vl.setVolumeWritable(vid)
	}
	return false
}

func (vl *VolumeLayout) SetVolumeCapacityFull(vid storage.VolumeId) bool {
	vl.accessLock.Lock()
	defer vl.accessLock.Unlock()

	// glog.V(0).Infoln("Volume", vid, "reaches full capacity.")
	return vl.removeFromWritable(vid)
}

func (vl *VolumeLayout) ToMap() map[string]interface{} {
	m := make(map[string]interface{})
	m["replication"] = vl.rp.String()
	m["ttl"] = vl.ttl.String()
	m["writables"] = vl.writables
	//m["locations"] = vl.vid2location
	return m
}

func (vl *VolumeLayout) Stats() *VolumeLayoutStats {
	vl.accessLock.RLock()
	defer vl.accessLock.RUnlock()

	ret := &VolumeLayoutStats{}

	freshThreshold := time.Now().Unix() - 60

	for vid, vll := range vl.vid2location {
		size, fileCount := vll.Stats(vid, freshThreshold)
		ret.FileCount += uint64(fileCount)
		ret.UsedSize += size
		if vl.readonlyVolumes[vid] {
			ret.TotalSize += size
		} else {
			ret.TotalSize += vl.volumeSizeLimit
		}
	}

	return ret
}
<commit_msg>fix test<commit_after>package topology

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

	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/storage"
)

// mapping from volume to its locations, inverted from server to volume
type VolumeLayout struct {
	rp               *storage.ReplicaPlacement
	ttl              *storage.TTL
	vid2location     map[storage.VolumeId]*VolumeLocationList
	writables        []storage.VolumeId        // transient array of writable volume id
	readonlyVolumes  map[storage.VolumeId]bool // transient set of readonly volumes
	oversizedVolumes map[storage.VolumeId]bool // set of oversized volumes
	volumeSizeLimit  uint64
	accessLock       sync.RWMutex
}

type VolumeLayoutStats struct {
	TotalSize uint64
	UsedSize  uint64
	FileCount uint64
}

func NewVolumeLayout(rp *storage.ReplicaPlacement, ttl *storage.TTL, volumeSizeLimit uint64) *VolumeLayout {
	return &VolumeLayout{
		rp:               rp,
		ttl:              ttl,
		vid2location:     make(map[storage.VolumeId]*VolumeLocationList),
		writables:        *new([]storage.VolumeId),
		readonlyVolumes:  make(map[storage.VolumeId]bool),
		oversizedVolumes: make(map[storage.VolumeId]bool),
		volumeSizeLimit:  volumeSizeLimit,
	}
}

func (vl *VolumeLayout) String() string {
	return fmt.Sprintf("rp:%v, ttl:%v, vid2location:%v, writables:%v, volumeSizeLimit:%v", vl.rp, vl.ttl, vl.vid2location, vl.writables, vl.volumeSizeLimit)
}

func (vl *VolumeLayout) RegisterVolume(v *storage.VolumeInfo, dn *DataNode) {
	vl.accessLock.Lock()
	defer vl.accessLock.Unlock()

	if _, ok := vl.vid2location[v.Id]; !ok {
		vl.vid2location[v.Id] = NewVolumeLocationList()
	}
	vl.vid2location[v.Id].Set(dn)
	glog.V(4).Infof("volume %d added to %s len %d copy %d", v.Id, dn.Id(), vl.vid2location[v.Id].Length(), v.ReplicaPlacement.GetCopyCount())
	for _, dn := range vl.vid2location[v.Id].list {
		if v_info, err := dn.GetVolumesById(v.Id); err == nil {
			if v_info.ReadOnly {
				glog.V(3).Infof("vid %d removed from writable", v.Id)
				vl.removeFromWritable(v.Id)
				vl.readonlyVolumes[v.Id] = true
				return
			} else {
				delete(vl.readonlyVolumes, v.Id)
			}
		} else {
			glog.V(3).Infof("vid %d removed from writable", v.Id)
			vl.removeFromWritable(v.Id)
			delete(vl.readonlyVolumes, v.Id)
			return
		}
	}
	if vl.vid2location[v.Id].Length() == vl.rp.GetCopyCount() && vl.isWritable(v) {
		if _, ok := vl.oversizedVolumes[v.Id]; !ok {
			vl.addToWritable(v.Id)
		}
	} else {
		vl.rememberOversizedVolumne(v)
		vl.removeFromWritable(v.Id)
	}
}

func (vl *VolumeLayout) rememberOversizedVolumne(v *storage.VolumeInfo) {
	if vl.isOversized(v) {
		vl.oversizedVolumes[v.Id] = true
	}
}

func (vl *VolumeLayout) UnRegisterVolume(v *storage.VolumeInfo, dn *DataNode) {
	vl.accessLock.Lock()
	defer vl.accessLock.Unlock()

	vl.removeFromWritable(v.Id)
	delete(vl.vid2location, v.Id)
}

func (vl *VolumeLayout) addToWritable(vid storage.VolumeId) {
	for _, id := range vl.writables {
		if vid == id {
			return
		}
	}
	vl.writables = append(vl.writables, vid)
}

func (vl *VolumeLayout) isOversized(v *storage.VolumeInfo) bool {
	return uint64(v.Size) >= vl.volumeSizeLimit
}

func (vl *VolumeLayout) isWritable(v *storage.VolumeInfo) bool {
	return !vl.isOversized(v) &&
		v.Version == storage.CurrentVersion &&
		!v.ReadOnly
}

func (vl *VolumeLayout) isEmpty() bool {
	vl.accessLock.RLock()
	defer vl.accessLock.RUnlock()

	return len(vl.vid2location) == 0
}

func (vl *VolumeLayout) Lookup(vid storage.VolumeId) []*DataNode {
	vl.accessLock.RLock()
	defer vl.accessLock.RUnlock()

	if location := vl.vid2location[vid]; location != nil {
		return location.list
	}
	return nil
}

func (vl *VolumeLayout) ListVolumeServers() (nodes []*DataNode) {
	vl.accessLock.RLock()
	defer vl.accessLock.RUnlock()

	for _, location := range vl.vid2location {
		nodes = append(nodes, location.list...)
	}
	return
}

func (vl *VolumeLayout) PickForWrite(count uint64, option *VolumeGrowOption) (*storage.VolumeId, uint64, *VolumeLocationList, error) {
	vl.accessLock.RLock()
	defer vl.accessLock.RUnlock()

	len_writers := len(vl.writables)
	if len_writers <= 0 {
		glog.V(0).Infoln("No more writable volumes!")
		return nil, 0, nil, errors.New("No more writable volumes!")
	}
	if option.DataCenter == "" {
		vid := vl.writables[rand.Intn(len_writers)]
		locationList := vl.vid2location[vid]
		if locationList != nil {
			return &vid, count, locationList, nil
		}
		return nil, 0, nil, errors.New("Strangely vid " + vid.String() + " is on no machine!")
	}
	var vid storage.VolumeId
	var locationList *VolumeLocationList
	counter := 0
	for _, v := range vl.writables {
		volumeLocationList := vl.vid2location[v]
		for _, dn := range volumeLocationList.list {
			if dn.GetDataCenter().Id() == NodeId(option.DataCenter) {
				if option.Rack != "" && dn.GetRack().Id() != NodeId(option.Rack) {
					continue
				}
				if option.DataNode != "" && dn.Id() != NodeId(option.DataNode) {
					continue
				}
				counter++
				if rand.Intn(counter) < 1 {
					vid, locationList = v, volumeLocationList
				}
			}
		}
	}
	return &vid, count, locationList, nil
}

func (vl *VolumeLayout) GetActiveVolumeCount(option *VolumeGrowOption) int {
	vl.accessLock.RLock()
	defer vl.accessLock.RUnlock()

	if option.DataCenter == "" {
		return len(vl.writables)
	}
	counter := 0
	for _, v := range vl.writables {
		for _, dn := range vl.vid2location[v].list {
			if dn.GetDataCenter().Id() == NodeId(option.DataCenter) {
				if option.Rack != "" && dn.GetRack().Id() != NodeId(option.Rack) {
					continue
				}
				if option.DataNode != "" && dn.Id() != NodeId(option.DataNode) {
					continue
				}
				counter++
			}
		}
	}
	return counter
}

func (vl *VolumeLayout) removeFromWritable(vid storage.VolumeId) bool {
	toDeleteIndex := -1
	for k, id := range vl.writables {
		if id == vid {
			toDeleteIndex = k
			break
		}
	}
	if toDeleteIndex >= 0 {
		glog.V(0).Infoln("Volume", vid, "becomes unwritable")
		vl.writables = append(vl.writables[0:toDeleteIndex], vl.writables[toDeleteIndex+1:]...)
		return true
	}
	return false
}
func (vl *VolumeLayout) setVolumeWritable(vid storage.VolumeId) bool {
	for _, v := range vl.writables {
		if v == vid {
			return false
		}
	}
	glog.V(0).Infoln("Volume", vid, "becomes writable")
	vl.writables = append(vl.writables, vid)
	return true
}

func (vl *VolumeLayout) SetVolumeUnavailable(dn *DataNode, vid storage.VolumeId) bool {
	vl.accessLock.Lock()
	defer vl.accessLock.Unlock()

	if location, ok := vl.vid2location[vid]; ok {
		if location.Remove(dn) {
			if location.Length() < vl.rp.GetCopyCount() {
				glog.V(0).Infoln("Volume", vid, "has", location.Length(), "replica, less than required", vl.rp.GetCopyCount())
				return vl.removeFromWritable(vid)
			}
		}
	}
	return false
}
func (vl *VolumeLayout) SetVolumeAvailable(dn *DataNode, vid storage.VolumeId) bool {
	vl.accessLock.Lock()
	defer vl.accessLock.Unlock()

	vl.vid2location[vid].Set(dn)
	if vl.vid2location[vid].Length() >= vl.rp.GetCopyCount() {
		return vl.setVolumeWritable(vid)
	}
	return false
}

func (vl *VolumeLayout) SetVolumeCapacityFull(vid storage.VolumeId) bool {
	vl.accessLock.Lock()
	defer vl.accessLock.Unlock()

	// glog.V(0).Infoln("Volume", vid, "reaches full capacity.")
	return vl.removeFromWritable(vid)
}

func (vl *VolumeLayout) ToMap() map[string]interface{} {
	m := make(map[string]interface{})
	m["replication"] = vl.rp.String()
	m["ttl"] = vl.ttl.String()
	m["writables"] = vl.writables
	//m["locations"] = vl.vid2location
	return m
}

func (vl *VolumeLayout) Stats() *VolumeLayoutStats {
	vl.accessLock.RLock()
	defer vl.accessLock.RUnlock()

	ret := &VolumeLayoutStats{}

	freshThreshold := time.Now().Unix() - 60

	for vid, vll := range vl.vid2location {
		size, fileCount := vll.Stats(vid, freshThreshold)
		ret.FileCount += uint64(fileCount)
		ret.UsedSize += size
		if vl.readonlyVolumes[vid] {
			ret.TotalSize += size
		} else {
			ret.TotalSize += vl.volumeSizeLimit
		}
	}

	return ret
}
<|endoftext|>


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

// This package provides basic interfaces to I/O primitives.
// Its primary job is to wrap existing implementations of such primitives,
// such as those in package os, into shared public interfaces that
// abstract the functionality, plus some other related primitives.
package io

import "os"

// Error represents an unexpected I/O behavior.
type Error struct {
	os.ErrorString
}

// ErrShortWrite means that a write accepted fewer bytes than requested
// but failed to return an explicit error.
var ErrShortWrite os.Error = &Error{"short write"}

// ErrUnexpectedEOF means that os.EOF was encountered in the
// middle of reading a fixed-size block or data structure.
var ErrUnexpectedEOF os.Error = &Error{"unexpected EOF"}

// Reader is the interface that wraps the basic Read method.
//
// Read reads up to len(p) bytes into p.  It returns the number of bytes
// read (0 <= n <= len(p)) and any error encountered.
// Even if Read returns n < len(p),
// it may use all of p as scratch space during the call.
// If some data is available but not len(p) bytes, Read conventionally
// returns what is available rather than block waiting for more.
//
// At the end of the input stream, Read returns 0, os.EOF.
// Read may return a non-zero number of bytes with a non-nil err.
// In particular, a Read that exhausts the input may return n > 0, os.EOF.
type Reader interface {
	Read(p []byte) (n int, err os.Error)
}

// Writer is the interface that wraps the basic Write method.
//
// Write writes len(p) bytes from p to the underlying data stream.
// It returns the number of bytes written from p (0 <= n <= len(p))
// and any error encountered that caused the write to stop early.
// Write must return a non-nil error if it returns n < len(p).
type Writer interface {
	Write(p []byte) (n int, err os.Error)
}

// Closer is the interface that wraps the basic Close method.
type Closer interface {
	Close() os.Error
}

// Seeker is the interface that wraps the basic Seek method.
//
// Seek sets the offset for the next Read or Write to offset,
// interpreted according to whence: 0 means relative to the origin of
// the file, 1 means relative to the current offset, and 2 means
// relative to the end.  Seek returns the new offset and an Error, if
// any.
type Seeker interface {
	Seek(offset int64, whence int) (ret int64, err os.Error)
}

// ReadWriter is the interface that groups the basic Read and Write methods.
type ReadWriter interface {
	Reader
	Writer
}

// ReadCloser is the interface that groups the basic Read and Close methods.
type ReadCloser interface {
	Reader
	Closer
}

// WriteCloser is the interface that groups the basic Write and Close methods.
type WriteCloser interface {
	Writer
	Closer
}

// ReadWriteCloser is the interface that groups the basic Read, Write and Close methods.
type ReadWriteCloser interface {
	Reader
	Writer
	Closer
}

// ReadSeeker is the interface that groups the basic Read and Seek methods.
type ReadSeeker interface {
	Reader
	Seeker
}

// WriteSeeker is the interface that groups the basic Write and Seek methods.
type WriteSeeker interface {
	Writer
	Seeker
}

// ReadWriteSeeker is the interface that groups the basic Read, Write and Seek methods.
type ReadWriteSeeker interface {
	Reader
	Writer
	Seeker
}

// ReaderFrom is the interface that wraps the ReadFrom method.
type ReaderFrom interface {
	ReadFrom(r Reader) (n int64, err os.Error)
}

// WriterTo is the interface that wraps the WriteTo method.
type WriterTo interface {
	WriteTo(w Writer) (n int64, err os.Error)
}

// ReaderAt is the interface that wraps the basic ReadAt method.
//
// ReadAt reads len(p) bytes into p starting at offset off in the
// underlying data stream.  It returns the number of bytes
// read (0 <= n <= len(p)) and any error encountered.
//
// Even if ReadAt returns n < len(p),
// it may use all of p as scratch space during the call.
// If some data is available but not len(p) bytes, ReadAt blocks
// until either all the data is available or an error occurs.
//
// At the end of the input stream, ReadAt returns 0, os.EOF.
// ReadAt may return a non-zero number of bytes with a non-nil err.
// In particular, a ReadAt that exhausts the input may return n > 0, os.EOF.
type ReaderAt interface {
	ReadAt(p []byte, off int64) (n int, err os.Error)
}

// WriterAt is the interface that wraps the basic WriteAt method.
//
// WriteAt writes len(p) bytes from p to the underlying data stream
// at offset off.  It returns the number of bytes written from p (0 <= n <= len(p))
// and any error encountered that caused the write to stop early.
// WriteAt must return a non-nil error if it returns n < len(p).
type WriterAt interface {
	WriteAt(p []byte, off int64) (n int, err os.Error)
}

// ReadByter is the interface that wraps the ReadByte method.
//
// ReadByte reads and returns the next byte from the input.
// If no byte is available, err will be set.
type ReadByter interface {
	ReadByte() (c byte, err os.Error)
}

// WriteString writes the contents of the string s to w, which accepts an array of bytes.
func WriteString(w Writer, s string) (n int, err os.Error) {
	return w.Write([]byte(s))
}

// ReadAtLeast reads from r into buf until it has read at least min bytes.
// It returns the number of bytes copied and an error if fewer bytes were read.
// The error is os.EOF only if no bytes were read.
// If an EOF happens after reading fewer than min bytes,
// ReadAtLeast returns ErrUnexpectedEOF.
func ReadAtLeast(r Reader, buf []byte, min int) (n int, err os.Error) {
	n = 0
	for n < min {
		nn, e := r.Read(buf[n:])
		if nn > 0 {
			n += nn
		}
		if e != nil {
			if e == os.EOF && n > 0 {
				e = ErrUnexpectedEOF
			}
			return n, e
		}
	}
	return n, nil
}

// ReadFull reads exactly len(buf) bytes from r into buf.
// It returns the number of bytes copied and an error if fewer bytes were read.
// The error is os.EOF only if no bytes were read.
// If an EOF happens after reading some but not all the bytes,
// ReadFull returns ErrUnexpectedEOF.
func ReadFull(r Reader, buf []byte) (n int, err os.Error) {
	return ReadAtLeast(r, buf, len(buf))
}

// Copyn copies n bytes (or until an error) from src to dst.
// It returns the number of bytes copied and the error, if any.
//
// If dst implements the ReaderFrom interface,
// the copy is implemented by calling dst.ReadFrom(src).
func Copyn(dst Writer, src Reader, n int64) (written int64, err os.Error) {
	// If the writer has a ReadFrom method, use it to to do the copy.
	// Avoids a buffer allocation and a copy.
	if rt, ok := dst.(ReaderFrom); ok {
		return rt.ReadFrom(LimitReader(src, n))
	}
	buf := make([]byte, 32*1024)
	for written < n {
		l := len(buf)
		if d := n - written; d < int64(l) {
			l = int(d)
		}
		nr, er := src.Read(buf[0:l])
		if nr > 0 {
			nw, ew := dst.Write(buf[0:nr])
			if nw > 0 {
				written += int64(nw)
			}
			if ew != nil {
				err = ew
				break
			}
			if nr != nw {
				err = ErrShortWrite
				break
			}
		}
		if er != nil {
			err = er
			break
		}
	}
	return written, err
}

// Copy copies from src to dst until either EOF is reached
// on src or an error occurs.  It returns the number of bytes
// copied and the error, if any.
//
// If dst implements the ReaderFrom interface,
// the copy is implemented by calling dst.ReadFrom(src).
// Otherwise, if src implements the WriterTo interface,
// the copy is implemented by calling src.WriteTo(dst).
func Copy(dst Writer, src Reader) (written int64, err os.Error) {
	// If the writer has a ReadFrom method, use it to to do the copy.
	// Avoids an allocation and a copy.
	if rt, ok := dst.(ReaderFrom); ok {
		return rt.ReadFrom(src)
	}
	// Similarly, if the reader has a WriteTo method, use it to to do the copy.
	if wt, ok := src.(WriterTo); ok {
		return wt.WriteTo(dst)
	}
	buf := make([]byte, 32*1024)
	for {
		nr, er := src.Read(buf)
		if nr > 0 {
			nw, ew := dst.Write(buf[0:nr])
			if nw > 0 {
				written += int64(nw)
			}
			if ew != nil {
				err = ew
				break
			}
			if nr != nw {
				err = ErrShortWrite
				break
			}
		}
		if er == os.EOF {
			break
		}
		if er != nil {
			err = er
			break
		}
	}
	return written, err
}

// LimitReader returns a Reader that reads from r
// but stops with os.EOF after n bytes.
func LimitReader(r Reader, n int64) Reader { return &limitedReader{r, n} }

type limitedReader struct {
	r Reader
	n int64
}

func (l *limitedReader) Read(p []byte) (n int, err os.Error) {
	if l.n <= 0 {
		return 0, os.EOF
	}
	if int64(len(p)) > l.n {
		p = p[0:l.n]
	}
	n, err = l.r.Read(p)
	l.n -= int64(n)
	return
}

// NewSectionReader returns a SectionReader that reads from r
// starting at offset off and stops with os.EOF after n bytes.
func NewSectionReader(r ReaderAt, off int64, n int64) *SectionReader {
	return &SectionReader{r, off, off, off + n}
}

// SectionReader implements Read, Seek, and ReadAt on a section
// of an underlying ReaderAt.
type SectionReader struct {
	r     ReaderAt
	base  int64
	off   int64
	limit int64
}

func (s *SectionReader) Read(p []byte) (n int, err os.Error) {
	if s.off >= s.limit {
		return 0, os.EOF
	}
	if max := s.limit - s.off; int64(len(p)) > max {
		p = p[0:max]
	}
	n, err = s.r.ReadAt(p, s.off)
	s.off += int64(n)
	return
}

func (s *SectionReader) Seek(offset int64, whence int) (ret int64, err os.Error) {
	switch whence {
	default:
		return 0, os.EINVAL
	case 0:
		offset += s.base
	case 1:
		offset += s.off
	case 2:
		offset += s.limit
	}
	if offset < s.off || offset > s.limit {
		return 0, os.EINVAL
	}
	s.off = offset
	return offset - s.base, nil
}

func (s *SectionReader) ReadAt(p []byte, off int64) (n int, err os.Error) {
	if off < 0 || off >= s.limit-s.base {
		return 0, os.EOF
	}
	off += s.base
	if max := s.limit - off; int64(len(p)) > max {
		p = p[0:max]
	}
	return s.r.ReadAt(p, off)
}

// Size returns the size of the section in bytes.
func (s *SectionReader) Size() int64 { return s.limit - s.base }
<commit_msg>io: fix SectionReader Seek to seek backwards<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This package provides basic interfaces to I/O primitives.
// Its primary job is to wrap existing implementations of such primitives,
// such as those in package os, into shared public interfaces that
// abstract the functionality, plus some other related primitives.
package io

import "os"

// Error represents an unexpected I/O behavior.
type Error struct {
	os.ErrorString
}

// ErrShortWrite means that a write accepted fewer bytes than requested
// but failed to return an explicit error.
var ErrShortWrite os.Error = &Error{"short write"}

// ErrUnexpectedEOF means that os.EOF was encountered in the
// middle of reading a fixed-size block or data structure.
var ErrUnexpectedEOF os.Error = &Error{"unexpected EOF"}

// Reader is the interface that wraps the basic Read method.
//
// Read reads up to len(p) bytes into p.  It returns the number of bytes
// read (0 <= n <= len(p)) and any error encountered.
// Even if Read returns n < len(p),
// it may use all of p as scratch space during the call.
// If some data is available but not len(p) bytes, Read conventionally
// returns what is available rather than block waiting for more.
//
// At the end of the input stream, Read returns 0, os.EOF.
// Read may return a non-zero number of bytes with a non-nil err.
// In particular, a Read that exhausts the input may return n > 0, os.EOF.
type Reader interface {
	Read(p []byte) (n int, err os.Error)
}

// Writer is the interface that wraps the basic Write method.
//
// Write writes len(p) bytes from p to the underlying data stream.
// It returns the number of bytes written from p (0 <= n <= len(p))
// and any error encountered that caused the write to stop early.
// Write must return a non-nil error if it returns n < len(p).
type Writer interface {
	Write(p []byte) (n int, err os.Error)
}

// Closer is the interface that wraps the basic Close method.
type Closer interface {
	Close() os.Error
}

// Seeker is the interface that wraps the basic Seek method.
//
// Seek sets the offset for the next Read or Write to offset,
// interpreted according to whence: 0 means relative to the origin of
// the file, 1 means relative to the current offset, and 2 means
// relative to the end.  Seek returns the new offset and an Error, if
// any.
type Seeker interface {
	Seek(offset int64, whence int) (ret int64, err os.Error)
}

// ReadWriter is the interface that groups the basic Read and Write methods.
type ReadWriter interface {
	Reader
	Writer
}

// ReadCloser is the interface that groups the basic Read and Close methods.
type ReadCloser interface {
	Reader
	Closer
}

// WriteCloser is the interface that groups the basic Write and Close methods.
type WriteCloser interface {
	Writer
	Closer
}

// ReadWriteCloser is the interface that groups the basic Read, Write and Close methods.
type ReadWriteCloser interface {
	Reader
	Writer
	Closer
}

// ReadSeeker is the interface that groups the basic Read and Seek methods.
type ReadSeeker interface {
	Reader
	Seeker
}

// WriteSeeker is the interface that groups the basic Write and Seek methods.
type WriteSeeker interface {
	Writer
	Seeker
}

// ReadWriteSeeker is the interface that groups the basic Read, Write and Seek methods.
type ReadWriteSeeker interface {
	Reader
	Writer
	Seeker
}

// ReaderFrom is the interface that wraps the ReadFrom method.
type ReaderFrom interface {
	ReadFrom(r Reader) (n int64, err os.Error)
}

// WriterTo is the interface that wraps the WriteTo method.
type WriterTo interface {
	WriteTo(w Writer) (n int64, err os.Error)
}

// ReaderAt is the interface that wraps the basic ReadAt method.
//
// ReadAt reads len(p) bytes into p starting at offset off in the
// underlying data stream.  It returns the number of bytes
// read (0 <= n <= len(p)) and any error encountered.
//
// Even if ReadAt returns n < len(p),
// it may use all of p as scratch space during the call.
// If some data is available but not len(p) bytes, ReadAt blocks
// until either all the data is available or an error occurs.
//
// At the end of the input stream, ReadAt returns 0, os.EOF.
// ReadAt may return a non-zero number of bytes with a non-nil err.
// In particular, a ReadAt that exhausts the input may return n > 0, os.EOF.
type ReaderAt interface {
	ReadAt(p []byte, off int64) (n int, err os.Error)
}

// WriterAt is the interface that wraps the basic WriteAt method.
//
// WriteAt writes len(p) bytes from p to the underlying data stream
// at offset off.  It returns the number of bytes written from p (0 <= n <= len(p))
// and any error encountered that caused the write to stop early.
// WriteAt must return a non-nil error if it returns n < len(p).
type WriterAt interface {
	WriteAt(p []byte, off int64) (n int, err os.Error)
}

// ReadByter is the interface that wraps the ReadByte method.
//
// ReadByte reads and returns the next byte from the input.
// If no byte is available, err will be set.
type ReadByter interface {
	ReadByte() (c byte, err os.Error)
}

// WriteString writes the contents of the string s to w, which accepts an array of bytes.
func WriteString(w Writer, s string) (n int, err os.Error) {
	return w.Write([]byte(s))
}

// ReadAtLeast reads from r into buf until it has read at least min bytes.
// It returns the number of bytes copied and an error if fewer bytes were read.
// The error is os.EOF only if no bytes were read.
// If an EOF happens after reading fewer than min bytes,
// ReadAtLeast returns ErrUnexpectedEOF.
func ReadAtLeast(r Reader, buf []byte, min int) (n int, err os.Error) {
	n = 0
	for n < min {
		nn, e := r.Read(buf[n:])
		if nn > 0 {
			n += nn
		}
		if e != nil {
			if e == os.EOF && n > 0 {
				e = ErrUnexpectedEOF
			}
			return n, e
		}
	}
	return n, nil
}

// ReadFull reads exactly len(buf) bytes from r into buf.
// It returns the number of bytes copied and an error if fewer bytes were read.
// The error is os.EOF only if no bytes were read.
// If an EOF happens after reading some but not all the bytes,
// ReadFull returns ErrUnexpectedEOF.
func ReadFull(r Reader, buf []byte) (n int, err os.Error) {
	return ReadAtLeast(r, buf, len(buf))
}

// Copyn copies n bytes (or until an error) from src to dst.
// It returns the number of bytes copied and the error, if any.
//
// If dst implements the ReaderFrom interface,
// the copy is implemented by calling dst.ReadFrom(src).
func Copyn(dst Writer, src Reader, n int64) (written int64, err os.Error) {
	// If the writer has a ReadFrom method, use it to to do the copy.
	// Avoids a buffer allocation and a copy.
	if rt, ok := dst.(ReaderFrom); ok {
		return rt.ReadFrom(LimitReader(src, n))
	}
	buf := make([]byte, 32*1024)
	for written < n {
		l := len(buf)
		if d := n - written; d < int64(l) {
			l = int(d)
		}
		nr, er := src.Read(buf[0:l])
		if nr > 0 {
			nw, ew := dst.Write(buf[0:nr])
			if nw > 0 {
				written += int64(nw)
			}
			if ew != nil {
				err = ew
				break
			}
			if nr != nw {
				err = ErrShortWrite
				break
			}
		}
		if er != nil {
			err = er
			break
		}
	}
	return written, err
}

// Copy copies from src to dst until either EOF is reached
// on src or an error occurs.  It returns the number of bytes
// copied and the error, if any.
//
// If dst implements the ReaderFrom interface,
// the copy is implemented by calling dst.ReadFrom(src).
// Otherwise, if src implements the WriterTo interface,
// the copy is implemented by calling src.WriteTo(dst).
func Copy(dst Writer, src Reader) (written int64, err os.Error) {
	// If the writer has a ReadFrom method, use it to to do the copy.
	// Avoids an allocation and a copy.
	if rt, ok := dst.(ReaderFrom); ok {
		return rt.ReadFrom(src)
	}
	// Similarly, if the reader has a WriteTo method, use it to to do the copy.
	if wt, ok := src.(WriterTo); ok {
		return wt.WriteTo(dst)
	}
	buf := make([]byte, 32*1024)
	for {
		nr, er := src.Read(buf)
		if nr > 0 {
			nw, ew := dst.Write(buf[0:nr])
			if nw > 0 {
				written += int64(nw)
			}
			if ew != nil {
				err = ew
				break
			}
			if nr != nw {
				err = ErrShortWrite
				break
			}
		}
		if er == os.EOF {
			break
		}
		if er != nil {
			err = er
			break
		}
	}
	return written, err
}

// LimitReader returns a Reader that reads from r
// but stops with os.EOF after n bytes.
func LimitReader(r Reader, n int64) Reader { return &limitedReader{r, n} }

type limitedReader struct {
	r Reader
	n int64
}

func (l *limitedReader) Read(p []byte) (n int, err os.Error) {
	if l.n <= 0 {
		return 0, os.EOF
	}
	if int64(len(p)) > l.n {
		p = p[0:l.n]
	}
	n, err = l.r.Read(p)
	l.n -= int64(n)
	return
}

// NewSectionReader returns a SectionReader that reads from r
// starting at offset off and stops with os.EOF after n bytes.
func NewSectionReader(r ReaderAt, off int64, n int64) *SectionReader {
	return &SectionReader{r, off, off, off + n}
}

// SectionReader implements Read, Seek, and ReadAt on a section
// of an underlying ReaderAt.
type SectionReader struct {
	r     ReaderAt
	base  int64
	off   int64
	limit int64
}

func (s *SectionReader) Read(p []byte) (n int, err os.Error) {
	if s.off >= s.limit {
		return 0, os.EOF
	}
	if max := s.limit - s.off; int64(len(p)) > max {
		p = p[0:max]
	}
	n, err = s.r.ReadAt(p, s.off)
	s.off += int64(n)
	return
}

func (s *SectionReader) Seek(offset int64, whence int) (ret int64, err os.Error) {
	switch whence {
	default:
		return 0, os.EINVAL
	case 0:
		offset += s.base
	case 1:
		offset += s.off
	case 2:
		offset += s.limit
	}
	if offset < s.base || offset > s.limit {
		return 0, os.EINVAL
	}
	s.off = offset
	return offset - s.base, nil
}

func (s *SectionReader) ReadAt(p []byte, off int64) (n int, err os.Error) {
	if off < 0 || off >= s.limit-s.base {
		return 0, os.EOF
	}
	off += s.base
	if max := s.limit - off; int64(len(p)) > max {
		p = p[0:max]
	}
	return s.r.ReadAt(p, off)
}

// Size returns the size of the section in bytes.
func (s *SectionReader) Size() int64 { return s.limit - s.base }
<|endoftext|>


<commit_before>/*
Copyright IBM Corp. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/

package chaincode

import (
	"fmt"
	"testing"

	"github.com/hyperledger/fabric/internal/peer/common"
	"github.com/spf13/cobra"
	"github.com/stretchr/testify/assert"
)

func TestQueryCmd(t *testing.T) {
	mockCF, err := getMockChaincodeCmdFactory()
	assert.NoError(t, err, "Error getting mock chaincode command factory")
	// reset channelID, it might have been set by previous test
	channelID = ""

	// Failure case: run query command without -C option
	args := []string{"-n", "example02", "-c", "{\"Args\": [\"query\",\"a\"]}"}
	cmd := newQueryCmdForTest(mockCF, args)
	err = cmd.Execute()
	assert.Error(t, err, "'peer chaincode query' command should have failed without -C flag")

	// Success case: run query command without -r or -x option
	args = []string{"-C", "mychannel", "-n", "example02", "-c", "{\"Args\": [\"query\",\"a\"]}"}
	cmd = newQueryCmdForTest(mockCF, args)
	err = cmd.Execute()
	assert.NoError(t, err, "Run chaincode query cmd error")

	// Success case: run query command with -r option
	args = []string{"-r", "-C", "mychannel", "-n", "example02", "-c", "{\"Args\": [\"query\",\"a\"]}"}
	cmd = newQueryCmdForTest(mockCF, args)
	err = cmd.Execute()
	assert.NoError(t, err, "Run chaincode query cmd error")
	chaincodeQueryRaw = false

	// Success case: run query command with -x option
	args = []string{"-x", "-C", "mychannel", "-n", "example02", "-c", "{\"Args\": [\"query\",\"a\"]}"}
	cmd = newQueryCmdForTest(mockCF, args)
	err = cmd.Execute()
	assert.NoError(t, err, "Run chaincode query cmd error")

	// Failure case: run query command with both -x and -r options
	args = []string{"-r", "-x", "-C", "mychannel", "-n", "example02", "-c", "{\"Args\": [\"query\",\"a\"]}"}
	cmd = newQueryCmdForTest(mockCF, args)
	err = cmd.Execute()
	assert.Error(t, err, "Expected error executing query command with both -r and -x options")

	// Failure case: run query command with mock chaincode cmd factory built to return error
	mockCF, err = getMockChaincodeCmdFactoryWithErr()
	assert.NoError(t, err, "Error getting mock chaincode command factory")
	args = []string{"-r", "-n", "example02", "-c", "{\"Args\": [\"query\",\"a\"]}"}
	cmd = newQueryCmdForTest(mockCF, args)
	err = cmd.Execute()
	assert.Error(t, err, "Expected error executing query command")
}

func TestQueryCmdEndorsementFailure(t *testing.T) {
	args := []string{"-C", "mychannel", "-n", "example02", "-c", "{\"Args\": [\"queryinvalid\",\"a\"]}"}
	ccRespStatus := [2]int32{502, 400}
	ccRespPayload := [][]byte{[]byte("Invalid function name"), []byte("Incorrect parameters")}

	for i := 0; i < 2; i++ {
		mockCF, err := getMockChaincodeCmdFactoryEndorsementFailure(ccRespStatus[i], ccRespPayload[i])
		assert.NoError(t, err, "Error getting mock chaincode command factory")

		cmd := newQueryCmdForTest(mockCF, args)
		err = cmd.Execute()
		assert.Error(t, err)
		assert.Regexp(t, "endorsement failure during query", err.Error())
		assert.Regexp(t, fmt.Sprintf("response: status:%d payload:\"%s\"", ccRespStatus[i], ccRespPayload[i]), err.Error())
	}

	// failure - nil proposal response
	mockCF, err := getMockChaincodeCmdFactory()
	assert.NoError(t, err, "Error getting mock chaincode command factory")
	mockCF.EndorserClients[0] = common.GetMockEndorserClient(nil, nil)

	cmd := newQueryCmdForTest(mockCF, args)
	err = cmd.Execute()
	assert.Error(t, err)
	assert.Regexp(t, "error during query: received nil proposal response", err.Error())
}

func newQueryCmdForTest(cf *ChaincodeCmdFactory, args []string) *cobra.Command {
	cmd := queryCmd(cf)
	addFlags(cmd)
	cmd.SetArgs(args)
	return cmd
}
<commit_msg>Fix Broken Master<commit_after>/*
Copyright IBM Corp. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/

package chaincode

import (
	"fmt"
	"testing"

	"github.com/hyperledger/fabric/internal/peer/common"
	"github.com/spf13/cobra"
	"github.com/stretchr/testify/assert"
)

func TestQueryCmd(t *testing.T) {
	mockCF, err := getMockChaincodeCmdFactory()
	assert.NoError(t, err, "Error getting mock chaincode command factory")
	// reset channelID, it might have been set by previous test
	channelID = ""

	// Failure case: run query command without -C option
	args := []string{"-n", "example02", "-c", "{\"Args\": [\"query\",\"a\"]}"}
	cmd := newQueryCmdForTest(mockCF, args)
	err = cmd.Execute()
	assert.Error(t, err, "'peer chaincode query' command should have failed without -C flag")

	// Success case: run query command without -r or -x option
	args = []string{"-C", "mychannel", "-n", "example02", "-c", "{\"Args\": [\"query\",\"a\"]}"}
	cmd = newQueryCmdForTest(mockCF, args)
	err = cmd.Execute()
	assert.NoError(t, err, "Run chaincode query cmd error")

	// Success case: run query command with -r option
	args = []string{"-r", "-C", "mychannel", "-n", "example02", "-c", "{\"Args\": [\"query\",\"a\"]}"}
	cmd = newQueryCmdForTest(mockCF, args)
	err = cmd.Execute()
	assert.NoError(t, err, "Run chaincode query cmd error")
	chaincodeQueryRaw = false

	// Success case: run query command with -x option
	args = []string{"-x", "-C", "mychannel", "-n", "example02", "-c", "{\"Args\": [\"query\",\"a\"]}"}
	cmd = newQueryCmdForTest(mockCF, args)
	err = cmd.Execute()
	assert.NoError(t, err, "Run chaincode query cmd error")

	// Failure case: run query command with both -x and -r options
	args = []string{"-r", "-x", "-C", "mychannel", "-n", "example02", "-c", "{\"Args\": [\"query\",\"a\"]}"}
	cmd = newQueryCmdForTest(mockCF, args)
	err = cmd.Execute()
	assert.Error(t, err, "Expected error executing query command with both -r and -x options")

	// Failure case: run query command with mock chaincode cmd factory built to return error
	mockCF, err = getMockChaincodeCmdFactoryWithErr()
	assert.NoError(t, err, "Error getting mock chaincode command factory")
	args = []string{"-r", "-n", "example02", "-c", "{\"Args\": [\"query\",\"a\"]}"}
	cmd = newQueryCmdForTest(mockCF, args)
	err = cmd.Execute()
	assert.Error(t, err, "Expected error executing query command")
}

func TestQueryCmdEndorsementFailure(t *testing.T) {
	args := []string{"-C", "mychannel", "-n", "example02", "-c", "{\"Args\": [\"queryinvalid\",\"a\"]}"}
	ccRespStatus := [2]int32{502, 400}
	ccRespPayload := [][]byte{[]byte("Invalid function name"), []byte("Incorrect parameters")}

	for i := 0; i < 2; i++ {
		mockCF, err := getMockChaincodeCmdFactoryEndorsementFailure(ccRespStatus[i], ccRespPayload[i])
		assert.NoError(t, err, "Error getting mock chaincode command factory")

		cmd := newQueryCmdForTest(mockCF, args)
		err = cmd.Execute()
		assert.Error(t, err)
		assert.Regexp(t, "endorsement failure during query", err.Error())
		assert.Regexp(t, fmt.Sprintf("response: status:%d payload:\"%s\"", ccRespStatus[i], ccRespPayload[i]), err.Error())
	}

	// failure - nil proposal response
	mockCF, err := getMockChaincodeCmdFactory()
	assert.NoError(t, err, "Error getting mock chaincode command factory")
	mockCF.EndorserClients[0] = common.GetMockEndorserClient(nil, nil)
	mockCF.EndorserClients[1] = common.GetMockEndorserClient(nil, nil)

	cmd := newQueryCmdForTest(mockCF, args)
	err = cmd.Execute()
	assert.Error(t, err)
	assert.Regexp(t, "error during query: received nil proposal response", err.Error())
}

func newQueryCmdForTest(cf *ChaincodeCmdFactory, args []string) *cobra.Command {
	cmd := queryCmd(cf)
	addFlags(cmd)
	cmd.SetArgs(args)
	return cmd
}
<|endoftext|>


<commit_before>package webhookd

import (
	"errors"
	"fmt"
	"net/http"
)

type WebhookError struct {
	Code    int
	Message string
}

func (e WebhookError) Error() string {
	return fmt.Sprintf("%d %s", e.Code, e.Message)
}

type WebhookReceiver interface {
	Receive(*http.Request) ([]byte, *WebhookError)
}

type WebhookDispatcher interface {
	Dispatch([]byte) *WebhookError // sudo make me an io.Reader or something
}

type WebhookHandler interface {
	Endpoint() string // sudo make me a net.URI or something
	Receiver() WebhookReceiver
	Dispatcher() WebhookDispatcher
}

type Webhook struct {
	WebhookHandler
	endpoint   string
	receiver   WebhookReceiver
	dispatcher WebhookDispatcher
}

func NewWebhook(endpoint string, receiver WebhookReceiver, dispatcher WebhookDispatcher) (Webhook, error) {

	wh := Webhook{
		endpoint:   endpoint,
		receiver:   receiver,
		dispatcher: dispatcher,
	}

	return wh, nil
}

func (wh Webhook) Endpoint() string {
	return wh.endpoint
}

func (wh Webhook) Receiver() WebhookReceiver {
	return wh.receiver
}

func (wh Webhook) Dispatcher() WebhookDispatcher {
	return wh.dispatcher
}

type WebhookDaemon struct {
	host     string
	port     int
	webhooks map[string]WebhookHandler
}

func NewWebhookDaemon(host string, port int) (WebhookDaemon, error) {

	webhooks := make(map[string]WebhookHandler)

	d := WebhookDaemon{
		host:     host,
		port:     port,
		webhooks: webhooks,
	}

	return d, nil
}

func (d *WebhookDaemon) AddWebhook(wh Webhook) error {

	endpoint := wh.Endpoint()
	_, ok := d.webhooks[endpoint]

	if ok {
		return errors.New("endpoint already configured")
	}

	d.webhooks[endpoint] = wh
	return nil
}

func (d *WebhookDaemon) Start() error {

	if len(d.webhooks) == 0 {
		return errors.New("no webhooks configured")
	}

	handler := func(rsp http.ResponseWriter, req *http.Request) {

		endpoint := req.URL.Path

		wh, ok := d.webhooks[endpoint]

		if !ok {
			http.Error(rsp, "404 Not found", http.StatusNotFound)
			return
		}

		rcvr := wh.Receiver()
		dspt := wh.Dispatcher()

		body, err := rcvr.Receive(req)

		if err != nil {
			http.Error(rsp, err.Error(), http.StatusInternalServerError)
			return
		}

		err = dspt.Dispatch(body)

		if err != nil {
			http.Error(rsp, err.Error(), 500)
			return
		}

		return
	}

	endpoint := fmt.Sprintf("%s:%d", d.host, d.port)

	http.HandleFunc("/", handler)
	err := http.ListenAndServe(endpoint, nil)

	if err != nil {
		return err
	}

	return nil
}
<commit_msg>more better error codes<commit_after>package webhookd

import (
	"errors"
	"fmt"
	"net/http"
)

type WebhookError struct {
	Code    int
	Message string
}

func (e WebhookError) Error() string {
	return fmt.Sprintf("%d %s", e.Code, e.Message)
}

type WebhookReceiver interface {
	Receive(*http.Request) ([]byte, *WebhookError)
}

type WebhookDispatcher interface {
	Dispatch([]byte) *WebhookError // sudo make me an io.Reader or something
}

type WebhookHandler interface {
	Endpoint() string // sudo make me a net.URI or something
	Receiver() WebhookReceiver
	Dispatcher() WebhookDispatcher
}

type Webhook struct {
	WebhookHandler
	endpoint   string
	receiver   WebhookReceiver
	dispatcher WebhookDispatcher
}

func NewWebhook(endpoint string, receiver WebhookReceiver, dispatcher WebhookDispatcher) (Webhook, error) {

	wh := Webhook{
		endpoint:   endpoint,
		receiver:   receiver,
		dispatcher: dispatcher,
	}

	return wh, nil
}

func (wh Webhook) Endpoint() string {
	return wh.endpoint
}

func (wh Webhook) Receiver() WebhookReceiver {
	return wh.receiver
}

func (wh Webhook) Dispatcher() WebhookDispatcher {
	return wh.dispatcher
}

type WebhookDaemon struct {
	host     string
	port     int
	webhooks map[string]WebhookHandler
}

func NewWebhookDaemon(host string, port int) (WebhookDaemon, error) {

	webhooks := make(map[string]WebhookHandler)

	d := WebhookDaemon{
		host:     host,
		port:     port,
		webhooks: webhooks,
	}

	return d, nil
}

func (d *WebhookDaemon) AddWebhook(wh Webhook) error {

	endpoint := wh.Endpoint()
	_, ok := d.webhooks[endpoint]

	if ok {
		return errors.New("endpoint already configured")
	}

	d.webhooks[endpoint] = wh
	return nil
}

func (d *WebhookDaemon) Start() error {

	if len(d.webhooks) == 0 {
		return errors.New("no webhooks configured")
	}

	handler := func(rsp http.ResponseWriter, req *http.Request) {

		endpoint := req.URL.Path

		wh, ok := d.webhooks[endpoint]

		if !ok {
			http.Error(rsp, "404 Not found", http.StatusNotFound)
			return
		}

		rcvr := wh.Receiver()
		dspt := wh.Dispatcher()

		body, err := rcvr.Receive(req)

		if err != nil {
			http.Error(rsp, err.Error(), err.Code)
			return
		}

		err = dspt.Dispatch(body)

		if err != nil {
			http.Error(rsp, err.Error(), http.StatusInternalServerError)
			return
		}

		return
	}

	endpoint := fmt.Sprintf("%s:%d", d.host, d.port)

	http.HandleFunc("/", handler)
	err := http.ListenAndServe(endpoint, nil)

	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/http"

	c "github.com/zephyyrr/autobot/config"
)

func init() {
	http.HandleFunc("/hook", handleHook)
	http.HandleFunc("/", handleRoot)
}

func handleRoot(w http.ResponseWriter, req *http.Request) {
	fmt.Fprintln(w, "")
	fmt.Fprintln(w, "Welcome to Autobot!
")
	fmt.Fprintln(w, "Autobot is designed to be interfaced with Github's Webhooks API.
")
	fmt.Fprintf(w, "To use, setup your projects Github repository to use the Webhook %s.
\n", hookAddress(req))
	fmt.Fprintln(w, "")
}

func handleHook(w http.ResponseWriter, req *http.Request) {
	processes.Add(1)
	defer processes.Done()

	event := req.Header.Get("Sch-Github-Event")

	switch event {
	case c.Ping:
	default:
		//Unknown event
		//Log and exit
	}

	if err := rollOut(config.Events[event]); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

}
<commit_msg>Implements a config handler that (will) write the active configuration (debug purposes)<commit_after>package main

import (
	"fmt"
	"net/http"

	c "github.com/zephyyrr/autobot/config"
)

func init() {
	http.HandleFunc("/hook", handleHook)
	http.HandleFunc("/", handleRoot)
	http.HandleFunc("/config", handleConfig)
}

func handleRoot(w http.ResponseWriter, req *http.Request) {
	fmt.Fprintln(w, "")
	fmt.Fprintln(w, "Welcome to Autobot!
")
	fmt.Fprintln(w, "Autobot is designed to be interfaced with Github's Webhooks API.
")
	fmt.Fprintf(w, "To use, setup your projects Github repository to use the Webhook %s.
\n", hookAddress(req))
	fmt.Fprintln(w, "")
}

func handleHook(w http.ResponseWriter, req *http.Request) {
	processes.Add(1)
	defer processes.Done()

	event := req.Header.Get("Sch-Github-Event")

	switch event {
	case c.Ping:
	default:
		//Unknown event
		//Log and exit
	}

	if err := rollOut(config.Events[event]); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func handleConfig(w http.ResponseWriter, req *http.Request) {
	c.WriteConfig(w, c.DefautlConfig())
}
<|endoftext|>