<commit_before>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

// Package tide contains a controller for managing a tide pool of PRs. The
// controller will automatically retest PRs in the pool and merge them if they
// pass tests.
package tide

import (
	"context"
	"fmt"
	"net/url"
	"sort"
	"strings"
	"sync"
	"time"

	"github.com/shurcooL/githubql"
	"github.com/sirupsen/logrus"

	"k8s.io/apimachinery/pkg/util/sets"
	"k8s.io/test-infra/prow/config"
	"k8s.io/test-infra/prow/github"
)

const (
	statusContext string = "tide"
	statusInPool         = "In merge pool."
	// statusNotInPool is a format string used when a PR is not in a tide pool.
	// The '%s' field is populated with the reason why the PR is not in a
	// tide pool or the empty string if the reason is unknown. See requirementDiff.
	statusNotInPool = "Not mergeable.%s"
)

type statusController struct {
	logger *logrus.Entry
	ca     *config.Agent
	ghc    githubClient

	// newPoolPending is a size 1 chan that signals that the main Tide loop has
	// updated the 'poolPRs' field with a freshly updated pool.
	newPoolPending chan bool
	// shutDown is used to signal to the main controller that the statusController
	// has completed processing after newPoolPending is closed.
	shutDown chan bool

	// lastSyncStart is used to ensure that the status update period is at least
	// the minimum status update period.
	lastSyncStart time.Time
	// lastSuccessfulQueryStart is used to only list PRs that have changed since
	// we last successfully listed PRs in order to make status context updates
	// cheaper.
	lastSuccessfulQueryStart time.Time

	sync.Mutex
	poolPRs map[string]PullRequest
}

func (sc *statusController) shutdown() {
	close(sc.newPoolPending)
	<-sc.shutDown
}

// requirementDiff calculates the diff between a PR and a TideQuery.
// This diff is defined with a string that describes some subset of the
// differences and an integer counting the total number of differences.
// The diff count should always reflect the total number of differences between
// the current state of the PR and the query, but the message returned need not
// attempt to convey all of that information if some differences are more severe.
// For instance, we need to convey that a PR is open against a forbidden branch
// more than we need to detail which status contexts are failed against the PR.
// Note: an empty diff can be returned if the reason that the PR does not match
// the TideQuery is unknown. This can happen happen if this function's logic
// does not match GitHub's and does not indicate that the PR matches the query.
func requirementDiff(pr *PullRequest, q *config.TideQuery, cc contextChecker) (string, int) {
	const maxLabelChars = 50
	var desc string
	var diff int
	// Drops labels if needed to fit the description text area, but keep at least 1.
	truncate := func(labels []string) []string {
		i := 1
		chars := len(labels[0])
		for ; i < len(labels); i++ {
			if chars+len(labels[i]) > maxLabelChars {
				break
			}
			chars += len(labels[i]) + 2 // ", "
		}
		return labels[:i]
	}

	for _, excludedBranch := range q.ExcludedBranches {
		if string(pr.BaseRef.Name) == excludedBranch {
			desc = fmt.Sprintf(" Merging to branch %s is forbidden.", pr.BaseRef.Name)
			diff = 1
		}
	}

	// if no whitelist is configured, the target is OK by default
	targetBranchWhitelisted := len(q.IncludedBranches) == 0
	for _, includedBranch := range q.IncludedBranches {
		if string(pr.BaseRef.Name) == includedBranch {
			targetBranchWhitelisted = true
		}
	}

	if !targetBranchWhitelisted {
		desc = fmt.Sprintf(" Merging to branch %s is forbidden.", pr.BaseRef.Name)
		diff++
	}

	var missingLabels []string
	for _, l1 := range q.Labels {
		var found bool
		for _, l2 := range pr.Labels.Nodes {
			if string(l2.Name) == l1 {
				found = true
				break
			}
		}
		if !found {
			missingLabels = append(missingLabels, l1)
		}
	}
	diff += len(missingLabels)
	if desc == "" && len(missingLabels) > 0 {
		sort.Strings(missingLabels)
		trunced := truncate(missingLabels)
		if len(trunced) == 1 {
			desc = fmt.Sprintf(" Needs %s label.", trunced[0])
		} else {
			desc = fmt.Sprintf(" Needs %s labels.", strings.Join(trunced, ", "))
		}
	}

	var presentLabels []string
	for _, l1 := range q.MissingLabels {
		for _, l2 := range pr.Labels.Nodes {
			if string(l2.Name) == l1 {
				presentLabels = append(presentLabels, l1)
				break
			}
		}
	}
	diff += len(presentLabels)
	if desc == "" && len(presentLabels) > 0 {
		sort.Strings(presentLabels)
		trunced := truncate(presentLabels)
		if len(trunced) == 1 {
			desc = fmt.Sprintf(" Should not have %s label.", trunced[0])
		} else {
			desc = fmt.Sprintf(" Should not have %s labels.", strings.Join(trunced, ", "))
		}
	}

	// fixing label issues takes precedence over status contexts
	var contexts []string
	for _, commit := range pr.Commits.Nodes {
		if commit.Commit.OID == pr.HeadRefOID {
			for _, ctx := range unsuccessfulContexts(commit.Commit.Status.Contexts, cc, logrus.New().WithFields(pr.logFields())) {
				contexts = append(contexts, string(ctx.Context))
			}
		}
	}
	diff += len(contexts)
	if desc == "" && len(contexts) > 0 {
		sort.Strings(contexts)
		trunced := truncate(contexts)
		if len(trunced) == 1 {
			desc = fmt.Sprintf(" Job %s has not succeeded.", trunced[0])
		} else {
			desc = fmt.Sprintf(" Jobs %s have not succeeded.", strings.Join(trunced, ", "))
		}
	}

	if q.Milestone != "" && (pr.Milestone == nil || string(pr.Milestone.Title) != q.Milestone) {
		diff++
		if desc == "" {
			desc = fmt.Sprintf(" Must be in milestone %s.", q.Milestone)
		}
	}

	// TODO(cjwagner): List reviews (states:[APPROVED], first: 1) as part of open
	// PR query.

	return desc, diff
}

// Returns expected status state and description.
// If a PR is not mergeable, we have to select a TideQuery to compare it against
// in order to generate a diff for the status description. We choose the query
// for the repo that the PR is closest to meeting (as determined by the number
// of unmet/violated requirements).
func expectedStatus(queryMap config.QueryMap, pr *PullRequest, pool map[string]PullRequest, cc contextChecker) (string, string) {
	if _, ok := pool[prKey(pr)]; !ok {
		minDiffCount := -1
		var minDiff string
		for _, q := range queryMap.ForRepo(string(pr.Repository.Owner.Login), string(pr.Repository.Name)) {
			diff, diffCount := requirementDiff(pr, &q, cc)
			if minDiffCount == -1 || diffCount < minDiffCount {
				minDiffCount = diffCount
				minDiff = diff
			}
		}
		return github.StatusPending, fmt.Sprintf(statusNotInPool, minDiff)
	}
	return github.StatusSuccess, statusInPool
}

// targetURL determines the URL used for more details in the status
// context on GitHub. If no PR dashboard is configured, we will use
// the administrative Prow overview.
func targetURL(c *config.Agent, pr *PullRequest, log *logrus.Entry) string {
	var link string
	if tideURL := c.Config().Tide.TargetURL; tideURL != "" {
		link = tideURL
	} else if baseURL := c.Config().Tide.PRStatusBaseURL; baseURL != "" {
		parseURL, err := url.Parse(baseURL)
		if err != nil {
			log.WithError(err).Error("Failed to parse PR status base URL")
		} else {
			prQuery := fmt.Sprintf("is:pr repo:%s author:%s head:%s", pr.Repository.NameWithOwner, pr.Author.Login, pr.HeadRefName)
			values := parseURL.Query()
			values.Set("query", prQuery)
			parseURL.RawQuery = values.Encode()
			link = parseURL.String()
		}
	}
	return link
}

func (sc *statusController) setStatuses(all []PullRequest, pool map[string]PullRequest) {
	queryMap := sc.ca.Config().Tide.Queries.QueryMap()
	processed := sets.NewString()

	process := func(pr *PullRequest) {
		processed.Insert(prKey(pr))
		log := sc.logger.WithFields(pr.logFields())
		contexts, err := headContexts(log, sc.ghc, pr)
		if err != nil {
			log.WithError(err).Error("Getting head commit status contexts, skipping...")
			return
		}
		cr, err := sc.ca.Config().GetTideContextPolicy(
			string(pr.Repository.Owner.Login),
			string(pr.Repository.Name),
			string(pr.BaseRef.Name))
		if err != nil {
			log.WithError(err).Error("setting up context register")
			return
		}

		wantState, wantDesc := expectedStatus(queryMap, pr, pool, cr)
		var actualState githubql.StatusState
		var actualDesc string
		for _, ctx := range contexts {
			if string(ctx.Context) == statusContext {
				actualState = ctx.State
				actualDesc = string(ctx.Description)
			}
		}
		if wantState != strings.ToLower(string(actualState)) || wantDesc != actualDesc {
			if err := sc.ghc.CreateStatus(
				string(pr.Repository.Owner.Login),
				string(pr.Repository.Name),
				string(pr.HeadRefOID),
				github.Status{
					Context:     statusContext,
					State:       wantState,
					Description: wantDesc,
					TargetURL:   targetURL(sc.ca, pr, log),
				}); err != nil {
				log.WithError(err).Errorf(
					"Failed to set status context from %q to %q.",
					string(actualState),
					wantState,
				)
			}
		}
	}

	for _, pr := range all {
		process(&pr)
	}
	// The list of all open PRs may not contain a PR if it was merged before we
	// listed all open PRs. To prevent a new PR that starts in the pool and
	// immediately merges from missing a tide status context we need to ensure that
	// every PR in the pool is processed even if it doesn't appear in all.
	//
	// Note: We could still fail to update a status context if the statusController
	// falls behind the main Tide sync loop by multiple loops (if we are lapped).
	// This would be unlikely to occur, could only occur if the status update sync
	// period is longer than the main sync period, and would only result in a
	// missing tide status context on a successfully merged PR.
	for key, poolPR := range pool {
		if !processed.Has(key) {
			process(&poolPR)
		}
	}
}

func (sc *statusController) run() {
	for {
		// wait for a new pool
		if !<-sc.newPoolPending {
			// chan was closed
			break
		}
		sc.waitSync()
	}
	close(sc.shutDown)
}

// waitSync waits until the minimum status update period has elapsed then syncs,
// returning the sync start time.
// If newPoolPending is closed while waiting (indicating a shutdown request)
// this function returns immediately without syncing.
func (sc *statusController) waitSync() {
	// wait for the min sync period time to elapse if needed.
	wait := time.After(time.Until(sc.lastSyncStart.Add(sc.ca.Config().Tide.StatusUpdatePeriod)))
	for {
		select {
		case <-wait:
			sc.Lock()
			pool := sc.poolPRs
			sc.Unlock()
			sc.sync(pool)
			return
		case more := <-sc.newPoolPending:
			if !more {
				return
			}
		}
	}
}

func (sc *statusController) sync(pool map[string]PullRequest) {
	sc.lastSyncStart = time.Now()

	sinceTime := sc.lastSuccessfulQueryStart.Add(-10 * time.Second)
	query := sc.ca.Config().Tide.Queries.AllPRsSince(sinceTime)
	queryStartTime := time.Now()
	allPRs, err := search(context.Background(), sc.ghc, sc.logger, query)
	if err != nil {
		sc.logger.WithError(err).Errorf("Searching for open PRs.")
		return
	}
	// We were able to find all open PRs so update the last successful query time.
	sc.lastSuccessfulQueryStart = queryStartTime
	sc.setStatuses(allPRs, pool)
}
<commit_msg>Increase Tide status controller query overlap to 30s.<commit_after>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

// Package tide contains a controller for managing a tide pool of PRs. The
// controller will automatically retest PRs in the pool and merge them if they
// pass tests.
package tide

import (
	"context"
	"fmt"
	"net/url"
	"sort"
	"strings"
	"sync"
	"time"

	"github.com/shurcooL/githubql"
	"github.com/sirupsen/logrus"

	"k8s.io/apimachinery/pkg/util/sets"
	"k8s.io/test-infra/prow/config"
	"k8s.io/test-infra/prow/github"
)

