<commit_before>package workers

import (
	"fmt"
	"github.com/APTrust/exchange/constants"
	"github.com/APTrust/exchange/context"
	"github.com/APTrust/exchange/models"
	"net/url"
	"strconv"
	"time"
)

type APTSpotTestRestore struct {
	Context          *context.Context
	CreatedBefore    time.Time
	NotRestoredSince time.Time
	MaxSize          int64
	DryRun           bool
}

// NewAPTSpotTestRestore creates a new restore spot test worker.
// This is meant to run as a cron job.
//
// Param maxSize tells the worker to choose bags no larger than
// maxSize for restoration. Param createdBefore means choose bags
// created before this date. Param notRestoredSince means choose
// bags that have not been restored since this date (which helps
// prevent us restoring the same bag again and again).
func NewAPTSpotTestRestore(_context *context.Context, maxSize int64, createdBefore, notRestoredSince time.Time) *APTSpotTestRestore {
	return &APTSpotTestRestore{
		Context:          _context,
		CreatedBefore:    createdBefore,
		NotRestoredSince: notRestoredSince,
		MaxSize:          maxSize,
		DryRun:           false,
	}
}

// Run runs the spot test by choosing ONE bag from each institution
// that matches the specified criteria (smaller than maxSize, createdBefore
// the specified date and notRestoredSince the specified date).
// It creates a Restore WorkItem for each bag, and returns the WorkItems
// it created. The caller can get the WorkItem.Id and object identifier from there.
func (restoreTest *APTSpotTestRestore) Run() ([]*models.WorkItem, error) {
	restoreTest.logFacts()
	workItems := make([]*models.WorkItem, 0)
	institutions, err := restoreTest.GetInstitutions()
	if err != nil {
		return workItems, fmt.Errorf("Error getting list of institutions from Pharos: %v", err)
	}
	for _, inst := range institutions {
		restoreTest.Context.MessageLog.Info("Looking up objects for %s", inst.Identifier)
		obj, err := restoreTest.GetObjectFor(inst.Identifier)
		if err != nil {
			restoreTest.Context.MessageLog.Error(err.Error())
			continue
		}
		if obj == nil {
			restoreTest.Context.MessageLog.Info("No suitable objects for %s", inst.Identifier)
			continue
		}
		workItem, err := restoreTest.CreateWorkItem(obj)
		if err != nil {
			restoreTest.Context.MessageLog.Error("Error creating new Restore WorkItem for %s: %v",
				obj.Identifier, err)
			continue
		}
		workItems = append(workItems, workItem)
	}

	return workItems, nil
}

// logFacts logs our basic working parameters.
func (restoreTest *APTSpotTestRestore) logFacts() {
	restoreTest.Context.MessageLog.Info("MaxSize: %d, CreatedBefore: %s, NotRestoredSince: %s",
		restoreTest.MaxSize,
		restoreTest.CreatedBefore.Format(time.RFC3339),
		restoreTest.NotRestoredSince.Format(time.RFC3339))
	if restoreTest.DryRun {
		restoreTest.Context.MessageLog.Info("This is a DRY RUN, so no WorkItems will be created.")
	}
}

// GetInstitutions returns a list of all depositing institutions from Pharos.
func (restoreTest *APTSpotTestRestore) GetInstitutions() ([]*models.Institution, error) {
	resp := restoreTest.Context.PharosClient.InstitutionList(url.Values{})
	if resp.Error != nil {
		return nil, resp.Error
	}
	institutions := resp.Institutions()
	restoreTest.Context.MessageLog.Info("Got %d institutions from Pharos", len(institutions))
	return institutions, nil
}

// GetObjectFor returns the IntellectualObject we should restore for the
// specified institution. This object will be the first one we find in
// Pharos that matches all of the criteria, which include:
//
// institution - it belongs the specified institution
//
// createdBefore - it was created before the specified date
//
// notRestoredSince - it has not been restored since the specified date
//
// maxSize - it's total size is less than or equal to this many bytes
//
// state - is "A" for active
//
// access - is not "restricted"
func (restoreTest *APTSpotTestRestore) GetObjectFor(institution string) (*models.IntellectualObject, error) {
	var obj *models.IntellectualObject
	var err error
	hasMoreResults := true
	pageNumber := 1
	for hasMoreResults {
		obj, hasMoreResults, err = restoreTest.findOne(institution, pageNumber)
		if obj != nil || err != nil {
			break
		}
		pageNumber++
	}
	return obj, err
}

// findOne finds one IntellectualObject from the specified page of results
// that meets our criteria for restoration spot tests.
//
// Returns an IntellectualObject (or nil if none match our criteria), a boolean
// indicating whether Pharos has more results to fetch, and an error
// if there is one.
func (restoreTest *APTSpotTestRestore) findOne(institution string, pageNumber int) (*models.IntellectualObject, bool, error) {
	var selectedObject *models.IntellectualObject
	params := url.Values{}
	params.Set("institution", institution)
	params.Set("state", "A")
	params.Set("createdBefore", restoreTest.CreatedBefore.Format(time.RFC3339))
	params.Set("page", strconv.Itoa(pageNumber))
	params.Set("per_page", "100")
	resp := restoreTest.Context.PharosClient.IntellectualObjectList(params)
	if resp.Error != nil {
		return nil, false, resp.Error
	}
	objects := resp.IntellectualObjects()
	restoreTest.Context.MessageLog.Info("Found %d object candidates for %s", len(objects), institution)
	for _, obj := range objects {
		if obj.Access == "restricted" {
			restoreTest.Context.MessageLog.Info("Skipping %s: restricted", obj.Identifier)
			continue
		}
		if obj.FileSize == 0 {
			restoreTest.Context.MessageLog.Info("Skipping %s: FileSize zero seems incorrect",
				obj.Identifier)
			continue
		}
		if obj.FileSize > restoreTest.MaxSize {
			restoreTest.Context.MessageLog.Info("Skipping %s: size %d is greater than max %d",
				obj.Identifier, obj.FileSize, restoreTest.MaxSize)
			continue
		}
		hasCompletedRestore, err := restoreTest.HasCompletedRestore(obj.Identifier)
		if err != nil {
			restoreTest.Context.MessageLog.Warning("Error checking restore WorkItem for %s: %v",
				obj.Identifier, err)
			continue
		}
		if !hasCompletedRestore {
			restoreTest.Context.MessageLog.Info("Object %s meets all criteria", obj.Identifier)
			selectedObject = obj
			break
		} else {
			restoreTest.Context.MessageLog.Info("Object %s disqualified by recent restore", obj.Identifier)
		}
	}
	return selectedObject, resp.HasNextPage(), nil
}

// HasCompletedRestore returns true if the object with the specified identifier
// has been successfully restored since NotRestoredSince.
func (restoreTest *APTSpotTestRestore) HasCompletedRestore(objIdentifier string) (bool, error) {
	params := url.Values{}
	params.Set("object_identifier", objIdentifier)
	params.Set("action", constants.ActionRestore)
	params.Set("status", constants.StatusSuccess)
	params.Set("updated_after", restoreTest.NotRestoredSince.Format(time.RFC3339))
	params.Set("page", "1")
	params.Set("per_page", "1")
	restoreTest.Context.MessageLog.Info("Checking recent restorations for %s", objIdentifier)
	resp := restoreTest.Context.PharosClient.WorkItemList(params)
	if resp.Error != nil {
		return false, resp.Error
	}
	hasRestore := resp.WorkItem() != nil
	return hasRestore, nil
}

func (restoreTest *APTSpotTestRestore) GetLastIngestWorkItem(objIdentifier string) (*models.WorkItem, error) {
	params := url.Values{}
	params.Set("object_identifier", objIdentifier)
	params.Set("action", constants.ActionIngest)
	params.Set("status", constants.StatusSuccess)
	params.Set("sort", "date") // Sorts by date_processed desc
	params.Set("page", "1")
	params.Set("per_page", "1")
	resp := restoreTest.Context.PharosClient.WorkItemList(params)
	if resp.Error != nil {
		return nil, resp.Error
	}
	return resp.WorkItem(), nil
}

// CreateWorkItem creates the Restore WorkItem for the specified object identifier.
func (restoreTest *APTSpotTestRestore) CreateWorkItem(obj *models.IntellectualObject) (*models.WorkItem, error) {
	lastIngestItem, err := restoreTest.GetLastIngestWorkItem(obj.Identifier)
	if err != nil {
		return nil, fmt.Errorf("Cannot find last ingest WorkItem for %s: %v", obj.Identifier, err)
	}
	if lastIngestItem == nil {
		return nil, fmt.Errorf("Last ingest WorkItem is missing for %s", obj.Identifier)
	}
	workItem := &models.WorkItem{
		ObjectIdentifier: obj.Identifier,
		Name:             lastIngestItem.Name,
		Bucket:           lastIngestItem.Bucket,
		ETag:             lastIngestItem.ETag,
		Size:             obj.FileSize, // may have changed with file deletions or overwrites
		BagDate:          lastIngestItem.BagDate,
		InstitutionId:    lastIngestItem.InstitutionId,
		User:             "system@aptrust.org", // because this is an automated spot test
		Action:           constants.ActionRestore,
		Stage:            constants.StageRequested,
		Status:           constants.StatusPending,
		Outcome:          "Pending",
		Retry:            true,
		Note:             "Automated object restoration spot test created by system",
	}
	if !restoreTest.DryRun {
		resp := restoreTest.Context.PharosClient.WorkItemSave(workItem)
		if resp.Error != nil {
			return nil, resp.Error
		}
		// Returned item includes Id.
		workItem = resp.WorkItem()
	}
	return workItem, nil
}
<commit_msg>Log work item creation<commit_after>package workers

import (
	"fmt"
	"github.com/APTrust/exchange/constants"
	"github.com/APTrust/exchange/context"
	"github.com/APTrust/exchange/models"
	"net/url"
	"strconv"
	"time"
)

type APTSpotTestRestore struct {
	Context          *context.Context
	CreatedBefore    time.Time
	NotRestoredSince time.Time
	MaxSize          int64
	DryRun           bool
}

// NewAPTSpotTestRestore creates a new restore spot test worker.
// This is meant to run as a cron job.
//
// Param maxSize tells the worker to choose bags no larger than
// maxSize for restoration. Param createdBefore means choose bags
// created before this date. Param notRestoredSince means choose
// bags that have not been restored since this date (which helps
// prevent us restoring the same bag again and again).
func NewAPTSpotTestRestore(_context *context.Context, maxSize int64, createdBefore, notRestoredSince time.Time) *APTSpotTestRestore {
	return &APTSpotTestRestore{
		Context:          _context,
		CreatedBefore:    createdBefore,
		NotRestoredSince: notRestoredSince,
		MaxSize:          maxSize,
		DryRun:           false,
	}
}

// Run runs the spot test by choosing ONE bag from each institution
// that matches the specified criteria (smaller than maxSize, createdBefore
// the specified date and notRestoredSince the specified date).
// It creates a Restore WorkItem for each bag, and returns the WorkItems
// it created. The caller can get the WorkItem.Id and object identifier from there.
func (restoreTest *APTSpotTestRestore) Run() ([]*models.WorkItem, error) {
	restoreTest.logFacts()
	workItems := make([]*models.WorkItem, 0)
	institutions, err := restoreTest.GetInstitutions()
	if err != nil {
		return workItems, fmt.Errorf("Error getting list of institutions from Pharos: %v", err)
	}
	for _, inst := range institutions {
		restoreTest.Context.MessageLog.Info("Looking up objects for %s", inst.Identifier)
		obj, err := restoreTest.GetObjectFor(inst.Identifier)
		if err != nil {
			restoreTest.Context.MessageLog.Error(err.Error())
			continue
		}
		if obj == nil {
			restoreTest.Context.MessageLog.Info("No suitable objects for %s", inst.Identifier)
			continue
		}
		workItem, err := restoreTest.CreateWorkItem(obj)
		if err != nil {
			restoreTest.Context.MessageLog.Error("Error creating new Restore WorkItem for %s: %v",
				obj.Identifier, err)
			continue
		}
		workItems = append(workItems, workItem)
	}

	return workItems, nil
}

// logFacts logs our basic working parameters.
func (restoreTest *APTSpotTestRestore) logFacts() {
	restoreTest.Context.MessageLog.Info("MaxSize: %d, CreatedBefore: %s, NotRestoredSince: %s",
		restoreTest.MaxSize,
		restoreTest.CreatedBefore.Format(time.RFC3339),
		restoreTest.NotRestoredSince.Format(time.RFC3339))
	if restoreTest.DryRun {
		restoreTest.Context.MessageLog.Info("This is a DRY RUN, so no WorkItems will be created.")
	}
}

