<commit_before>// +build integration

/*
Copyright 2018 Google, Inc. All rights reserved.

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

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

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

package tests

import (
	"bytes"
	"context"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"testing"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/client"
)

const (
	diffBase     = "gcr.io/gcp-runtimes/container-diff-tests/diff-base"
	diffModified = "gcr.io/gcp-runtimes/container-diff-tests/diff-modified"

	diffLayerBase     = "gcr.io/gcp-runtimes/container-diff-tests/diff-layer-base"
	diffLayerModified = "gcr.io/gcp-runtimes/container-diff-tests/diff-layer-modified"

	metadataBase     = "gcr.io/gcp-runtimes/container-diff-tests/metadata-base"
	metadataModified = "gcr.io/gcp-runtimes/container-diff-tests/metadata-modified"

	aptBase     = "gcr.io/gcp-runtimes/container-diff-tests/apt-base"
	aptModified = "gcr.io/gcp-runtimes/container-diff-tests/apt-modified"

	rpmBase     = "valentinrothberg/containerdiff:diff-base"
	rpmModified = "valentinrothberg/containerdiff:diff-modified"

	// Why is this node-modified:2.0?
	nodeBase     = "gcr.io/gcp-runtimes/container-diff-tests/node-modified:2.0"
	nodeModified = "gcr.io/gcp-runtimes/container-diff-tests/node-modified"

	pipModified = "gcr.io/gcp-runtimes/container-diff-tests/pip-modified"

	multiBase     = "gcr.io/gcp-runtimes/container-diff-tests/multi-base"
	multiModified = "gcr.io/gcp-runtimes/container-diff-tests/multi-modified"

	multiBaseLocal     = "daemon://gcr.io/gcp-runtimes/container-diff-tests/multi-base"
	multiModifiedLocal = "daemon://gcr.io/gcp-runtimes/container-diff-tests/multi-modified"
)

type ContainerDiffRunner struct {
	t          *testing.T
	binaryPath string
}

func (c *ContainerDiffRunner) Run(command ...string) (string, string, error) {
	path, err := filepath.Abs(c.binaryPath)
	if err != nil {
		c.t.Fatalf("Error finding container-diff binary: %s", err)
	}
	c.t.Logf("Running command: %s %s", path, command)
	cmd := exec.Command(path, command...)

	var stdout, stderr bytes.Buffer
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr
	if err := cmd.Run(); err != nil {
		return "", "", fmt.Errorf("Error running command %s: %s Stderr: %s", command, err, stderr.String())
	}
	return stdout.String(), stderr.String(), nil
}

func TestDiffAndAnalysis(t *testing.T) {
	runner := ContainerDiffRunner{
		t:          t,
		binaryPath: "../out/container-diff",
	}

	var tests = []struct {
		description string
		imageA      string
		imageB      string
		differFlags []string
		subcommand  string

		//TODO: Don't consume a json file
		expectedFile string
	}{
		{
			description:  "file differ",
			subcommand:   "diff",
			imageA:       diffBase,
			imageB:       diffModified,
			differFlags:  []string{"--type=file", "--no-cache"},
			expectedFile: "file_diff_expected.json",
		},
		{
			description:  "file layer differ",
			subcommand:   "diff",
			imageA:       diffLayerBase,
			imageB:       diffLayerModified,
			differFlags:  []string{"--type=layer", "--no-cache"},
			expectedFile: "file_layer_diff_expected.json",
		},
		{
			description:  "size differ",
			subcommand:   "diff",
			imageA:       diffLayerBase,
			imageB:       diffLayerModified,
			differFlags:  []string{"--type=size", "--no-cache"},
			expectedFile: "size_diff_expected.json",
		},
		{
			description:  "size layer differ",
			subcommand:   "diff",
			imageA:       diffLayerBase,
			imageB:       diffLayerModified,
			differFlags:  []string{"--type=sizelayer", "--no-cache"},
			expectedFile: "size_layer_diff_expected.json",
		},
		{
			description:  "apt differ",
			subcommand:   "diff",
			imageA:       aptBase,
			imageB:       aptModified,
			differFlags:  []string{"--type=apt", "--no-cache"},
			expectedFile: "apt_diff_expected.json",
		},
		{
			description:  "node differ",
			subcommand:   "diff",
			imageA:       nodeBase,
			imageB:       nodeModified,
			differFlags:  []string{"--type=node", "--no-cache"},
			expectedFile: "node_diff_order_expected.json",
		},
		{
			description:  "multi differ",
			subcommand:   "diff",
			imageA:       multiBase,
			imageB:       multiModified,
			differFlags:  []string{"--type=node", "--type=pip", "--type=apt", "--no-cache"},
			expectedFile: "multi_diff_expected.json",
		},
		{
			description:  "multi differ local",
			subcommand:   "diff",
			imageA:       multiBaseLocal,
			imageB:       multiModifiedLocal,
			differFlags:  []string{"--type=node", "--type=pip", "--type=apt", "--no-cache"},
			expectedFile: "multi_diff_expected.json",
		},
		{
			description:  "history differ",
			subcommand:   "diff",
			imageA:       diffBase,
			imageB:       diffModified,
			differFlags:  []string{"--type=history", "--no-cache"},
			expectedFile: "hist_diff_expected.json",
		},
		{
			description:  "metadata differ",
			subcommand:   "diff",
			imageA:       metadataBase,
			imageB:       metadataModified,
			differFlags:  []string{"--type=metadata", "--no-cache"},
			expectedFile: "metadata_diff_expected.json",
		},
		{
			description:  "apt sorted differ",
			subcommand:   "diff",
			imageA:       aptBase,
			imageB:       aptModified,
			differFlags:  []string{"--type=apt", "-o", "--no-cache"},
			expectedFile: "apt_sorted_diff_expected.json",
		},
		{
			description:  "apt analysis",
			subcommand:   "analyze",
			imageA:       aptModified,
			differFlags:  []string{"--type=apt", "--no-cache"},
			expectedFile: "apt_analysis_expected.json",
		},
		{
			description:  "file sorted analysis",
			subcommand:   "analyze",
			imageA:       diffModified,
			differFlags:  []string{"--type=file", "-o", "--no-cache"},
			expectedFile: "file_sorted_analysis_expected.json",
		},
		{
			description:  "file layer analysis",
			subcommand:   "analyze",
			imageA:       diffLayerBase,
			differFlags:  []string{"--type=layer", "--no-cache"},
			expectedFile: "file_layer_analysis_expected.json",
		},
		{
			description:  "size analysis",
			subcommand:   "analyze",
			imageA:       diffBase,
			differFlags:  []string{"--type=size", "--no-cache"},
			expectedFile: "size_analysis_expected.json",
		},
		{
			description:  "size layer analysis",
			subcommand:   "analyze",
			imageA:       diffLayerBase,
			differFlags:  []string{"--type=sizelayer", "--no-cache"},
			expectedFile: "size_layer_analysis_expected.json",
		},
		{
			description:  "pip analysis",
			subcommand:   "analyze",
			imageA:       pipModified,
			differFlags:  []string{"--type=pip", "--no-cache"},
			expectedFile: "pip_analysis_expected.json",
		},
		{
			description:  "node analysis",
			subcommand:   "analyze",
			imageA:       nodeModified,
			differFlags:  []string{"--type=node", "--no-cache"},
			expectedFile: "node_analysis_expected.json",
		},
	}
	for _, test := range tests {
		// Capture the range variable for parallel testing.
		test := test
		t.Run(test.description, func(t *testing.T) {
			t.Parallel()
			args := []string{test.subcommand, test.imageA}
			if test.imageB != "" {
				args = append(args, test.imageB)
			}
			args = append(args, test.differFlags...)
			args = append(args, "-j")
			actual, stderr, err := runner.Run(args...)
			if err != nil {
				t.Fatalf("Error running command: %s. Stderr: %s", err, stderr)
			}
			e, err := ioutil.ReadFile(test.expectedFile)
			if err != nil {
				t.Fatalf("Error reading expected file output file: %s", err)
			}
			actual = strings.TrimSpace(actual)
			expected := strings.TrimSpace(string(e))
			if actual != expected {
				t.Errorf("Error actual output does not match expected.  \n\nExpected: %s\n\n Actual: %s\n\n, Stderr: %s", expected, actual, stderr)
			}
		})
	}
}

func newClient() (*client.Client, error) {
	cli, err := client.NewEnvClient()
	if err != nil {
		return nil, fmt.Errorf("Error getting docker client: %s", err)
	}
	cli.NegotiateAPIVersion(context.Background())

	return cli, nil
}

func TestMain(m *testing.M) {
	// setup
	ctx := context.Background()
	cli, _ := newClient()
	closer, err := cli.ImagePull(ctx, multiBase, types.ImagePullOptions{})
	if err != nil {
		fmt.Printf("Error retrieving docker client: %s", err)
		os.Exit(1)
	}
	io.Copy(os.Stdout, closer)

	closer, err = cli.ImagePull(ctx, multiModified, types.ImagePullOptions{})
	if err != nil {
		fmt.Printf("Error retrieving docker client: %s", err)
		os.Exit(1)
	}
	io.Copy(os.Stdout, closer)

	closer.Close()
	os.Exit(m.Run())
}
<commit_msg>Removing flaky test<commit_after>// +build integration

/*
Copyright 2018 Google, Inc. All rights reserved.

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

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

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

package tests

import (
	"bytes"
	"context"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"testing"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/client"
)

const (
	diffBase     = "gcr.io/gcp-runtimes/container-diff-tests/diff-base"
	diffModified = "gcr.io/gcp-runtimes/container-diff-tests/diff-modified"

	diffLayerBase     = "gcr.io/gcp-runtimes/container-diff-tests/diff-layer-base"
	diffLayerModified = "gcr.io/gcp-runtimes/container-diff-tests/diff-layer-modified"

	metadataBase     = "gcr.io/gcp-runtimes/container-diff-tests/metadata-base"
	metadataModified = "gcr.io/gcp-runtimes/container-diff-tests/metadata-modified"

	aptBase     = "gcr.io/gcp-runtimes/container-diff-tests/apt-base"
	aptModified = "gcr.io/gcp-runtimes/container-diff-tests/apt-modified"

	rpmBase     = "valentinrothberg/containerdiff:diff-base"
	rpmModified = "valentinrothberg/containerdiff:diff-modified"

	// Why is this node-modified:2.0?
	nodeBase     = "gcr.io/gcp-runtimes/container-diff-tests/node-modified:2.0"
	nodeModified = "gcr.io/gcp-runtimes/container-diff-tests/node-modified"

	pipModified = "gcr.io/gcp-runtimes/container-diff-tests/pip-modified"

	multiBase     = "gcr.io/gcp-runtimes/container-diff-tests/multi-base"
	multiModified = "gcr.io/gcp-runtimes/container-diff-tests/multi-modified"

	multiBaseLocal     = "daemon://gcr.io/gcp-runtimes/container-diff-tests/multi-base"
	multiModifiedLocal = "daemon://gcr.io/gcp-runtimes/container-diff-tests/multi-modified"
)

type ContainerDiffRunner struct {
	t          *testing.T
	binaryPath string
}

func (c *ContainerDiffRunner) Run(command ...string) (string, string, error) {
	path, err := filepath.Abs(c.binaryPath)
	if err != nil {
		c.t.Fatalf("Error finding container-diff binary: %s", err)
	}
	c.t.Logf("Running command: %s %s", path, command)
	cmd := exec.Command(path, command...)

	var stdout, stderr bytes.Buffer
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr
	if err := cmd.Run(); err != nil {
		return "", "", fmt.Errorf("Error running command %s: %s Stderr: %s", command, err, stderr.String())
	}
	return stdout.String(), stderr.String(), nil
}

func TestDiffAndAnalysis(t *testing.T) {
	runner := ContainerDiffRunner{
		t:          t,
		binaryPath: "../out/container-diff",
	}

	var tests = []struct {
		description string
		imageA      string
		imageB      string
		differFlags []string
		subcommand  string

		//TODO: Don't consume a json file
		expectedFile string
	}{
		{
			description:  "file differ",
			subcommand:   "diff",
			imageA:       diffBase,
			imageB:       diffModified,
			differFlags:  []string{"--type=file", "--no-cache"},
			expectedFile: "file_diff_expected.json",
		},
		{
			description:  "file layer differ",
			subcommand:   "diff",
			imageA:       diffLayerBase,
			imageB:       diffLayerModified,
			differFlags:  []string{"--type=layer", "--no-cache"},
			expectedFile: "file_layer_diff_expected.json",
		},
		{
			description:  "size differ",
			subcommand:   "diff",
			imageA:       diffLayerBase,
			imageB:       diffLayerModified,
			differFlags:  []string{"--type=size", "--no-cache"},
			expectedFile: "size_diff_expected.json",
		},
		{
			description:  "size layer differ",
			subcommand:   "diff",
			imageA:       diffLayerBase,
			imageB:       diffLayerModified,
			differFlags:  []string{"--type=sizelayer", "--no-cache"},
			expectedFile: "size_layer_diff_expected.json",
		},
		{
			description:  "apt differ",
			subcommand:   "diff",
			imageA:       aptBase,
			imageB:       aptModified,
			differFlags:  []string{"--type=apt", "--no-cache"},
			expectedFile: "apt_diff_expected.json",
		},
		{
			description:  "node differ",
			subcommand:   "diff",
			imageA:       nodeBase,
			imageB:       nodeModified,
			differFlags:  []string{"--type=node", "--no-cache"},
			expectedFile: "node_diff_order_expected.json",
		},
		{
			description:  "multi differ",
			subcommand:   "diff",
			imageA:       multiBase,
			imageB:       multiModified,
			differFlags:  []string{"--type=node", "--type=pip", "--type=apt", "--no-cache"},
			expectedFile: "multi_diff_expected.json",
		},
		{
			description:  "multi differ local",
			subcommand:   "diff",
			imageA:       multiBaseLocal,
			imageB:       multiModifiedLocal,
			differFlags:  []string{"--type=node", "--type=pip", "--type=apt", "--no-cache"},
			expectedFile: "multi_diff_expected.json",
		},
		{
			description:  "history differ",
			subcommand:   "diff",
			imageA:       diffBase,
			imageB:       diffModified,
			differFlags:  []string{"--type=history", "--no-cache"},
			expectedFile: "hist_diff_expected.json",
		},
		{
			description:  "metadata differ",
			subcommand:   "diff",
			imageA:       metadataBase,
			imageB:       metadataModified,
			differFlags:  []string{"--type=metadata", "--no-cache"},
			expectedFile: "metadata_diff_expected.json",
		},
		{
			description:  "apt sorted differ",
			subcommand:   "diff",
			imageA:       aptBase,
			imageB:       aptModified,
			differFlags:  []string{"--type=apt", "-o", "--no-cache"},
			expectedFile: "apt_sorted_diff_expected.json",
		},
		{
			description:  "apt analysis",
			subcommand:   "analyze",
			imageA:       aptModified,
			differFlags:  []string{"--type=apt", "--no-cache"},
			expectedFile: "apt_analysis_expected.json",
		},
		{
			description:  "size analysis",
			subcommand:   "analyze",
			imageA:       diffBase,
			differFlags:  []string{"--type=size", "--no-cache"},
			expectedFile: "size_analysis_expected.json",
		},
		{
			description:  "size layer analysis",
			subcommand:   "analyze",
			imageA:       diffLayerBase,
			differFlags:  []string{"--type=sizelayer", "--no-cache"},
			expectedFile: "size_layer_analysis_expected.json",
		},
		{
			description:  "pip analysis",
			subcommand:   "analyze",
			imageA:       pipModified,
			differFlags:  []string{"--type=pip", "--no-cache"},
			expectedFile: "pip_analysis_expected.json",
		},
		{
			description:  "node analysis",
			subcommand:   "analyze",
			imageA:       nodeModified,
			differFlags:  []string{"--type=node", "--no-cache"},
			expectedFile: "node_analysis_expected.json",
		},
	}
	for _, test := range tests {
		// Capture the range variable for parallel testing.
		test := test
		t.Run(test.description, func(t *testing.T) {
			t.Parallel()
			args := []string{test.subcommand, test.imageA}
			if test.imageB != "" {
				args = append(args, test.imageB)
			}
			args = append(args, test.differFlags...)
			args = append(args, "-j")
			actual, stderr, err := runner.Run(args...)
			if err != nil {
				t.Fatalf("Error running command: %s. Stderr: %s", err, stderr)
			}
			e, err := ioutil.ReadFile(test.expectedFile)
			if err != nil {
				t.Fatalf("Error reading expected file output file: %s", err)
			}
			actual = strings.TrimSpace(actual)
			expected := strings.TrimSpace(string(e))
			if actual != expected {
				t.Errorf("Error actual output does not match expected.  \n\nExpected: %s\n\n Actual: %s\n\n, Stderr: %s", expected, actual, stderr)
			}
		})
	}
}

func newClient() (*client.Client, error) {
	cli, err := client.NewEnvClient()
	if err != nil {
		return nil, fmt.Errorf("Error getting docker client: %s", err)
	}
	cli.NegotiateAPIVersion(context.Background())

	return cli, nil
}

func TestMain(m *testing.M) {
	// setup
	ctx := context.Background()
	cli, _ := newClient()
	closer, err := cli.ImagePull(ctx, multiBase, types.ImagePullOptions{})
	if err != nil {
		fmt.Printf("Error retrieving docker client: %s", err)
		os.Exit(1)
	}
	io.Copy(os.Stdout, closer)

	closer, err = cli.ImagePull(ctx, multiModified, types.ImagePullOptions{})
	if err != nil {
		fmt.Printf("Error retrieving docker client: %s", err)
		os.Exit(1)
	}
	io.Copy(os.Stdout, closer)

	closer.Close()
	os.Exit(m.Run())
}
<|endoftext|>


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

package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"math/rand"
	"sync/atomic"
	"time"

	"github.com/cockroachdb/cockroach/client"
	"github.com/cockroachdb/cockroach/security"
	"github.com/cockroachdb/cockroach/security/securitytest"
	"github.com/cockroachdb/cockroach/server"
	"github.com/cockroachdb/cockroach/util/log"
)

var dbName = flag.String("db-name", "", "Name/URL of the distributed database backend.")
var useTransaction = flag.Bool("use-transaction", true, "Turn off to disable transaction.")

// These two flags configure a range of accounts over which the program functions.
var firstAccount = flag.Int("first-account", 0, "First account in the account range.")
var numAccounts = flag.Int("num-accounts", 1000, "Number of accounts in the account range.")

var numParallelTransfers = flag.Int("num-parallel-transfers", 100, "Number of parallel transfers.")

// Bank stores all the bank related state.
type Bank struct {
	db *client.DB
	// First account in the account range.
	firstAccount int
	// Total number of accounts.
	numAccounts  int
	numTransfers int32
}

// Account holds all the customers account information
type Account struct {
	Balance int64
}

func (a Account) encode() ([]byte, error) {
	return json.Marshal(a)
}

func (a *Account) decode(b []byte) error {
	return json.Unmarshal(b, a)
}

// Makes an id string from an id int.
func (bank *Bank) makeAccountID(id int) []byte {
	return []byte(fmt.Sprintf("%09d", bank.firstAccount+id))
}

// Read the balances in all the accounts and return them.
func (bank *Bank) sumAllAccounts() int64 {
	var result int64
	err := bank.db.Tx(func(tx *client.Tx) error {
		scan, err := tx.Scan(bank.makeAccountID(0), bank.makeAccountID(bank.numAccounts), int64(bank.numAccounts))
		if err != nil {
			return err
		}
		if len(scan.Rows) != bank.numAccounts {
			return fmt.Errorf("Could only read %d of %d rows of the database.\n", len(scan.Rows), bank.numAccounts)
		}
		// Sum up the balances.
		for i := 0; i < bank.numAccounts; i++ {
			account := &Account{}
			err := account.decode(scan.Rows[i].ValueBytes())
			if err != nil {
				return err
			}
			// fmt.Printf("Account %d contains %d$\n", bank.firstAccount+i, account.Balance)
			result += account.Balance
		}
		return nil
	})
	if err != nil {
		log.Fatal(err)
	}
	return result
}

// continuouslyTransferMoney() keeps moving random amounts between
// random accounts.
func (bank *Bank) continuousMoneyTransfer(cash int64) {
	for {
		from := bank.makeAccountID(rand.Intn(bank.numAccounts))
		to := bank.makeAccountID(rand.Intn(bank.numAccounts))
		// Continue when from == to
		if bytes.Equal(from, to) {
			continue
		}
		exchangeAmount := rand.Int63n(cash)
		// transferMoney transfers exchangeAmount between the two accounts
		transferMoney := func(runner client.Runner) error {
			batchRead := &client.Batch{}
			batchRead.Get(from, to)
			if err := runner.Run(batchRead); err != nil {
				return err
			}
			if batchRead.Results[0].Err != nil {
				return batchRead.Results[0].Err
			}
			// Read from value.
			fromAccount := &Account{}
			err := fromAccount.decode(batchRead.Results[0].Rows[0].ValueBytes())
			if err != nil {
				return err
			}
			// Ensure there is enough cash.
			if fromAccount.Balance < exchangeAmount {
				return nil
			}
			// Read to value.
			toAccount := &Account{}
			errRead := toAccount.decode(batchRead.Results[0].Rows[1].ValueBytes())
			if errRead != nil {
				return errRead
			}
			// Update both accounts.
			batchWrite := &client.Batch{}
			fromAccount.Balance -= exchangeAmount
			toAccount.Balance += exchangeAmount
			if fromValue, err := fromAccount.encode(); err != nil {
				return err
			} else if toValue, err := toAccount.encode(); err != nil {
				return err
			} else {
				batchWrite.Put(fromValue, toValue)
			}
			return runner.Run(batchWrite)
		}
		if *useTransaction {
			if err := bank.db.Tx(func(tx *client.Tx) error { return transferMoney(tx) }); err != nil {
				log.Fatal(err)
			}
		} else if err := transferMoney(bank.db); err != nil {
			log.Fatal(err)
		}
		atomic.AddInt32(&bank.numTransfers, 1)
	}
}

// Initialize all the bank accounts with cash.
// When multiple instances of the bank app are running,
// only one gets to initialize the bank.
func (bank *Bank) initBankAccounts(cash int64) {
	if err := bank.db.Tx(func(tx *client.Tx) error {
		// Check if the accounts have been initialized by another instance
		if scan, err := tx.Scan(bank.makeAccountID(0), bank.makeAccountID(bank.numAccounts), int64(bank.numAccounts)); err != nil {
			return err
		} else if len(scan.Rows) == bank.numAccounts {
			log.Warning("accounts have already been initialized")
			return nil
		} else if len(scan.Rows) > 0 {
			// TODO(vivek): recover from this error
			return fmt.Errorf("%d of %d accounts of the database are initialized", len(scan.Rows), bank.numAccounts)
		}
		// Let's initialize all the accounts
		batch := &client.Batch{}
		account := Account{Balance: cash}
		value, err := account.encode()
		if err != nil {
			return err
		}
		for i := 0; i < bank.numAccounts; i++ {
			batch.Put(bank.makeAccountID(i), value)
		}
		if err := tx.Run(batch); err != nil {
			return err
		}
		return nil
	}); err != nil {
		log.Fatal(err)
	}
	log.Info("done initializing all accounts")
}

func (bank *Bank) periodicallyCheckBalances(initCash int64) {
	for {
		// Sleep for a bit to allow money transfers to happen in the background.
		time.Sleep(time.Second)
		fmt.Printf("%d transfers were executed.\n\n", bank.numTransfers)
		// Check that all the money is accounted for.
		totalAmount := bank.sumAllAccounts()
		if totalAmount != int64(bank.numAccounts)*initCash {
			err := fmt.Sprintf("\nTotal cash in the bank = %d.\n", totalAmount)
			log.Fatal(err)
		}
		fmt.Printf("\nThe bank is in good order\n\n")
	}
}

func main() {
	fmt.Printf("A simple program that keeps moving money between bank accounts.\n\n")
	flag.Parse()
	if !*useTransaction {
		fmt.Printf("Use of a transaction has been disabled.\n")
	}
	// Initialize the bank.
	var bank Bank
	bank.firstAccount = *firstAccount
	bank.numAccounts = *numAccounts
	if *dbName == "" {
		// Run a test cockroach instance to represent the bank.
		security.SetReadFileFn(securitytest.Asset)
		serv := server.StartTestServer(nil)
		defer serv.Stop()
		*dbName = "https://root@" + serv.ServingAddr() + "?certs=test_certs"
	}
	// Create a database handle
	db, err := client.Open(*dbName)
	if err != nil {
		log.Fatal(err)
	}
	bank.db = db
	// Initialize all the bank accounts.
	const initCash = 1000
	bank.initBankAccounts(initCash)

	// Start all the money transfer routines.
	for i := 0; i < *numParallelTransfers; i++ {
		// Keep transferring upto 10% of initCash between accounts.
		go bank.continuousMoneyTransfer(initCash / 10)
	}

	bank.periodicallyCheckBalances(initCash)
}
<commit_msg>Fix a bug introduced while moving to the new client API.<commit_after>// Copyright 2015 The Cockroach Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License. See the AUTHORS file
// for names of contributors.
//
// Author: Vivek Menezes (vivek.menezes@gmail.com)

package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"math/rand"
	"sync/atomic"
	"time"

	"github.com/cockroachdb/cockroach/client"
	"github.com/cockroachdb/cockroach/security"
	"github.com/cockroachdb/cockroach/security/securitytest"
	"github.com/cockroachdb/cockroach/server"
	"github.com/cockroachdb/cockroach/util/log"
)

var dbName = flag.String("db-name", "", "Name/URL of the distributed database backend.")
var useTransaction = flag.Bool("use-transaction", true, "Turn off to disable transaction.")

// These two flags configure a range of accounts over which the program functions.
var firstAccount = flag.Int("first-account", 0, "First account in the account range.")
var numAccounts = flag.Int("num-accounts", 1000, "Number of accounts in the account range.")

var numParallelTransfers = flag.Int("num-parallel-transfers", 100, "Number of parallel transfers.")

// Bank stores all the bank related state.
type Bank struct {
	db *client.DB
	// First account in the account range.
	firstAccount int
	// Total number of accounts.
	numAccounts  int
	numTransfers int32
}

// Account holds all the customers account information
type Account struct {
	Balance int64
}

func (a Account) encode() ([]byte, error) {
	return json.Marshal(a)
}

func (a *Account) decode(b []byte) error {
	return json.Unmarshal(b, a)
}

// Makes an id string from an id int.
func (bank *Bank) makeAccountID(id int) []byte {
	return []byte(fmt.Sprintf("%09d", bank.firstAccount+id))
}

// Read the balances in all the accounts and return them.
func (bank *Bank) sumAllAccounts() int64 {
	var result int64
	err := bank.db.Tx(func(tx *client.Tx) error {
		scan, err := tx.Scan(bank.makeAccountID(0), bank.makeAccountID(bank.numAccounts), int64(bank.numAccounts))
		if err != nil {
			return err
		}
		if len(scan.Rows) != bank.numAccounts {
			return fmt.Errorf("Could only read %d of %d rows of the database.\n", len(scan.Rows), bank.numAccounts)
		}
		// Sum up the balances.
		for i := 0; i < bank.numAccounts; i++ {
			account := &Account{}
			err := account.decode(scan.Rows[i].ValueBytes())
			if err != nil {
				return err
			}
			// fmt.Printf("Account %d contains %d$\n", bank.firstAccount+i, account.Balance)
			result += account.Balance
		}
		return nil
	})
	if err != nil {
		log.Fatal(err)
	}
	return result
}

// continuouslyTransferMoney() keeps moving random amounts between
// random accounts.
func (bank *Bank) continuousMoneyTransfer(cash int64) {
	for {
		from := bank.makeAccountID(rand.Intn(bank.numAccounts))
		to := bank.makeAccountID(rand.Intn(bank.numAccounts))
		// Continue when from == to
		if bytes.Equal(from, to) {
			continue
		}
		exchangeAmount := rand.Int63n(cash)
		// transferMoney transfers exchangeAmount between the two accounts
		transferMoney := func(runner client.Runner) error {
			batchRead := &client.Batch{}
			batchRead.Get(from, to)
			if err := runner.Run(batchRead); err != nil {
				return err
			}
			if batchRead.Results[0].Err != nil {
				return batchRead.Results[0].Err
			}
			// Read from value.
			fromAccount := &Account{}
			err := fromAccount.decode(batchRead.Results[0].Rows[0].ValueBytes())
			if err != nil {
				return err
			}
			// Ensure there is enough cash.
			if fromAccount.Balance < exchangeAmount {
				return nil
			}
			// Read to value.
			toAccount := &Account{}
			errRead := toAccount.decode(batchRead.Results[0].Rows[1].ValueBytes())
			if errRead != nil {
				return errRead
			}
			// Update both accounts.
			batchWrite := &client.Batch{}
			fromAccount.Balance -= exchangeAmount
			toAccount.Balance += exchangeAmount
			if fromValue, err := fromAccount.encode(); err != nil {
				return err
			} else if toValue, err := toAccount.encode(); err != nil {
				return err
			} else {
				batchWrite.Put(from, fromValue).Put(to, toValue)
			}
			return runner.Run(batchWrite)
		}
		if *useTransaction {
			if err := bank.db.Tx(func(tx *client.Tx) error { return transferMoney(tx) }); err != nil {
				log.Fatal(err)
			}
		} else if err := transferMoney(bank.db); err != nil {
			log.Fatal(err)
		}
		atomic.AddInt32(&bank.numTransfers, 1)
	}
}

// Initialize all the bank accounts with cash.
// When multiple instances of the bank app are running,
// only one gets to initialize the bank.
func (bank *Bank) initBankAccounts(cash int64) {
	if err := bank.db.Tx(func(tx *client.Tx) error {
		// Check if the accounts have been initialized by another instance
		if scan, err := tx.Scan(bank.makeAccountID(0), bank.makeAccountID(bank.numAccounts), int64(bank.numAccounts)); err != nil {
			return err
		} else if len(scan.Rows) == bank.numAccounts {
			log.Warning("accounts have already been initialized")
			return nil
		} else if len(scan.Rows) > 0 {
			// TODO(vivek): recover from this error
			return fmt.Errorf("%d of %d accounts of the database are initialized", len(scan.Rows), bank.numAccounts)
		}
		// Let's initialize all the accounts
		batch := &client.Batch{}
		account := Account{Balance: cash}
		value, err := account.encode()
		if err != nil {
			return err
		}
		for i := 0; i < bank.numAccounts; i++ {
			batch.Put(bank.makeAccountID(i), value)
		}
		if err := tx.Run(batch); err != nil {
			return err
		}
		return nil
	}); err != nil {
		log.Fatal(err)
	}
	log.Info("done initializing all accounts")
}

func (bank *Bank) periodicallyCheckBalances(initCash int64) {
	for {
		// Sleep for a bit to allow money transfers to happen in the background.
		time.Sleep(time.Second)
		fmt.Printf("%d transfers were executed.\n\n", bank.numTransfers)
		// Check that all the money is accounted for.
		totalAmount := bank.sumAllAccounts()
		if totalAmount != int64(bank.numAccounts)*initCash {
			err := fmt.Sprintf("\nTotal cash in the bank = %d.\n", totalAmount)
			log.Fatal(err)
		}
		fmt.Printf("\nThe bank is in good order\n\n")
	}
}

func main() {
	fmt.Printf("A simple program that keeps moving money between bank accounts.\n\n")
	flag.Parse()
	if !*useTransaction {
		fmt.Printf("Use of a transaction has been disabled.\n")
	}
	// Initialize the bank.
	var bank Bank
	bank.firstAccount = *firstAccount
	bank.numAccounts = *numAccounts
	if *dbName == "" {
		// Run a test cockroach instance to represent the bank.
		security.SetReadFileFn(securitytest.Asset)
		serv := server.StartTestServer(nil)
		defer serv.Stop()
		*dbName = "https://root@" + serv.ServingAddr() + "?certs=test_certs"
	}
	// Create a database handle
	db, err := client.Open(*dbName)
	if err != nil {
		log.Fatal(err)
	}
	bank.db = db
	// Initialize all the bank accounts.
	const initCash = 1000
	bank.initBankAccounts(initCash)

	// Start all the money transfer routines.
	for i := 0; i < *numParallelTransfers; i++ {
		// Keep transferring upto 10% of initCash between accounts.
		go bank.continuousMoneyTransfer(initCash / 10)
	}

	bank.periodicallyCheckBalances(initCash)
}
<|endoftext|>


<commit_before>package core

import "github.com/sclevine/agouti/core/internal/page"

type userPage struct {
	*page.Page
	*userSelection
}

func (u *userPage) SetCookie(cookie WebCookie) error {
	return u.SetCookie(cookie)
}

func (u *userPage) ReadLogs(logType string, all ...bool) ([]Log, error) {
	logs, err := u.Page.ReadLogs(logType, all...)
	if err != nil {
		return nil, err
	}

	var copiedLogs []Log
	for _, log := range logs {
		copiedLogs = append(copiedLogs, Log(log))
	}

	return copiedLogs, nil
}
<commit_msg>Fix core.Page.SetCookie() to point to page.Page.SetCookie()<commit_after>package core

import "github.com/sclevine/agouti/core/internal/page"

type userPage struct {
	*page.Page
	*userSelection
}

func (u *userPage) SetCookie(cookie WebCookie) error {
	return u.Page.SetCookie(cookie)
}

func (u *userPage) ReadLogs(logType string, all ...bool) ([]Log, error) {
	logs, err := u.Page.ReadLogs(logType, all...)
	if err != nil {
		return nil, err
	}

	var copiedLogs []Log
	for _, log := range logs {
		copiedLogs = append(copiedLogs, Log(log))
	}

	return copiedLogs, nil
}
<|endoftext|>


<commit_before>// This is an example program that shows the usage of the memsearch package.
//
// With this program you can:
//   - Search for a string in the memory of a process with a given PID
//   - Print an arbitrary amount of bytes from the process memory.
package main

import (
	"flag"
	"github.com/mozilla/masche/memaccess"
	"github.com/mozilla/masche/memsearch"
	"github.com/mozilla/masche/process"
	"log"
	"regexp"
)

var (
	action = flag.String("action", "<nil>", "Action to perfom. One of: search, regexp-search, print")
	pid    = flag.Int("pid", 0, "Process id to analyze")
	addr   = flag.Int("addr", 0x0, "The initial address in the process address space to search/print")

	// print action flags
	size = flag.Int("n", 4, "Amount of bytes to print")

	// search action flags
	needle = flag.String("needle", "Find This!", "String to search for (interpreted as []byte)")

	// regexp-search action flags
	regexpString = flag.String("regexp", "regexp?", "Regexp to search for")
)

func logErrors(harderror error, softerrors []error) {
	if harderror != nil {
		log.Fatal(harderror)
	}
	for _, soft := range softerrors {
		log.Print(soft)
	}
}

func main() {
	flag.Parse()

	proc, harderror, softerrors := process.OpenFromPid(uint(*pid))
	logErrors(harderror, softerrors)

	switch *action {

	case "<nil>":
		log.Fatal("Missing action flag.")

	case "search":
		found, address, harderror, softerrors := memsearch.FindBytesSequence(proc, uintptr(*addr), []byte(*needle))
		logErrors(harderror, softerrors)
		if found {
			log.Printf("Found in address: %x\n", address)
		}

	case "regexp-search":
		r, err := regexp.Compile(*regexpString)
		if err != nil {
			log.Fatal(err)
		}

		found, address, harderror, softerrors := memsearch.FindRegexpMatch(proc, uintptr(*addr), r)
		logErrors(harderror, softerrors)
		if found {
			log.Printf("Found in address: %x\n", address)
		}

	case "print":
		buf := make([]byte, *size)
		harderror, softerrors = memaccess.CopyMemory(proc, uintptr(*addr), buf)
		logErrors(harderror, softerrors)
		log.Println(string(buf))

	default:
		log.Fatal("Unrecognized action ", *action)
	}
}
<commit_msg>[examples] Add memsearch's file-search action<commit_after>// This is an example program that shows the usage of the memsearch package.
//
// With this program you can:
//   - Search for a string in the memory of a process with a given PID
//   - Print an arbitrary amount of bytes from the process memory.
package main

import (
	"encoding/hex"
	"flag"
	"io/ioutil"
	"log"
	"regexp"
	"strings"

	"github.com/mozilla/masche/memaccess"
	"github.com/mozilla/masche/memsearch"
	"github.com/mozilla/masche/process"
)

var (
	action = flag.String("action", "<nil>", "Action to perfom. One of: search, regexp-search, file-search, print")
	pid    = flag.Int("pid", 0, "Process id to analyze")
	addr   = flag.Int("addr", 0x0, "The initial address in the process address space to search/print")

	// print action flags
	size = flag.Int("n", 4, "Amount of bytes to print")

	// search action flags
	needle = flag.String("needle", "Find This!", "String to search for (interpreted as []byte)")

	// regexp-search action flags
	regexpString = flag.String("regexp", "regexp?", "Regexp to search for")

	// file-search action flags
	fileneedle = flag.String("fileneedle", "example.in", "Filename that contains hex-encoded needle (spaces are ignored)")
)

func logErrors(harderror error, softerrors []error) {
	if harderror != nil {
		log.Fatal(harderror)
	}
	for _, soft := range softerrors {
		log.Print(soft)
	}
}

func main() {
	flag.Parse()

	proc, harderror, softerrors := process.OpenFromPid(uint(*pid))
	logErrors(harderror, softerrors)

	switch *action {

	case "<nil>":
		log.Fatal("Missing action flag.")
	case "file-search":
		data, err := ioutil.ReadFile(*fileneedle)
		if err != nil {
			log.Fatal(err)
		}
		encoded := strings.Replace(strings.TrimSpace(string(data)), " ", "", -1)
		data, err = hex.DecodeString(encoded)
		if err != nil {
			log.Fatal(err)
		}
		found, address, harderror, softerrors := memsearch.FindBytesSequence(proc, uintptr(*addr), data)
		logErrors(harderror, softerrors)
		if found {
			log.Printf("Found in address: %x\n", address)
		}

	case "search":
		found, address, harderror, softerrors := memsearch.FindBytesSequence(proc, uintptr(*addr), []byte(*needle))
		logErrors(harderror, softerrors)
		if found {
			log.Printf("Found in address: %x\n", address)
		}

	case "regexp-search":
		r, err := regexp.Compile(*regexpString)
		if err != nil {
			log.Fatal(err)
		}

		found, address, harderror, softerrors := memsearch.FindRegexpMatch(proc, uintptr(*addr), r)
		logErrors(harderror, softerrors)
		if found {
			log.Printf("Found in address: %x\n", address)
		}

	case "print":
		buf := make([]byte, *size)
		harderror, softerrors = memaccess.CopyMemory(proc, uintptr(*addr), buf)
		logErrors(harderror, softerrors)
		log.Println(string(buf))

	default:
		log.Fatal("Unrecognized action ", *action)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"os"
)

import "github.com/derdon/ini"

func main() {
	filename := "example.ini"
	file, err := os.Open(filename)
	if err != nil {
		panic(fmt.Sprintf("Error: could not read %s. %s", filename, err))
	}
	reader := bufio.NewReader(file)
	linereader := ini.NewLineReader(reader)
	conf, err := ini.ParseINI(linereader)
	if err != nil {
		panic(fmt.Sprintf("Error: could not parse ini file. %s", err))
	}
	fmt.Printf("%#v\n", *conf)
}
<commit_msg>close the file after having parsed it<commit_after>package main

import (
	"bufio"
	"fmt"
	"os"
)

import "github.com/derdon/ini"

func main() {
	filename := "example.ini"
	file, err := os.Open(filename)
	if err != nil {
		panic(fmt.Sprintf("Error: could not read %s. %s", filename, err))
	}
	defer f.Close()
	reader := bufio.NewReader(file)
	linereader := ini.NewLineReader(reader)
	conf, err := ini.ParseINI(linereader)
	if err != nil {
		panic(fmt.Sprintf("Error: could not parse ini file. %s", err))
	}
	fmt.Printf("%#v\n", *conf)
}
<|endoftext|>


<commit_before>// Copyright 2020 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.

// +build !disable_events

package event_test

import (
	"context"
	"fmt"
	"strings"
	"testing"

	"github.com/google/go-cmp/cmp"
	"golang.org/x/exp/event"
	"golang.org/x/exp/event/keys"
)

func TestClone(t *testing.T) {
	var labels []event.Label
	for i := 0; i < 5; i++ { // one greater than len(Builder.labels)
		labels = append(labels, keys.Int(fmt.Sprintf("l%d", i)).Of(i))
	}

	ctx := event.WithExporter(context.Background(), event.NewExporter(event.NopHandler{}, nil))
	b1 := event.To(ctx)
	b1.With(labels[0]).With(labels[1])
	check(t, b1, labels[:2])
	b2 := b1.Clone()
	check(t, b1, labels[:2])
	check(t, b2, labels[:2])

	b2.With(labels[2])
	check(t, b1, labels[:2])
	check(t, b2, labels[:3])

	// Force a new backing array for b.Event.Labels.
	for i := 3; i < len(labels); i++ {
		b2.With(labels[i])
	}
	check(t, b1, labels[:2])
	check(t, b2, labels)

	b2.Log("") // put b2 back in the pool.
	b2 = event.To(ctx)
	check(t, b1, labels[:2])
	check(t, b2, []event.Label{})

	b2.With(labels[3]).With(labels[4])
	check(t, b1, labels[:2])
	check(t, b2, labels[3:5])
}

func check(t *testing.T, b event.Builder, want []event.Label) {
	t.Helper()
	if got := b.Event().Labels; !cmp.Equal(got, want, cmp.Comparer(valueEqual)) {
		t.Fatalf("got %v, want %v", got, want)
	}
}

func valueEqual(l1, l2 event.Value) bool {
	return fmt.Sprint(l1) == fmt.Sprint(l2)
}

func TestTraceBuilder(t *testing.T) {
	// Verify that the context returned from the handler is also returned from Start,
	// and is the context passed to End.
	ctx := event.WithExporter(context.Background(), event.NewExporter(&testTraceHandler{t}, nil))
	ctx, end := event.To(ctx).Start("s")
	val := ctx.Value("x")
	if val != 1 {
		t.Fatal("context not returned from Start")
	}
	end()
}

type testTraceHandler struct {
	t *testing.T
}

func (*testTraceHandler) Log(ctx context.Context, _ *event.Event)      {}
func (*testTraceHandler) Annotate(ctx context.Context, _ *event.Event) {}
func (*testTraceHandler) Metric(ctx context.Context, _ *event.Event)   {}

func (*testTraceHandler) Start(ctx context.Context, _ *event.Event) context.Context {
	return context.WithValue(ctx, "x", 1)
}

func (t *testTraceHandler) End(ctx context.Context, _ *event.Event) {
	val := ctx.Value("x")
	if val != 1 {
		t.t.Fatal("Start context not passed to End")
	}
}

func TestFailToClone(t *testing.T) {
	ctx := event.WithExporter(context.Background(), event.NewExporter(event.NopHandler{}, nil))

	catch := func(f func()) {
		defer func() {
			r := recover()
			if r == nil {
				t.Error("expected panic, did not get one")
				return
			}
			got, ok := r.(string)
			if !ok || !strings.Contains(got, "Clone") {
				t.Errorf("got panic(%v), want string with 'Clone'", r)
			}
		}()

		f()
	}

	catch(func() {
		b1 := event.To(ctx)
		b1.Log("msg1")
		// Reuse of Builder without Clone; b1.data has been cleared.
		b1.Log("msg2")
	})

	catch(func() {
		b1 := event.To(ctx)
		b1.Log("msg1")
		_ = event.To(ctx) // re-allocate the builder
		// b1.data is populated, but with the wrong information.
		b1.Log("msg2")
	})
}
<commit_msg>event: add benchmarks for context lookups<commit_after>// Copyright 2020 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.

// +build !disable_events

package event_test

import (
	"context"
	"fmt"
	"strings"
	"testing"

	"github.com/google/go-cmp/cmp"
	"golang.org/x/exp/event"
	"golang.org/x/exp/event/keys"
)

func TestClone(t *testing.T) {
	var labels []event.Label
	for i := 0; i < 5; i++ { // one greater than len(Builder.labels)
		labels = append(labels, keys.Int(fmt.Sprintf("l%d", i)).Of(i))
	}

	ctx := event.WithExporter(context.Background(), event.NewExporter(event.NopHandler{}, nil))
	b1 := event.To(ctx)
	b1.With(labels[0]).With(labels[1])
	check(t, b1, labels[:2])
	b2 := b1.Clone()
	check(t, b1, labels[:2])
	check(t, b2, labels[:2])

	b2.With(labels[2])
	check(t, b1, labels[:2])
	check(t, b2, labels[:3])

	// Force a new backing array for b.Event.Labels.
	for i := 3; i < len(labels); i++ {
		b2.With(labels[i])
	}
	check(t, b1, labels[:2])
	check(t, b2, labels)

	b2.Log("") // put b2 back in the pool.
	b2 = event.To(ctx)
	check(t, b1, labels[:2])
	check(t, b2, []event.Label{})

	b2.With(labels[3]).With(labels[4])
	check(t, b1, labels[:2])
	check(t, b2, labels[3:5])
}

func check(t *testing.T, b event.Builder, want []event.Label) {
	t.Helper()
	if got := b.Event().Labels; !cmp.Equal(got, want, cmp.Comparer(valueEqual)) {
		t.Fatalf("got %v, want %v", got, want)
	}
}

func valueEqual(l1, l2 event.Value) bool {
	return fmt.Sprint(l1) == fmt.Sprint(l2)
}

func TestTraceBuilder(t *testing.T) {
	// Verify that the context returned from the handler is also returned from Start,
	// and is the context passed to End.
	ctx := event.WithExporter(context.Background(), event.NewExporter(&testTraceHandler{t}, nil))
	ctx, end := event.To(ctx).Start("s")
	val := ctx.Value("x")
	if val != 1 {
		t.Fatal("context not returned from Start")
	}
	end()
}

type testTraceHandler struct {
	t *testing.T
}

func (*testTraceHandler) Log(ctx context.Context, _ *event.Event)      {}
func (*testTraceHandler) Annotate(ctx context.Context, _ *event.Event) {}
func (*testTraceHandler) Metric(ctx context.Context, _ *event.Event)   {}

func (*testTraceHandler) Start(ctx context.Context, _ *event.Event) context.Context {
	return context.WithValue(ctx, "x", 1)
}

func (t *testTraceHandler) End(ctx context.Context, _ *event.Event) {
	val := ctx.Value("x")
	if val != 1 {
		t.t.Fatal("Start context not passed to End")
	}
}

func TestFailToClone(t *testing.T) {
	ctx := event.WithExporter(context.Background(), event.NewExporter(event.NopHandler{}, nil))

	catch := func(f func()) {
		defer func() {
			r := recover()
			if r == nil {
				t.Error("expected panic, did not get one")
				return
			}
			got, ok := r.(string)
			if !ok || !strings.Contains(got, "Clone") {
				t.Errorf("got panic(%v), want string with 'Clone'", r)
			}
		}()

		f()
	}

	catch(func() {
		b1 := event.To(ctx)
		b1.Log("msg1")
		// Reuse of Builder without Clone; b1.data has been cleared.
		b1.Log("msg2")
	})

	catch(func() {
		b1 := event.To(ctx)
		b1.Log("msg1")
		_ = event.To(ctx) // re-allocate the builder
		// b1.data is populated, but with the wrong information.
		b1.Log("msg2")
	})
}

func BenchmarkBuildContext(b *testing.B) {
	// How long does it take to deliver an event from a nested context?
	for _, depth := range []int{1, 5, 7, 10} {
		b.Run(fmt.Sprintf("depth %d", depth), func(b *testing.B) {
			ctx := event.WithExporter(context.Background(), event.NewExporter(event.NopHandler{}, nil))
			for i := 0; i < depth; i++ {
				ctx = context.WithValue(ctx, i, i)
			}
			b.Run("direct", func(b *testing.B) {
				for i := 0; i < b.N; i++ {
					event.To(ctx).With(event.Name.Of("foo")).Metric()
				}
			})
			b.Run("cloned", func(b *testing.B) {
				bu := event.To(ctx)
				for i := 0; i < b.N; i++ {
					bu.Clone().With(event.Name.Of("foo")).Metric()
				}
			})
		})
	}
}
<|endoftext|>


<commit_before>package acceptance

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"net/http/httputil"
	"os"
	"os/exec"
	"path/filepath"
	"time"

	"github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("import-installation command", func() {
	var (
		installation                string
		passphrase                  string
		content                     *os.File
		server                      *httptest.Server
		ensureAvailabilityCallCount int
	)

	BeforeEach(func() {
		var err error
		content, err = ioutil.TempFile("", "cool_name.com")
		Expect(err).NotTo(HaveOccurred())

		_, err = content.WriteString("content so validation does not fail")
		Expect(err).NotTo(HaveOccurred())

		ensureAvailabilityCallCount = 0

		server = httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
			var responseString string
			w.Header().Set("Content-Type", "application/json")

			switch req.URL.Path {
			case "/login/ensure_availability":
				if ensureAvailabilityCallCount < 2 {
					w.Header().Set("Location", "/setup")
					w.WriteHeader(http.StatusFound)
				} else {
					w.Header().Set("Location", "/auth/cloudfoundry")
					w.WriteHeader(http.StatusFound)
				}
				ensureAvailabilityCallCount++
			case "/api/v0/installation_asset_collection":
				err := req.ParseMultipartForm(100)
				Expect(err).NotTo(HaveOccurred())

				installation = req.MultipartForm.File["installation[file]"][0].Filename
				passphrase = req.MultipartForm.Value["passphrase"][0]
				responseString = "{}"
				time.Sleep(2 * time.Second)
			default:
				out, err := httputil.DumpRequest(req, true)
				Expect(err).NotTo(HaveOccurred())
				Fail(fmt.Sprintf("unexpected request: %s", out))
			}

			w.Write([]byte(responseString))
		}))
	})

	AfterEach(func() {
		os.Remove(content.Name())
	})

	It("successfully uploads an installation to the Ops Manager", func() {
		command := exec.Command(pathToMain,
			"--target", server.URL,
			"--skip-ssl-validation",
			"import-installation",
			"--installation", content.Name(),
			"--decryption-passphrase", "fake-passphrase",
		)

		session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
		Expect(err).NotTo(HaveOccurred())

		Eventually(session, 5).Should(gexec.Exit(0))
		Eventually(session.Out, 5).Should(gbytes.Say("processing installation"))
		Eventually(session.Out, 5).Should(gbytes.Say("beginning installation import to Ops Manager"))
		Eventually(session.Out, 5).Should(gbytes.Say("finished import"))

		Expect(installation).To(Equal(filepath.Base(content.Name())))
		Expect(passphrase).To(Equal("fake-passphrase"))
	})

	Context("when the ops manager is already configured", func() {
		BeforeEach(func() {
			server = httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
				var responseString string
				w.Header().Set("Content-Type", "application/json")

				switch req.URL.Path {
				case "/login/ensure_availability":
					w.Header().Set("Location", "/auth/cloudfoundry")
					w.WriteHeader(http.StatusFound)
				default:
					out, err := httputil.DumpRequest(req, true)
					Expect(err).NotTo(HaveOccurred())
					Fail(fmt.Sprintf("unexpected request: %s", out))
				}

				w.Write([]byte(responseString))
			}))
		})

		It("returns an error", func() {
			command := exec.Command(pathToMain,
				"--target", server.URL,
				"--skip-ssl-validation",
				"import-installation",
				"--installation", content.Name(),
				"--decryption-passphrase", "fake-passphrase",
			)

			session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
			Expect(err).NotTo(HaveOccurred())

			Eventually(session, 5).Should(gexec.Exit(1))
			Eventually(session.Out, 5).Should(gbytes.Say("cannot import installation to an Ops Manager that is already configured"))
		})
	})

	Context("when an error occurs", func() {
		Context("when the content to upload is empty", func() {
			var emptyContent *os.File

			BeforeEach(func() {
				var err error
				emptyContent, err = ioutil.TempFile("", "")
				Expect(err).NotTo(HaveOccurred())
			})

			AfterEach(func() {
				err := os.Remove(emptyContent.Name())
				Expect(err).NotTo(HaveOccurred())
			})

			It("returns an error", func() {
				command := exec.Command(pathToMain,
					"--target", server.URL,
					"--skip-ssl-validation",
					"import-installation",
					"--installation", emptyContent.Name(),
					"--decryption-passphrase", "fake-passphrase",
				)

				session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
				Expect(err).NotTo(HaveOccurred())

				Eventually(session, 5).Should(gexec.Exit(1))
				Eventually(session.Out, 5).Should(gbytes.Say("failed to load installation: file provided has no content"))
			})
		})

		Context("when the content cannot be read", func() {
			BeforeEach(func() {
				err := os.Remove(content.Name())
				Expect(err).NotTo(HaveOccurred())
			})

			It("returns an error", func() {
				command := exec.Command(pathToMain,
					"--target", server.URL,
					"--skip-ssl-validation",
					"import-installation",
					"--installation", content.Name(),
					"--decryption-passphrase", "fake-passphrase",
				)

				session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
				Expect(err).NotTo(HaveOccurred())

				Eventually(session, 5).Should(gexec.Exit(1))
				Eventually(session.Out, 5).Should(gbytes.Say(`no such file or directory`))
			})
		})
	})
})
<commit_msg>Incorrect response to error<commit_after>package acceptance

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"net/http/httputil"
	"os"
	"os/exec"
	"path/filepath"
	"time"

	"github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("import-installation command", func() {
	var (
		installation                string
		passphrase                  string
		content                     *os.File
		server                      *httptest.Server
		ensureAvailabilityCallCount int
	)

	BeforeEach(func() {
		var err error
		content, err = ioutil.TempFile("", "cool_name.com")
		Expect(err).NotTo(HaveOccurred())

		_, err = content.WriteString("content so validation does not fail")
		Expect(err).NotTo(HaveOccurred())

		ensureAvailabilityCallCount = 0

		server = httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
			var responseString string
			w.Header().Set("Content-Type", "application/json")

			switch req.URL.Path {
			case "/login/ensure_availability":
				if ensureAvailabilityCallCount < 2 {
					w.Header().Set("Location", "/setup")
					w.WriteHeader(http.StatusFound)
				} else {
					w.Header().Set("Location", "/auth/cloudfoundry")
					w.WriteHeader(http.StatusFound)
				}
				ensureAvailabilityCallCount++
			case "/api/v0/installation_asset_collection":
				err := req.ParseMultipartForm(100)
				Expect(err).NotTo(HaveOccurred())

				installation = req.MultipartForm.File["installation[file]"][0].Filename
				passphrase = req.MultipartForm.Value["passphrase"][0]
				responseString = "{}"
				time.Sleep(2 * time.Second)
			default:
				out, err := httputil.DumpRequest(req, true)
				Expect(err).NotTo(HaveOccurred())
				Fail(fmt.Sprintf("unexpected request: %s", out))
			}

			w.Write([]byte(responseString))
		}))
	})

	AfterEach(func() {
		os.Remove(content.Name())
	})

	It("successfully uploads an installation to the Ops Manager", func() {
		command := exec.Command(pathToMain,
			"--target", server.URL,
			"--skip-ssl-validation",
			"import-installation",
			"--installation", content.Name(),
			"--decryption-passphrase", "fake-passphrase",
		)

		session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
		Expect(err).NotTo(HaveOccurred())

		Eventually(session, 5).Should(gexec.Exit(0))
		Eventually(session.Out, 5).Should(gbytes.Say("processing installation"))
		Eventually(session.Out, 5).Should(gbytes.Say("beginning installation import to Ops Manager"))
		Eventually(session.Out, 5).Should(gbytes.Say("finished import"))

		Expect(installation).To(Equal(filepath.Base(content.Name())))
		Expect(passphrase).To(Equal("fake-passphrase"))
	})

	Context("when the ops manager is already configured", func() {
		BeforeEach(func() {
			server = httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
				var responseString string
				w.Header().Set("Content-Type", "application/json")

				switch req.URL.Path {
				case "/login/ensure_availability":
					w.Header().Set("Location", "/auth/cloudfoundry")
					w.WriteHeader(http.StatusFound)
				default:
					out, err := httputil.DumpRequest(req, true)
					Expect(err).NotTo(HaveOccurred())
					Fail(fmt.Sprintf("unexpected request: %s", out))
				}

				w.Write([]byte(responseString))
			}))
		})

		It("returns an error", func() {
			command := exec.Command(pathToMain,
				"--target", server.URL,
				"--skip-ssl-validation",
				"import-installation",
				"--installation", content.Name(),
				"--decryption-passphrase", "fake-passphrase",
			)

			session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
			Expect(err).NotTo(HaveOccurred())

			Eventually(session, 5).Should(gexec.Exit(1))
			Eventually(session.Out, 5).Should(gbytes.Say("cannot import installation to an Ops Manager that is already configured"))
		})
	})

	Context("when an error occurs", func() {
		Context("when the content to upload is empty", func() {
			var emptyContent *os.File

			BeforeEach(func() {
				var err error
				emptyContent, err = ioutil.TempFile("", "")
				Expect(err).NotTo(HaveOccurred())
			})

			AfterEach(func() {
				err := os.Remove(emptyContent.Name())
				Expect(err).NotTo(HaveOccurred())
			})

			It("returns an error", func() {
				command := exec.Command(pathToMain,
					"--target", server.URL,
					"--skip-ssl-validation",
					"import-installation",
					"--installation", emptyContent.Name(),
					"--decryption-passphrase", "fake-passphrase",
				)

				session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
				Expect(err).NotTo(HaveOccurred())

				Eventually(session, 5).Should(gexec.Exit(1))
				Eventually(session.Out, 5).Should(gbytes.Say("failed to load installation: file provided has no content"))
			})
		})

		Context("when the content cannot be read", func() {
			BeforeEach(func() {
				err := os.Remove(content.Name())
				Expect(err).NotTo(HaveOccurred())
			})

			It("returns an error", func() {
				command := exec.Command(pathToMain,
					"--target", server.URL,
					"--skip-ssl-validation",
					"import-installation",
					"--installation", content.Name(),
					"--decryption-passphrase", "fake-passphrase",
				)

				session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
				Expect(err).NotTo(HaveOccurred())

				Eventually(session, 5).Should(gexec.Exit(1))
				Eventually(session.Out, 5).Should(gbytes.Say(`no such file or directory`))
			})
		})

		Context("when server is not available", func() {
			server_nonlistening := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
				var responseString string
				w.Header().Set("Content-Type", "application/json")
				w.Write([]byte(responseString))
			}))
			It("should return appropriate error", func() {
				command := exec.Command(pathToMain,
					"--target", server_nonlistening.URL,
					"--skip-ssl-validation",
					"import-installation",
					"--installation", content.Name(),
					"--decryption-passphrase", "fake-passphrase",
				)

				session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
				Expect(err).NotTo(HaveOccurred())
				Eventually(session, 5).Should(gexec.Exit(1))
				Eventually(session.Out, 5).ShouldNot(gbytes.Say("cannot import installation to an Ops Manager that is already configured"))
			})
		})
	})
})
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"math/rand"
	"os"
	"testing"
	"time"

	"github.com/keybase/client/go/libkb"
	bserver "github.com/keybase/kbfs/bserver"
)

var BServerRemoteAddr *string

func TestMain(m *testing.M) {

	log.SetFlags(log.LstdFlags | log.Lshortfile)

	libkb.G.Init()
	libkb.G.ConfigureConfig()
	libkb.G.ConfigureLogging()
	libkb.G.ConfigureSocketInfo()

	rand.Seed(time.Now().UnixNano())

	useRemote := flag.Bool("kbfs.bserverRemote", false, "which bserver to use, local or remote")
	flag.Parse()

	if *useRemote {
		BServerRemoteAddr = &bserver.Config.BServerAddr
		fmt.Printf("Testing Using Remote Backend: %s\n", bserver.Config.BServerAddr)
		bserver.InitConfig("../bserver/testconfig.json")
		bserver.Config.TestNoSession = true
		bserver.StartBServer(nil)
	}

	os.Exit(m.Run())
}
<commit_msg>kbfsfuse: fix bserver test compilation<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"math/rand"
	"os"
	"testing"
	"time"

	"github.com/keybase/client/go/libkb"
	bserver "github.com/keybase/kbfs/bserver"
)

var BServerRemoteAddr *string

func TestMain(m *testing.M) {

	log.SetFlags(log.LstdFlags | log.Lshortfile)

	libkb.G.Init()
	libkb.G.ConfigureConfig()
	libkb.G.ConfigureLogging()
	libkb.G.ConfigureSocketInfo()

	rand.Seed(time.Now().UnixNano())

	useRemote := flag.Bool("kbfs.bserverRemote", false, "which bserver to use, local or remote")
	flag.Parse()

	if *useRemote {
		BServerRemoteAddr = &bserver.Config.BServerAddr
		fmt.Printf("Testing Using Remote Backend: %s\n", bserver.Config.BServerAddr)
		bserver.InitConfig("../bserver/testconfig.json")
		bserver.Config.TestNoSession = true
		bserver.StartBServer()
	}

	os.Exit(m.Run())
}
<|endoftext|>


<commit_before>package kdtree

import (
	"testing"

	"github.com/sjwhitworth/golearn/metrics/pairwise"
	. "github.com/smartystreets/goconvey/convey"
)

func TestKdtree(t *testing.T) {
	kd := New()

	Convey("Given a kdtree", t, func() {
		data := [][]float64{{2, 3}, {5, 4}, {4, 7}, {8, 1}, {7, 2}, {9, 6}}
		kd.Build(data)
		euclidean := pairwise.NewEuclidean()

		Convey("When k is 3 with euclidean", func() {
			result, _, _ := kd.Search(3, euclidean, []float64{7, 3})

			Convey("The result[0] should be 4", func() {
				So(result[0], ShouldEqual, 4)
			})
			Convey("The result[1] should be 3", func() {
				So(result[1], ShouldEqual, 3)
			})
			Convey("The result[2] should be 1", func() {
				So(result[2], ShouldEqual, 1)
			})
		})

		Convey("When k is 2 with euclidean", func() {
			result, _, _ := kd.Search(2, euclidean, []float64{7, 3})

			Convey("The result[0] should be 4", func() {
				So(result[0], ShouldEqual, 4)
			})
			Convey("The result[1] should be 1", func() {
				So(result[1], ShouldEqual, 1)
			})
		})

	})
}
<commit_msg>ci test<commit_after>package kdtree

import (
	"testing"

	"github.com/sjwhitworth/golearn/metrics/pairwise"
	. "github.com/smartystreets/goconvey/convey"
)

func TestKdtree(t *testing.T) {
	kd := New()

	Convey("Given a kdtree", t, func() {
		data := [][]float64{{2, 3}, {5, 4}, {4, 7}, {8, 1}, {7, 2}, {9, 6}}
		kd.Build(data)
		euclidean := pairwise.NewEuclidean()

		Convey("When k is 3 with euclidean", func() {
			result, _, _ := kd.Search(3, euclidean, []float64{7, 3})

			Convey("The result[0] should be 4", func() {
				So(result[0], ShouldEqual, 4)
			})
			Convey("The result[1] should be 3", func() {
				So(result[1], ShouldEqual, 3)
			})
			Convey("The result[2] should be 1", func() {
				So(result[2], ShouldEqual, 1)
			})
		})

		Convey("When k is 2 with euclidean ", func() {
			result, _, _ := kd.Search(2, euclidean, []float64{7, 3})

			Convey("The result[0] should be 4", func() {
				So(result[0], ShouldEqual, 4)
			})
			Convey("The result[1] should be 1", func() {
				So(result[1], ShouldEqual, 1)
			})
		})

	})
}
<|endoftext|>


<commit_before>package statsd

import (
	"fmt"
	"log"
	"math/rand"
	"net"
	"time"
)

// The StatsdClient type defines the relevant properties of a StatsD connection.
type StatsdClient struct {
	Host string
	Port int
	conn net.Conn
}

// Factory method to initialize udp connection
//
// Usage:
//
//     import "statsd"
//     client := statsd.New('localhost', 8125)
func New(host string, port int) *StatsdClient {
	client := StatsdClient{Host: host, Port: port}
	client.Open()
	return &client
}

// Method to open udp connection, called by default client factory
func (client *StatsdClient) Open() {
	connectionString := fmt.Sprintf("%s:%d", client.Host, client.Port)
	conn, err := net.Dial("udp", connectionString)
	if err != nil {
		log.Println(err)
	}
	client.conn = conn
}

// Method to close udp connection
func (client *StatsdClient) Close() {
	client.conn.Close()
}

// Log timing information (in milliseconds) without sampling
//
// Usage:
//
//     import (
//         "statsd"
//         "time"
//     )
//
//     client := statsd.New('localhost', 8125)
//     t1 := time.Now()
//     expensiveCall()
//     t2 := time.Now()
//     duration := int64(t2.Sub(t1)/time.Millisecond)
//     client.Timing("foo.time", duration)
func (client *StatsdClient) Timing(stat string, time int64) {
	updateString := fmt.Sprintf("%d|ms", time)
	stats := map[string]string{stat: updateString}
	client.Send(stats, 1)
}

// Log timing information (in milliseconds) with sampling
//
// Usage:
//
//     import (
//         "statsd"
//         "time"
//     )
//
//     client := statsd.New('localhost', 8125)
//     t1 := time.Now()
//     expensiveCall()
//     t2 := time.Now()
//     duration := int64(t2.Sub(t1)/time.Millisecond)
//     client.TimingWithSampleRate("foo.time", duration, 0.2)
func (client *StatsdClient) TimingWithSampleRate(stat string, time int64, sampleRate float32) {
	updateString := fmt.Sprintf("%d|ms", time)
	stats := map[string]string{stat: updateString}
	client.Send(stats, sampleRate)
}

// Increments one stat counter without sampling
//
// Usage:
//
//     import "statsd"
//     client := statsd.New('localhost', 8125)
//     client.Increment('foo.bar')
func (client *StatsdClient) Increment(stat string) {
	stats := []string{stat}
	client.UpdateStats(stats, 1, 1)
}

// Increments one stat counter by value provided without sampling
//
// Usage:
//
//     import "statsd"
//     client := statsd.New('localhost', 8125)
//     client.Increment('foo.bar', 5)
func (client *StatsdClient) IncrementByValue(stat string, val int) {
	stats := []string{stat}
	client.UpdateStats(stats, val, 1)
}

// Increments one stat counter with sampling
//
// Usage:
//
//     import "statsd"
//     client := statsd.New('localhost', 8125)
//     client.Increment('foo.bar', 0.2)
func (client *StatsdClient) IncrementWithSampling(stat string, sampleRate float32) {
	stats := []string{stat}
	client.UpdateStats(stats[:], 1, sampleRate)
}

// Decrements one stat counter without sampling
//
// Usage:
//
//     import "statsd"
//     client := statsd.New('localhost', 8125)
//     client.Decrement('foo.bar')
func (client *StatsdClient) Decrement(stat string) {
	stats := []string{stat}
	client.UpdateStats(stats[:], -1, 1)
}

// Decrements one stat counter with sampling
//
// Usage:
//
//     import "statsd"
//     client := statsd.New('localhost', 8125)
//     client.Decrement('foo.bar', 0.2)
func (client *StatsdClient) DecrementWithSampling(stat string, sampleRate float32) {
	stats := []string{stat}
	client.UpdateStats(stats[:], -1, sampleRate)
}

// Arbitrarily updates a list of stats by a delta
func (client *StatsdClient) UpdateStats(stats []string, delta int, sampleRate float32) {
	statsToSend := make(map[string]string)
	for _, stat := range stats {
		updateString := fmt.Sprintf("%d|c", delta)
		statsToSend[stat] = updateString
	}
	client.Send(statsToSend, sampleRate)
}

// Sends data to udp statsd daemon
func (client *StatsdClient) Send(data map[string]string, sampleRate float32) {
	sampledData := make(map[string]string)
	if sampleRate < 1 {
		r := rand.New(rand.NewSource(time.Now().Unix()))
		rNum := r.Float32()
		if rNum <= sampleRate {
			for stat, value := range data {
				sampledUpdateString := fmt.Sprintf("%s|@%f", value, sampleRate)
				sampledData[stat] = sampledUpdateString
			}
		}
	} else {
		sampledData = data
	}

	for k, v := range sampledData {
		update_string := fmt.Sprintf("%s:%s", k, v)
		_, err := fmt.Fprintf(client.conn, update_string)
		if err != nil {
			log.Println(err)
		}
	}
}
<commit_msg>IncrementByValue method added<commit_after>package statsd

import (
	"fmt"
	"log"
	"math/rand"
	"net"
	"time"
)

// The StatsdClient type defines the relevant properties of a StatsD connection.
type StatsdClient struct {
	Host string
	Port int
	conn net.Conn
}

// Factory method to initialize udp connection
//
// Usage:
//
//     import "statsd"
//     client := statsd.New('localhost', 8125)
func New(host string, port int) *StatsdClient {
	client := StatsdClient{Host: host, Port: port}
	client.Open()
	return &client
}

// Method to open udp connection, called by default client factory
func (client *StatsdClient) Open() {
	connectionString := fmt.Sprintf("%s:%d", client.Host, client.Port)
	conn, err := net.Dial("udp", connectionString)
	if err != nil {
		log.Println(err)
	}
	client.conn = conn
}

// Method to close udp connection
func (client *StatsdClient) Close() {
	client.conn.Close()
}

// Log timing information (in milliseconds) without sampling
//
// Usage:
//
//     import (
//         "statsd"
//         "time"
//     )
//
//     client := statsd.New('localhost', 8125)
//     t1 := time.Now()
//     expensiveCall()
//     t2 := time.Now()
//     duration := int64(t2.Sub(t1)/time.Millisecond)
//     client.Timing("foo.time", duration)
func (client *StatsdClient) Timing(stat string, time int64) {
	updateString := fmt.Sprintf("%d|ms", time)
	stats := map[string]string{stat: updateString}
	client.Send(stats, 1)
}

// Log timing information (in milliseconds) with sampling
//
// Usage:
//
//     import (
//         "statsd"
//         "time"
//     )
//
//     client := statsd.New('localhost', 8125)
//     t1 := time.Now()
//     expensiveCall()
//     t2 := time.Now()
//     duration := int64(t2.Sub(t1)/time.Millisecond)
//     client.TimingWithSampleRate("foo.time", duration, 0.2)
func (client *StatsdClient) TimingWithSampleRate(stat string, time int64, sampleRate float32) {
	updateString := fmt.Sprintf("%d|ms", time)
	stats := map[string]string{stat: updateString}
	client.Send(stats, sampleRate)
}

// Increments one stat counter without sampling
//
// Usage:
//
//     import "statsd"
//     client := statsd.New('localhost', 8125)
//     client.Increment('foo.bar')
func (client *StatsdClient) Increment(stat string) {
	stats := []string{stat}
	client.UpdateStats(stats, 1, 1)
}

// Increments one stat counter by value provided without sampling
//
// Usage:
//
//     import "statsd"
//     client := statsd.New('localhost', 8125)
//     client.IncrementByValue('foo.bar', 5)
func (client *StatsdClient) IncrementByValue(stat string, val int) {
	stats := []string{stat}
	client.UpdateStats(stats, val, 1)
}

// Increments one stat counter with sampling
//
// Usage:
//
//     import "statsd"
//     client := statsd.New('localhost', 8125)
//     client.Increment('foo.bar', 0.2)
func (client *StatsdClient) IncrementWithSampling(stat string, sampleRate float32) {
	stats := []string{stat}
	client.UpdateStats(stats[:], 1, sampleRate)
}

// Decrements one stat counter without sampling
//
// Usage:
//
//     import "statsd"
//     client := statsd.New('localhost', 8125)
//     client.Decrement('foo.bar')
func (client *StatsdClient) Decrement(stat string) {
	stats := []string{stat}
	client.UpdateStats(stats[:], -1, 1)
}

// Decrements one stat counter with sampling
//
// Usage:
//
//     import "statsd"
//     client := statsd.New('localhost', 8125)
//     client.Decrement('foo.bar', 0.2)
func (client *StatsdClient) DecrementWithSampling(stat string, sampleRate float32) {
	stats := []string{stat}
	client.UpdateStats(stats[:], -1, sampleRate)
}

// Arbitrarily updates a list of stats by a delta
func (client *StatsdClient) UpdateStats(stats []string, delta int, sampleRate float32) {
	statsToSend := make(map[string]string)
	for _, stat := range stats {
		updateString := fmt.Sprintf("%d|c", delta)
		statsToSend[stat] = updateString
	}
	client.Send(statsToSend, sampleRate)
}

// Sends data to udp statsd daemon
func (client *StatsdClient) Send(data map[string]string, sampleRate float32) {
	sampledData := make(map[string]string)
	if sampleRate < 1 {
		r := rand.New(rand.NewSource(time.Now().Unix()))
		rNum := r.Float32()
		if rNum <= sampleRate {
			for stat, value := range data {
				sampledUpdateString := fmt.Sprintf("%s|@%f", value, sampleRate)
				sampledData[stat] = sampledUpdateString
			}
		}
	} else {
		sampledData = data
	}

	for k, v := range sampledData {
		update_string := fmt.Sprintf("%s:%s", k, v)
		_, err := fmt.Fprintf(client.conn, update_string)
		if err != nil {
			log.Println(err)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"image"
	_ "image/gif"
	_ "image/jpeg"
	_ "image/png"
	"net/http"
	"net/http/httptest"
	"net/url"
	"testing"

	"github.com/pierrre/imageserver"
	"github.com/pierrre/imageserver/testdata"
)

func TestServer(t *testing.T) {
	type TC struct {
		query              url.Values
		expectedStatusCode int
		expectedFormat     string
		expectedWidth      int
		expectedHeight     int
	}
	for _, tc := range []TC{
		{
			expectedStatusCode: http.StatusBadRequest,
		},
		{
			query: url.Values{
				imageserver.SourceParam: {testdata.SmallFileName},
			},
		},
		{
			query: url.Values{
				imageserver.SourceParam: {testdata.MediumFileName},
			},
		},
		{
			query: url.Values{
				imageserver.SourceParam: {testdata.LargeFileName},
			},
		},
		{
			query: url.Values{
				imageserver.SourceParam: {testdata.HugeFileName},
			},
		},
		{
			query: url.Values{
				imageserver.SourceParam: {testdata.AnimatedFileName},
			},
		},
		{
			query: url.Values{
				imageserver.SourceParam: {testdata.MediumFileName},
			},
		},
		{
			query: url.Values{
				imageserver.SourceParam: {testdata.MediumFileName},
				"format":                {"foobar"},
			},
			expectedStatusCode: http.StatusBadRequest,
		},
		{
			query: url.Values{
				imageserver.SourceParam: {testdata.MediumFileName},
				"format":                {"png"},
			},
			expectedFormat: "png",
		},
		{
			query: url.Values{
				imageserver.SourceParam: {testdata.MediumFileName},
				"format":                {"gif"},
			},
			expectedFormat: "gif",
		},
		{
			query: url.Values{
				imageserver.SourceParam: {testdata.MediumFileName},
				"format":                {"jpeg"},
				"quality":               {"-10"},
			},
			expectedStatusCode: http.StatusBadRequest,
		},
		{
			query: url.Values{
				imageserver.SourceParam: {testdata.MediumFileName},
				"format":                {"jpeg"},
				"quality":               {"50"},
			},
			expectedFormat: "jpeg",
		},
		{
			query: url.Values{
				imageserver.SourceParam: {testdata.MediumFileName},
				"width":                 {"-100"},
			},
			expectedStatusCode: http.StatusBadRequest,
		},
		{
			query: url.Values{
				imageserver.SourceParam: {testdata.MediumFileName},
				"width":                 {"100"},
			},
			expectedWidth: 100,
		},
		{
			query: url.Values{
				imageserver.SourceParam: {testdata.MediumFileName},
				"height":                {"-100"},
			},
			expectedStatusCode: http.StatusBadRequest,
		},
		{
			query: url.Values{
				imageserver.SourceParam: {testdata.MediumFileName},
				"height":                {"200"},
			},
			expectedHeight: 200,
		},
	} {
		func() {
			defer func() {
				if t.Failed() {
					t.Logf("%#v", tc)
				}
			}()
			h := newImageHTTPHandler()
			u := &url.URL{
				Scheme:   "http",
				Host:     "localhost",
				RawQuery: tc.query.Encode(),
			}
			req, err := http.NewRequest("GET", u.String(), nil)
			if err != nil {
				t.Fatal(err)
			}
			w := httptest.NewRecorder()
			h.ServeHTTP(w, req)
			w.Flush()
			if tc.expectedStatusCode != 0 && w.Code != tc.expectedStatusCode {
				t.Fatalf("unexpected http status: %d", w.Code)
			}
			if w.Code != http.StatusOK {
				if tc.expectedStatusCode != 0 {
					return
				}
				t.Fatalf("http status not OK: %d", w.Code)
			}
			im, format, err := image.Decode(w.Body)
			if err != nil {
				t.Fatal(err)
			}
			if tc.expectedFormat != "" && format != tc.expectedFormat {
				t.Fatalf("unexpected format: %s", format)
			}
			if tc.expectedWidth != 0 && im.Bounds().Dx() != tc.expectedWidth {
				t.Fatalf("unexpected width: %d", im.Bounds().Dx())
			}
			if tc.expectedHeight != 0 && im.Bounds().Dy() != tc.expectedHeight {
				t.Fatalf("unexpected height: %d", im.Bounds().Dy())
			}
		}()
	}
}
<commit_msg>create only 1 HTTP handler in advanced example tests<commit_after>package main

import (
	"image"
	_ "image/gif"
	_ "image/jpeg"
	_ "image/png"
	"net/http"
	"net/http/httptest"
	"net/url"
	"testing"

	"github.com/pierrre/imageserver"
	"github.com/pierrre/imageserver/testdata"
)

func TestServer(t *testing.T) {
	h := newImageHTTPHandler()
	type TC struct {
		query              url.Values
		expectedStatusCode int
		expectedFormat     string
		expectedWidth      int
		expectedHeight     int
	}
	for _, tc := range []TC{
		{
			expectedStatusCode: http.StatusBadRequest,
		},
		{
			query: url.Values{
				imageserver.SourceParam: {testdata.SmallFileName},
			},
		},
		{
			query: url.Values{
				imageserver.SourceParam: {testdata.MediumFileName},
			},
		},
		{
			query: url.Values{
				imageserver.SourceParam: {testdata.LargeFileName},
			},
		},
		{
			query: url.Values{
				imageserver.SourceParam: {testdata.HugeFileName},
			},
		},
		{
			query: url.Values{
				imageserver.SourceParam: {testdata.AnimatedFileName},
			},
		},
		{
			query: url.Values{
				imageserver.SourceParam: {testdata.MediumFileName},
			},
		},
		{
			query: url.Values{
				imageserver.SourceParam: {testdata.MediumFileName},
				"format":                {"foobar"},
			},
			expectedStatusCode: http.StatusBadRequest,
		},
		{
			query: url.Values{
				imageserver.SourceParam: {testdata.MediumFileName},
				"format":                {"png"},
			},
			expectedFormat: "png",
		},
		{
			query: url.Values{
				imageserver.SourceParam: {testdata.MediumFileName},
				"format":                {"gif"},
			},
			expectedFormat: "gif",
		},
		{
			query: url.Values{
				imageserver.SourceParam: {testdata.MediumFileName},
				"format":                {"jpeg"},
				"quality":               {"-10"},
			},
			expectedStatusCode: http.StatusBadRequest,
		},
		{
			query: url.Values{
				imageserver.SourceParam: {testdata.MediumFileName},
				"format":                {"jpeg"},
				"quality":               {"50"},
			},
			expectedFormat: "jpeg",
		},
		{
			query: url.Values{
				imageserver.SourceParam: {testdata.MediumFileName},
				"width":                 {"-100"},
			},
			expectedStatusCode: http.StatusBadRequest,
		},
		{
			query: url.Values{
				imageserver.SourceParam: {testdata.MediumFileName},
				"width":                 {"100"},
			},
			expectedWidth: 100,
		},
		{
			query: url.Values{
				imageserver.SourceParam: {testdata.MediumFileName},
				"height":                {"-100"},
			},
			expectedStatusCode: http.StatusBadRequest,
		},
		{
			query: url.Values{
				imageserver.SourceParam: {testdata.MediumFileName},
				"height":                {"200"},
			},
			expectedHeight: 200,
		},
	} {
		func() {
			defer func() {
				if t.Failed() {
					t.Logf("%#v", tc)
				}
			}()
			u := &url.URL{
				Scheme:   "http",
				Host:     "localhost",
				RawQuery: tc.query.Encode(),
			}
			req, err := http.NewRequest("GET", u.String(), nil)
			if err != nil {
				t.Fatal(err)
			}
			w := httptest.NewRecorder()
			h.ServeHTTP(w, req)
			w.Flush()
			if tc.expectedStatusCode != 0 && w.Code != tc.expectedStatusCode {
				t.Fatalf("unexpected http status: %d", w.Code)
			}
			if w.Code != http.StatusOK {
				if tc.expectedStatusCode != 0 {
					return
				}
				t.Fatalf("http status not OK: %d", w.Code)
			}
			im, format, err := image.Decode(w.Body)
			if err != nil {
				t.Fatal(err)
			}
			if tc.expectedFormat != "" && format != tc.expectedFormat {
				t.Fatalf("unexpected format: %s", format)
			}
			if tc.expectedWidth != 0 && im.Bounds().Dx() != tc.expectedWidth {
				t.Fatalf("unexpected width: %d", im.Bounds().Dx())
			}
			if tc.expectedHeight != 0 && im.Bounds().Dy() != tc.expectedHeight {
				t.Fatalf("unexpected height: %d", im.Bounds().Dy())
			}
		}()
	}
}
<|endoftext|>


<commit_before>package androidcomponents

import (
	"bufio"
	"bytes"
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"time"

	"github.com/bitrise-io/go-utils/retry"
	"github.com/bitrise-io/go-utils/sliceutil"

	"github.com/bitrise-tools/go-android/sdk"
	"github.com/bitrise-tools/go-android/sdkcomponent"
	"github.com/bitrise-tools/go-android/sdkmanager"
	"github.com/bitrise-tools/go-steputils/tools"

	"github.com/bitrise-io/go-utils/command"
	"github.com/bitrise-io/go-utils/fileutil"
	_log "github.com/bitrise-io/go-utils/log"
	"github.com/bitrise-io/go-utils/pathutil"
)

type logger interface {
	Warnf(string, ...interface{})
	Printf(string, ...interface{})
	Errorf(string, ...interface{})
}

var log logger = _log.NewDummyLogger()

type installer struct {
	androidSDK  *sdk.Model
	sdkManager  *sdkmanager.Model
	gradlewPath string
}

// SetLogger ...
func SetLogger(l logger) {
	log = l
}

// InstallLicences ...
func InstallLicences(androidSdk *sdk.Model) error {
	sdkManager, err := sdkmanager.New(androidSdk)
	if err != nil {
		return err
	}

	if !sdkManager.IsLegacySDK() {
		licensesCmd := command.New(filepath.Join(androidSdk.GetAndroidHome(), "tools/bin/sdkmanager"), "--licenses")
		licensesCmd.SetStdin(bytes.NewReader([]byte(strings.Repeat("y\n", 1000))))
		if err := licensesCmd.Run(); err != nil {
			log.Warnf("Failed to install licenses using $(sdkmanager --licenses) command")
			log.Printf("Continue using legacy license installation...")
			log.Printf("")
		} else {
			return nil
		}
	}

	licenceMap := map[string]string{
		"android-sdk-license":           "8933bad161af4178b1185d1a37fbf41ea5269c55\n\nd56f5187479451eabf01fb78af6dfcb131a6481e",
		"android-googletv-license":      "\n601085b94cd77f0b54ff86406957099ebe79c4d6",
		"android-sdk-preview-license":   "\n84831b9409646a918e30573bab4c9c91346d8abd",
		"intel-android-extra-license":   "\nd975f751698a77b662f1254ddbeed3901e976f5a",
		"google-gdk-license":            "\n33b6a2b64607f11b759f320ef9dff4ae5c47d97a",
		"mips-android-sysimage-license": "\ne9acab5b5fbb560a72cfaecce8946896ff6aab9d",
	}

	licencesDir := filepath.Join(androidSdk.GetAndroidHome(), "licenses")
	if exist, err := pathutil.IsDirExists(licencesDir); err != nil {
		return err
	} else if !exist {
		if err := os.MkdirAll(licencesDir, os.ModePerm); err != nil {
			return err
		}
	}

	for name, content := range licenceMap {
		pth := filepath.Join(licencesDir, name)

		if err := fileutil.WriteStringToFile(pth, content); err != nil {
			return err
		}
	}

	return nil
}

// Ensure ...
func Ensure(androidSdk *sdk.Model, gradlewPath string) error {
	sdkManager, err := sdkmanager.New(androidSdk)
	if err != nil {
		return err
	}
	i := installer{
		androidSdk,
		sdkManager,
		gradlewPath,
	}

	return retry.Times(1).Wait(time.Second).Try(func(attempt uint) error {
		if attempt > 0 {
			log.Warnf("Retrying...")
		}
		return i.scanDependencies()
	})
}

func (i installer) getDependencyCases() map[string]func(match string) error {
	return map[string]func(match string) error{
		`(Observed package id 'ndk-bundle' in inconsistent location)`:         i.ndkInconsistentLocation,
		`(NDK not configured)`:                                                i.ndkNotConfigured,
		`failed to find target with hash string 'android-(.*)'\s*`:            i.target,
		`failed to find Build Tools revision ([0-9.]*)\s*`:                    i.buildTool,
		`Could not find (com\.android\.support\..*)\.`:                        i.extrasLib,
		`Could not find any version that matches (com\.android\.support.*)\.`: i.extrasLib,
	}
}

func getDependenciesOutput(projectLocation string) (string, error) {
	gradleCmd := command.New("./gradlew", "dependencies")
	gradleCmd.SetStdin(strings.NewReader("y"))
	gradleCmd.SetDir(projectLocation)
	return gradleCmd.RunAndReturnTrimmedCombinedOutput()
}

func (i installer) scanDependencies(foundMatches ...string) error {
	out, err := getDependenciesOutput(filepath.Dir(i.gradlewPath))
	if err == nil {
		return nil
	}
	err = fmt.Errorf("output: %s\nerror: %s", out, err)
	scanner := bufio.NewScanner(strings.NewReader(out))
	for scanner.Scan() {
		line := scanner.Text()
		for pattern, callback := range i.getDependencyCases() {
			re := regexp.MustCompile(pattern)
			if matches := re.FindStringSubmatch(line); len(matches) == 2 {
				if sliceutil.IsStringInSlice(matches[1], foundMatches) {
					return fmt.Errorf("unable to solve a dependency installation for the output:\n%s", out)
				}
				if callbackErr := callback(matches[1]); callbackErr != nil {
					log.Printf(out)
					return callbackErr
				}
				err = nil
				return i.scanDependencies(append(foundMatches, matches[1])...)
			}
		}
	}
	if scanner.Err() != nil {
		log.Printf(out)
		return scanner.Err()
	}
	return err
}

func (i installer) ndkNotConfigured(_ string) error {
	log.Warnf("NDK not configured")

	ndkComponent := sdkcomponent.SDKTool{SDKStylePath: "ndk-bundle", LegacySDKStylePath: "ndk-bundle"}
	cmd := i.sdkManager.InstallCommand(ndkComponent)
	cmd.SetStdin(strings.NewReader("y"))

	log.Printf("Install and configure NDK bundle using:")
	log.Printf("$ %s", cmd.PrintableCommandArgs())

	if out, err := cmd.RunAndReturnTrimmedCombinedOutput(); err != nil {
		return fmt.Errorf("output: %s, error: %s", out, err)
	}

	bundlePath := filepath.Join(i.androidSDK.GetAndroidHome(), "ndk-bundle")

	log.Printf("Setting environment variable (ANDROID_NDK_HOME) to:  %s", bundlePath)
	if err := os.Setenv("ANDROID_NDK_HOME", bundlePath); err != nil {
		return err
	}
	return tools.ExportEnvironmentWithEnvman("ANDROID_NDK_HOME", bundlePath)
}

func (i installer) ndkInconsistentLocation(_ string) error {
	log.Warnf("NDK found on inconsistent path")

	ndkUninstallComponent := sdkcomponent.SDKTool{SDKStylePath: "ndk-bundle", LegacySDKStylePath: "ndk-bundle"}
	cmd := i.sdkManager.InstallCommand(ndkUninstallComponent)
	cmd.SetStdin(strings.NewReader("y"))
	cmd.GetCmd().Args = append([]string{cmd.GetCmd().Args[0], "--uninstall"}, cmd.GetCmd().Args[1:]...)

	log.Printf("Removing NDK bundle using:")
	log.Printf("$ %s", cmd.PrintableCommandArgs())

	if out, err := cmd.RunAndReturnTrimmedCombinedOutput(); err != nil {
		return fmt.Errorf("output: %s, error: %s", out, err)
	}
	return i.ndkNotConfigured("")
}

func (i installer) target(version string) error {
	log.Warnf("Missing platform version found: %s", version)

	version = "android-" + version
	platformComponent := sdkcomponent.Platform{
		Version: version,
	}
	cmd := i.sdkManager.InstallCommand(platformComponent)
	cmd.SetStdin(strings.NewReader("y"))

	log.Printf("Installing platform version using:")
	log.Printf("$ %s", cmd.PrintableCommandArgs())

	out, err := cmd.RunAndReturnTrimmedCombinedOutput()
	if err != nil {
		return fmt.Errorf("output: %s, error: %s", out, err)
	}
	return nil
}

func (i installer) buildTool(buildToolsVersion string) error {
	log.Warnf("Missing build tools version found: %s", buildToolsVersion)

	buildToolsComponent := sdkcomponent.BuildTool{
		Version: buildToolsVersion,
	}

	cmd := i.sdkManager.InstallCommand(buildToolsComponent)
	cmd.SetStdin(strings.NewReader("y"))

	log.Printf("Installing build tools version using:")
	log.Printf("$ %s", cmd.PrintableCommandArgs())

	out, err := cmd.RunAndReturnTrimmedCombinedOutput()
	if err != nil {
		return fmt.Errorf("output: %s, error: %s", out, err)
	}
	return nil
}

func (i installer) extrasLib(lib string) error {
	log.Warnf("Missing extras library found: %s", lib)

	firstColon := strings.Index(lib, ":")
	lib = strings.Replace(lib[:firstColon], ".", ";", -1) + strings.Replace(lib[firstColon:], ":", ";", -1)

	extrasComponents := sdkcomponent.SupportLibraryInstallComponents()
	extrasComponents = append(extrasComponents, sdkcomponent.Extras{
		Provider:    "m2repository",
		PackageName: lib,
	})
	for _, e := range extrasComponents {
		cmd := i.sdkManager.InstallCommand(e)
		cmd.SetStdin(strings.NewReader("y"))

		log.Printf("Installing extras using:")
		log.Printf("$ %s", cmd.PrintableCommandArgs())

		out, err := cmd.RunAndReturnTrimmedCombinedOutput()
		if err != nil {
			return fmt.Errorf("output: %s, error: %s", out, err)
		}
		return nil
	}
	return nil
}
<commit_msg>added stacktrace command flag (#50)<commit_after>package androidcomponents

import (
	"bufio"
	"bytes"
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"time"

	"github.com/bitrise-io/go-utils/retry"
	"github.com/bitrise-io/go-utils/sliceutil"

	"github.com/bitrise-tools/go-android/sdk"
	"github.com/bitrise-tools/go-android/sdkcomponent"
	"github.com/bitrise-tools/go-android/sdkmanager"
	"github.com/bitrise-tools/go-steputils/tools"

	"github.com/bitrise-io/go-utils/command"
	"github.com/bitrise-io/go-utils/fileutil"
	_log "github.com/bitrise-io/go-utils/log"
	"github.com/bitrise-io/go-utils/pathutil"
)

type logger interface {
	Warnf(string, ...interface{})
	Printf(string, ...interface{})
	Errorf(string, ...interface{})
}

var log logger = _log.NewDummyLogger()

type installer struct {
	androidSDK  *sdk.Model
	sdkManager  *sdkmanager.Model
	gradlewPath string
}

// SetLogger ...
func SetLogger(l logger) {
	log = l
}

// InstallLicences ...
func InstallLicences(androidSdk *sdk.Model) error {
	sdkManager, err := sdkmanager.New(androidSdk)
	if err != nil {
		return err
	}

	if !sdkManager.IsLegacySDK() {
		licensesCmd := command.New(filepath.Join(androidSdk.GetAndroidHome(), "tools/bin/sdkmanager"), "--licenses")
		licensesCmd.SetStdin(bytes.NewReader([]byte(strings.Repeat("y\n", 1000))))
		if err := licensesCmd.Run(); err != nil {
			log.Warnf("Failed to install licenses using $(sdkmanager --licenses) command")
			log.Printf("Continue using legacy license installation...")
			log.Printf("")
		} else {
			return nil
		}
	}

	licenceMap := map[string]string{
		"android-sdk-license":           "8933bad161af4178b1185d1a37fbf41ea5269c55\n\nd56f5187479451eabf01fb78af6dfcb131a6481e",
		"android-googletv-license":      "\n601085b94cd77f0b54ff86406957099ebe79c4d6",
		"android-sdk-preview-license":   "\n84831b9409646a918e30573bab4c9c91346d8abd",
		"intel-android-extra-license":   "\nd975f751698a77b662f1254ddbeed3901e976f5a",
		"google-gdk-license":            "\n33b6a2b64607f11b759f320ef9dff4ae5c47d97a",
		"mips-android-sysimage-license": "\ne9acab5b5fbb560a72cfaecce8946896ff6aab9d",
	}

	licencesDir := filepath.Join(androidSdk.GetAndroidHome(), "licenses")
	if exist, err := pathutil.IsDirExists(licencesDir); err != nil {
		return err
	} else if !exist {
		if err := os.MkdirAll(licencesDir, os.ModePerm); err != nil {
			return err
		}
	}

	for name, content := range licenceMap {
		pth := filepath.Join(licencesDir, name)

		if err := fileutil.WriteStringToFile(pth, content); err != nil {
			return err
		}
	}

	return nil
}

// Ensure ...
func Ensure(androidSdk *sdk.Model, gradlewPath string) error {
	sdkManager, err := sdkmanager.New(androidSdk)
	if err != nil {
		return err
	}
	i := installer{
		androidSdk,
		sdkManager,
		gradlewPath,
	}

	return retry.Times(1).Wait(time.Second).Try(func(attempt uint) error {
		if attempt > 0 {
			log.Warnf("Retrying...")
		}
		return i.scanDependencies()
	})
}

func (i installer) getDependencyCases() map[string]func(match string) error {
	return map[string]func(match string) error{
		`(Observed package id 'ndk-bundle' in inconsistent location)`:         i.ndkInconsistentLocation,
		`(NDK not configured)`:                                                i.ndkNotConfigured,
		`failed to find target with hash string 'android-(.*)'\s*`:            i.target,
		`failed to find Build Tools revision ([0-9.]*)\s*`:                    i.buildTool,
		`Could not find (com\.android\.support\..*)\.`:                        i.extrasLib,
		`Could not find any version that matches (com\.android\.support.*)\.`: i.extrasLib,
	}
}

func getDependenciesOutput(projectLocation string) (string, error) {
	gradleCmd := command.New("./gradlew", "dependencies", "--stacktrace")
	gradleCmd.SetStdin(strings.NewReader("y"))
	gradleCmd.SetDir(projectLocation)
	return gradleCmd.RunAndReturnTrimmedCombinedOutput()
}

func (i installer) scanDependencies(foundMatches ...string) error {
	out, err := getDependenciesOutput(filepath.Dir(i.gradlewPath))
	if err == nil {
		return nil
	}
	err = fmt.Errorf("output: %s\nerror: %s", out, err)
	scanner := bufio.NewScanner(strings.NewReader(out))
	for scanner.Scan() {
		line := scanner.Text()
		for pattern, callback := range i.getDependencyCases() {
			re := regexp.MustCompile(pattern)
			if matches := re.FindStringSubmatch(line); len(matches) == 2 {
				if sliceutil.IsStringInSlice(matches[1], foundMatches) {
					return fmt.Errorf("unable to solve a dependency installation for the output:\n%s", out)
				}
				if callbackErr := callback(matches[1]); callbackErr != nil {
					log.Printf(out)
					return callbackErr
				}
				err = nil
				return i.scanDependencies(append(foundMatches, matches[1])...)
			}
		}
	}
	if scanner.Err() != nil {
		log.Printf(out)
		return scanner.Err()
	}
	return err
}

func (i installer) ndkNotConfigured(_ string) error {
	log.Warnf("NDK not configured")

	ndkComponent := sdkcomponent.SDKTool{SDKStylePath: "ndk-bundle", LegacySDKStylePath: "ndk-bundle"}
	cmd := i.sdkManager.InstallCommand(ndkComponent)
	cmd.SetStdin(strings.NewReader("y"))

	log.Printf("Install and configure NDK bundle using:")
	log.Printf("$ %s", cmd.PrintableCommandArgs())

	if out, err := cmd.RunAndReturnTrimmedCombinedOutput(); err != nil {
		return fmt.Errorf("output: %s, error: %s", out, err)
	}

	bundlePath := filepath.Join(i.androidSDK.GetAndroidHome(), "ndk-bundle")

	log.Printf("Setting environment variable (ANDROID_NDK_HOME) to:  %s", bundlePath)
	if err := os.Setenv("ANDROID_NDK_HOME", bundlePath); err != nil {
		return err
	}
	return tools.ExportEnvironmentWithEnvman("ANDROID_NDK_HOME", bundlePath)
}

func (i installer) ndkInconsistentLocation(_ string) error {
	log.Warnf("NDK found on inconsistent path")

	ndkUninstallComponent := sdkcomponent.SDKTool{SDKStylePath: "ndk-bundle", LegacySDKStylePath: "ndk-bundle"}
	cmd := i.sdkManager.InstallCommand(ndkUninstallComponent)
	cmd.SetStdin(strings.NewReader("y"))
	cmd.GetCmd().Args = append([]string{cmd.GetCmd().Args[0], "--uninstall"}, cmd.GetCmd().Args[1:]...)

	log.Printf("Removing NDK bundle using:")
	log.Printf("$ %s", cmd.PrintableCommandArgs())

	if out, err := cmd.RunAndReturnTrimmedCombinedOutput(); err != nil {
		return fmt.Errorf("output: %s, error: %s", out, err)
	}
	return i.ndkNotConfigured("")
}

func (i installer) target(version string) error {
	log.Warnf("Missing platform version found: %s", version)

	version = "android-" + version
	platformComponent := sdkcomponent.Platform{
		Version: version,
	}
	cmd := i.sdkManager.InstallCommand(platformComponent)
	cmd.SetStdin(strings.NewReader("y"))

	log.Printf("Installing platform version using:")
	log.Printf("$ %s", cmd.PrintableCommandArgs())

	out, err := cmd.RunAndReturnTrimmedCombinedOutput()
	if err != nil {
		return fmt.Errorf("output: %s, error: %s", out, err)
	}
	return nil
}

func (i installer) buildTool(buildToolsVersion string) error {
	log.Warnf("Missing build tools version found: %s", buildToolsVersion)

	buildToolsComponent := sdkcomponent.BuildTool{
		Version: buildToolsVersion,
	}

	cmd := i.sdkManager.InstallCommand(buildToolsComponent)
	cmd.SetStdin(strings.NewReader("y"))

	log.Printf("Installing build tools version using:")
	log.Printf("$ %s", cmd.PrintableCommandArgs())

	out, err := cmd.RunAndReturnTrimmedCombinedOutput()
	if err != nil {
		return fmt.Errorf("output: %s, error: %s", out, err)
	}
	return nil
}

func (i installer) extrasLib(lib string) error {
	log.Warnf("Missing extras library found: %s", lib)

	firstColon := strings.Index(lib, ":")
	lib = strings.Replace(lib[:firstColon], ".", ";", -1) + strings.Replace(lib[firstColon:], ":", ";", -1)

	extrasComponents := sdkcomponent.SupportLibraryInstallComponents()
	extrasComponents = append(extrasComponents, sdkcomponent.Extras{
		Provider:    "m2repository",
		PackageName: lib,
	})
	for _, e := range extrasComponents {
		cmd := i.sdkManager.InstallCommand(e)
		cmd.SetStdin(strings.NewReader("y"))

		log.Printf("Installing extras using:")
		log.Printf("$ %s", cmd.PrintableCommandArgs())

		out, err := cmd.RunAndReturnTrimmedCombinedOutput()
		if err != nil {
			return fmt.Errorf("output: %s, error: %s", out, err)
		}
		return nil
	}
	return nil
}
<|endoftext|>