const (
	statusContext string = "tide"
	statusInPool         = "In merge pool."
	// statusNotInPool is a format string used when a PR is not in a tide pool.
	// The '%s' field is populated with the reason why the PR is not in a
	// tide pool or the empty string if the reason is unknown. See requirementDiff.
	statusNotInPool = "Not mergeable.%s"
)

type statusController struct {
	logger *logrus.Entry
	ca     *config.Agent
	ghc    githubClient

	// newPoolPending is a size 1 chan that signals that the main Tide loop has
	// updated the 'poolPRs' field with a freshly updated pool.
	newPoolPending chan bool
	// shutDown is used to signal to the main controller that the statusController
	// has completed processing after newPoolPending is closed.
	shutDown chan bool

	// lastSyncStart is used to ensure that the status update period is at least
	// the minimum status update period.
	lastSyncStart time.Time
	// lastSuccessfulQueryStart is used to only list PRs that have changed since
	// we last successfully listed PRs in order to make status context updates
	// cheaper.
	lastSuccessfulQueryStart time.Time

	sync.Mutex
	poolPRs map[string]PullRequest
}

func (sc *statusController) shutdown() {
	close(sc.newPoolPending)
	<-sc.shutDown
}

// requirementDiff calculates the diff between a PR and a TideQuery.
// This diff is defined with a string that describes some subset of the
// differences and an integer counting the total number of differences.
// The diff count should always reflect the total number of differences between
// the current state of the PR and the query, but the message returned need not
// attempt to convey all of that information if some differences are more severe.
// For instance, we need to convey that a PR is open against a forbidden branch
// more than we need to detail which status contexts are failed against the PR.
// Note: an empty diff can be returned if the reason that the PR does not match
// the TideQuery is unknown. This can happen happen if this function's logic
// does not match GitHub's and does not indicate that the PR matches the query.
func requirementDiff(pr *PullRequest, q *config.TideQuery, cc contextChecker) (string, int) {
	const maxLabelChars = 50
	var desc string
	var diff int
	// Drops labels if needed to fit the description text area, but keep at least 1.
	truncate := func(labels []string) []string {
		i := 1
		chars := len(labels[0])
		for ; i < len(labels); i++ {
			if chars+len(labels[i]) > maxLabelChars {
				break
			}
			chars += len(labels[i]) + 2 // ", "
		}
		return labels[:i]
	}

	for _, excludedBranch := range q.ExcludedBranches {
		if string(pr.BaseRef.Name) == excludedBranch {
			desc = fmt.Sprintf(" Merging to branch %s is forbidden.", pr.BaseRef.Name)
			diff = 1
		}
	}

	// if no whitelist is configured, the target is OK by default
	targetBranchWhitelisted := len(q.IncludedBranches) == 0
	for _, includedBranch := range q.IncludedBranches {
		if string(pr.BaseRef.Name) == includedBranch {
			targetBranchWhitelisted = true
		}
	}

	if !targetBranchWhitelisted {
		desc = fmt.Sprintf(" Merging to branch %s is forbidden.", pr.BaseRef.Name)
		diff++
	}

	var missingLabels []string
	for _, l1 := range q.Labels {
		var found bool
		for _, l2 := range pr.Labels.Nodes {
			if string(l2.Name) == l1 {
				found = true
				break
			}
		}
		if !found {
			missingLabels = append(missingLabels, l1)
		}
	}
	diff += len(missingLabels)
	if desc == "" && len(missingLabels) > 0 {
		sort.Strings(missingLabels)
		trunced := truncate(missingLabels)
		if len(trunced) == 1 {
			desc = fmt.Sprintf(" Needs %s label.", trunced[0])
		} else {
			desc = fmt.Sprintf(" Needs %s labels.", strings.Join(trunced, ", "))
		}
	}

	var presentLabels []string
	for _, l1 := range q.MissingLabels {
		for _, l2 := range pr.Labels.Nodes {
			if string(l2.Name) == l1 {
				presentLabels = append(presentLabels, l1)
				break
			}
		}
	}
	diff += len(presentLabels)
	if desc == "" && len(presentLabels) > 0 {
		sort.Strings(presentLabels)
		trunced := truncate(presentLabels)
		if len(trunced) == 1 {
			desc = fmt.Sprintf(" Should not have %s label.", trunced[0])
		} else {
			desc = fmt.Sprintf(" Should not have %s labels.", strings.Join(trunced, ", "))
		}
	}

	// fixing label issues takes precedence over status contexts
	var contexts []string
	for _, commit := range pr.Commits.Nodes {
		if commit.Commit.OID == pr.HeadRefOID {
			for _, ctx := range unsuccessfulContexts(commit.Commit.Status.Contexts, cc, logrus.New().WithFields(pr.logFields())) {
				contexts = append(contexts, string(ctx.Context))
			}
		}
	}
	diff += len(contexts)
	if desc == "" && len(contexts) > 0 {
		sort.Strings(contexts)
		trunced := truncate(contexts)
		if len(trunced) == 1 {
			desc = fmt.Sprintf(" Job %s has not succeeded.", trunced[0])
		} else {
			desc = fmt.Sprintf(" Jobs %s have not succeeded.", strings.Join(trunced, ", "))
		}
	}

	if q.Milestone != "" && (pr.Milestone == nil || string(pr.Milestone.Title) != q.Milestone) {
		diff++
		if desc == "" {
			desc = fmt.Sprintf(" Must be in milestone %s.", q.Milestone)
		}
	}

	// TODO(cjwagner): List reviews (states:[APPROVED], first: 1) as part of open
	// PR query.

	return desc, diff
}

// Returns expected status state and description.
// If a PR is not mergeable, we have to select a TideQuery to compare it against
// in order to generate a diff for the status description. We choose the query
// for the repo that the PR is closest to meeting (as determined by the number
// of unmet/violated requirements).
func expectedStatus(queryMap config.QueryMap, pr *PullRequest, pool map[string]PullRequest, cc contextChecker) (string, string) {
	if _, ok := pool[prKey(pr)]; !ok {
		minDiffCount := -1
		var minDiff string
		for _, q := range queryMap.ForRepo(string(pr.Repository.Owner.Login), string(pr.Repository.Name)) {
			diff, diffCount := requirementDiff(pr, &q, cc)
			if minDiffCount == -1 || diffCount < minDiffCount {
				minDiffCount = diffCount
				minDiff = diff
			}
		}
		return github.StatusPending, fmt.Sprintf(statusNotInPool, minDiff)
	}
	return github.StatusSuccess, statusInPool
}

// targetURL determines the URL used for more details in the status
// context on GitHub. If no PR dashboard is configured, we will use
// the administrative Prow overview.
func targetURL(c *config.Agent, pr *PullRequest, log *logrus.Entry) string {
	var link string
	if tideURL := c.Config().Tide.TargetURL; tideURL != "" {
		link = tideURL
	} else if baseURL := c.Config().Tide.PRStatusBaseURL; baseURL != "" {
		parseURL, err := url.Parse(baseURL)
		if err != nil {
			log.WithError(err).Error("Failed to parse PR status base URL")
		} else {
			prQuery := fmt.Sprintf("is:pr repo:%s author:%s head:%s", pr.Repository.NameWithOwner, pr.Author.Login, pr.HeadRefName)
			values := parseURL.Query()
			values.Set("query", prQuery)
			parseURL.RawQuery = values.Encode()
			link = parseURL.String()
		}
	}
	return link
}

func (sc *statusController) setStatuses(all []PullRequest, pool map[string]PullRequest) {
	queryMap := sc.ca.Config().Tide.Queries.QueryMap()
	processed := sets.NewString()

	process := func(pr *PullRequest) {
		processed.Insert(prKey(pr))
		log := sc.logger.WithFields(pr.logFields())
		contexts, err := headContexts(log, sc.ghc, pr)
		if err != nil {
			log.WithError(err).Error("Getting head commit status contexts, skipping...")
			return
		}
		cr, err := sc.ca.Config().GetTideContextPolicy(
			string(pr.Repository.Owner.Login),
			string(pr.Repository.Name),
			string(pr.BaseRef.Name))
		if err != nil {
			log.WithError(err).Error("setting up context register")
			return
		}

		wantState, wantDesc := expectedStatus(queryMap, pr, pool, cr)
		var actualState githubql.StatusState
		var actualDesc string
		for _, ctx := range contexts {
			if string(ctx.Context) == statusContext {
				actualState = ctx.State
				actualDesc = string(ctx.Description)
			}
		}
		if wantState != strings.ToLower(string(actualState)) || wantDesc != actualDesc {
			if err := sc.ghc.CreateStatus(
				string(pr.Repository.Owner.Login),
				string(pr.Repository.Name),
				string(pr.HeadRefOID),
				github.Status{
					Context:     statusContext,
					State:       wantState,
					Description: wantDesc,
					TargetURL:   targetURL(sc.ca, pr, log),
				}); err != nil {
				log.WithError(err).Errorf(
					"Failed to set status context from %q to %q.",
					string(actualState),
					wantState,
				)
			}
		}
	}

	for _, pr := range all {
		process(&pr)
	}
	// The list of all open PRs may not contain a PR if it was merged before we
	// listed all open PRs. To prevent a new PR that starts in the pool and
	// immediately merges from missing a tide status context we need to ensure that
	// every PR in the pool is processed even if it doesn't appear in all.
	//
	// Note: We could still fail to update a status context if the statusController
	// falls behind the main Tide sync loop by multiple loops (if we are lapped).
	// This would be unlikely to occur, could only occur if the status update sync
	// period is longer than the main sync period, and would only result in a
	// missing tide status context on a successfully merged PR.
	for key, poolPR := range pool {
		if !processed.Has(key) {
			process(&poolPR)
		}
	}
}

func (sc *statusController) run() {
	for {
		// wait for a new pool
		if !<-sc.newPoolPending {
			// chan was closed
			break
		}
		sc.waitSync()
	}
	close(sc.shutDown)
}

// waitSync waits until the minimum status update period has elapsed then syncs,
// returning the sync start time.
// If newPoolPending is closed while waiting (indicating a shutdown request)
// this function returns immediately without syncing.
func (sc *statusController) waitSync() {
	// wait for the min sync period time to elapse if needed.
	wait := time.After(time.Until(sc.lastSyncStart.Add(sc.ca.Config().Tide.StatusUpdatePeriod)))
	for {
		select {
		case <-wait:
			sc.Lock()
			pool := sc.poolPRs
			sc.Unlock()
			sc.sync(pool)
			return
		case more := <-sc.newPoolPending:
			if !more {
				return
			}
		}
	}
}

func (sc *statusController) sync(pool map[string]PullRequest) {
	sc.lastSyncStart = time.Now()

	// Query for PRs changed since the last time we successfully queried.
	// We offset for 30 seconds of overlap because GitHub sometimes doesn't
	// include recently changed/new PRs in the query results.
	sinceTime := sc.lastSuccessfulQueryStart.Add(-30 * time.Second)
	query := sc.ca.Config().Tide.Queries.AllPRsSince(sinceTime)
	queryStartTime := time.Now()
	allPRs, err := search(context.Background(), sc.ghc, sc.logger, query)
	if err != nil {
		sc.logger.WithError(err).Errorf("Searching for open PRs.")
		return
	}
	// We were able to find all open PRs so update the last successful query time.
	sc.lastSuccessfulQueryStart = queryStartTime
	sc.setStatuses(allPRs, pool)
}
<|endoftext|>


<commit_before>// Copyright 2015 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 flushfs_test

import (
	"io"
	"os"
	"path"
	"sync"
	"testing"

	"github.com/jacobsa/fuse"
	"github.com/jacobsa/fuse/samples"
	"github.com/jacobsa/fuse/samples/flushfs"
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
)