// GetInstitutions returns a list of all depositing institutions from Pharos.
func (restoreTest *APTSpotTestRestore) GetInstitutions() ([]*models.Institution, error) {
	resp := restoreTest.Context.PharosClient.InstitutionList(url.Values{})
	if resp.Error != nil {
		return nil, resp.Error
	}
	institutions := resp.Institutions()
	restoreTest.Context.MessageLog.Info("Got %d institutions from Pharos", len(institutions))
	return institutions, nil
}

// GetObjectFor returns the IntellectualObject we should restore for the
// specified institution. This object will be the first one we find in
// Pharos that matches all of the criteria, which include:
//
// institution - it belongs the specified institution
//
// createdBefore - it was created before the specified date
//
// notRestoredSince - it has not been restored since the specified date
//
// maxSize - it's total size is less than or equal to this many bytes
//
// state - is "A" for active
//
// access - is not "restricted"
func (restoreTest *APTSpotTestRestore) GetObjectFor(institution string) (*models.IntellectualObject, error) {
	var obj *models.IntellectualObject
	var err error
	hasMoreResults := true
	pageNumber := 1
	for hasMoreResults {
		obj, hasMoreResults, err = restoreTest.findOne(institution, pageNumber)
		if obj != nil || err != nil {
			break
		}
		pageNumber++
	}
	return obj, err
}

// findOne finds one IntellectualObject from the specified page of results
// that meets our criteria for restoration spot tests.
//
// Returns an IntellectualObject (or nil if none match our criteria), a boolean
// indicating whether Pharos has more results to fetch, and an error
// if there is one.
func (restoreTest *APTSpotTestRestore) findOne(institution string, pageNumber int) (*models.IntellectualObject, bool, error) {
	var selectedObject *models.IntellectualObject
	params := url.Values{}
	params.Set("institution", institution)
	params.Set("state", "A")
	params.Set("createdBefore", restoreTest.CreatedBefore.Format(time.RFC3339))
	params.Set("page", strconv.Itoa(pageNumber))
	params.Set("per_page", "100")
	resp := restoreTest.Context.PharosClient.IntellectualObjectList(params)
	if resp.Error != nil {
		return nil, false, resp.Error
	}
	objects := resp.IntellectualObjects()
	restoreTest.Context.MessageLog.Info("Found %d object candidates for %s", len(objects), institution)
	for _, obj := range objects {
		if obj.Access == "restricted" {
			restoreTest.Context.MessageLog.Info("Skipping %s: restricted", obj.Identifier)
			continue
		}
		if obj.FileSize == 0 {
			restoreTest.Context.MessageLog.Info("Skipping %s: FileSize zero seems incorrect",
				obj.Identifier)
			continue
		}
		if obj.FileSize > restoreTest.MaxSize {
			restoreTest.Context.MessageLog.Info("Skipping %s: size %d is greater than max %d",
				obj.Identifier, obj.FileSize, restoreTest.MaxSize)
			continue
		}
		hasCompletedRestore, err := restoreTest.HasCompletedRestore(obj.Identifier)
		if err != nil {
			restoreTest.Context.MessageLog.Warning("Error checking restore WorkItem for %s: %v",
				obj.Identifier, err)
			continue
		}
		if !hasCompletedRestore {
			restoreTest.Context.MessageLog.Info("Object %s meets all criteria", obj.Identifier)
			selectedObject = obj
			break
		} else {
			restoreTest.Context.MessageLog.Info("Object %s disqualified by recent restore", obj.Identifier)
		}
	}
	return selectedObject, resp.HasNextPage(), nil
}

// HasCompletedRestore returns true if the object with the specified identifier
// has been successfully restored since NotRestoredSince.
func (restoreTest *APTSpotTestRestore) HasCompletedRestore(objIdentifier string) (bool, error) {
	params := url.Values{}
	params.Set("object_identifier", objIdentifier)
	params.Set("action", constants.ActionRestore)
	params.Set("status", constants.StatusSuccess)
	params.Set("updated_after", restoreTest.NotRestoredSince.Format(time.RFC3339))
	params.Set("page", "1")
	params.Set("per_page", "1")
	restoreTest.Context.MessageLog.Info("Checking recent restorations for %s", objIdentifier)
	resp := restoreTest.Context.PharosClient.WorkItemList(params)
	if resp.Error != nil {
		return false, resp.Error
	}
	hasRestore := resp.WorkItem() != nil
	return hasRestore, nil
}

func (restoreTest *APTSpotTestRestore) GetLastIngestWorkItem(objIdentifier string) (*models.WorkItem, error) {
	params := url.Values{}
	params.Set("object_identifier", objIdentifier)
	params.Set("action", constants.ActionIngest)
	params.Set("status", constants.StatusSuccess)
	params.Set("sort", "date") // Sorts by date_processed desc
	params.Set("page", "1")
	params.Set("per_page", "1")
	resp := restoreTest.Context.PharosClient.WorkItemList(params)
	if resp.Error != nil {
		return nil, resp.Error
	}
	return resp.WorkItem(), nil
}

// CreateWorkItem creates the Restore WorkItem for the specified object identifier.
func (restoreTest *APTSpotTestRestore) CreateWorkItem(obj *models.IntellectualObject) (*models.WorkItem, error) {
	lastIngestItem, err := restoreTest.GetLastIngestWorkItem(obj.Identifier)
	if err != nil {
		return nil, fmt.Errorf("Cannot find last ingest WorkItem for %s: %v", obj.Identifier, err)
	}
	if lastIngestItem == nil {
		return nil, fmt.Errorf("Last ingest WorkItem is missing for %s", obj.Identifier)
	}
	workItem := &models.WorkItem{
		ObjectIdentifier: obj.Identifier,
		Name:             lastIngestItem.Name,
		Bucket:           lastIngestItem.Bucket,
		ETag:             lastIngestItem.ETag,
		Size:             obj.FileSize, // may have changed with file deletions or overwrites
		BagDate:          lastIngestItem.BagDate,
		InstitutionId:    lastIngestItem.InstitutionId,
		User:             "system@aptrust.org", // because this is an automated spot test
		Action:           constants.ActionRestore,
		Stage:            constants.StageRequested,
		Status:           constants.StatusPending,
		Outcome:          "Pending",
		Retry:            true,
		Note:             "Automated object restoration spot test created by system",
	}
	if !restoreTest.DryRun {
		restoreTest.Context.MessageLog.Info("Creating Restore WorkItem for %s", obj.Identifier)
		resp := restoreTest.Context.PharosClient.WorkItemSave(workItem)
		if resp.Error != nil {
			return nil, resp.Error
		}
		// Returned item includes Id.
		workItem = resp.WorkItem()
	}
	return workItem, nil
}
<|endoftext|>


<commit_before>package publicsuffix

import (
	"crypto/x509"
	"crypto/x509/pkix"
	"fmt"
	"testing"

	"github.com/globalsign/certlint/certdata"
)

func TestPublicSuffix(t *testing.T) {
	cd := &certdata.Data{
		Cert: &x509.Certificate{
			Subject: pkix.Name{
				CommonName: "*.com",
			},
			DNSNames: []string{"*.com", "com", "*.co.uk", "gov.uk", "*.eu.com"},
		},
		Type: "DV",
	}

	e := Check(cd)
	if len(e.List()) != 6 {
		t.Errorf("Expected 6 errors, got %d", len(e.List()))
	}

	for _, err := range e.List() {
		fmt.Println(err)
	}
}
<commit_msg>Only print detected errors on test failure<commit_after>package publicsuffix

import (
	"crypto/x509"
	"crypto/x509/pkix"
	"fmt"
	"testing"

	"github.com/globalsign/certlint/certdata"
)

func TestPublicSuffix(t *testing.T) {
	cd := &certdata.Data{
		Cert: &x509.Certificate{
			Subject: pkix.Name{
				CommonName: "*.com",
			},
			DNSNames: []string{"*.com", "com", "*.co.uk", "gov.uk", "*.eu.com"},
		},
		Type: "DV",
	}

	e := Check(cd)
	if len(e.List()) != 6 {
		for _, err := range e.List() {
			fmt.Println(err)
		}
		t.Errorf("Expected 6 errors, got %d", len(e.List()))
	}
}
<|endoftext|>


<commit_before>// Copyright 2014 The Go Authors.
// See https://code.google.com/p/go/source/browse/CONTRIBUTORS
// Licensed under the same terms as Go itself:
// https://code.google.com/p/go/source/browse/LICENSE

package hpack

import (
	"bufio"
	"bytes"
	"encoding/hex"
	"fmt"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"testing"
)

func TestStaticTable(t *testing.T) {
	fromSpec := `
          +-------+-----------------------------+---------------+
          | 1     | :authority                  |               |
          | 2     | :method                     | GET           |
          | 3     | :method                     | POST          |
          | 4     | :path                       | /             |
          | 5     | :path                       | /index.html   |
          | 6     | :scheme                     | http          |
          | 7     | :scheme                     | https         |
          | 8     | :status                     | 200           |
          | 9     | :status                     | 204           |
          | 10    | :status                     | 206           |
          | 11    | :status                     | 304           |
          | 12    | :status                     | 400           |
          | 13    | :status                     | 404           |
          | 14    | :status                     | 500           |
          | 15    | accept-charset              |               |
          | 16    | accept-encoding             | gzip, deflate |
          | 17    | accept-language             |               |
          | 18    | accept-ranges               |               |
          | 19    | accept                      |               |
          | 20    | access-control-allow-origin |               |
          | 21    | age                         |               |
          | 22    | allow                       |               |
          | 23    | authorization               |               |
          | 24    | cache-control               |               |
          | 25    | content-disposition         |               |
          | 26    | content-encoding            |               |
          | 27    | content-language            |               |
          | 28    | content-length              |               |
          | 29    | content-location            |               |
          | 30    | content-range               |               |
          | 31    | content-type                |               |
          | 32    | cookie                      |               |
          | 33    | date                        |               |
          | 34    | etag                        |               |
          | 35    | expect                      |               |
          | 36    | expires                     |               |
          | 37    | from                        |               |
          | 38    | host                        |               |
          | 39    | if-match                    |               |
          | 40    | if-modified-since           |               |
          | 41    | if-none-match               |               |
          | 42    | if-range                    |               |
          | 43    | if-unmodified-since         |               |
          | 44    | last-modified               |               |
          | 45    | link                        |               |
          | 46    | location                    |               |
          | 47    | max-forwards                |               |
          | 48    | proxy-authenticate          |               |
          | 49    | proxy-authorization         |               |
          | 50    | range                       |               |
          | 51    | referer                     |               |
          | 52    | refresh                     |               |
          | 53    | retry-after                 |               |
          | 54    | server                      |               |
          | 55    | set-cookie                  |               |
          | 56    | strict-transport-security   |               |
          | 57    | transfer-encoding           |               |
          | 58    | user-agent                  |               |
          | 59    | vary                        |               |
          | 60    | via                         |               |
          | 61    | www-authenticate            |               |
          +-------+-----------------------------+---------------+
`
	bs := bufio.NewScanner(strings.NewReader(fromSpec))
	re := regexp.MustCompile(`\| (\d+)\s+\| (\S+)\s*\| (\S(.*\S)?)?\s+\|`)
	for bs.Scan() {
		l := bs.Text()
		if !strings.Contains(l, "|") {
			continue
		}
		m := re.FindStringSubmatch(l)
		if m == nil {
			continue
		}
		i, err := strconv.Atoi(m[1])
		if err != nil {
			t.Errorf("Bogus integer on line %q", l)
			continue
		}
		if i < 1 || i > len(staticTable) {
			t.Errorf("Bogus index %d on line %q", i, l)
			continue
		}
		if got, want := staticTable[i-1].Name, m[2]; got != want {
			t.Errorf("header index %d name = %q; want %q", i, got, want)
		}
		if got, want := staticTable[i-1].Value, m[3]; got != want {
			t.Errorf("header index %d value = %q; want %q", i, got, want)
		}
	}
	if err := bs.Err(); err != nil {
		t.Error(err)
	}
}

func (d *Decoder) mustAt(idx int) HeaderField {
	if hf, ok := d.at(idx); !ok {
		panic(fmt.Sprintf("bogus index %d", idx))
	} else {
		return hf
	}
}

func TestDynamicTableAt(t *testing.T) {
	d := NewDecoder(4096, nil)
	at := d.mustAt
	if got, want := at(2), (HeaderField{":method", "GET"}); got != want {
		t.Errorf("at(2) = %q; want %q", got, want)
	}
	d.dynTab.add(HeaderField{"foo", "bar"})
	d.dynTab.add(HeaderField{"blake", "miz"})
	if got, want := at(len(staticTable)+1), (HeaderField{"blake", "miz"}); got != want {
		t.Errorf("at(dyn 1) = %q; want %q", got, want)
	}
	if got, want := at(len(staticTable)+2), (HeaderField{"foo", "bar"}); got != want {
		t.Errorf("at(dyn 2) = %q; want %q", got, want)
	}
	if got, want := at(3), (HeaderField{":method", "POST"}); got != want {
		t.Errorf("at(3) = %q; want %q", got, want)
	}
}

func TestDynamicTableSizeEvict(t *testing.T) {
	d := NewDecoder(4096, nil)
	if want := uint32(0); d.dynTab.size != want {
		t.Fatalf("size = %d; want %d", d.dynTab.size, want)
	}
	add := d.dynTab.add
	add(HeaderField{"blake", "eats pizza"})
	if want := uint32(15 + 32); d.dynTab.size != want {
		t.Fatalf("after pizza, size = %d; want %d", d.dynTab.size, want)
	}
	add(HeaderField{"foo", "bar"})
	if want := uint32(15 + 32 + 6 + 32); d.dynTab.size != want {
		t.Fatalf("after foo bar, size = %d; want %d", d.dynTab.size, want)
	}
	d.dynTab.setMaxSize(15 + 32 + 1 /* slop */)
	if want := uint32(6 + 32); d.dynTab.size != want {
		t.Fatalf("after setMaxSize, size = %d; want %d", d.dynTab.size, want)
	}
	if got, want := d.mustAt(len(staticTable)+1), (HeaderField{"foo", "bar"}); got != want {
		t.Errorf("at(dyn 1) = %q; want %q", got, want)
	}
	add(HeaderField{"long", strings.Repeat("x", 500)})
	if want := uint32(0); d.dynTab.size != want {
		t.Fatalf("after big one, size = %d; want %d", d.dynTab.size, want)
	}
}

func TestDecoderDecode(t *testing.T) {
	d := NewDecoder(4096, nil)

	// Indexed Header Field
	// http://http2.github.io/http2-spec/compression.html#rfc.section.C.2.4
	hf, err := d.Decode([]byte("\x82"))
	if err != nil {
		t.Fatal(err)
	}
	want := []HeaderField{{":method", "GET"}}
	if !reflect.DeepEqual(hf, want) {
		t.Errorf("Got %v; want %v", hf, want)
	}
}

func TestHuffmanDecode(t *testing.T) {
	tests := []struct {
		inHex, want string
	}{
		{"f1e3 c2e5 f23a 6ba0 ab90 f4ff", "www.example.com"},
		{"a8eb 1064 9cbf", "no-cache"},
		{"25a8 49e9 5ba9 7d7f", "custom-key"},
		{"25a8 49e9 5bb8 e8b4 bf", "custom-value"},
		{"6402", "302"},
		{"aec3 771a 4b", "private"},
		{"d07a be94 1054 d444 a820 0595 040b 8166 e082 a62d 1bff", "Mon, 21 Oct 2013 20:13:21 GMT"},
		{"9d29 ad17 1863 c78f 0b97 c8e9 ae82 ae43 d3", "https://www.example.com"},
		{"9bd9 ab", "gzip"},
		{"94e7 821d d7f2 e6c7 b335 dfdf cd5b 3960 d5af 2708 7f36 72c1 ab27 0fb5 291f 9587 3160 65c0 03ed 4ee5 b106 3d50 07",
			"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"},
	}
	for i, tt := range tests {
		var buf bytes.Buffer
		in, err := hex.DecodeString(strings.Replace(tt.inHex, " ", "", -1))
		if err != nil {
			t.Errorf("%d. hex input error: %v", i, err)
			continue
		}
		if _, err := HuffmanDecode(&buf, in); err != nil {
			t.Errorf("%d. decode error: %v", i, err)
			continue
		}
		if got := buf.String(); tt.want != got {
			t.Errorf("%d. decode = %q; want %q", i, got, tt.want)
		}
	}
}

func TestReadVarInt(t *testing.T) {
	type res struct {
		i        uint64
		consumed int
		err      error
	}
	tests := []struct {
		n    byte
		p    []byte
		want res
	}{
		// Fits in a byte:
		{1, []byte{0}, res{0, 1, nil}},
		{2, []byte{2}, res{2, 1, nil}},
		{3, []byte{6}, res{6, 1, nil}},
		{4, []byte{14}, res{14, 1, nil}},
		{5, []byte{30}, res{30, 1, nil}},
		{6, []byte{62}, res{62, 1, nil}},
		{7, []byte{126}, res{126, 1, nil}},
		{8, []byte{254}, res{254, 1, nil}},

		// Doesn't fit in a byte:
		{1, []byte{1}, res{0, 0, nil}},
		{2, []byte{3}, res{0, 0, nil}},
		{3, []byte{7}, res{0, 0, nil}},
		{4, []byte{15}, res{0, 0, nil}},
		{5, []byte{31}, res{0, 0, nil}},
		{6, []byte{63}, res{0, 0, nil}},
		{7, []byte{127}, res{0, 0, nil}},
		{8, []byte{255}, res{0, 0, nil}},

		// Ignoring top bits:
		{5, []byte{255, 154, 10}, res{1337, 3, nil}}, // high dummy three bits: 111
		{5, []byte{159, 154, 10}, res{1337, 3, nil}}, // high dummy three bits: 100
		{5, []byte{191, 154, 10}, res{1337, 3, nil}}, // high dummy three bits: 101

		// Extra byte:
		{5, []byte{191, 154, 10, 2}, res{1337, 3, nil}}, // extra byte

		// Short a byte:
		{5, []byte{191, 154}, res{0, 0, nil}},

		// integer overflow:
		{1, []byte{255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128}, res{0, 0, errVarintOverflow}},
	}
	for _, tt := range tests {
		i, consumed, err := readVarInt(tt.n, tt.p)
		got := res{i, consumed, err}
		if got != tt.want {
			t.Errorf("readVarInt(%d, %v ~ %x) = %+v; want %+v", tt.n, tt.p, tt.p, got, tt.want)
		}
	}
}
<commit_msg>make TestDecoderDecode a table-driven test, in prep for more tests<commit_after>// Copyright 2014 The Go Authors.
// See https://code.google.com/p/go/source/browse/CONTRIBUTORS
// Licensed under the same terms as Go itself:
// https://code.google.com/p/go/source/browse/LICENSE

package hpack

import (
	"bufio"
	"bytes"
	"encoding/hex"
	"fmt"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"testing"
)

func TestStaticTable(t *testing.T) {
	fromSpec := `
          +-------+-----------------------------+---------------+
          | 1     | :authority                  |               |
          | 2     | :method                     | GET           |
          | 3     | :method                     | POST          |
          | 4     | :path                       | /             |
          | 5     | :path                       | /index.html   |
          | 6     | :scheme                     | http          |
          | 7     | :scheme                     | https         |
          | 8     | :status                     | 200           |
          | 9     | :status                     | 204           |
          | 10    | :status                     | 206           |
          | 11    | :status                     | 304           |
          | 12    | :status                     | 400           |
          | 13    | :status                     | 404           |
          | 14    | :status                     | 500           |
          | 15    | accept-charset              |               |
          | 16    | accept-encoding             | gzip, deflate |
          | 17    | accept-language             |               |
          | 18    | accept-ranges               |               |
          | 19    | accept                      |               |
          | 20    | access-control-allow-origin |               |
          | 21    | age                         |               |
          | 22    | allow                       |               |
          | 23    | authorization               |               |
          | 24    | cache-control               |               |
          | 25    | content-disposition         |               |
          | 26    | content-encoding            |               |
          | 27    | content-language            |               |
          | 28    | content-length              |               |
          | 29    | content-location            |               |
          | 30    | content-range               |               |
          | 31    | content-type                |               |
          | 32    | cookie                      |               |
          | 33    | date                        |               |
          | 34    | etag                        |               |
          | 35    | expect                      |               |
          | 36    | expires                     |               |
          | 37    | from                        |               |
          | 38    | host                        |               |
          | 39    | if-match                    |               |
          | 40    | if-modified-since           |               |
          | 41    | if-none-match               |               |
          | 42    | if-range                    |               |
          | 43    | if-unmodified-since         |               |
          | 44    | last-modified               |               |
          | 45    | link                        |               |
          | 46    | location                    |               |
          | 47    | max-forwards                |               |
          | 48    | proxy-authenticate          |               |
          | 49    | proxy-authorization         |               |
          | 50    | range                       |               |
          | 51    | referer                     |               |
          | 52    | refresh                     |               |
          | 53    | retry-after                 |               |
          | 54    | server                      |               |
          | 55    | set-cookie                  |               |
          | 56    | strict-transport-security   |               |
          | 57    | transfer-encoding           |               |
          | 58    | user-agent                  |               |
          | 59    | vary                        |               |
          | 60    | via                         |               |
          | 61    | www-authenticate            |               |
          +-------+-----------------------------+---------------+
`
	bs := bufio.NewScanner(strings.NewReader(fromSpec))
	re := regexp.MustCompile(`\| (\d+)\s+\| (\S+)\s*\| (\S(.*\S)?)?\s+\|`)
	for bs.Scan() {
		l := bs.Text()
		if !strings.Contains(l, "|") {
			continue
		}
		m := re.FindStringSubmatch(l)
		if m == nil {
			continue
		}
		i, err := strconv.Atoi(m[1])
		if err != nil {
			t.Errorf("Bogus integer on line %q", l)
			continue
		}
		if i < 1 || i > len(staticTable) {
			t.Errorf("Bogus index %d on line %q", i, l)
			continue
		}
		if got, want := staticTable[i-1].Name, m[2]; got != want {
			t.Errorf("header index %d name = %q; want %q", i, got, want)
		}
		if got, want := staticTable[i-1].Value, m[3]; got != want {
			t.Errorf("header index %d value = %q; want %q", i, got, want)
		}
	}
	if err := bs.Err(); err != nil {
		t.Error(err)
	}
}

func (d *Decoder) mustAt(idx int) HeaderField {
	if hf, ok := d.at(idx); !ok {
		panic(fmt.Sprintf("bogus index %d", idx))
	} else {
		return hf
	}
}

func TestDynamicTableAt(t *testing.T) {
	d := NewDecoder(4096, nil)
	at := d.mustAt
	if got, want := at(2), (HeaderField{":method", "GET"}); got != want {
		t.Errorf("at(2) = %q; want %q", got, want)
	}
	d.dynTab.add(HeaderField{"foo", "bar"})
	d.dynTab.add(HeaderField{"blake", "miz"})
	if got, want := at(len(staticTable)+1), (HeaderField{"blake", "miz"}); got != want {
		t.Errorf("at(dyn 1) = %q; want %q", got, want)
	}
	if got, want := at(len(staticTable)+2), (HeaderField{"foo", "bar"}); got != want {
		t.Errorf("at(dyn 2) = %q; want %q", got, want)
	}
	if got, want := at(3), (HeaderField{":method", "POST"}); got != want {
		t.Errorf("at(3) = %q; want %q", got, want)
	}
}

func TestDynamicTableSizeEvict(t *testing.T) {
	d := NewDecoder(4096, nil)
	if want := uint32(0); d.dynTab.size != want {
		t.Fatalf("size = %d; want %d", d.dynTab.size, want)
	}
	add := d.dynTab.add
	add(HeaderField{"blake", "eats pizza"})
	if want := uint32(15 + 32); d.dynTab.size != want {
		t.Fatalf("after pizza, size = %d; want %d", d.dynTab.size, want)
	}
	add(HeaderField{"foo", "bar"})
	if want := uint32(15 + 32 + 6 + 32); d.dynTab.size != want {
		t.Fatalf("after foo bar, size = %d; want %d", d.dynTab.size, want)
	}
	d.dynTab.setMaxSize(15 + 32 + 1 /* slop */)
	if want := uint32(6 + 32); d.dynTab.size != want {
		t.Fatalf("after setMaxSize, size = %d; want %d", d.dynTab.size, want)
	}
	if got, want := d.mustAt(len(staticTable)+1), (HeaderField{"foo", "bar"}); got != want {
		t.Errorf("at(dyn 1) = %q; want %q", got, want)
	}
	add(HeaderField{"long", strings.Repeat("x", 500)})
	if want := uint32(0); d.dynTab.size != want {
		t.Fatalf("after big one, size = %d; want %d", d.dynTab.size, want)
	}
}

func TestDecoderDecode(t *testing.T) {
	tests := []struct {
		name string
		in   []byte
		want []HeaderField
	}{
		// Indexed Header Field
		// http://http2.github.io/http2-spec/compression.html#rfc.section.C.2.4
		{"C.2.4", []byte("\x82"), []HeaderField{{":method", "GET"}}},
	}
	for _, tt := range tests {
		d := NewDecoder(4096, nil)
		hf, err := d.Decode(tt.in)
		if err != nil {
			t.Errorf("%s: %v", tt.name, err)
			continue
		}
		if !reflect.DeepEqual(hf, tt.want) {
			t.Errorf("%s: Got %v; want %v", tt.name, hf, tt.want)
		}
	}
}