func TestFlushFS(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

type FlushFSTest struct {
	samples.SampleTest

	mu sync.Mutex

	// GUARDED_BY(mu)
	flushes  []string
	flushErr error

	// GUARDED_BY(mu)
	fsyncs   []string
	fsyncErr error
}

func init() { RegisterTestSuite(&FlushFSTest{}) }

func (t *FlushFSTest) SetUp(ti *TestInfo) {
	var err error

	// Set up a file system.
	reportTo := func(slice *[]string, err *error) func(string) error {
		return func(s string) error {
			t.mu.Lock()
			defer t.mu.Unlock()

			*slice = append(*slice, s)
			return *err
		}
	}

	t.FileSystem, err = flushfs.NewFileSystem(
		reportTo(&t.flushes, &t.flushErr),
		reportTo(&t.fsyncs, &t.fsyncErr))

	if err != nil {
		panic(err)
	}

	// Mount it.
	t.SampleTest.SetUp(ti)
}

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

// Return a copy of the current contents of t.flushes.
//
// LOCKS_EXCLUDED(t.mu)
func (t *FlushFSTest) getFlushes() (p []string) {
	t.mu.Lock()
	defer t.mu.Unlock()

	p = make([]string, len(t.flushes))
	copy(p, t.flushes)
	return
}

// Return a copy of the current contents of t.fsyncs.
//
// LOCKS_EXCLUDED(t.mu)
func (t *FlushFSTest) getFsyncs() (p []string) {
	t.mu.Lock()
	defer t.mu.Unlock()

	p = make([]string, len(t.fsyncs))
	copy(p, t.fsyncs)
	return
}

// LOCKS_EXCLUDED(t.mu)
func (t *FlushFSTest) setFlushError(err error) {
	t.mu.Lock()
	defer t.mu.Unlock()

	t.flushErr = err
}

// LOCKS_EXCLUDED(t.mu)
func (t *FlushFSTest) setFsyncError(err error) {
	t.mu.Lock()
	defer t.mu.Unlock()

	t.fsyncErr = err
}

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *FlushFSTest) CloseReports_ReadWrite() {
	var n int
	var off int64
	var err error
	buf := make([]byte, 1024)

	// Open the file.
	f, err := os.OpenFile(path.Join(t.Dir, "foo"), os.O_RDWR, 0)
	AssertEq(nil, err)

	defer func() {
		if f != nil {
			ExpectEq(nil, f.Close())
		}
	}()

	// Write some contents to the file.
	n, err = f.Write([]byte("taco"))
	AssertEq(nil, err)
	AssertEq(4, n)

	// Seek and read them back.
	off, err = f.Seek(0, 0)
	AssertEq(nil, err)
	AssertEq(0, off)

	n, err = f.Read(buf)
	AssertThat(err, AnyOf(nil, io.EOF))
	AssertEq("taco", string(buf[:n]))

	// At this point, no flushes or fsyncs should have happened.
	AssertThat(t.getFlushes(), ElementsAre())
	AssertThat(t.getFsyncs(), ElementsAre())

	// Close the file.
	err = f.Close()
	f = nil
	AssertEq(nil, err)

	// Now we should have received the flush operation (but still no fsync).
	ExpectThat(t.getFlushes(), ElementsAre("taco"))
	ExpectThat(t.getFsyncs(), ElementsAre())
}

func (t *FlushFSTest) CloseReports_ReadOnly() {
	var err error

	// Open the file.
	f, err := os.OpenFile(path.Join(t.Dir, "foo"), os.O_RDONLY, 0)
	AssertEq(nil, err)

	defer func() {
		if f != nil {
			ExpectEq(nil, f.Close())
		}
	}()

	// At this point, no flushes or fsyncs should have happened.
	AssertThat(t.getFlushes(), ElementsAre())
	AssertThat(t.getFsyncs(), ElementsAre())

	// Close the file.
	err = f.Close()
	f = nil
	AssertEq(nil, err)

	// Now we should have received the flush operation (but still no fsync).
	ExpectThat(t.getFlushes(), ElementsAre(""))
	ExpectThat(t.getFsyncs(), ElementsAre())
}

func (t *FlushFSTest) CloseReports_WriteOnly() {
	var n int
	var err error

	// Open the file.
	f, err := os.OpenFile(path.Join(t.Dir, "foo"), os.O_WRONLY, 0)
	AssertEq(nil, err)

	defer func() {
		if f != nil {
			ExpectEq(nil, f.Close())
		}
	}()

	// Write some contents to the file.
	n, err = f.Write([]byte("taco"))
	AssertEq(nil, err)
	AssertEq(4, n)

	// At this point, no flushes or fsyncs should have happened.
	AssertThat(t.getFlushes(), ElementsAre())
	AssertThat(t.getFsyncs(), ElementsAre())

	// Close the file.
	err = f.Close()
	f = nil
	AssertEq(nil, err)

	// Now we should have received the flush operation (but still no fsync).
	ExpectThat(t.getFlushes(), ElementsAre("taco"))
	ExpectThat(t.getFsyncs(), ElementsAre())
}

func (t *FlushFSTest) CloseReports_MultipleTimes_NonOverlappingFileHandles() {
	var n int
	var err error

	// Open the file.
	f, err := os.OpenFile(path.Join(t.Dir, "foo"), os.O_WRONLY, 0)
	AssertEq(nil, err)

	defer func() {
		if f != nil {
			ExpectEq(nil, f.Close())
		}
	}()

	// Write some contents to the file.
	n, err = f.Write([]byte("taco"))
	AssertEq(nil, err)
	AssertEq(4, n)

	// At this point, no flushes or fsyncs should have happened.
	AssertThat(t.getFlushes(), ElementsAre())
	AssertThat(t.getFsyncs(), ElementsAre())

	// Close the file.
	err = f.Close()
	f = nil
	AssertEq(nil, err)

	// Now we should have received the flush operation (but still no fsync).
	AssertThat(t.getFlushes(), ElementsAre("taco"))
	AssertThat(t.getFsyncs(), ElementsAre())

	// Open the file again.
	f, err = os.OpenFile(path.Join(t.Dir, "foo"), os.O_WRONLY, 0)
	AssertEq(nil, err)

	// Write again; expect no further flushes.
	n, err = f.Write([]byte("p"))
	AssertEq(nil, err)
	AssertEq(1, n)

	AssertThat(t.getFlushes(), ElementsAre("taco"))
	AssertThat(t.getFsyncs(), ElementsAre())

	// Close the file. Now the new contents should be flushed.
	err = f.Close()
	f = nil
	AssertEq(nil, err)

	AssertThat(t.getFlushes(), ElementsAre("taco", "paco"))
	AssertThat(t.getFsyncs(), ElementsAre())
}

func (t *FlushFSTest) CloseReports_MultipleTimes_OverlappingFileHandles() {
	var n int
	var err error

	// Open the file with two handles.
	f1, err := os.OpenFile(path.Join(t.Dir, "foo"), os.O_WRONLY, 0)
	AssertEq(nil, err)

	f2, err := os.OpenFile(path.Join(t.Dir, "foo"), os.O_WRONLY, 0)
	AssertEq(nil, err)

	defer func() {
		if f1 != nil {
			ExpectEq(nil, f1.Close())
		}

		if f2 != nil {
			ExpectEq(nil, f2.Close())
		}
	}()

	// Write some contents with each handle.
	n, err = f1.Write([]byte("taco"))
	AssertEq(nil, err)
	AssertEq(4, n)

	n, err = f2.Write([]byte("p"))
	AssertEq(nil, err)
	AssertEq(1, n)

	// At this point, no flushes or fsyncs should have happened.
	AssertThat(t.getFlushes(), ElementsAre())
	AssertThat(t.getFsyncs(), ElementsAre())

	// Close one handle. The current contents should be flushed.
	err = f1.Close()
	f1 = nil
	AssertEq(nil, err)

	AssertThat(t.getFlushes(), ElementsAre("paco"))
	AssertThat(t.getFsyncs(), ElementsAre())

	// Write some more contents via the other handle. Again, no further flushes.
	n, err = f2.Write([]byte("orp"))
	AssertEq(nil, err)
	AssertEq(3, n)

	AssertThat(t.getFlushes(), ElementsAre("paco"))
	AssertThat(t.getFsyncs(), ElementsAre())

	// Close the handle. Now the new contents should be flushed.
	err = f2.Close()
	f2 = nil
	AssertEq(nil, err)

	AssertThat(t.getFlushes(), ElementsAre("paco", "porp"))
	AssertThat(t.getFsyncs(), ElementsAre())
}

func (t *FlushFSTest) CloseError() {
	// Open the file.
	f, err := os.OpenFile(path.Join(t.Dir, "foo"), os.O_RDWR, 0)
	AssertEq(nil, err)

	defer func() {
		if f != nil {
			ExpectEq(nil, f.Close())
		}
	}()

	// Configure a flush error.
	t.setFlushError(fuse.ENOENT)

	// Close the file.
	err = f.Close()
	f = nil

	AssertNe(nil, err)
	ExpectThat(err, Error(HasSubstr("TODO")))
}

func (t *FlushFSTest) FsyncReports() {
	var n int
	var err error

	// Open the file.
	f, err := os.OpenFile(path.Join(t.Dir, "foo"), os.O_WRONLY, 0)
	AssertEq(nil, err)

	defer func() {
		if f != nil {
			ExpectEq(nil, f.Close())
		}
	}()

	// Write some contents to the file.
	n, err = f.Write([]byte("taco"))
	AssertEq(nil, err)
	AssertEq(4, n)

	AssertThat(t.getFlushes(), ElementsAre())
	AssertThat(t.getFsyncs(), ElementsAre())

	// Fsync.
	err = f.Sync()
	AssertEq(nil, err)

	AssertThat(t.getFlushes(), ElementsAre())
	AssertThat(t.getFsyncs(), ElementsAre("taco"))

	// Write some more contents.
	n, err = f.Write([]byte("s"))
	AssertEq(nil, err)
	AssertEq(1, n)

	AssertThat(t.getFlushes(), ElementsAre())
	AssertThat(t.getFsyncs(), ElementsAre("taco"))

	// Fsync.
	err = f.Sync()
	AssertEq(nil, err)

	AssertThat(t.getFlushes(), ElementsAre())
	AssertThat(t.getFsyncs(), ElementsAre("taco", "tacos"))
}

func (t *FlushFSTest) FsyncError() {
	// Open the file.
	f, err := os.OpenFile(path.Join(t.Dir, "foo"), os.O_RDWR, 0)
	AssertEq(nil, err)

	defer func() {
		if f != nil {
			ExpectEq(nil, f.Close())
		}
	}()

	// Configure an fsync error.
	t.setFsyncError(fuse.ENOENT)

	// Fsync.
	err = f.Sync()

	AssertNe(nil, err)
	ExpectThat(err, Error(HasSubstr("TODO")))
}
<commit_msg>Added a test name for dup.<commit_after>// Copyright 2015 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 flushfs_test

import (
	"io"
	"os"
	"path"
	"sync"
	"testing"

	"github.com/jacobsa/fuse"
	"github.com/jacobsa/fuse/samples"
	"github.com/jacobsa/fuse/samples/flushfs"
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
)

func TestFlushFS(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

type FlushFSTest struct {
	samples.SampleTest

	mu sync.Mutex

	// GUARDED_BY(mu)
	flushes  []string
	flushErr error

	// GUARDED_BY(mu)
	fsyncs   []string
	fsyncErr error
}

func init() { RegisterTestSuite(&FlushFSTest{}) }

func (t *FlushFSTest) SetUp(ti *TestInfo) {
	var err error

	// Set up a file system.
	reportTo := func(slice *[]string, err *error) func(string) error {
		return func(s string) error {
			t.mu.Lock()
			defer t.mu.Unlock()

			*slice = append(*slice, s)
			return *err
		}
	}

	t.FileSystem, err = flushfs.NewFileSystem(
		reportTo(&t.flushes, &t.flushErr),
		reportTo(&t.fsyncs, &t.fsyncErr))

	if err != nil {
		panic(err)
	}

	// Mount it.
	t.SampleTest.SetUp(ti)
}

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

// Return a copy of the current contents of t.flushes.
//
// LOCKS_EXCLUDED(t.mu)
func (t *FlushFSTest) getFlushes() (p []string) {
	t.mu.Lock()
	defer t.mu.Unlock()

	p = make([]string, len(t.flushes))
	copy(p, t.flushes)
	return
}

// Return a copy of the current contents of t.fsyncs.
//
// LOCKS_EXCLUDED(t.mu)
func (t *FlushFSTest) getFsyncs() (p []string) {
	t.mu.Lock()
	defer t.mu.Unlock()

	p = make([]string, len(t.fsyncs))
	copy(p, t.fsyncs)
	return
}

// LOCKS_EXCLUDED(t.mu)
func (t *FlushFSTest) setFlushError(err error) {
	t.mu.Lock()
	defer t.mu.Unlock()

	t.flushErr = err
}

// LOCKS_EXCLUDED(t.mu)
func (t *FlushFSTest) setFsyncError(err error) {
	t.mu.Lock()
	defer t.mu.Unlock()

	t.fsyncErr = err
}

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *FlushFSTest) CloseReports_ReadWrite() {
	var n int
	var off int64
	var err error
	buf := make([]byte, 1024)

	// Open the file.
	f, err := os.OpenFile(path.Join(t.Dir, "foo"), os.O_RDWR, 0)
	AssertEq(nil, err)

	defer func() {
		if f != nil {
			ExpectEq(nil, f.Close())
		}
	}()

	// Write some contents to the file.
	n, err = f.Write([]byte("taco"))
	AssertEq(nil, err)
	AssertEq(4, n)

	// Seek and read them back.
	off, err = f.Seek(0, 0)
	AssertEq(nil, err)
	AssertEq(0, off)

	n, err = f.Read(buf)
	AssertThat(err, AnyOf(nil, io.EOF))
	AssertEq("taco", string(buf[:n]))

	// At this point, no flushes or fsyncs should have happened.
	AssertThat(t.getFlushes(), ElementsAre())
	AssertThat(t.getFsyncs(), ElementsAre())

	// Close the file.
	err = f.Close()
	f = nil
	AssertEq(nil, err)

	// Now we should have received the flush operation (but still no fsync).
	ExpectThat(t.getFlushes(), ElementsAre("taco"))
	ExpectThat(t.getFsyncs(), ElementsAre())
}

func (t *FlushFSTest) CloseReports_ReadOnly() {
	var err error

	// Open the file.
	f, err := os.OpenFile(path.Join(t.Dir, "foo"), os.O_RDONLY, 0)
	AssertEq(nil, err)

	defer func() {
		if f != nil {
			ExpectEq(nil, f.Close())
		}
	}()

	// At this point, no flushes or fsyncs should have happened.
	AssertThat(t.getFlushes(), ElementsAre())
	AssertThat(t.getFsyncs(), ElementsAre())

	// Close the file.
	err = f.Close()
	f = nil
	AssertEq(nil, err)

	// Now we should have received the flush operation (but still no fsync).
	ExpectThat(t.getFlushes(), ElementsAre(""))
	ExpectThat(t.getFsyncs(), ElementsAre())
}

func (t *FlushFSTest) CloseReports_WriteOnly() {
	var n int
	var err error

	// Open the file.
	f, err := os.OpenFile(path.Join(t.Dir, "foo"), os.O_WRONLY, 0)
	AssertEq(nil, err)

	defer func() {
		if f != nil {
			ExpectEq(nil, f.Close())
		}
	}()

	// Write some contents to the file.
	n, err = f.Write([]byte("taco"))
	AssertEq(nil, err)
	AssertEq(4, n)

	// At this point, no flushes or fsyncs should have happened.
	AssertThat(t.getFlushes(), ElementsAre())
	AssertThat(t.getFsyncs(), ElementsAre())

	// Close the file.
	err = f.Close()
	f = nil
	AssertEq(nil, err)

	// Now we should have received the flush operation (but still no fsync).
	ExpectThat(t.getFlushes(), ElementsAre("taco"))
	ExpectThat(t.getFsyncs(), ElementsAre())
}

func (t *FlushFSTest) CloseReports_MultipleTimes_NonOverlappingFileHandles() {
	var n int
	var err error

	// Open the file.
	f, err := os.OpenFile(path.Join(t.Dir, "foo"), os.O_WRONLY, 0)
	AssertEq(nil, err)

	defer func() {
		if f != nil {
			ExpectEq(nil, f.Close())
		}
	}()

	// Write some contents to the file.
	n, err = f.Write([]byte("taco"))
	AssertEq(nil, err)
	AssertEq(4, n)

	// At this point, no flushes or fsyncs should have happened.
	AssertThat(t.getFlushes(), ElementsAre())
	AssertThat(t.getFsyncs(), ElementsAre())

	// Close the file.
	err = f.Close()
	f = nil
	AssertEq(nil, err)

	// Now we should have received the flush operation (but still no fsync).
	AssertThat(t.getFlushes(), ElementsAre("taco"))
	AssertThat(t.getFsyncs(), ElementsAre())

	// Open the file again.
	f, err = os.OpenFile(path.Join(t.Dir, "foo"), os.O_WRONLY, 0)
	AssertEq(nil, err)

	// Write again; expect no further flushes.
	n, err = f.Write([]byte("p"))
	AssertEq(nil, err)
	AssertEq(1, n)

	AssertThat(t.getFlushes(), ElementsAre("taco"))
	AssertThat(t.getFsyncs(), ElementsAre())

	// Close the file. Now the new contents should be flushed.
	err = f.Close()
	f = nil
	AssertEq(nil, err)

	AssertThat(t.getFlushes(), ElementsAre("taco", "paco"))
	AssertThat(t.getFsyncs(), ElementsAre())
}

func (t *FlushFSTest) CloseReports_MultipleTimes_OverlappingFileHandles() {
	var n int
	var err error

	// Open the file with two handles.
	f1, err := os.OpenFile(path.Join(t.Dir, "foo"), os.O_WRONLY, 0)
	AssertEq(nil, err)

	f2, err := os.OpenFile(path.Join(t.Dir, "foo"), os.O_WRONLY, 0)
	AssertEq(nil, err)

	defer func() {
		if f1 != nil {
			ExpectEq(nil, f1.Close())
		}

		if f2 != nil {
			ExpectEq(nil, f2.Close())
		}
	}()

	// Write some contents with each handle.
	n, err = f1.Write([]byte("taco"))
	AssertEq(nil, err)
	AssertEq(4, n)

	n, err = f2.Write([]byte("p"))
	AssertEq(nil, err)
	AssertEq(1, n)

	// At this point, no flushes or fsyncs should have happened.
	AssertThat(t.getFlushes(), ElementsAre())
	AssertThat(t.getFsyncs(), ElementsAre())

	// Close one handle. The current contents should be flushed.
	err = f1.Close()
	f1 = nil
	AssertEq(nil, err)

	AssertThat(t.getFlushes(), ElementsAre("paco"))
	AssertThat(t.getFsyncs(), ElementsAre())

	// Write some more contents via the other handle. Again, no further flushes.
	n, err = f2.Write([]byte("orp"))
	AssertEq(nil, err)
	AssertEq(3, n)

	AssertThat(t.getFlushes(), ElementsAre("paco"))
	AssertThat(t.getFsyncs(), ElementsAre())

	// Close the handle. Now the new contents should be flushed.
	err = f2.Close()
	f2 = nil
	AssertEq(nil, err)

	AssertThat(t.getFlushes(), ElementsAre("paco", "porp"))
	AssertThat(t.getFsyncs(), ElementsAre())
}

func (t *FlushFSTest) CloseReports_DuplicatedFileDescriptor() {
	AssertTrue(false, "TODO")
}

func (t *FlushFSTest) CloseError() {
	// Open the file.
	f, err := os.OpenFile(path.Join(t.Dir, "foo"), os.O_RDWR, 0)
	AssertEq(nil, err)

	defer func() {
		if f != nil {
			ExpectEq(nil, f.Close())
		}
	}()

	// Configure a flush error.
	t.setFlushError(fuse.ENOENT)

	// Close the file.
	err = f.Close()
	f = nil

	AssertNe(nil, err)
	ExpectThat(err, Error(HasSubstr("TODO")))
}

func (t *FlushFSTest) FsyncReports() {
	var n int
	var err error

	// Open the file.
	f, err := os.OpenFile(path.Join(t.Dir, "foo"), os.O_WRONLY, 0)
	AssertEq(nil, err)

	defer func() {
		if f != nil {
			ExpectEq(nil, f.Close())
		}
	}()

	// Write some contents to the file.
	n, err = f.Write([]byte("taco"))
	AssertEq(nil, err)
	AssertEq(4, n)

	AssertThat(t.getFlushes(), ElementsAre())
	AssertThat(t.getFsyncs(), ElementsAre())

	// Fsync.
	err = f.Sync()
	AssertEq(nil, err)

	AssertThat(t.getFlushes(), ElementsAre())
	AssertThat(t.getFsyncs(), ElementsAre("taco"))

	// Write some more contents.
	n, err = f.Write([]byte("s"))
	AssertEq(nil, err)
	AssertEq(1, n)

	AssertThat(t.getFlushes(), ElementsAre())
	AssertThat(t.getFsyncs(), ElementsAre("taco"))

	// Fsync.
	err = f.Sync()
	AssertEq(nil, err)

	AssertThat(t.getFlushes(), ElementsAre())
	AssertThat(t.getFsyncs(), ElementsAre("taco", "tacos"))
}

func (t *FlushFSTest) FsyncError() {
	// Open the file.
	f, err := os.OpenFile(path.Join(t.Dir, "foo"), os.O_RDWR, 0)
	AssertEq(nil, err)

	defer func() {
		if f != nil {
			ExpectEq(nil, f.Close())
		}
	}()

	// Configure an fsync error.
	t.setFsyncError(fuse.ENOENT)

	// Fsync.
	err = f.Sync()

	AssertNe(nil, err)
	ExpectThat(err, Error(HasSubstr("TODO")))
}
<|endoftext|>


<commit_before>package tests

import (
	"testing"
	"github.com/kalcok/jc"
	"fmt"
)

// Creates <num> of records of ImplicitID type
func prepareSimpleRecords(num int, customData string) (ids []interface{}) {
	var doc ImplicitID

	if customData == "" {
		customData = "prepareSimpleRecords"
	}

	for i := 0; i < num; i++ {
		doc = ImplicitID{Data: customData}
		jc.NewDocument(&doc)
		doc.Save(true)
		ids = append(ids, doc.ID())
	}
	return ids
}

func TestQueryInit(t *testing.T) {
	var docs []ImplicitID
	_, err := jc.NewQuery(&docs)

	if err != nil {
		t.Error(fmt.Sprintf("Failed to initialize new query: %s", err))
	}
}

func TestQueryImplicitCollection(t *testing.T) {
	var docs []ImplicitCollection
	expectedCollection := "implicit_collection"

	q, _ := jc.NewQuery(&docs)

	if q.Collection() != expectedCollection {
		t.Error(fmt.Sprintf("Failed to set implicit collection to query. Expected '%s', got '%s'",
			q.Collection(),
			expectedCollection))
	}
}

func TestQueryExplicitCollection(t *testing.T) {
	var docs []ExplicitCollection
	expectedCollection := "my_collection"

	q, _ := jc.NewQuery(&docs)

	if q.Collection() != expectedCollection {
		t.Error(fmt.Sprintf("Failed to set explicit collection to query. Expected '%s', got '%s'",
			q.Collection(),
			expectedCollection))
	}
}

func TestQuerySelectSliceResult(t *testing.T) {
	prepareSimpleRecords(2, "")
	var docs []ImplicitID

	q, _ := jc.NewQuery(&docs)

	err := q.Execute(true)

	if err != nil {
		t.Error(fmt.Sprintf("Failed to select multiple documents from DB. Error: %s", err))
	}
}

func TestQuerySelectNonSliceResult(t *testing.T) {
	data := "single record"
	prepareSimpleRecords(2, data)
	var doc ImplicitID

	q, _ := jc.NewQuery(&doc)

	err := q.Execute(true)

	if err != nil {
		t.Error(fmt.Sprintf("Failed to select single document from DB. Error: %s", err))
	}
}

func TestQuerySelectAll(t *testing.T) {
	dropTestDB()
	recordNumber := 14
	prepareSimpleRecords(recordNumber, "")
	var docs []ImplicitID

	q, _ := jc.NewQuery(&docs)

	q.Execute(true)

	if len(docs) != recordNumber {
		t.Error(fmt.Sprintf("Failed to select All records from DB. Expected %d, got %d",
			recordNumber, len(docs)))
	}
}

func TestQuerySliceIntegrity(t *testing.T) {
	const recordsNumber = 10

	var data [recordsNumber]string
	var results []ExplicitID

	dropTestDB()

	for i := 0; i < recordsNumber; i++ {
		data[i] = fmt.Sprintf("Integrity test %d", i)
		doc := ExplicitID{MyID: i, Data: data[i]}

		jc.NewDocument(&doc)
		doc.Save(true)
	}

	q, _ := jc.NewQuery(&results)

	q.Execute(true)

	for _, record := range results {
		if record.Data != data[record.MyID] {
			t.Error(
				fmt.Sprintf("Integrity failed for record ID '%d'. Expected data '%s', got '%s'",
					record.MyID, data[record.MyID], record.Data))
		}
	}
}

func TestQueryNonSliceIntegrity(t *testing.T) {
	dropTestDB()
	data := "NonSliceIntegrity"
	prepareSimpleRecords(3, data)

	var doc ImplicitID

	q, _ := jc.NewQuery(&doc)
	q.Execute(true)

	if doc.Data != data {
		t.Error(fmt.Sprintf("Integrity failed for single record query. Expected '%s', got '%s'", data, doc.Data))
	}

}