func TestHuffmanDecode(t *testing.T) {
	tests := []struct {
		inHex, want string
	}{
		{"f1e3 c2e5 f23a 6ba0 ab90 f4ff", "www.example.com"},
		{"a8eb 1064 9cbf", "no-cache"},
		{"25a8 49e9 5ba9 7d7f", "custom-key"},
		{"25a8 49e9 5bb8 e8b4 bf", "custom-value"},
		{"6402", "302"},
		{"aec3 771a 4b", "private"},
		{"d07a be94 1054 d444 a820 0595 040b 8166 e082 a62d 1bff", "Mon, 21 Oct 2013 20:13:21 GMT"},
		{"9d29 ad17 1863 c78f 0b97 c8e9 ae82 ae43 d3", "https://www.example.com"},
		{"9bd9 ab", "gzip"},
		{"94e7 821d d7f2 e6c7 b335 dfdf cd5b 3960 d5af 2708 7f36 72c1 ab27 0fb5 291f 9587 3160 65c0 03ed 4ee5 b106 3d50 07",
			"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"},
	}
	for i, tt := range tests {
		var buf bytes.Buffer
		in, err := hex.DecodeString(strings.Replace(tt.inHex, " ", "", -1))
		if err != nil {
			t.Errorf("%d. hex input error: %v", i, err)
			continue
		}
		if _, err := HuffmanDecode(&buf, in); err != nil {
			t.Errorf("%d. decode error: %v", i, err)
			continue
		}
		if got := buf.String(); tt.want != got {
			t.Errorf("%d. decode = %q; want %q", i, got, tt.want)
		}
	}
}

func TestReadVarInt(t *testing.T) {
	type res struct {
		i        uint64
		consumed int
		err      error
	}
	tests := []struct {
		n    byte
		p    []byte
		want res
	}{
		// Fits in a byte:
		{1, []byte{0}, res{0, 1, nil}},
		{2, []byte{2}, res{2, 1, nil}},
		{3, []byte{6}, res{6, 1, nil}},
		{4, []byte{14}, res{14, 1, nil}},
		{5, []byte{30}, res{30, 1, nil}},
		{6, []byte{62}, res{62, 1, nil}},
		{7, []byte{126}, res{126, 1, nil}},
		{8, []byte{254}, res{254, 1, nil}},

		// Doesn't fit in a byte:
		{1, []byte{1}, res{0, 0, nil}},
		{2, []byte{3}, res{0, 0, nil}},
		{3, []byte{7}, res{0, 0, nil}},
		{4, []byte{15}, res{0, 0, nil}},
		{5, []byte{31}, res{0, 0, nil}},
		{6, []byte{63}, res{0, 0, nil}},
		{7, []byte{127}, res{0, 0, nil}},
		{8, []byte{255}, res{0, 0, nil}},

		// Ignoring top bits:
		{5, []byte{255, 154, 10}, res{1337, 3, nil}}, // high dummy three bits: 111
		{5, []byte{159, 154, 10}, res{1337, 3, nil}}, // high dummy three bits: 100
		{5, []byte{191, 154, 10}, res{1337, 3, nil}}, // high dummy three bits: 101

		// Extra byte:
		{5, []byte{191, 154, 10, 2}, res{1337, 3, nil}}, // extra byte

		// Short a byte:
		{5, []byte{191, 154}, res{0, 0, nil}},

		// integer overflow:
		{1, []byte{255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128}, res{0, 0, errVarintOverflow}},
	}
	for _, tt := range tests {
		i, consumed, err := readVarInt(tt.n, tt.p)
		got := res{i, consumed, err}
		if got != tt.want {
			t.Errorf("readVarInt(%d, %v ~ %x) = %+v; want %+v", tt.n, tt.p, tt.p, got, tt.want)
		}
	}
}
<|endoftext|>


<commit_before>package proto

import (
	"sync"
	"testing"
	"time"

	"github.com/NebulousLabs/Sia/build"
	"github.com/NebulousLabs/Sia/crypto"
	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/types"

	"github.com/NebulousLabs/fastrand"
)

// mustAcquire is a convenience function for acquiring contracts that are
// known to be in the set.
func (cs *ContractSet) mustAcquire(t *testing.T, id types.FileContractID) *SafeContract {
	t.Helper()
	c, ok := cs.Acquire(id)
	if !ok {
		t.Fatal("no contract with that id")
	}
	return c
}

// TestContractSet tests that the ContractSet type is safe for concurrent use.
func TestContractSet(t *testing.T) {
	// create contract set
	testDir := build.TempDir(t.Name())
	cs, err := NewContractSet(testDir, modules.ProdDependencies)
	if err != nil {
		t.Fatal(err)
	}
	header1 := contractHeader{Transaction: types.Transaction{
		FileContractRevisions: []types.FileContractRevision{{
			ParentID:             types.FileContractID{1},
			NewValidProofOutputs: []types.SiacoinOutput{{}, {}},
			UnlockConditions: types.UnlockConditions{
				PublicKeys: []types.SiaPublicKey{{}, {}},
			},
		}},
	}}
	header2 := contractHeader{Transaction: types.Transaction{
		FileContractRevisions: []types.FileContractRevision{{
			ParentID:             types.FileContractID{2},
			NewValidProofOutputs: []types.SiacoinOutput{{}, {}},
			UnlockConditions: types.UnlockConditions{
				PublicKeys: []types.SiaPublicKey{{}, {}},
			},
		}},
	}}
	id1 := header1.ID()
	id2 := header2.ID()

	_, err = cs.managedInsertContract(header1, []crypto.Hash{})
	if err != nil {
		t.Fatal(err)
	}
	_, err = cs.managedInsertContract(header2, []crypto.Hash{})
	if err != nil {
		t.Fatal(err)
	}

	// uncontested acquire/release
	c1 := cs.mustAcquire(t, id1)
	cs.Return(c1)

	// 100 concurrent serialized mutations
	var wg sync.WaitGroup
	for i := 0; i < 100; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			c1 := cs.mustAcquire(t, id1)
			c1.header.Transaction.FileContractRevisions[0].NewRevisionNumber++
			time.Sleep(time.Duration(fastrand.Intn(100)))
			cs.Return(c1)
		}()
	}
	wg.Wait()
	c1 = cs.mustAcquire(t, id1)
	cs.Return(c1)
	if c1.header.LastRevision().NewRevisionNumber != 100 {
		t.Fatal("expected exactly 100 increments, got", c1.header.LastRevision().NewRevisionNumber)
	}

	// a blocked acquire shouldn't prevent a return
	c1 = cs.mustAcquire(t, id1)
	go func() {
		time.Sleep(time.Millisecond)
		cs.Return(c1)
	}()
	c1 = cs.mustAcquire(t, id1)
	cs.Return(c1)

	// delete and reinsert id2
	c2 := cs.mustAcquire(t, id2)
	cs.Delete(c2)
	roots, err := c2.merkleRoots.merkleRoots()
	if err != nil {
		t.Fatal(err)
	}
	cs.managedInsertContract(c2.header, roots)

	// call all the methods in parallel haphazardly
	funcs := []func(){
		func() { cs.Len() },
		func() { cs.IDs() },
		func() { cs.View(id1); cs.View(id2) },
		func() { cs.ViewAll() },
		func() { cs.Return(cs.mustAcquire(t, id1)) },
		func() { cs.Return(cs.mustAcquire(t, id2)) },
		func() {
			header3 := contractHeader{
				Transaction: types.Transaction{
					FileContractRevisions: []types.FileContractRevision{{
						ParentID:             types.FileContractID{3},
						NewValidProofOutputs: []types.SiacoinOutput{{}, {}},
						UnlockConditions: types.UnlockConditions{
							PublicKeys: []types.SiaPublicKey{{}, {}},
						},
					}},
				},
			}
			id3 := header3.ID()
			_, err := cs.managedInsertContract(header3, []crypto.Hash{})
			if err != nil {
				t.Fatal(err)
			}
			c3 := cs.mustAcquire(t, id3)
			cs.Delete(c3)
		},
	}
	wg = sync.WaitGroup{}
	for _, fn := range funcs {
		wg.Add(1)
		go func(fn func()) {
			defer wg.Done()
			for i := 0; i < 100; i++ {
				time.Sleep(time.Duration(fastrand.Intn(100)))
				fn()
			}
		}(fn)
	}
	wg.Wait()
}
<commit_msg>skip test with disk io in short test<commit_after>package proto

import (
	"sync"
	"testing"
	"time"

	"github.com/NebulousLabs/Sia/build"
	"github.com/NebulousLabs/Sia/crypto"
	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/types"

	"github.com/NebulousLabs/fastrand"
)

// mustAcquire is a convenience function for acquiring contracts that are
// known to be in the set.
func (cs *ContractSet) mustAcquire(t *testing.T, id types.FileContractID) *SafeContract {
	t.Helper()
	c, ok := cs.Acquire(id)
	if !ok {
		t.Fatal("no contract with that id")
	}
	return c
}

// TestContractSet tests that the ContractSet type is safe for concurrent use.
func TestContractSet(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}
	// create contract set
	testDir := build.TempDir(t.Name())
	cs, err := NewContractSet(testDir, modules.ProdDependencies)
	if err != nil {
		t.Fatal(err)
	}
	header1 := contractHeader{Transaction: types.Transaction{
		FileContractRevisions: []types.FileContractRevision{{
			ParentID:             types.FileContractID{1},
			NewValidProofOutputs: []types.SiacoinOutput{{}, {}},
			UnlockConditions: types.UnlockConditions{
				PublicKeys: []types.SiaPublicKey{{}, {}},
			},
		}},
	}}
	header2 := contractHeader{Transaction: types.Transaction{
		FileContractRevisions: []types.FileContractRevision{{
			ParentID:             types.FileContractID{2},
			NewValidProofOutputs: []types.SiacoinOutput{{}, {}},
			UnlockConditions: types.UnlockConditions{
				PublicKeys: []types.SiaPublicKey{{}, {}},
			},
		}},
	}}
	id1 := header1.ID()
	id2 := header2.ID()

	_, err = cs.managedInsertContract(header1, []crypto.Hash{})
	if err != nil {
		t.Fatal(err)
	}
	_, err = cs.managedInsertContract(header2, []crypto.Hash{})
	if err != nil {
		t.Fatal(err)
	}

	// uncontested acquire/release
	c1 := cs.mustAcquire(t, id1)
	cs.Return(c1)

	// 100 concurrent serialized mutations
	var wg sync.WaitGroup
	for i := 0; i < 100; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			c1 := cs.mustAcquire(t, id1)
			c1.header.Transaction.FileContractRevisions[0].NewRevisionNumber++
			time.Sleep(time.Duration(fastrand.Intn(100)))
			cs.Return(c1)
		}()
	}
	wg.Wait()
	c1 = cs.mustAcquire(t, id1)
	cs.Return(c1)
	if c1.header.LastRevision().NewRevisionNumber != 100 {
		t.Fatal("expected exactly 100 increments, got", c1.header.LastRevision().NewRevisionNumber)
	}

	// a blocked acquire shouldn't prevent a return
	c1 = cs.mustAcquire(t, id1)
	go func() {
		time.Sleep(time.Millisecond)
		cs.Return(c1)
	}()
	c1 = cs.mustAcquire(t, id1)
	cs.Return(c1)

	// delete and reinsert id2
	c2 := cs.mustAcquire(t, id2)
	cs.Delete(c2)
	roots, err := c2.merkleRoots.merkleRoots()
	if err != nil {
		t.Fatal(err)
	}
	cs.managedInsertContract(c2.header, roots)

	// call all the methods in parallel haphazardly
	funcs := []func(){
		func() { cs.Len() },
		func() { cs.IDs() },
		func() { cs.View(id1); cs.View(id2) },
		func() { cs.ViewAll() },
		func() { cs.Return(cs.mustAcquire(t, id1)) },
		func() { cs.Return(cs.mustAcquire(t, id2)) },
		func() {
			header3 := contractHeader{
				Transaction: types.Transaction{
					FileContractRevisions: []types.FileContractRevision{{
						ParentID:             types.FileContractID{3},
						NewValidProofOutputs: []types.SiacoinOutput{{}, {}},
						UnlockConditions: types.UnlockConditions{
							PublicKeys: []types.SiaPublicKey{{}, {}},
						},
					}},
				},
			}
			id3 := header3.ID()
			_, err := cs.managedInsertContract(header3, []crypto.Hash{})
			if err != nil {
				t.Fatal(err)
			}
			c3 := cs.mustAcquire(t, id3)
			cs.Delete(c3)
		},
	}
	wg = sync.WaitGroup{}
	for _, fn := range funcs {
		wg.Add(1)
		go func(fn func()) {
			defer wg.Done()
			for i := 0; i < 100; i++ {
				time.Sleep(time.Duration(fastrand.Intn(100)))
				fn()
			}
		}(fn)
	}
	wg.Wait()
}
<|endoftext|>


<commit_before>package autostart

import (
	"os"
	"path/filepath"
	"text/template"
)

const jobTemplate = `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>{{.Name}}</string>
    <key>ProgramArguments</key>
      <array>
        {{range .Exec -}}
        <string>{{.}}</string>
        {{end}}
      </array>
    <key>RunAtLoad</key>
    <true/>
  </dict>
</plist>`

var launchDir string

func init() {
	launchDir = filepath.Join(os.Getenv("HOME"), "Library", "LaunchAgents")
}

func (a *App) path() string {
	return filepath.Join(launchDir, a.Name+".plist")
}

// IsEnabled Check is app enabled startup.
func (a *App) IsEnabled() bool {
	_, err := os.Stat(a.path())
	return err == nil
}

// Enable this app on startup.
func (a *App) Enable() error {
	t := template.Must(template.New("job").Parse(jobTemplate))

	if err := os.MkdirAll(launchDir, 0777); err != nil {
		return err
	}
	f, err := os.Create(a.path())
	if err != nil {
		return err
	}
	defer f.Close()

	if err := t.Execute(f, a); err != nil {
		return err
	}

	return nil
}

// Disable this app on startup.
func (a *App) Disable() error {

	return os.Remove(a.path())
}
<commit_msg>add AbandonProcessGroup for macos<commit_after>package autostart

import (
	"os"
	"path/filepath"
	"text/template"
)

const jobTemplate = `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>{{.Name}}</string>
    <key>ProgramArguments</key>
      <array>
        {{range .Exec -}}
        <string>{{.}}</string>
        {{end}}
      </array>
    <key>RunAtLoad</key>
    <true/>
    <key>AbandonProcessGroup</key>
    <true/>
  </dict>
</plist>`

var launchDir string

func init() {
	launchDir = filepath.Join(os.Getenv("HOME"), "Library", "LaunchAgents")
}

func (a *App) path() string {
	return filepath.Join(launchDir, a.Name+".plist")
}

// IsEnabled Check is app enabled startup.
func (a *App) IsEnabled() bool {
	_, err := os.Stat(a.path())
	return err == nil
}

// Enable this app on startup.
func (a *App) Enable() error {
	t := template.Must(template.New("job").Parse(jobTemplate))

	if err := os.MkdirAll(launchDir, 0777); err != nil {
		return err
	}
	f, err := os.Create(a.path())
	if err != nil {
		return err
	}
	defer f.Close()

	if err := t.Execute(f, a); err != nil {
		return err
	}

	return nil
}

// Disable this app on startup.
func (a *App) Disable() error {

	return os.Remove(a.path())
}
<|endoftext|>


<commit_before>package main

import (
	"eaciit/gdrj/model"
	"eaciit/gdrj/modules"
	"os"

	"flag"
	"github.com/eaciit/dbox"
	"github.com/eaciit/orm/v1"
	"github.com/eaciit/toolkit"
	"strings"
	"sync"
	"time"
)

var conn dbox.IConnection
var count, step, fiscalyear int
var vdistdetail string
var vdistheader string
var mutex *sync.Mutex
var eperiode, speriode time.Time
var ggrossamount, cggrossamount float64

func setinitialconnection() {
	var err error
	conn, err = modules.GetDboxIConnection("db_godrej")

	if err != nil {
		toolkit.Println("Initial connection found : ", err)
		os.Exit(1)
	}

	err = gdrj.SetDb(conn)
	if err != nil {
		toolkit.Println("Initial connection found : ", err)
		os.Exit(1)
	}
}

var (
	shs           = toolkit.M{}
	pcs           = toolkit.M{}
	ccs           = toolkit.M{}
	ledgers       = toolkit.M{}
	prods         = toolkit.M{}
	custs         = toolkit.M{}
	vdistskus     = toolkit.M{}
	mapskuids     = toolkit.M{}
	lastSalesLine = toolkit.M{}
)

func getCursor(obj orm.IModel) dbox.ICursor {
	c, e := gdrj.Find(obj, nil, nil)
	if e != nil {
		return nil
	}
	return c
}

func prepMaster() {
	pc := new(gdrj.ProfitCenter)
	cc := new(gdrj.CostCenter)
	prod := new(gdrj.Product)
	ledger := new(gdrj.LedgerMaster)

	var e error

	cpc := getCursor(pc)
	defer cpc.Close()
	for e = cpc.Fetch(pc, 1, false); e == nil; {
		pcs.Set(pc.ID, pc)
		pc = new(gdrj.ProfitCenter)
		e = cpc.Fetch(pc, 1, false)
	}

	ccc := getCursor(cc)
	defer ccc.Close()
	for e = ccc.Fetch(cc, 1, false); e == nil; {
		ccs.Set(cc.ID, cc)
		cc = new(gdrj.CostCenter)
		e = ccc.Fetch(cc, 1, false)
	}

	cprod := getCursor(prod)
	defer cprod.Close()
	for e = cprod.Fetch(prod, 1, false); e == nil; {
		prods.Set(prod.ID, prod)
		prod = new(gdrj.Product)
		e = cprod.Fetch(prod, 1, false)
	}

	cledger := getCursor(ledger)
	defer cledger.Close()
	for e = cledger.Fetch(ledger, 1, false); e == nil; {
		ledgers.Set(ledger.ID, ledger)
		ledger = new(gdrj.LedgerMaster)
		e = cledger.Fetch(ledger, 1, false)
	}

	cust := new(gdrj.Customer)
	ccust := getCursor(cust)
	defer ccust.Close()
	for e = ccust.Fetch(cust, 1, false); e == nil; {
		custs.Set(cust.ID, cust)
		cust = new(gdrj.Customer)
		e = ccust.Fetch(cust, 1, false)
	}

	sku := new(gdrj.MappingInventory)
	cskus := getCursor(sku)
	defer cskus.Close()
	for e = cskus.Fetch(sku, 1, false); e == nil; {
		vdistskus.Set(sku.SKUID_VDIST, sku.ID)
		sku = new(gdrj.MappingInventory)
		e = cskus.Fetch(sku, 1, false)
	}

	sh := new(gdrj.SalesHeader)
	// cshs := getCursor(sh)
	filter := dbox.And(dbox.Gte("date", speriode), dbox.Lt("date", eperiode))
	// filter = dbox.Eq("_id", "FK/IGA/14001247")

	cshs, _ := gdrj.Find(sh,
		filter,
		toolkit.M{})
	defer cshs.Close()
	for e = cshs.Fetch(sh, 1, false); e == nil; {
		shs.Set(sh.ID, sh)
		sh = new(gdrj.SalesHeader)
		e = cshs.Fetch(sh, 1, false)
	}
}

func main() {
	setinitialconnection()
	defer gdrj.CloseDb()
	mutex = &sync.Mutex{}

	flag.StringVar(&vdistdetail, "vdistdetail", "", "vdistdetail representation of collection vdist detail that want to be processed. Default is blank")
	flag.StringVar(&vdistheader, "vdistheader", "rawsalesheader", "vdistheader representation of collection vdist header that want to be processed. Default is rawsalesheader")
	flag.IntVar(&fiscalyear, "year", 2015, "fiscal year to process. Default is 2015")
	flag.Parse()

	if vdistdetail == "" {
		toolkit.Println("VDist detail collection need to be fill,")
		os.Exit(1)
	}

	eperiode = time.Date(fiscalyear, 4, 1, 0, 0, 0, 0, time.UTC)
	speriode = eperiode.AddDate(-1, 0, 0)

	toolkit.Println("Reading Master")
	prepMaster()

	toolkit.Println("START...")

	conn, _ := modules.GetDboxIConnection("db_godrej")
	// filter := dbox.Eq("iv_no", "FK/IGA/14001247")
	crx, _ := conn.NewQuery().Select().From(vdistdetail).Cursor(nil)
	defer crx.Close()
	defer conn.Close()

	lastSalesLine = toolkit.M{}
	count = crx.Count()
	step = count / 100
	i := 0

	jobs := make(chan toolkit.M, count)
	result := make(chan string, count)
	for wi := 0; wi < 10; wi++ {
		go workerProc(wi, jobs, result)
	}

	t0 := time.Now()
	for {
		i++
		tkmsd := toolkit.M{}
		e := crx.Fetch(&tkmsd, 1, false)
		if e != nil {
			break
		}

		invid := toolkit.ToString(tkmsd.Get("iv_no", ""))
		if lastSalesLine.Has(invid) {
			lastLineNo := lastSalesLine.GetInt(invid) + 1
			tkmsd.Set("lineno", lastLineNo)
			lastSalesLine.Set(invid, lastLineNo)
		} else {
			tkmsd.Set("lineno", 1)
			lastSalesLine.Set(invid, 1)
		}

		jobs <- tkmsd
		// gdrj.Save(st)
		if step == 0 {
			step = 100
		}

		if i%step == 0 {
			toolkit.Printfn("Processing %d of %d (%d) in %s",
				i, count, i/step,
				time.Since(t0).String())
		}
	}

	for ri := 0; ri < i; ri++ {
		<-result
		if step == 0 {
			step = 100
		}

		if ri%step == 0 {
			toolkit.Printfn("Saving %d of %d (%d pct) in %s",
				ri, count, ri/step, time.Since(t0).String())
		}
	}

	toolkit.Printfn("Processing done in %s with gross %v and correct %v",
		time.Since(t0).String(), ggrossamount, cggrossamount)
}

func workerProc(wi int, jobs <-chan toolkit.M, result chan<- string) {
	workerconn, _ := modules.GetDboxIConnection("db_godrej")
	defer workerconn.Close()

	tkmsd := toolkit.M{}
	for tkmsd = range jobs {
		gdrjdate := new(gdrj.Date)

		st := new(gdrj.SalesTrx)
		st.SalesHeaderID = toolkit.ToString(tkmsd.Get("iv_no", ""))

		st.LineNo = tkmsd.GetInt("lineno")
		dgrossamount := toolkit.ToFloat64(tkmsd.Get("gross", 0), 6, toolkit.RoundingAuto)
		ggrossamount += dgrossamount

		if shs.Has(st.SalesHeaderID) {
			sho := shs.Get(st.SalesHeaderID).(*gdrj.SalesHeader)
			sho.OutletID = strings.ToUpper(sho.OutletID)

			if sho.SalesDiscountAmount != 0 && sho.SalesGrossAmount != 0 {
				st.DiscountAmount = dgrossamount * sho.SalesDiscountAmount / sho.SalesGrossAmount
			}

			if sho.SalesTaxAmount != 0 && sho.SalesGrossAmount != 0 {
				st.TaxAmount = dgrossamount * sho.SalesTaxAmount / sho.SalesGrossAmount
			}

			st.OutletID = sho.BranchID + sho.OutletID
			st.Date = sho.Date
			st.HeaderValid = true

			gdrjdate = gdrj.SetDate(sho.Date)
			st.Year = gdrjdate.Year
			st.Month = int(gdrjdate.Month)
			st.Fiscal = gdrjdate.Fiscal

		} else {
			st.HeaderValid = false
		}
		//brsap,iv_no,dtsales,inv_no,qty,price,gross,net
		st.SKUID_VDIST = toolkit.ToString(tkmsd.Get("inv_no", ""))
		if vdistskus.Has(st.SKUID_VDIST) {
			st.SKUID = toolkit.ToString(vdistskus[st.SKUID_VDIST])
		} else {
			st.SKUID = "not found"
		}

		st.SalesQty = toolkit.ToFloat64(tkmsd.Get("qty", 0), 6, toolkit.RoundingAuto)
		st.GrossAmount = dgrossamount
		st.NetAmount = toolkit.ToFloat64(tkmsd.Get("net", 0), 6, toolkit.RoundingAuto)

		if prods.Has(st.SKUID) {
			st.ProductValid = true
			st.Product = prods.Get(st.SKUID).(*gdrj.Product)
		} else {
			st.ProductValid = false
		}

		if custs.Has(st.OutletID) {
			st.CustomerValid = true
			st.Customer = custs.Get(st.OutletID).(*gdrj.Customer)
			if st.Customer.ChannelID == "I1" {
				st.CustomerValid = false
			}
		} else {
			st.CustomerValid = false
		}

		if st.ProductValid && st.CustomerValid {
			pcid := st.Customer.BranchID + st.Product.BrandCategoryID
			if pcs.Has(pcid) {
				st.PCValid = true
				st.PC = pcs.Get(pcid).(*gdrj.ProfitCenter)
			} else {
				st.PCValid = false
			}
		} else {
			st.PCValid = false
		}

		if st.CustomerValid && st.HeaderValid {
			cggrossamount += st.GrossAmount
		}

		st.Src = "VDIST"
		st.ID = toolkit.ToString(st.PrepareID())
		workerconn.NewQuery().From(st.TableName()).
			Save().Exec(toolkit.M{}.Set("data", st))

		result <- st.ID
	}
}
<commit_msg>update<commit_after>package main