func TestQuerySliceResetOnMultipleSelects(t *testing.T) {
	dropTestDB()
	firstData := "First batch"
	firstBatch := 10
	secondData := "Second batch"
	secondBatch := 5
	prepareSimpleRecords(firstBatch, firstData)

	docs := []ImplicitID{}

	q, _ := jc.NewQuery(&docs)
	q.Execute(true)

	dropTestDB()
	prepareSimpleRecords(secondBatch, secondData)
	q.Execute(true)

	if len(docs) != secondBatch {
		t.Error("Failed to clean up target slice between multiple selects")
	}
}
<commit_msg>More Query tests<commit_after>package tests

import (
	"testing"
	"github.com/kalcok/jc"
	"fmt"
	"gopkg.in/mgo.v2/bson"
)

// Creates <num> of records of ImplicitID type
func prepareSimpleRecords(num int, customData string) (ids []interface{}) {
	var doc ImplicitID

	if customData == "" {
		customData = "prepareSimpleRecords"
	}

	for i := 0; i < num; i++ {
		doc = ImplicitID{Data: customData}
		jc.NewDocument(&doc)
		doc.Save(true)
		ids = append(ids, doc.ID())
	}
	return ids
}

func TestQueryInit(t *testing.T) {
	var docs []ImplicitID
	_, err := jc.NewQuery(&docs)

	if err != nil {
		t.Error(fmt.Sprintf("Failed to initialize new query: %s", err))
	}
}

func TestQueryImplicitCollection(t *testing.T) {
	var docs []ImplicitCollection
	expectedCollection := "implicit_collection"

	q, _ := jc.NewQuery(&docs)

	if q.Collection() != expectedCollection {
		t.Error(fmt.Sprintf("Failed to set implicit collection to query. Expected '%s', got '%s'",
			q.Collection(),
			expectedCollection))
	}
}

func TestQueryExplicitCollection(t *testing.T) {
	var docs []ExplicitCollection
	expectedCollection := "my_collection"

	q, _ := jc.NewQuery(&docs)

	if q.Collection() != expectedCollection {
		t.Error(fmt.Sprintf("Failed to set explicit collection to query. Expected '%s', got '%s'",
			q.Collection(),
			expectedCollection))
	}
}

func TestQuerySelectSliceResult(t *testing.T) {
	prepareSimpleRecords(2, "")
	var docs []ImplicitID

	q, _ := jc.NewQuery(&docs)

	err := q.Execute(true)

	if err != nil {
		t.Error(fmt.Sprintf("Failed to select multiple documents from DB. Error: %s", err))
	}
}

func TestQuerySelectNonSliceResult(t *testing.T) {
	data := "single record"
	prepareSimpleRecords(2, data)
	var doc ImplicitID

	q, _ := jc.NewQuery(&doc)

	err := q.Execute(true)

	if err != nil {
		t.Error(fmt.Sprintf("Failed to select single document from DB. Error: %s", err))
	}
}

func TestQuerySelectAll(t *testing.T) {
	dropTestDB()
	recordNumber := 14
	prepareSimpleRecords(recordNumber, "")
	var docs []ImplicitID

	q, _ := jc.NewQuery(&docs)

	q.Execute(true)

	if len(docs) != recordNumber {
		t.Error(fmt.Sprintf("Failed to select All records from DB. Expected %d, got %d",
			recordNumber, len(docs)))
	}
}

func TestQuerySliceIntegrity(t *testing.T) {
	const recordsNumber = 10

	var data [recordsNumber]string
	var results []ExplicitID

	dropTestDB()

	for i := 0; i < recordsNumber; i++ {
		data[i] = fmt.Sprintf("Integrity test %d", i)
		doc := ExplicitID{MyID: i, Data: data[i]}

		jc.NewDocument(&doc)
		doc.Save(true)
	}

	q, _ := jc.NewQuery(&results)

	q.Execute(true)

	for _, record := range results {
		if record.Data != data[record.MyID] {
			t.Error(
				fmt.Sprintf("Integrity failed for record ID '%d'. Expected data '%s', got '%s'",
					record.MyID, data[record.MyID], record.Data))
		}
	}
}

func TestQueryNonSliceIntegrity(t *testing.T) {
	dropTestDB()
	data := "NonSliceIntegrity"
	prepareSimpleRecords(3, data)

	var doc ImplicitID

	q, _ := jc.NewQuery(&doc)
	q.Execute(true)

	if doc.Data != data {
		t.Error(fmt.Sprintf("Integrity failed for single record query. Expected '%s', got '%s'", data, doc.Data))
	}

}

func TestQuerySliceResetOnMultipleSelects(t *testing.T) {
	dropTestDB()
	firstData := "First batch"
	firstBatch := 10
	secondData := "Second batch"
	secondBatch := 5
	prepareSimpleRecords(firstBatch, firstData)

	docs := []ImplicitID{}

	q, _ := jc.NewQuery(&docs)
	q.Execute(true)

	dropTestDB()
	prepareSimpleRecords(secondBatch, secondData)
	q.Execute(true)

	if len(docs) != secondBatch {
		t.Error("Failed to clean up target slice between multiple selects")
	}
}

func TestQueryLimit(t *testing.T) {
	limit := 5
	prepareSimpleRecords(10, "TestQueryLimit")
	docs := []ImplicitID{}

	q, _ := jc.NewQuery(&docs)
	q.Limit(limit).Execute(true)

	if len(docs) != limit {
		t.Error("Failed to impose query limit")
	}
}

func TestQuerySkip(t *testing.T) {
	dropTestDB()
	skip := 1

	sample := ExplicitID{MyID: 1, Data: "TestQuery"}
	jc.NewDocument(&sample)
	sample.Save(true)
	sample.MyID = 2
	sample.Save(true)
	sample.MyID = 3
	sample.Save(true)

	result := []ExplicitID{}
	q, _ := jc.NewQuery(&result)
	q.Skip(skip).Execute(true)

	for _, record := range result {
		if record.MyID == 1 {
			t.Error("Failed to skip over entries in DB")
		}
	}
}

func TestQueryFilter(t *testing.T) {
	expectedData := "This is waht we want"
	prepareSimpleRecords(3, "Not what We want")

	expected := ImplicitID{Data: expectedData}
	jc.NewDocument(&expected)

	expected.Save(true)

	result := ImplicitID{}
	q, _ := jc.NewQuery(&result)

	q.Filter(bson.M{"data": expectedData}).Execute(true)

	if result.Data != expectedData {
		t.Error("Failed to select records based on selected filter")
	}
}<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"

	"github.com/codegangsta/cli"
	"github.com/coreos/go-etcd/etcd"
)

const (
	dockerIP = "172.17.42.1"
)

func commandExecuter(c *cli.Context) {
	if !c.IsSet("container") {
		fmt.Println("--container argument is required")
		return
	}

	if c.IsSet("delete-all") {
		if err := deregister(c.GlobalString("container")); err != nil {
			fmt.Fprintf(os.Stderr, "deregistration for container %s, failed: %s\n", c.GlobalString("container"), err)
			os.Exit(1)
		}

		fmt.Printf("%s container deregistered\n", c.GlobalString("container"))
		os.Exit(0)
	}

	if !c.IsSet("port") {
		fmt.Println("--port argument is required")
		return
	}

	var mappedPort string
	if c.IsSet("mapped-port") {
		mappedPort = c.GlobalString("mapped-port")
	} else {
		mappedPort = c.GlobalString("port")
	}

	if err := register(c.GlobalString("container"), c.GlobalString("ip"), c.GlobalString("port"), mappedPort, uint64(c.GlobalInt("ttl"))); err != nil {
		fmt.Fprintf(os.Stderr, "registration for container %s, failed: %s\n", c.GlobalString("container"), err)
		os.Exit(1)
	}

	fmt.Printf("host's ip and port for container %s registered\n", c.GlobalString("container"))
	os.Exit(0)
}

func register(container string, ip string, port string, mappedPort string, ttl uint64) error {
	etcdClient := etcd.NewClient([]string{fmt.Sprintf("http://%s:4001", dockerIP)})

	// Create directory if it already exist it report an error, but it is ignore
	etcdClient.SetDir(fmt.Sprint("containers/", container), ttl)

	if _, err := etcdClient.Set(fmt.Sprintf("containers/%s/ports/%s/host/", container, port), ip, ttl); err != nil {
		return err
	}

	if _, err := etcdClient.Set(fmt.Sprintf("containers/%s/ports/%s/port/", container, port), mappedPort, ttl); err != nil {
		return err
	}

	return nil
}

func deregister(container string) error {
	etcdClient := etcd.NewClient([]string{fmt.Sprintf("http://%s:4001", dockerIP)})

	if _, err := etcdClient.Delete(fmt.Sprint("containers/", container), true); err != nil {
		return err
	}

	return nil
}

func main() {
	app := cli.NewApp()
	app.Name = "register"
	app.Usage = "Register and deregister in local Etcd container the host and port of the specified service name"
	app.Action = commandExecuter
	app.Version = "0.0.0"
	app.Flags = []cli.Flag{
		cli.StringFlag{Name: "container, c", Usage: "The container name or id"},
		cli.StringFlag{Name: "ip, i", Value: "127.0.0.1", Usage: "The host's ip name or ip where the service is running"},
		cli.StringFlag{Name: "port, p", Usage: "The original port of the service"},
		cli.StringFlag{Name: "mapped-port, mp", Usage: "The real port which the service is listening; by default port"},
		cli.IntFlag{Name: "ttl", Value: 0, Usage: "The time to live for the registration"},
		cli.BoolFlag{Name: "delete-all, da", Usage: "Remove all the entries for this container on etcd"},
	}

	app.Run(os.Args)
}
<commit_msg>Improved commanline help output message<commit_after>package main

import (
	"fmt"
	"os"

	"github.com/codegangsta/cli"
	"github.com/coreos/go-etcd/etcd"
)

const (
	dockerIP = "172.17.42.1"
)

func commandExecuter(c *cli.Context) {
	if !c.IsSet("container") {
		fmt.Println("--container argument is required")
		return
	}

	if c.IsSet("delete-all") {
		if err := deregister(c.GlobalString("container")); err != nil {
			fmt.Fprintf(os.Stderr, "deregistration for container %s, failed: %s\n", c.GlobalString("container"), err)
			os.Exit(1)
		}

		fmt.Printf("%s container deregistered\n", c.GlobalString("container"))
		os.Exit(0)
	}

	if !c.IsSet("port") {
		fmt.Println("--port argument is required")
		return
	}

	var mappedPort string
	if c.IsSet("mapped-port") {
		mappedPort = c.GlobalString("mapped-port")
	} else {
		mappedPort = c.GlobalString("port")
	}

	if err := register(c.GlobalString("container"), c.GlobalString("ip"), c.GlobalString("port"), mappedPort, uint64(c.GlobalInt("ttl"))); err != nil {
		fmt.Fprintf(os.Stderr, "registration for container %s, failed: %s\n", c.GlobalString("container"), err)
		os.Exit(1)
	}

	fmt.Printf("the ip or name host and port for container %s registered\n", c.GlobalString("container"))
	os.Exit(0)
}

func register(container string, ip string, port string, mappedPort string, ttl uint64) error {
	etcdClient := etcd.NewClient([]string{fmt.Sprintf("http://%s:4001", dockerIP)})

	// Create directory if it already exist it report an error, but it is ignore
	etcdClient.SetDir(fmt.Sprint("containers/", container), ttl)

	if _, err := etcdClient.Set(fmt.Sprintf("containers/%s/ports/%s/host/", container, port), ip, ttl); err != nil {
		return err
	}

	if _, err := etcdClient.Set(fmt.Sprintf("containers/%s/ports/%s/port/", container, port), mappedPort, ttl); err != nil {
		return err
	}

	return nil
}

func deregister(container string) error {
	etcdClient := etcd.NewClient([]string{fmt.Sprintf("http://%s:4001", dockerIP)})

	if _, err := etcdClient.Delete(fmt.Sprint("containers/", container), true); err != nil {
		return err
	}

	return nil
}

func main() {
	app := cli.NewApp()
	app.Name = "register"
	app.Usage = "Register and deregister in local Etcd container the host and port of the specified service name"
	app.Action = commandExecuter
	app.Version = "0.0.0"
	app.Flags = []cli.Flag{
		cli.StringFlag{Name: "container, c", Usage: "The container name or id [REQUIRED]"},
		cli.StringFlag{Name: "ip, i", Value: "127.0.0.1", Usage: "The ip or name of the host where the service is running"},
		cli.StringFlag{Name: "port, p", Usage: "The original port of the service [REQUIRED]"},
		cli.StringFlag{Name: "mapped-port, mp", Usage: "The real port which the service is listening; by default port"},
		cli.IntFlag{Name: "ttl", Value: 0, Usage: "The time to live for the registration"},
		cli.BoolFlag{Name: "delete-all, da", Usage: "Remove all the entries for this container on etcd; when used only --container is required and used"},
	}

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


<commit_before>package vm

import (
	"bytes"
	"math/big"
	"strconv"
	"testing"

	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/ethutil"
	"github.com/ethereum/go-ethereum/logger"
	"github.com/ethereum/go-ethereum/state"
	"github.com/ethereum/go-ethereum/tests/helper"
)

type Account struct {
	Balance string
	Code    string
	Nonce   string
	Storage map[string]string
}

type Log struct {
	AddressF string   `json:"address"`
	DataF    string   `json:"data"`
	TopicsF  []string `json:"topics"`
	BloomF   string   `json:"bloom"`
}

func (self Log) Address() []byte      { return ethutil.Hex2Bytes(self.AddressF) }
func (self Log) Data() []byte         { return ethutil.Hex2Bytes(self.DataF) }
func (self Log) RlpData() interface{} { return nil }
func (self Log) Topics() [][]byte {
	t := make([][]byte, len(self.TopicsF))
	for i, topic := range self.TopicsF {
		t[i] = ethutil.Hex2Bytes(topic)
	}
	return t
}

func StateObjectFromAccount(addr string, account Account) *state.StateObject {
	obj := state.NewStateObject(ethutil.Hex2Bytes(addr))
	obj.SetBalance(ethutil.Big(account.Balance))

	if ethutil.IsHex(account.Code) {
		account.Code = account.Code[2:]
	}
	obj.Code = ethutil.Hex2Bytes(account.Code)
	obj.Nonce = ethutil.Big(account.Nonce).Uint64()

	return obj
}

type Env struct {
	CurrentCoinbase   string
	CurrentDifficulty string
	CurrentGasLimit   string
	CurrentNumber     string
	CurrentTimestamp  interface{}
	PreviousHash      string
}

type VmTest struct {
	Callcreates interface{}
	//Env         map[string]string
	Env         Env
	Exec        map[string]string
	Transaction map[string]string
	Logs        []Log
	Gas         string
	Out         string
	Post        map[string]Account
	Pre         map[string]Account
}

func RunVmTest(p string, t *testing.T) {
	tests := make(map[string]VmTest)
	helper.CreateFileTests(t, p, &tests)

	for name, test := range tests {
		statedb := state.New(helper.NewTrie())
		for addr, account := range test.Pre {
			obj := StateObjectFromAccount(addr, account)
			statedb.SetStateObject(obj)
			for a, v := range account.Storage {
				obj.SetState(helper.FromHex(a), ethutil.NewValue(helper.FromHex(v)))
			}
		}

		// XXX Yeah, yeah...
		env := make(map[string]string)
		env["currentCoinbase"] = test.Env.CurrentCoinbase
		env["currentDifficulty"] = test.Env.CurrentDifficulty
		env["currentGasLimit"] = test.Env.CurrentGasLimit
		env["currentNumber"] = test.Env.CurrentNumber
		env["previousHash"] = test.Env.PreviousHash
		if n, ok := test.Env.CurrentTimestamp.(float64); ok {
			env["currentTimestamp"] = strconv.Itoa(int(n))
		} else {
			env["currentTimestamp"] = test.Env.CurrentTimestamp.(string)
		}

		var (
			ret  []byte
			gas  *big.Int
			err  error
			logs state.Logs
		)

		if len(test.Exec) > 0 {
			ret, logs, gas, err = helper.RunVm(statedb, env, test.Exec)
		} else {
			ret, logs, gas, err = helper.RunState(statedb, env, test.Transaction)
		}

		// When an error is returned it doesn't always mean the tests fails.
		// Have to come up with some conditional failing mechanism.
		if err != nil {
			helper.Log.Infoln(err)
		}

		rexp := helper.FromHex(test.Out)
		if bytes.Compare(rexp, ret) != 0 {
			t.Errorf("%s's return failed. Expected %x, got %x\n", name, rexp, ret)
		}

		if len(test.Gas) > 0 {
			gexp := ethutil.Big(test.Gas)
			if gexp.Cmp(gas) != 0 {
				t.Errorf("%s's gas failed. Expected %v, got %v\n", name, gexp, gas)
			}
		}

		for addr, account := range test.Post {
			obj := statedb.GetStateObject(helper.FromHex(addr))
			if obj == nil {
				continue
			}

			if len(test.Exec) == 0 {
				if obj.Balance().Cmp(ethutil.Big(account.Balance)) != 0 {
					t.Errorf("%s's : (%x) balance failed. Expected %v, got %v => %v\n", name, obj.Address()[:4], account.Balance, obj.Balance(), new(big.Int).Sub(ethutil.Big(account.Balance), obj.Balance()))
				}
			}

			for addr, value := range account.Storage {
				v := obj.GetState(helper.FromHex(addr)).Bytes()
				vexp := helper.FromHex(value)

				if bytes.Compare(v, vexp) != 0 {
					t.Errorf("%s's : (%x: %s) storage failed. Expected %x, got %x (%v %v)\n", name, obj.Address()[0:4], addr, vexp, v, ethutil.BigD(vexp), ethutil.BigD(v))
				}
			}
		}

		if len(test.Logs) > 0 {
			// Logs within the test itself aren't correct, missing empty fields (32 0s)
			for i, log := range test.Logs {
				genBloom := ethutil.LeftPadBytes(types.LogsBloom(state.Logs{logs[i]}).Bytes(), 64)
				if !bytes.Equal(genBloom, ethutil.Hex2Bytes(log.BloomF)) {
					t.Errorf("bloom mismatch")
				}
			}
		}
	}
	logger.Flush()
}

// I've created a new function for each tests so it's easier to identify where the problem lies if any of them fail.
func TestVMArithmetic(t *testing.T) {
	const fn = "../files/vmtests/vmArithmeticTest.json"
	RunVmTest(fn, t)
}

func TestBitwiseLogicOperation(t *testing.T) {
	const fn = "../files/vmtests/vmBitwiseLogicOperationTest.json"
	RunVmTest(fn, t)
}

func TestBlockInfo(t *testing.T) {
	const fn = "../files/vmtests/vmBlockInfoTest.json"
	RunVmTest(fn, t)
}

func TestEnvironmentalInfo(t *testing.T) {
	const fn = "../files/vmtests/vmEnvironmentalInfoTest.json"
	RunVmTest(fn, t)
}

func TestFlowOperation(t *testing.T) {
	const fn = "../files/vmtests/vmIOandFlowOperationsTest.json"
	RunVmTest(fn, t)
}

func TestPushDupSwap(t *testing.T) {
	const fn = "../files/vmtests/vmPushDupSwapTest.json"
	RunVmTest(fn, t)
}

func TestVMSha3(t *testing.T) {
	const fn = "../files/vmtests/vmSha3Test.json"
	RunVmTest(fn, t)
}

func TestVm(t *testing.T) {
	const fn = "../files/vmtests/vmtests.json"
	RunVmTest(fn, t)
}

func TestVmLog(t *testing.T) {
	const fn = "../files/vmtests/vmLogTest.json"
	RunVmTest(fn, t)
}

func TestStateSystemOperations(t *testing.T) {
	const fn = "../files/StateTests/stSystemOperationsTest.json"
	RunVmTest(fn, t)
}

func TestStatePreCompiledContracts(t *testing.T) {
	const fn = "../files/StateTests/stPreCompiledContracts.json"
	RunVmTest(fn, t)
}

func TestStateRecursiveCreate(t *testing.T) {
	const fn = "../files/StateTests/stRecursiveCreate.json"
	RunVmTest(fn, t)
}

func TestStateSpecial(t *testing.T) {
	const fn = "../files/StateTests/stSpecialTest.json"
	RunVmTest(fn, t)
}

func TestStateRefund(t *testing.T) {
	const fn = "../files/StateTests/stRefundTest.json"
	RunVmTest(fn, t)
}
<commit_msg>Fixed gas check for vm test<commit_after>package vm

import (
	"bytes"
	"math/big"
	"strconv"
	"testing"

	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/ethutil"
	"github.com/ethereum/go-ethereum/logger"
	"github.com/ethereum/go-ethereum/state"
	"github.com/ethereum/go-ethereum/tests/helper"
)

type Account struct {
	Balance string
	Code    string
	Nonce   string
	Storage map[string]string
}

type Log struct {
	AddressF string   `json:"address"`
	DataF    string   `json:"data"`
	TopicsF  []string `json:"topics"`
	BloomF   string   `json:"bloom"`
}

func (self Log) Address() []byte      { return ethutil.Hex2Bytes(self.AddressF) }
func (self Log) Data() []byte         { return ethutil.Hex2Bytes(self.DataF) }
func (self Log) RlpData() interface{} { return nil }
func (self Log) Topics() [][]byte {
	t := make([][]byte, len(self.TopicsF))
	for i, topic := range self.TopicsF {
		t[i] = ethutil.Hex2Bytes(topic)
	}
	return t
}

func StateObjectFromAccount(addr string, account Account) *state.StateObject {
	obj := state.NewStateObject(ethutil.Hex2Bytes(addr))
	obj.SetBalance(ethutil.Big(account.Balance))

	if ethutil.IsHex(account.Code) {
		account.Code = account.Code[2:]
	}
	obj.Code = ethutil.Hex2Bytes(account.Code)
	obj.Nonce = ethutil.Big(account.Nonce).Uint64()

	return obj
}

type Env struct {
	CurrentCoinbase   string
	CurrentDifficulty string
	CurrentGasLimit   string
	CurrentNumber     string
	CurrentTimestamp  interface{}
	PreviousHash      string
}

type VmTest struct {
	Callcreates interface{}
	//Env         map[string]string
	Env         Env
	Exec        map[string]string
	Transaction map[string]string
	Logs        []Log
	Gas         string
	Out         string
	Post        map[string]Account
	Pre         map[string]Account
}

func RunVmTest(p string, t *testing.T) {
	tests := make(map[string]VmTest)
	helper.CreateFileTests(t, p, &tests)

	for name, test := range tests {
		statedb := state.New(helper.NewTrie())
		for addr, account := range test.Pre {
			obj := StateObjectFromAccount(addr, account)
			statedb.SetStateObject(obj)
			for a, v := range account.Storage {
				obj.SetState(helper.FromHex(a), ethutil.NewValue(helper.FromHex(v)))
			}
		}

		// XXX Yeah, yeah...
		env := make(map[string]string)
		env["currentCoinbase"] = test.Env.CurrentCoinbase
		env["currentDifficulty"] = test.Env.CurrentDifficulty
		env["currentGasLimit"] = test.Env.CurrentGasLimit
		env["currentNumber"] = test.Env.CurrentNumber
		env["previousHash"] = test.Env.PreviousHash
		if n, ok := test.Env.CurrentTimestamp.(float64); ok {
			env["currentTimestamp"] = strconv.Itoa(int(n))
		} else {
			env["currentTimestamp"] = test.Env.CurrentTimestamp.(string)
		}

		var (
			ret  []byte
			gas  *big.Int
			err  error
			logs state.Logs
		)

		isVmTest := len(test.Exec) > 0

		if isVmTest {
			ret, logs, gas, err = helper.RunVm(statedb, env, test.Exec)
		} else {
			ret, logs, gas, err = helper.RunState(statedb, env, test.Transaction)
		}

		// When an error is returned it doesn't always mean the tests fails.
		// Have to come up with some conditional failing mechanism.
		if err != nil {
			helper.Log.Infoln(err)
		}

		rexp := helper.FromHex(test.Out)
		if bytes.Compare(rexp, ret) != 0 {
			t.Errorf("%s's return failed. Expected %x, got %x\n", name, rexp, ret)
		}

		if isVmTest {
			if len(test.Gas) == 0 && err == nil {
				t.Errorf("%s's gas unspecified, indicating an error. VM returned (incorrectly) successfull")
			} else {
				gexp := ethutil.Big(test.Gas)
				if gexp.Cmp(gas) != 0 {
					t.Errorf("%s's gas failed. Expected %v, got %v\n", name, gexp, gas)
				}
			}
		}

		for addr, account := range test.Post {
			obj := statedb.GetStateObject(helper.FromHex(addr))
			if obj == nil {
				continue
			}

			if len(test.Exec) == 0 {
				if obj.Balance().Cmp(ethutil.Big(account.Balance)) != 0 {
					t.Errorf("%s's : (%x) balance failed. Expected %v, got %v => %v\n", name, obj.Address()[:4], account.Balance, obj.Balance(), new(big.Int).Sub(ethutil.Big(account.Balance), obj.Balance()))
				}
			}

			for addr, value := range account.Storage {
				v := obj.GetState(helper.FromHex(addr)).Bytes()
				vexp := helper.FromHex(value)

				if bytes.Compare(v, vexp) != 0 {
					t.Errorf("%s's : (%x: %s) storage failed. Expected %x, got %x (%v %v)\n", name, obj.Address()[0:4], addr, vexp, v, ethutil.BigD(vexp), ethutil.BigD(v))
				}
			}
		}

		if len(test.Logs) > 0 {
			// Logs within the test itself aren't correct, missing empty fields (32 0s)
			for i, log := range test.Logs {
				genBloom := ethutil.LeftPadBytes(types.LogsBloom(state.Logs{logs[i]}).Bytes(), 64)
				if !bytes.Equal(genBloom, ethutil.Hex2Bytes(log.BloomF)) {
					t.Errorf("bloom mismatch")
				}
			}
		}
	}
	logger.Flush()
}

// I've created a new function for each tests so it's easier to identify where the problem lies if any of them fail.
func TestVMArithmetic(t *testing.T) {
	const fn = "../files/vmtests/vmArithmeticTest.json"
	RunVmTest(fn, t)
}

func TestBitwiseLogicOperation(t *testing.T) {
	const fn = "../files/vmtests/vmBitwiseLogicOperationTest.json"
	RunVmTest(fn, t)
}

func TestBlockInfo(t *testing.T) {
	const fn = "../files/vmtests/vmBlockInfoTest.json"
	RunVmTest(fn, t)
}

func TestEnvironmentalInfo(t *testing.T) {
	const fn = "../files/vmtests/vmEnvironmentalInfoTest.json"
	RunVmTest(fn, t)
}

func TestFlowOperation(t *testing.T) {
	const fn = "../files/vmtests/vmIOandFlowOperationsTest.json"
	RunVmTest(fn, t)
}

func TestPushDupSwap(t *testing.T) {
	const fn = "../files/vmtests/vmPushDupSwapTest.json"
	RunVmTest(fn, t)
}

func TestVMSha3(t *testing.T) {
	const fn = "../files/vmtests/vmSha3Test.json"
	RunVmTest(fn, t)
}

func TestVm(t *testing.T) {
	const fn = "../files/vmtests/vmtests.json"
	RunVmTest(fn, t)
}

func TestVmLog(t *testing.T) {
	const fn = "../files/vmtests/vmLogTest.json"
	RunVmTest(fn, t)
}

func TestStateSystemOperations(t *testing.T) {
	const fn = "../files/StateTests/stSystemOperationsTest.json"
	RunVmTest(fn, t)
}

func TestStatePreCompiledContracts(t *testing.T) {
	const fn = "../files/StateTests/stPreCompiledContracts.json"
	RunVmTest(fn, t)
}

func TestStateRecursiveCreate(t *testing.T) {
	const fn = "../files/StateTests/stRecursiveCreate.json"
	RunVmTest(fn, t)
}

func TestStateSpecial(t *testing.T) {
	const fn = "../files/StateTests/stSpecialTest.json"
	RunVmTest(fn, t)
}

func TestStateRefund(t *testing.T) {
	const fn = "../files/StateTests/stRefundTest.json"
	RunVmTest(fn, t)
}
<|endoftext|>


<commit_before>package jwt

import "time"

// Mapper is the interface used internally to map key-value pairs
type Mapper interface {
	ToMap() map[string]interface{}
	Add(key string, value interface{})
	Get(key string) interface{}
}

// ToString will return a string representation of a map
func ToString(i interface{}) string {
	if i == nil {
		return ""
	}

	if s, ok := i.(string); ok {
		return s
	}

	return ""
}

// ToTime will try to convert a given input to a time.Time structure
func ToTime(i interface{}) time.Time {
	if i == nil {
		return time.Time{}
	}

	if t, ok := i.(int64); ok {
		return time.Unix(t, 0)
	} else if t, ok := i.(float64); ok {
		return time.Unix(int64(t), 0)
	}

	return time.Time{}
}

// Filter will filter out elemets based on keys in a given input map na key-slice
func Filter(elements map[string]interface{}, keys ...string) map[string]interface{} {
	var keyIdx = make(map[string]bool)
	var result = make(map[string]interface{})

	for _, key := range keys {
		keyIdx[key] = true
	}

	for k, e := range elements {
		if _, ok := keyIdx[k]; !ok {
			result[k] = e
		}
	}

	return result
}

// Copy will copy all elements in a map and return a new representational map
func Copy(elements map[string]interface{}) (result map[string]interface{}) {
	result = make(map[string]interface{}, len(elements))
	for k, v := range elements {
		result[k] = v
	}

	return result
}
<commit_msg>token/jwt: Allow single element string arrays to be treated as strings<commit_after>package jwt

import "time"

// Mapper is the interface used internally to map key-value pairs
type Mapper interface {
	ToMap() map[string]interface{}
	Add(key string, value interface{})
	Get(key string) interface{}
}

// ToString will return a string representation of a map
func ToString(i interface{}) string {
	if i == nil {
		return ""
	}

	if s, ok := i.(string); ok {
		return s
	}

	if sl, ok := i.([]string); ok {
		if len(sl) == 1 {
			return sl[0]
		}
	}

	return ""
}

// ToTime will try to convert a given input to a time.Time structure
func ToTime(i interface{}) time.Time {
	if i == nil {
		return time.Time{}
	}

	if t, ok := i.(int64); ok {
		return time.Unix(t, 0)
	} else if t, ok := i.(float64); ok {
		return time.Unix(int64(t), 0)
	}

	return time.Time{}
}

// Filter will filter out elemets based on keys in a given input map na key-slice
func Filter(elements map[string]interface{}, keys ...string) map[string]interface{} {
	var keyIdx = make(map[string]bool)
	var result = make(map[string]interface{})

	for _, key := range keys {
		keyIdx[key] = true
	}

	for k, e := range elements {
		if _, ok := keyIdx[k]; !ok {
			result[k] = e
		}
	}

	return result
}

// Copy will copy all elements in a map and return a new representational map
func Copy(elements map[string]interface{}) (result map[string]interface{}) {
	result = make(map[string]interface{}, len(elements))
	for k, v := range elements {
		result[k] = v
	}

	return result
}
<|endoftext|>


<commit_before>package metric_publish

import (
	"fmt"
	"time"

	"github.com/nsqio/go-nsq"
	"github.com/op/go-logging"
	"github.com/raintank/met"
	msg "github.com/raintank/raintank-metric/msg"
	"github.com/raintank/raintank-metric/schema"
)

var log = logging.MustGetLogger("default")

var (
	globalProducer    *nsq.Producer
	topic             string
	metricsPublished  met.Count
	messagesPublished met.Count
	messagesSize      met.Meter
	metricsPerMessage met.Meter
	publishDuration   met.Timer
)

func Init(metrics met.Backend, topic string, addr string, enabled bool) {
	if !enabled {
		return
	}

	cfg := nsq.NewConfig()
	cfg.UserAgent = fmt.Sprintf("raintank-apps-server")
	var err error
	globalProducer, err = nsq.NewProducer(addr, cfg)
	if err != nil {
		log.Fatalf("failed to initialize nsq producer. %s", err)
	}
	err = globalProducer.Ping()
	if err != nil {
		log.Fatalf("can't connect to nsqd: %s", err)
	}
	metricsPublished = metrics.NewCount("metricpublisher.metrics-published")
	messagesPublished = metrics.NewCount("metricpublisher.messages-published")
	messagesSize = metrics.NewMeter("metricpublisher.message_size", 0)
	metricsPerMessage = metrics.NewMeter("metricpublisher.metrics_per_message", 0)
	publishDuration = metrics.NewTimer("metricpublisher.publish_duration", 0)
}

func Publish(metrics []*schema.MetricData) error {
	if globalProducer == nil {
		return nil
	}
	if len(metrics) == 0 {
		return nil
	}

	id := time.Now().UnixNano()
	data, err := msg.CreateMsg(metrics, id, msg.FormatMetricDataArrayMsgp)
	if err != nil {
		log.Fatal(0, "Fatal error creating metric message: %s", err)
	}
	metricsPublished.Inc(int64(len(metrics)))
	messagesPublished.Inc(1)
	messagesSize.Value(int64(len(data)))
	metricsPerMessage.Value(int64(len(metrics)))
	pre := time.Now()
	err = globalProducer.Publish(topic, data)
	publishDuration.Value(time.Since(pre))
	if err != nil {
		log.Fatal(0, "can't publish to nsqd: %s", err)
	}
	log.Info("published metrics %d size=%d", id, len(data))

	//globalProducer.Stop()
	return nil
}
<commit_msg>debug log that metrics are not being published due to publishing disabled<commit_after>package metric_publish

import (
	"fmt"
	"time"

	"github.com/nsqio/go-nsq"
	"github.com/op/go-logging"
	"github.com/raintank/met"
	msg "github.com/raintank/raintank-metric/msg"
	"github.com/raintank/raintank-metric/schema"
)

var log = logging.MustGetLogger("default")

var (
	globalProducer    *nsq.Producer
	topic             string
	metricsPublished  met.Count
	messagesPublished met.Count
	messagesSize      met.Meter
	metricsPerMessage met.Meter
	publishDuration   met.Timer
)

func Init(metrics met.Backend, topic string, addr string, enabled bool) {
	if !enabled {
		return
	}

	cfg := nsq.NewConfig()
	cfg.UserAgent = fmt.Sprintf("raintank-apps-server")
	var err error
	globalProducer, err = nsq.NewProducer(addr, cfg)
	if err != nil {
		log.Fatalf("failed to initialize nsq producer. %s", err)
	}
	err = globalProducer.Ping()
	if err != nil {
		log.Fatalf("can't connect to nsqd: %s", err)
	}
	metricsPublished = metrics.NewCount("metricpublisher.metrics-published")
	messagesPublished = metrics.NewCount("metricpublisher.messages-published")
	messagesSize = metrics.NewMeter("metricpublisher.message_size", 0)
	metricsPerMessage = metrics.NewMeter("metricpublisher.metrics_per_message", 0)
	publishDuration = metrics.NewTimer("metricpublisher.publish_duration", 0)
}

func Publish(metrics []*schema.MetricData) error {
	if globalProducer == nil {
		log.Debugf("droping %d metrics as publishing is disbaled", len(metrics))
		return nil
	}
	if len(metrics) == 0 {
		return nil
	}

	id := time.Now().UnixNano()
	data, err := msg.CreateMsg(metrics, id, msg.FormatMetricDataArrayMsgp)
	if err != nil {
		log.Fatal(0, "Fatal error creating metric message: %s", err)
	}
	metricsPublished.Inc(int64(len(metrics)))
	messagesPublished.Inc(1)
	messagesSize.Value(int64(len(data)))
	metricsPerMessage.Value(int64(len(metrics)))
	pre := time.Now()
	err = globalProducer.Publish(topic, data)
	publishDuration.Value(time.Since(pre))
	if err != nil {
		log.Fatal(0, "can't publish to nsqd: %s", err)
	}
	log.Info("published metrics %d size=%d", id, len(data))

	//globalProducer.Stop()
	return nil
}
<|endoftext|>


<commit_before>package testutil

import (
	"crypto/rand"
	"io/ioutil"
	"os"
	"testing"

	istore "veyron/services/store/server"

	"veyron2/ipc"
	"veyron2/naming"
	"veyron2/security"
)

// NewStore creates a new testing instance of the store server and returns
// an object name that identifies the instance and a closure that can
// be used to terminate the instance and clean up.
func NewStore(t *testing.T, server ipc.Server, id security.PublicID) (string, func()) {
	// Create a temporary directory for the store server.
	prefix := "vstore-test-db"
	dbName, err := ioutil.TempDir("", prefix)
	if err != nil {
		t.Fatalf("TempDir(%v, %v) failed: %v", "", prefix, err)
	}

	// Create a new StoreService.
	config := istore.ServerConfig{Admin: id, DBName: dbName}
	storeService, err := istore.New(config)
	if err != nil {
		t.Fatalf("New(%v) failed: %v", config, err)
	}

	var buf [16]byte
	if _, err := rand.Read(buf[:]); err != nil {
		t.Fatalf("rand.Read() failed: %v", err)
	}

	// Register the services.
	storeDispatcher := istore.NewStoreDispatcher(storeService, nil)
	if err := server.Serve("", storeDispatcher); err != nil {
		t.Fatalf("Register(%v) failed: %v", storeDispatcher, err)
	}

	// Create an endpoint and start listening.
	protocol, hostname := "tcp", "127.0.0.1:0"
	ep, err := server.Listen(protocol, hostname)
	if err != nil {
		t.Fatalf("Listen(%v, %v) failed: %v", protocol, hostname, err)
	}

	name := naming.JoinAddressName(ep.String(), "")

	// Create a closure that cleans things up.
	cleanup := func() {
		server.Stop()
		os.RemoveAll(dbName)
	}

	return name, cleanup
}
<commit_msg>veyron/services/store/testutil: import type registry hack so that tests that use the mock store with user-defined types do not panic.<commit_after>package testutil

import (
	"crypto/rand"
	"io/ioutil"
	"os"
	"testing"

	istore "veyron/services/store/server"
	_ "veyron/services/store/typeregistryhack"

	"veyron2/ipc"
	"veyron2/naming"
	"veyron2/security"
)

// NewStore creates a new testing instance of the store server and returns
// an object name that identifies the instance and a closure that can
// be used to terminate the instance and clean up.
func NewStore(t *testing.T, server ipc.Server, id security.PublicID) (string, func()) {
	// Create a temporary directory for the store server.
	prefix := "vstore-test-db"
	dbName, err := ioutil.TempDir("", prefix)
	if err != nil {
		t.Fatalf("TempDir(%v, %v) failed: %v", "", prefix, err)
	}

	// Create a new StoreService.
	config := istore.ServerConfig{Admin: id, DBName: dbName}
	storeService, err := istore.New(config)
	if err != nil {
		t.Fatalf("New(%v) failed: %v", config, err)
	}

	var buf [16]byte
	if _, err := rand.Read(buf[:]); err != nil {
		t.Fatalf("rand.Read() failed: %v", err)
	}

	// Register the services.
	storeDispatcher := istore.NewStoreDispatcher(storeService, nil)
	if err := server.Serve("", storeDispatcher); err != nil {
		t.Fatalf("Register(%v) failed: %v", storeDispatcher, err)
	}

	// Create an endpoint and start listening.
	protocol, hostname := "tcp", "127.0.0.1:0"
	ep, err := server.Listen(protocol, hostname)
	if err != nil {
		t.Fatalf("Listen(%v, %v) failed: %v", protocol, hostname, err)
	}

	name := naming.JoinAddressName(ep.String(), "")

	// Create a closure that cleans things up.
	cleanup := func() {
		server.Stop()
		os.RemoveAll(dbName)
	}

	return name, cleanup
}
<|endoftext|>


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

package x11driver

import (
	"image"
	"image/color"
	"image/draw"
	"log"
	"sync"
	"unsafe"

	"github.com/BurntSushi/xgb"
	"github.com/BurntSushi/xgb/render"
	"github.com/BurntSushi/xgb/shm"
	"github.com/BurntSushi/xgb/xproto"

	"golang.org/x/exp/shiny/driver/internal/swizzle"
	"golang.org/x/exp/shiny/screen"
)

type bufferImpl struct {
	s *screenImpl

	addr unsafe.Pointer
	buf  []byte
	rgba image.RGBA
	size image.Point
	xs   shm.Seg

	mu        sync.Mutex
	nUpload   uint32
	released  bool
	cleanedUp bool
}

func (b *bufferImpl) Size() image.Point       { return b.size }
func (b *bufferImpl) Bounds() image.Rectangle { return image.Rectangle{Max: b.size} }
func (b *bufferImpl) RGBA() *image.RGBA       { return &b.rgba }

func (b *bufferImpl) preUpload() {
	b.mu.Lock()
	if b.released {
		b.mu.Unlock()
		panic("x11driver: Buffer.Upload called after Buffer.Release")
	}
	needsSwizzle := b.nUpload == 0
	b.nUpload++
	b.mu.Unlock()

	if needsSwizzle {
		swizzle.BGRA(b.buf)
	}
}

func (b *bufferImpl) postUpload() {
	b.mu.Lock()
	b.nUpload--
	more := b.nUpload != 0
	released := b.released
	b.mu.Unlock()

	if more {
		return
	}
	if released {
		b.cleanUp()
	} else {
		swizzle.BGRA(b.buf)
	}
}

func (b *bufferImpl) Release() {
	b.mu.Lock()
	cleanUp := !b.released && b.nUpload == 0
	b.released = true
	b.mu.Unlock()

	if cleanUp {
		b.cleanUp()
	}
}

func (b *bufferImpl) cleanUp() {
	b.mu.Lock()
	alreadyCleanedUp := b.cleanedUp
	b.cleanedUp = true
	b.mu.Unlock()

	if alreadyCleanedUp {
		panic("x11driver: Buffer clean-up occurred twice")
	}

	b.s.mu.Lock()
	delete(b.s.buffers, b.xs)
	b.s.mu.Unlock()

	shm.Detach(b.s.xc, b.xs)
	if err := shmClose(b.addr); err != nil {
		log.Printf("x11driver: shmClose: %v", err)
	}
}

func (b *bufferImpl) upload(u screen.Uploader, xd xproto.Drawable, xg xproto.Gcontext, depth uint8,
	dp image.Point, sr image.Rectangle, sender screen.Sender) {

	b.preUpload()

	// TODO: adjust if dp is outside dst bounds, or sr is outside src bounds.
	dr := sr.Sub(sr.Min).Add(dp)

	b.s.mu.Lock()
	b.s.nPendingUploads++
	b.s.mu.Unlock()

	cookie := shm.PutImage(
		b.s.xc, xd, xg,
		uint16(b.size.X), uint16(b.size.Y), // TotalWidth, TotalHeight,
		uint16(sr.Min.X), uint16(sr.Min.Y), // SrcX, SrcY,
		uint16(dr.Dx()), uint16(dr.Dy()), // SrcWidth, SrcHeight,
		int16(dr.Min.X), int16(dr.Min.Y), // DstX, DstY,
		depth, xproto.ImageFormatZPixmap,
		1, b.xs, 0, // 1 means send a completion event, 0 means a zero offset.
	)

	b.s.mu.Lock()
	b.s.uploads[cookie.Sequence] = completion{
		sender: sender,
		event: screen.UploadedEvent{
			Buffer:   b,
			Uploader: u,
		},
	}
	b.s.nPendingUploads--
	b.s.handleCompletions()
	b.s.mu.Unlock()
}

func fill(xc *xgb.Conn, xp render.Picture, dr image.Rectangle, src color.Color, op draw.Op) {
	r, g, b, a := src.RGBA()
	c := render.Color{
		Red:   uint16(r),
		Green: uint16(g),
		Blue:  uint16(b),
		Alpha: uint16(a),
	}
	x, y := dr.Min.X, dr.Min.Y
	if x < -0x8000 || 0x7fff < x || y < -0x8000 || 0x7fff < y {
		return
	}
	dx, dy := dr.Dx(), dr.Dy()
	if dx < 0 || 0xffff < dx || dy < 0 || 0xffff < dy {
		return
	}
	render.FillRectangles(xc, renderOp(op), xp, c, []xproto.Rectangle{{
		X:      int16(x),
		Y:      int16(y),
		Width:  uint16(dx),
		Height: uint16(dy),
	}})
}
<commit_msg>shiny/driver/x11driver: fix a buffer TOCTTOU race.<commit_after>// Copyright 2015 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.

package x11driver

import (
	"image"
	"image/color"
	"image/draw"
	"log"
	"sync"
	"unsafe"

	"github.com/BurntSushi/xgb"
	"github.com/BurntSushi/xgb/render"
	"github.com/BurntSushi/xgb/shm"
	"github.com/BurntSushi/xgb/xproto"

	"golang.org/x/exp/shiny/driver/internal/swizzle"
	"golang.org/x/exp/shiny/screen"
)

type bufferImpl struct {
	s *screenImpl

	addr unsafe.Pointer
	buf  []byte
	rgba image.RGBA
	size image.Point
	xs   shm.Seg

	mu        sync.Mutex
	nUpload   uint32
	released  bool
	cleanedUp bool
}

func (b *bufferImpl) Size() image.Point       { return b.size }
func (b *bufferImpl) Bounds() image.Rectangle { return image.Rectangle{Max: b.size} }
func (b *bufferImpl) RGBA() *image.RGBA       { return &b.rgba }

func (b *bufferImpl) preUpload() {
	b.mu.Lock()
	defer b.mu.Unlock()

	if b.released {
		panic("x11driver: Buffer.Upload called after Buffer.Release")
	}
	if b.nUpload == 0 {
		swizzle.BGRA(b.buf)
	}
	b.nUpload++
}

func (b *bufferImpl) postUpload() {
	b.mu.Lock()
	defer b.mu.Unlock()

	b.nUpload--
	if b.nUpload != 0 {
		return
	}

	if b.released {
		go b.cleanUp()
	} else {
		swizzle.BGRA(b.buf)
	}
}

func (b *bufferImpl) Release() {
	b.mu.Lock()
	defer b.mu.Unlock()

	if !b.released && b.nUpload == 0 {
		go b.cleanUp()
	}
	b.released = true
}

func (b *bufferImpl) cleanUp() {
	b.mu.Lock()
	if b.cleanedUp {
		b.mu.Unlock()
		panic("x11driver: Buffer clean-up occurred twice")
	}
	b.cleanedUp = true
	b.mu.Unlock()

	b.s.mu.Lock()
	delete(b.s.buffers, b.xs)
	b.s.mu.Unlock()

	shm.Detach(b.s.xc, b.xs)
	if err := shmClose(b.addr); err != nil {
		log.Printf("x11driver: shmClose: %v", err)
	}
}

func (b *bufferImpl) upload(u screen.Uploader, xd xproto.Drawable, xg xproto.Gcontext, depth uint8,
	dp image.Point, sr image.Rectangle, sender screen.Sender) {

	b.preUpload()

	// TODO: adjust if dp is outside dst bounds, or sr is outside src bounds.
	dr := sr.Sub(sr.Min).Add(dp)

	b.s.mu.Lock()
	b.s.nPendingUploads++
	b.s.mu.Unlock()

	cookie := shm.PutImage(
		b.s.xc, xd, xg,
		uint16(b.size.X), uint16(b.size.Y), // TotalWidth, TotalHeight,
		uint16(sr.Min.X), uint16(sr.Min.Y), // SrcX, SrcY,
		uint16(dr.Dx()), uint16(dr.Dy()), // SrcWidth, SrcHeight,
		int16(dr.Min.X), int16(dr.Min.Y), // DstX, DstY,
		depth, xproto.ImageFormatZPixmap,
		1, b.xs, 0, // 1 means send a completion event, 0 means a zero offset.
	)

	b.s.mu.Lock()
	b.s.uploads[cookie.Sequence] = completion{
		sender: sender,
		event: screen.UploadedEvent{
			Buffer:   b,
			Uploader: u,
		},
	}
	b.s.nPendingUploads--
	b.s.handleCompletions()
	b.s.mu.Unlock()
}

func fill(xc *xgb.Conn, xp render.Picture, dr image.Rectangle, src color.Color, op draw.Op) {
	r, g, b, a := src.RGBA()
	c := render.Color{
		Red:   uint16(r),
		Green: uint16(g),
		Blue:  uint16(b),
		Alpha: uint16(a),
	}
	x, y := dr.Min.X, dr.Min.Y
	if x < -0x8000 || 0x7fff < x || y < -0x8000 || 0x7fff < y {
		return
	}
	dx, dy := dr.Dx(), dr.Dy()
	if dx < 0 || 0xffff < dx || dy < 0 || 0xffff < dy {
		return
	}
	render.FillRectangles(xc, renderOp(op), xp, c, []xproto.Rectangle{{
		X:      int16(x),
		Y:      int16(y),
		Width:  uint16(dx),
		Height: uint16(dy),
	}})
}
<|endoftext|>


<commit_before><commit_msg>Fix tests. Confirmed that this is the last test that was broken.<commit_after><|endoftext|>