import (
	"eaciit/gdrj/model"
	"eaciit/gdrj/modules"
	"os"

	"flag"
	"github.com/eaciit/dbox"
	"github.com/eaciit/orm/v1"
	"github.com/eaciit/toolkit"
	"strings"
	"sync"
	"time"
)

var conn dbox.IConnection
var count, step, fiscalyear int
var vdistdetail string
var vdistheader string
var mutex *sync.Mutex
var eperiode, speriode time.Time
var ggrossamount, cggrossamount float64

func setinitialconnection() {
	var err error
	conn, err = modules.GetDboxIConnection("db_godrej")

	if err != nil {
		toolkit.Println("Initial connection found : ", err)
		os.Exit(1)
	}

	err = gdrj.SetDb(conn)
	if err != nil {
		toolkit.Println("Initial connection found : ", err)
		os.Exit(1)
	}
}

var (
	shs           = toolkit.M{}
	pcs           = toolkit.M{}
	ccs           = toolkit.M{}
	ledgers       = toolkit.M{}
	prods         = toolkit.M{}
	custs         = toolkit.M{}
	vdistskus     = toolkit.M{}
	mapskuids     = toolkit.M{}
	lastSalesLine = toolkit.M{}
)

func getCursor(obj orm.IModel) dbox.ICursor {
	c, e := gdrj.Find(obj, nil, nil)
	if e != nil {
		return nil
	}
	return c
}

func prepMaster() {
	pc := new(gdrj.ProfitCenter)
	cc := new(gdrj.CostCenter)
	prod := new(gdrj.Product)
	ledger := new(gdrj.LedgerMaster)

	var e error

	cpc := getCursor(pc)
	defer cpc.Close()
	for e = cpc.Fetch(pc, 1, false); e == nil; {
		pcs.Set(pc.ID, pc)
		pc = new(gdrj.ProfitCenter)
		e = cpc.Fetch(pc, 1, false)
	}

	ccc := getCursor(cc)
	defer ccc.Close()
	for e = ccc.Fetch(cc, 1, false); e == nil; {
		ccs.Set(cc.ID, cc)
		cc = new(gdrj.CostCenter)
		e = ccc.Fetch(cc, 1, false)
	}

	cprod := getCursor(prod)
	defer cprod.Close()
	for e = cprod.Fetch(prod, 1, false); e == nil; {
		prods.Set(prod.ID, prod)
		prod = new(gdrj.Product)
		e = cprod.Fetch(prod, 1, false)
	}

	cledger := getCursor(ledger)
	defer cledger.Close()
	for e = cledger.Fetch(ledger, 1, false); e == nil; {
		ledgers.Set(ledger.ID, ledger)
		ledger = new(gdrj.LedgerMaster)
		e = cledger.Fetch(ledger, 1, false)
	}

	cust := new(gdrj.Customer)
	ccust := getCursor(cust)
	defer ccust.Close()
	for e = ccust.Fetch(cust, 1, false); e == nil; {
		custs.Set(cust.ID, cust)
		cust = new(gdrj.Customer)
		e = ccust.Fetch(cust, 1, false)
	}

	sku := new(gdrj.MappingInventory)
	cskus := getCursor(sku)
	defer cskus.Close()
	for e = cskus.Fetch(sku, 1, false); e == nil; {
		vdistskus.Set(sku.SKUID_VDIST, sku.ID)
		sku = new(gdrj.MappingInventory)
		e = cskus.Fetch(sku, 1, false)
	}

	sh := new(gdrj.SalesHeader)
	// cshs := getCursor(sh)
	filter := dbox.And(dbox.Gte("date", speriode), dbox.Lt("date", eperiode))
	// filter = dbox.Eq("_id", "FK/IGA/14001247")

	cshs, _ := gdrj.Find(sh,
		filter,
		toolkit.M{})
	defer cshs.Close()
	for e = cshs.Fetch(sh, 1, false); e == nil; {
		shs.Set(sh.ID, sh)
		sh = new(gdrj.SalesHeader)
		e = cshs.Fetch(sh, 1, false)
	}
}

func main() {
	setinitialconnection()
	defer gdrj.CloseDb()
	mutex = &sync.Mutex{}

	flag.StringVar(&vdistdetail, "vdistdetail", "", "vdistdetail representation of collection vdist detail that want to be processed. Default is blank")
	flag.StringVar(&vdistheader, "vdistheader", "rawsalesheader", "vdistheader representation of collection vdist header that want to be processed. Default is rawsalesheader")
	flag.IntVar(&fiscalyear, "year", 2015, "fiscal year to process. Default is 2015")
	flag.Parse()

	if vdistdetail == "" {
		toolkit.Println("VDist detail collection need to be fill,")
		os.Exit(1)
	}

	eperiode = time.Date(fiscalyear, 4, 1, 0, 0, 0, 0, time.UTC)
	speriode = eperiode.AddDate(-1, 0, 0)

	toolkit.Println("Reading Master")
	prepMaster()

	toolkit.Println("START...")

	conn, _ := modules.GetDboxIConnection("db_godrej")
	// filter := dbox.Eq("iv_no", "FK/IGA/14001247")
	crx, _ := conn.NewQuery().Select().From(vdistdetail).Cursor(nil)
	defer crx.Close()
	defer conn.Close()

	lastSalesLine = toolkit.M{}
	count = crx.Count()
	step = count / 100
	i := 0

	jobs := make(chan toolkit.M, count)
	result := make(chan string, count)
	for wi := 0; wi < 10; wi++ {
		go workerProc(wi, jobs, result)
	}

	t0 := time.Now()
	for {
		i++
		tkmsd := toolkit.M{}
		e := crx.Fetch(&tkmsd, 1, false)
		if e != nil {
			break
		}

		invid := toolkit.ToString(tkmsd.Get("iv_no", ""))
		if lastSalesLine.Has(invid) {
			lastLineNo := lastSalesLine.GetInt(invid) + 1
			tkmsd.Set("lineno", lastLineNo)
			lastSalesLine.Set(invid, lastLineNo)
		} else {
			tkmsd.Set("lineno", 1)
			lastSalesLine.Set(invid, 1)
		}

		jobs <- tkmsd
		// gdrj.Save(st)
		if step == 0 {
			step = 100
		}

		if i%step == 0 {
			toolkit.Printfn("Processing %d of %d (%d) in %s",
				i, count, i/step,
				time.Since(t0).String())
		}
	}

	close(jobs)

	for ri := 0; ri < i; ri++ {
		<-result
		if step == 0 {
			step = 100
		}

		if ri%step == 0 {
			toolkit.Printfn("Saving %d of %d (%d pct) in %s",
				ri, count, ri/step, time.Since(t0).String())
		}
	}

	toolkit.Printfn("Processing done in %s with gross %v and correct %v",
		time.Since(t0).String(), ggrossamount, cggrossamount)
}

func workerProc(wi int, jobs <-chan toolkit.M, result chan<- string) {
	workerconn, _ := modules.GetDboxIConnection("db_godrej")
	defer workerconn.Close()

	tkmsd := toolkit.M{}
	for tkmsd = range jobs {
		gdrjdate := new(gdrj.Date)

		st := new(gdrj.SalesTrx)
		st.SalesHeaderID = toolkit.ToString(tkmsd.Get("iv_no", ""))

		st.LineNo = tkmsd.GetInt("lineno")
		dgrossamount := toolkit.ToFloat64(tkmsd.Get("gross", 0), 6, toolkit.RoundingAuto)
		ggrossamount += dgrossamount

		if shs.Has(st.SalesHeaderID) {
			sho := shs.Get(st.SalesHeaderID).(*gdrj.SalesHeader)
			sho.OutletID = strings.ToUpper(sho.OutletID)

			if sho.SalesDiscountAmount != 0 && sho.SalesGrossAmount != 0 {
				st.DiscountAmount = dgrossamount * sho.SalesDiscountAmount / sho.SalesGrossAmount
			}

			if sho.SalesTaxAmount != 0 && sho.SalesGrossAmount != 0 {
				st.TaxAmount = dgrossamount * sho.SalesTaxAmount / sho.SalesGrossAmount
			}

			st.OutletID = sho.BranchID + sho.OutletID
			st.Date = sho.Date
			st.HeaderValid = true

			gdrjdate = gdrj.SetDate(sho.Date)
			st.Year = gdrjdate.Year
			st.Month = int(gdrjdate.Month)
			st.Fiscal = gdrjdate.Fiscal

		} else {
			st.HeaderValid = false
		}
		//brsap,iv_no,dtsales,inv_no,qty,price,gross,net
		st.SKUID_VDIST = toolkit.ToString(tkmsd.Get("inv_no", ""))
		if vdistskus.Has(st.SKUID_VDIST) {
			st.SKUID = toolkit.ToString(vdistskus[st.SKUID_VDIST])
		} else {
			st.SKUID = "not found"
		}

		st.SalesQty = toolkit.ToFloat64(tkmsd.Get("qty", 0), 6, toolkit.RoundingAuto)
		st.GrossAmount = dgrossamount
		st.NetAmount = toolkit.ToFloat64(tkmsd.Get("net", 0), 6, toolkit.RoundingAuto)

		if prods.Has(st.SKUID) {
			st.ProductValid = true
			st.Product = prods.Get(st.SKUID).(*gdrj.Product)
		} else {
			st.ProductValid = false
		}

		if custs.Has(st.OutletID) {
			st.CustomerValid = true
			st.Customer = custs.Get(st.OutletID).(*gdrj.Customer)
			if st.Customer.ChannelID == "I1" {
				st.CustomerValid = false
			}
		} else {
			st.CustomerValid = false
		}

		if st.ProductValid && st.CustomerValid {
			pcid := st.Customer.BranchID + st.Product.BrandCategoryID
			if pcs.Has(pcid) {
				st.PCValid = true
				st.PC = pcs.Get(pcid).(*gdrj.ProfitCenter)
			} else {
				st.PCValid = false
			}
		} else {
			st.PCValid = false
		}

		if st.CustomerValid && st.HeaderValid {
			cggrossamount += st.GrossAmount
		}

		st.Src = "VDIST"
		st.ID = toolkit.ToString(st.PrepareID())
		workerconn.NewQuery().From(st.TableName()).
			Save().Exec(toolkit.M{}.Set("data", st))

		result <- st.ID
	}
}
<|endoftext|>


<commit_before>package dual

import (
	"context"
	"testing"
	"time"

	"github.com/ipfs/go-cid"
	u "github.com/ipfs/go-ipfs-util"
	"github.com/libp2p/go-libp2p-core/network"
	"github.com/libp2p/go-libp2p-core/peer"
	peerstore "github.com/libp2p/go-libp2p-core/peerstore"
	dht "github.com/libp2p/go-libp2p-kad-dht"
	test "github.com/libp2p/go-libp2p-kad-dht/internal/testing"
	record "github.com/libp2p/go-libp2p-record"
	swarmt "github.com/libp2p/go-libp2p-swarm/testing"
	bhost "github.com/libp2p/go-libp2p/p2p/host/basic"
)

var wancid, lancid cid.Cid

func init() {
	wancid = cid.NewCidV1(cid.DagCBOR, u.Hash([]byte("wan cid -- value")))
	lancid = cid.NewCidV1(cid.DagCBOR, u.Hash([]byte("lan cid -- value")))
}

type blankValidator struct{}

func (blankValidator) Validate(_ string, _ []byte) error        { return nil }
func (blankValidator) Select(_ string, _ [][]byte) (int, error) { return 0, nil }

type customRtHelper struct {
	allow peer.ID
}

func MkFilterForPeer() (func(d *dht.IpfsDHT, conns []network.Conn) bool, *customRtHelper) {
	helper := customRtHelper{}
	f := func(_ *dht.IpfsDHT, conns []network.Conn) bool {
		for _, c := range conns {
			if c.RemotePeer() == helper.allow {
				return true
			}
		}
		return false
	}
	return f, &helper
}

func setupDHTWithFilters(ctx context.Context, t *testing.T, options ...dht.Option) (*DHT, []*customRtHelper) {
	h := bhost.New(swarmt.GenSwarm(t, ctx, swarmt.OptDisableReuseport))

	wanFilter, wanRef := MkFilterForPeer()
	wanOpts := []dht.Option{
		dht.NamespacedValidator("v", blankValidator{}),
		dht.ProtocolPrefix("/test"),
		dht.DisableAutoRefresh(),
		dht.RoutingTableFilter(wanFilter),
	}
	wan, err := dht.New(ctx, h, wanOpts...)
	if err != nil {
		t.Fatal(err)
	}

	lanFilter, lanRef := MkFilterForPeer()
	lanOpts := []dht.Option{
		dht.NamespacedValidator("v", blankValidator{}),
		dht.ProtocolPrefix("/test"),
		dht.ProtocolExtension(LanExtension),
		dht.DisableAutoRefresh(),
		dht.RoutingTableFilter(lanFilter),
		dht.Mode(dht.ModeServer),
	}
	lan, err := dht.New(ctx, h, lanOpts...)
	if err != nil {
		t.Fatal(err)
	}

	impl := DHT{wan, lan}
	return &impl, []*customRtHelper{wanRef, lanRef}
}

func setupDHT(ctx context.Context, t *testing.T, options ...dht.Option) *DHT {
	t.Helper()
	baseOpts := []dht.Option{
		dht.NamespacedValidator("v", blankValidator{}),
		dht.ProtocolPrefix("/test"),
		dht.DisableAutoRefresh(),
	}

	d, err := New(
		ctx,
		bhost.New(swarmt.GenSwarm(t, ctx, swarmt.OptDisableReuseport)),
		append([]Option{DHTOption(baseOpts...)}, DHTOption(options...))...,
	)
	if err != nil {
		t.Fatal(err)
	}
	return d
}

func connect(ctx context.Context, t *testing.T, a, b *dht.IpfsDHT) {
	t.Helper()
	bid := b.PeerID()
	baddr := b.Host().Peerstore().Addrs(bid)
	if len(baddr) == 0 {
		t.Fatal("no addresses for connection.")
	}
	a.Host().Peerstore().AddAddrs(bid, baddr, peerstore.TempAddrTTL)
	if err := a.Host().Connect(ctx, peer.AddrInfo{ID: bid}); err != nil {
		t.Fatal(err)
	}
	wait(ctx, t, a, b)
}

func wait(ctx context.Context, t *testing.T, a, b *dht.IpfsDHT) {
	t.Helper()
	for a.RoutingTable().Find(b.PeerID()) == "" {
		//fmt.Fprintf(os.Stderr, "%v\n", a.RoutingTable().GetPeerInfos())
		select {
		case <-ctx.Done():
			t.Fatal(ctx.Err())
		case <-time.After(time.Millisecond * 5):
		}
	}
}

func setupTier(ctx context.Context, t *testing.T) (*DHT, *dht.IpfsDHT, *dht.IpfsDHT) {
	t.Helper()
	baseOpts := []dht.Option{
		dht.NamespacedValidator("v", blankValidator{}),
		dht.ProtocolPrefix("/test"),
		dht.DisableAutoRefresh(),
	}

	d, hlprs := setupDHTWithFilters(ctx, t)

	wan, err := dht.New(
		ctx,
		bhost.New(swarmt.GenSwarm(t, ctx, swarmt.OptDisableReuseport)),
		append(baseOpts, dht.Mode(dht.ModeServer))...,
	)
	if err != nil {
		t.Fatal(err)
	}
	hlprs[0].allow = wan.PeerID()
	connect(ctx, t, d.WAN, wan)

	lan, err := dht.New(
		ctx,
		bhost.New(swarmt.GenSwarm(t, ctx, swarmt.OptDisableReuseport)),
		append(baseOpts, dht.Mode(dht.ModeServer), dht.ProtocolExtension("/lan"))...,
	)
	if err != nil {
		t.Fatal(err)
	}
	hlprs[1].allow = lan.PeerID()
	connect(ctx, t, d.LAN, lan)

	return d, wan, lan
}

func TestDualModes(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
	defer cancel()

	d := setupDHT(ctx, t)
	defer d.Close()

	if d.WAN.Mode() != dht.ModeAuto {
		t.Fatal("wrong default mode for wan")
	} else if d.LAN.Mode() != dht.ModeServer {
		t.Fatal("wrong default mode for lan")
	}

	d2 := setupDHT(ctx, t, dht.Mode(dht.ModeClient))
	defer d2.Close()
	if d2.WAN.Mode() != dht.ModeClient ||
		d2.LAN.Mode() != dht.ModeClient {
		t.Fatal("wrong client mode operation")
	}
}

func TestFindProviderAsync(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
	defer cancel()

	d, wan, lan := setupTier(ctx, t)
	defer d.Close()
	defer wan.Close()
	defer lan.Close()

	time.Sleep(5 * time.Millisecond)

	if err := wan.Provide(ctx, wancid, false); err != nil {
		t.Fatal(err)
	}

	if err := lan.Provide(ctx, lancid, true); err != nil {
		t.Fatal(err)
	}

	wpc := d.FindProvidersAsync(ctx, wancid, 1)
	select {
	case p := <-wpc:
		if p.ID != wan.PeerID() {
			t.Fatal("wrong wan provider")
		}
	case <-ctx.Done():
		t.Fatal("find provider timeout.")
	}

	lpc := d.FindProvidersAsync(ctx, lancid, 1)
	select {
	case p := <-lpc:
		if p.ID != lan.PeerID() {
			t.Fatal("wrong lan provider")
		}
	case <-ctx.Done():
		t.Fatal("find provider timeout.")
	}
}

func TestValueGetSet(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
	defer cancel()

	d, wan, lan := setupTier(ctx, t)
	defer d.Close()
	defer wan.Close()
	defer lan.Close()

	time.Sleep(5 * time.Millisecond)

	err := d.PutValue(ctx, "/v/hello", []byte("valid"))
	if err != nil {
		t.Fatal(err)
	}
	val, err := wan.GetValue(ctx, "/v/hello")
	if err != nil {
		t.Fatal(err)
	}
	if string(val) != "valid" {
		t.Fatal("failed to get expected string.")
	}

	_, err = lan.GetValue(ctx, "/v/hello")
	if err == nil {
		t.Fatal(err)
	}
}

func TestSearchValue(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
	defer cancel()

	d, wan, lan := setupTier(ctx, t)
	defer d.Close()
	defer wan.Close()
	defer lan.Close()

	d.WAN.Validator.(record.NamespacedValidator)["v"] = test.TestValidator{}
	d.LAN.Validator.(record.NamespacedValidator)["v"] = test.TestValidator{}

	_ = wan.PutValue(ctx, "/v/hello", []byte("valid"))

	valCh, err := d.SearchValue(ctx, "/v/hello", dht.Quorum(0))
	if err != nil {
		t.Fatal(err)
	}

	select {
	case v := <-valCh:
		if string(v) != "valid" {
			t.Errorf("expected 'valid', got '%s'", string(v))
		}
	case <-ctx.Done():
		t.Fatal(ctx.Err())
	}

	select {
	case _, ok := <-valCh:
		if ok {
			t.Errorf("chan should close")
		}
	case <-ctx.Done():
		t.Fatal(ctx.Err())
	}

	err = lan.PutValue(ctx, "/v/hello", []byte("newer"))
	if err != nil {
		t.Error(err)
	}

	valCh, err = d.SearchValue(ctx, "/v/hello", dht.Quorum(0))
	if err != nil {
		t.Fatal(err)
	}

	var lastVal []byte
	for c := range valCh {
		lastVal = c
	}
	if string(lastVal) != "newer" {
		t.Fatal("incorrect best search value")
	}
}

func TestGetPublicKey(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
	defer cancel()

	d, wan, lan := setupTier(ctx, t)
	defer d.Close()
	defer wan.Close()
	defer lan.Close()

	time.Sleep(5 * time.Millisecond)

	pk, err := d.GetPublicKey(ctx, wan.PeerID())
	if err != nil {
		t.Fatal(err)
	}
	id, err := peer.IDFromPublicKey(pk)
	if err != nil {
		t.Fatal(err)
	}
	if id != wan.PeerID() {
		t.Fatal("incorrect PK")
	}

	pk, err = d.GetPublicKey(ctx, lan.PeerID())
	if err != nil {
		t.Fatal(err)
	}
	id, err = peer.IDFromPublicKey(pk)
	if err != nil {
		t.Fatal(err)
	}
	if id != lan.PeerID() {
		t.Fatal("incorrect PK")
	}
}

func TestFindPeer(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
	defer cancel()

	d, wan, lan := setupTier(ctx, t)
	defer d.Close()
	defer wan.Close()
	defer lan.Close()

	time.Sleep(5 * time.Millisecond)

	p, err := d.FindPeer(ctx, lan.PeerID())
	if err != nil {
		t.Fatal(err)
	}
	if len(p.Addrs) != 1 {
		t.Fatalf("expeced find peer to find 1 address, found %d", len(p.Addrs))
	}
	p, err = d.FindPeer(ctx, wan.PeerID())
	if err != nil {
		t.Fatal(err)
	}
	if len(p.Addrs) != 1 {
		t.Fatalf("expeced find peer to find addresses, found %d", len(p.Addrs))
	}
}
<commit_msg>test: fix unique addr check<commit_after>package dual

import (
	"context"
	"testing"
	"time"

	"github.com/ipfs/go-cid"
	u "github.com/ipfs/go-ipfs-util"
	"github.com/libp2p/go-libp2p-core/network"
	"github.com/libp2p/go-libp2p-core/peer"
	peerstore "github.com/libp2p/go-libp2p-core/peerstore"
	dht "github.com/libp2p/go-libp2p-kad-dht"
	test "github.com/libp2p/go-libp2p-kad-dht/internal/testing"
	record "github.com/libp2p/go-libp2p-record"
	swarmt "github.com/libp2p/go-libp2p-swarm/testing"
	bhost "github.com/libp2p/go-libp2p/p2p/host/basic"
	"github.com/multiformats/go-multiaddr"
)

var wancid, lancid cid.Cid

func init() {
	wancid = cid.NewCidV1(cid.DagCBOR, u.Hash([]byte("wan cid -- value")))
	lancid = cid.NewCidV1(cid.DagCBOR, u.Hash([]byte("lan cid -- value")))
}

type blankValidator struct{}

func (blankValidator) Validate(_ string, _ []byte) error        { return nil }
func (blankValidator) Select(_ string, _ [][]byte) (int, error) { return 0, nil }

type customRtHelper struct {
	allow peer.ID
}

func MkFilterForPeer() (func(d *dht.IpfsDHT, conns []network.Conn) bool, *customRtHelper) {
	helper := customRtHelper{}
	f := func(_ *dht.IpfsDHT, conns []network.Conn) bool {
		for _, c := range conns {
			if c.RemotePeer() == helper.allow {
				return true
			}
		}
		return false
	}
	return f, &helper
}

func setupDHTWithFilters(ctx context.Context, t *testing.T, options ...dht.Option) (*DHT, []*customRtHelper) {
	h := bhost.New(swarmt.GenSwarm(t, ctx, swarmt.OptDisableReuseport))

	wanFilter, wanRef := MkFilterForPeer()
	wanOpts := []dht.Option{
		dht.NamespacedValidator("v", blankValidator{}),
		dht.ProtocolPrefix("/test"),
		dht.DisableAutoRefresh(),
		dht.RoutingTableFilter(wanFilter),
	}
	wan, err := dht.New(ctx, h, wanOpts...)
	if err != nil {
		t.Fatal(err)
	}

	lanFilter, lanRef := MkFilterForPeer()
	lanOpts := []dht.Option{
		dht.NamespacedValidator("v", blankValidator{}),
		dht.ProtocolPrefix("/test"),
		dht.ProtocolExtension(LanExtension),
		dht.DisableAutoRefresh(),
		dht.RoutingTableFilter(lanFilter),
		dht.Mode(dht.ModeServer),
	}
	lan, err := dht.New(ctx, h, lanOpts...)
	if err != nil {
		t.Fatal(err)
	}

	impl := DHT{wan, lan}
	return &impl, []*customRtHelper{wanRef, lanRef}
}

func setupDHT(ctx context.Context, t *testing.T, options ...dht.Option) *DHT {
	t.Helper()
	baseOpts := []dht.Option{
		dht.NamespacedValidator("v", blankValidator{}),
		dht.ProtocolPrefix("/test"),
		dht.DisableAutoRefresh(),
	}

	d, err := New(
		ctx,
		bhost.New(swarmt.GenSwarm(t, ctx, swarmt.OptDisableReuseport)),
		append([]Option{DHTOption(baseOpts...)}, DHTOption(options...))...,
	)
	if err != nil {
		t.Fatal(err)
	}
	return d
}

func connect(ctx context.Context, t *testing.T, a, b *dht.IpfsDHT) {
	t.Helper()
	bid := b.PeerID()
	baddr := b.Host().Peerstore().Addrs(bid)
	if len(baddr) == 0 {
		t.Fatal("no addresses for connection.")
	}
	a.Host().Peerstore().AddAddrs(bid, baddr, peerstore.TempAddrTTL)
	if err := a.Host().Connect(ctx, peer.AddrInfo{ID: bid}); err != nil {
		t.Fatal(err)
	}
	wait(ctx, t, a, b)
}

func wait(ctx context.Context, t *testing.T, a, b *dht.IpfsDHT) {
	t.Helper()
	for a.RoutingTable().Find(b.PeerID()) == "" {
		//fmt.Fprintf(os.Stderr, "%v\n", a.RoutingTable().GetPeerInfos())
		select {
		case <-ctx.Done():
			t.Fatal(ctx.Err())
		case <-time.After(time.Millisecond * 5):
		}
	}
}

func setupTier(ctx context.Context, t *testing.T) (*DHT, *dht.IpfsDHT, *dht.IpfsDHT) {
	t.Helper()
	baseOpts := []dht.Option{
		dht.NamespacedValidator("v", blankValidator{}),
		dht.ProtocolPrefix("/test"),
		dht.DisableAutoRefresh(),
	}

	d, hlprs := setupDHTWithFilters(ctx, t)

	wan, err := dht.New(
		ctx,
		bhost.New(swarmt.GenSwarm(t, ctx, swarmt.OptDisableReuseport)),
		append(baseOpts, dht.Mode(dht.ModeServer))...,
	)
	if err != nil {
		t.Fatal(err)
	}
	hlprs[0].allow = wan.PeerID()
	connect(ctx, t, d.WAN, wan)

	lan, err := dht.New(
		ctx,
		bhost.New(swarmt.GenSwarm(t, ctx, swarmt.OptDisableReuseport)),
		append(baseOpts, dht.Mode(dht.ModeServer), dht.ProtocolExtension("/lan"))...,
	)
	if err != nil {
		t.Fatal(err)
	}
	hlprs[1].allow = lan.PeerID()
	connect(ctx, t, d.LAN, lan)

	return d, wan, lan
}

func TestDualModes(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
	defer cancel()

	d := setupDHT(ctx, t)
	defer d.Close()

	if d.WAN.Mode() != dht.ModeAuto {
		t.Fatal("wrong default mode for wan")
	} else if d.LAN.Mode() != dht.ModeServer {
		t.Fatal("wrong default mode for lan")
	}

	d2 := setupDHT(ctx, t, dht.Mode(dht.ModeClient))
	defer d2.Close()
	if d2.WAN.Mode() != dht.ModeClient ||
		d2.LAN.Mode() != dht.ModeClient {
		t.Fatal("wrong client mode operation")
	}
}

func TestFindProviderAsync(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
	defer cancel()

	d, wan, lan := setupTier(ctx, t)
	defer d.Close()
	defer wan.Close()
	defer lan.Close()

	time.Sleep(5 * time.Millisecond)

	if err := wan.Provide(ctx, wancid, false); err != nil {
		t.Fatal(err)
	}

	if err := lan.Provide(ctx, lancid, true); err != nil {
		t.Fatal(err)
	}

	wpc := d.FindProvidersAsync(ctx, wancid, 1)
	select {
	case p := <-wpc:
		if p.ID != wan.PeerID() {
			t.Fatal("wrong wan provider")
		}
	case <-ctx.Done():
		t.Fatal("find provider timeout.")
	}

	lpc := d.FindProvidersAsync(ctx, lancid, 1)
	select {
	case p := <-lpc:
		if p.ID != lan.PeerID() {
			t.Fatal("wrong lan provider")
		}
	case <-ctx.Done():
		t.Fatal("find provider timeout.")
	}
}

func TestValueGetSet(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
	defer cancel()

	d, wan, lan := setupTier(ctx, t)
	defer d.Close()
	defer wan.Close()
	defer lan.Close()

	time.Sleep(5 * time.Millisecond)

	err := d.PutValue(ctx, "/v/hello", []byte("valid"))
	if err != nil {
		t.Fatal(err)
	}
	val, err := wan.GetValue(ctx, "/v/hello")
	if err != nil {
		t.Fatal(err)
	}
	if string(val) != "valid" {
		t.Fatal("failed to get expected string.")
	}

	_, err = lan.GetValue(ctx, "/v/hello")
	if err == nil {
		t.Fatal(err)
	}
}

func TestSearchValue(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
	defer cancel()

	d, wan, lan := setupTier(ctx, t)
	defer d.Close()
	defer wan.Close()
	defer lan.Close()

	d.WAN.Validator.(record.NamespacedValidator)["v"] = test.TestValidator{}
	d.LAN.Validator.(record.NamespacedValidator)["v"] = test.TestValidator{}

	_ = wan.PutValue(ctx, "/v/hello", []byte("valid"))

	valCh, err := d.SearchValue(ctx, "/v/hello", dht.Quorum(0))
	if err != nil {
		t.Fatal(err)
	}

	select {
	case v := <-valCh:
		if string(v) != "valid" {
			t.Errorf("expected 'valid', got '%s'", string(v))
		}
	case <-ctx.Done():
		t.Fatal(ctx.Err())
	}

	select {
	case _, ok := <-valCh:
		if ok {
			t.Errorf("chan should close")
		}
	case <-ctx.Done():
		t.Fatal(ctx.Err())
	}

	err = lan.PutValue(ctx, "/v/hello", []byte("newer"))
	if err != nil {
		t.Error(err)
	}

	valCh, err = d.SearchValue(ctx, "/v/hello", dht.Quorum(0))
	if err != nil {
		t.Fatal(err)
	}

	var lastVal []byte
	for c := range valCh {
		lastVal = c
	}
	if string(lastVal) != "newer" {
		t.Fatal("incorrect best search value")
	}
}

func TestGetPublicKey(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
	defer cancel()

	d, wan, lan := setupTier(ctx, t)
	defer d.Close()
	defer wan.Close()
	defer lan.Close()

	time.Sleep(5 * time.Millisecond)

	pk, err := d.GetPublicKey(ctx, wan.PeerID())
	if err != nil {
		t.Fatal(err)
	}
	id, err := peer.IDFromPublicKey(pk)
	if err != nil {
		t.Fatal(err)
	}
	if id != wan.PeerID() {
		t.Fatal("incorrect PK")
	}

	pk, err = d.GetPublicKey(ctx, lan.PeerID())
	if err != nil {
		t.Fatal(err)
	}
	id, err = peer.IDFromPublicKey(pk)
	if err != nil {
		t.Fatal(err)
	}
	if id != lan.PeerID() {
		t.Fatal("incorrect PK")
	}
}

func TestFindPeer(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
	defer cancel()

	d, wan, lan := setupTier(ctx, t)
	defer d.Close()
	defer wan.Close()
	defer lan.Close()

	time.Sleep(5 * time.Millisecond)

	p, err := d.FindPeer(ctx, lan.PeerID())
	if err != nil {
		t.Fatal(err)
	}
	assertUniqueMultiaddrs(t, p.Addrs)
	p, err = d.FindPeer(ctx, wan.PeerID())
	if err != nil {
		t.Fatal(err)
	}
	assertUniqueMultiaddrs(t, p.Addrs)
}

func assertUniqueMultiaddrs(t *testing.T, addrs []multiaddr.Multiaddr) {
	set := make(map[string]bool)
	for _, addr := range addrs {
		if set[string(addr.Bytes())] {
			t.Errorf("duplicate address %s", addr)
		}
		set[string(addr.Bytes())] = true
	}
}
<|endoftext|>


<commit_before>// Package of API error interface accessors for the SDK.
package awserr

// An Error wraps lower level errors with code, message and an original error.
// The underlying concrete error type may also satisfy other interfaces which
// can be to used to obtain more specific information about the error.
//
// Calling Error() or String() will always include the full information about
// an error based on its underlying type.
//
// Example:
//
//     output, err := s3manage.Upload(svc, input, opts)
//     if err != nil {
//         // Get error details
//         log.Println("Error:", err.Code(), err.Message())
//
//         Prints out full error message, including original error if there was one.
//         log.Println("Error:", err.Error())
//
//         // Get original error
//         if origErr := err.Err(); origErr != nil {
//             // operate on original error.
//         }
//     }
//
type Error interface {
	// Satisfy the generic error interface.
	error

	// Returns the short phrase depicting the classification of the error.
	Code() string

	// Returns the error details message.
	Message() string

	// Returns the original error if one was set.  Nil is returned if not set.
	OrigErr() error
}

// A RequestFailure is an interface to extract request failure information from
// an Error such as the request ID of the failed request returned by a service.
// RequestFailures may not always have a requestID value if the request failed
// prior to reaching the service such as a connection error.
//
// Example:
//
//     output, err := s3manage.Upload(svc, input, opts)
//     if err != nil {
//         if reqerr, ok := err.(RequestFailure); ok {
//             log.Printf("Request failed", reqerr.Code(), reqerr.Message(), reqerr.RequestID())
//         } else {
//             log.Printf("Error:", err.Code(), err.Message()
//     }
//
// Combined with awserr.Error:
//
//    output, err := s3manage.Upload(svc, input, opts)
//    if err != nil {
//        if awsErr, ok := err.(awserr.Error); ok {
//            // Generic AWS Error with Code, Message, and original error (if any)
//            fmt.Println(awsErr.Code(), awsErr.Message(), awsErr.OrigErr())
//            if reqErr, ok := err.(awserr.RequestFailure); ok {
//                // A service error occurred
//                fmt.Println(reqErr.StatusCode(), reqErr.RequestID())
//            }
//        } else {
//            fmt.Println(err.Error())
//        }
//    }
//
type RequestFailure interface {
	Error

	// The status code of the HTTP response.
	StatusCode() int

	// The request ID returned by the service for a request failure. This will
	// be empty if no request ID is available such as the request failed due
	// to a connection error.
	RequestID() string
}
<commit_msg>aws/awserr: Cleaned up Error examples<commit_after>// Package of API error interface accessors for the SDK.
package awserr

// An Error wraps lower level errors with code, message and an original error.
// The underlying concrete error type may also satisfy other interfaces which
// can be to used to obtain more specific information about the error.
//
// Calling Error() or String() will always include the full information about
// an error based on its underlying type.
//
// Example:
//
//    output, err := s3manage.Upload(svc, input, opts)
//    if err != nil {
//        if awsErr, ok := err.(awserr.Error); ok {
//            // Get error details
//            log.Println("Error:", err.Code(), err.Message())
//
//            Prints out full error message, including original error if there was one.
//            log.Println("Error:", err.Error())
//
//            // Get original error
//            if origErr := err.Err(); origErr != nil {
//                // operate on original error.
//            }
//        } else {
//            fmt.Println(err.Error())
//        }
//    }
//
type Error interface {
	// Satisfy the generic error interface.
	error

	// Returns the short phrase depicting the classification of the error.
	Code() string

	// Returns the error details message.
	Message() string

	// Returns the original error if one was set.  Nil is returned if not set.
	OrigErr() error
}

// A RequestFailure is an interface to extract request failure information from
// an Error such as the request ID of the failed request returned by a service.
// RequestFailures may not always have a requestID value if the request failed
// prior to reaching the service such as a connection error.
//
// Example:
//
//     output, err := s3manage.Upload(svc, input, opts)
//     if err != nil {
//         if reqerr, ok := err.(RequestFailure); ok {
//             log.Printf("Request failed", reqerr.Code(), reqerr.Message(), reqerr.RequestID())
//         } else {
//             log.Printf("Error:", err.Error()
//         }
//     }
//
// Combined with awserr.Error:
//
//    output, err := s3manage.Upload(svc, input, opts)
//    if err != nil {
//        if awsErr, ok := err.(awserr.Error); ok {
//            // Generic AWS Error with Code, Message, and original error (if any)
//            fmt.Println(awsErr.Code(), awsErr.Message(), awsErr.OrigErr())
//
//            if reqErr, ok := err.(awserr.RequestFailure); ok {
//                // A service error occurred
//                fmt.Println(reqErr.StatusCode(), reqErr.RequestID())
//            }
//        } else {
//            fmt.Println(err.Error())
//        }
//    }
//
type RequestFailure interface {
	Error

	// The status code of the HTTP response.
	StatusCode() int

	// The request ID returned by the service for a request failure. This will
	// be empty if no request ID is available such as the request failed due
	// to a connection error.
	RequestID() string
}
<|endoftext|>