<commit_before>package gosmparse

import (
	"fmt"
	"io"
	"runtime"
	"sync"

	"github.com/thomersch/gosmparse/OSMPBF"
)

func Decode(r io.Reader, o OSMReader) error {
	dec := newDecoder()
	header, _, err := dec.Block(r)
	if err != nil {
		return err
	}
	// TODO: parser checks
	if header.GetType() != "OSMHeader" {
		return fmt.Errorf("Invalid header of first data block. Wanted: OSMHeader, have: %s", header.GetType())
	}

	// errChan := make(chan error)
	// feeder
	blobs := make(chan *OSMPBF.Blob, 200)
	go func() {
		defer close(blobs)
		for {
			_, blob, err := dec.Block(r)
			if err != nil {
				if err == io.EOF {
					return
				}
				// TODO: proper handling
				panic("error during parsing")
			}
			blobs <- blob
		}
	}()

	// processer
	numcpus := runtime.NumCPU() - 1
	if numcpus < 1 {
		numcpus = 1
	}

	var wg sync.WaitGroup
	for i := 0; i < numcpus; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			for blob := range blobs {
				err := readElements(blob, dec, o)
				// TODO: proper error handling
				if err != nil {
					panic(err)
				}
			}
		}()
	}
	wg.Wait()
	return nil
}

func readElements(blob *OSMPBF.Blob, dec *decoder, o OSMReader) error {
	pb, err := dec.BlobData(blob)
	if err != nil {
		return err
	}

	for _, pg := range pb.Primitivegroup {
		switch {
		case pg.Dense != nil:
			if err := denseNode(o, pb, pg.Dense); err != nil {
				return err
			}
		case len(pg.Ways) != 0:
			if err := way(o, pb, pg.Ways); err != nil {
				return err
			}
		case len(pg.Relations) != 0:
			if err := relation(o, pb, pg.Relations); err != nil {
				return err
			}
		case len(pg.Nodes) != 0:
			return fmt.Errorf("Nodes are not supported")
		default:
			return fmt.Errorf("no supported data in primitive group")
		}
	}
	return nil
}
<commit_msg>now panic free (error handling through dedicated chan)<commit_after>package gosmparse

import (
	"fmt"
	"io"
	"runtime"
	"sync"

	"github.com/thomersch/gosmparse/OSMPBF"
)

func Decode(r io.Reader, o OSMReader) error {
	dec := newDecoder()
	header, _, err := dec.Block(r)
	if err != nil {
		return err
	}
	// TODO: parser checks
	if header.GetType() != "OSMHeader" {
		return fmt.Errorf("Invalid header of first data block. Wanted: OSMHeader, have: %s", header.GetType())
	}

	errChan := make(chan error)
	// feeder
	blobs := make(chan *OSMPBF.Blob, 200)
	go func() {
		defer close(blobs)
		for {
			_, blob, err := dec.Block(r)
			if err != nil {
				if err == io.EOF {
					return
				}
				errChan <- err
			}
			blobs <- blob
		}
	}()

	// processer
	numcpus := runtime.NumCPU() - 1
	if numcpus < 1 {
		numcpus = 1
	}

	var wg sync.WaitGroup
	for i := 0; i < numcpus; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			for blob := range blobs {
				err := readElements(blob, dec, o)
				if err != nil {
					errChan <- err
				}
			}
		}()
	}

	finished := make(chan bool)
	go func() {
		wg.Wait()
		finished <- true
	}()
	select {
	case err = <-errChan:
		return err
	case <-finished:
		return nil
	}
}

func readElements(blob *OSMPBF.Blob, dec *decoder, o OSMReader) error {
	pb, err := dec.BlobData(blob)
	if err != nil {
		return err
	}

	for _, pg := range pb.Primitivegroup {
		switch {
		case pg.Dense != nil:
			if err := denseNode(o, pb, pg.Dense); err != nil {
				return err
			}
		case len(pg.Ways) != 0:
			if err := way(o, pb, pg.Ways); err != nil {
				return err
			}
		case len(pg.Relations) != 0:
			if err := relation(o, pb, pg.Relations); err != nil {
				return err
			}
		case len(pg.Nodes) != 0:
			return fmt.Errorf("Nodes are not supported")
		default:
			return fmt.Errorf("no supported data in primitive group")
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package lich

import (
	"errors" //Why would anyone want to import more errors into their code???
	"strconv"
)

var UnparseableError = errors.New("Couldn't parse string.")

func Parse(s string) (Element, error) {
	if len(s) < 1 {
		return nil, UnparseableError
	}

	el := getElement(s, 0, len(s))

	if el == nil {
		return nil, UnparseableError
	}

	return el, nil
}

func isdigit(r uint8) bool {
	return r >= '0' && r <= '9'
}

func getElement(s string, start, stop int) Element {
	r := s[start]

	if !isdigit(r) {
		return nil
	}

	current := start + 1
	for isdigit(s[current]) {
		current++
	}

	size, _ := strconv.Atoi(s[start:current])

	//If this doesn't match, the reported size is screwed up.
	//Doing this check helps make sure we don't try to read too far.
	if current+size+2 <= stop {
		return nil
	}

	switch s[current] {
	case '<':
		return getData(s, current+1, stop)
	}
	return nil
}

func getData(s string, start, stop int) Element {
	if s[stop-1] != '>' {
		return nil
	}
	return Data(s[start : stop-1])
}
<commit_msg>Error system<commit_after>package lich

import (
	"fmt"
	"strconv"
)

type UnparseableError struct {
	Parsestring string
	Location    int
	Problem     string
}

const errformat = "Couldn't parse string %q...\nProblem at index %d was %q."

func (u UnparseableError) Error() string {
	return fmt.Sprintf(errformat, u.Parsestring[:10], u.Location, u.Problem)
}

func Parse(s string) (Element, error) {
	return topLevel(s, 0, len(s))
}

func isdigit(r uint8) bool {
	return r >= '0' && r <= '9'
}

func topLevel(s string, start, stop int) (Element, error) {
	if len(s) < 1 {
		return nil, UnparseableError{s, 0, "Empty string!"}
	}

	current := start
	for isdigit(s[current]) {
		current++
	}

	size, err := strconv.Atoi(s[start:current])

	if err != nil {
		return nil, UnparseableError{s, current, "Non-digit start"}
	}

	//If this doesn't match, the reported size is screwed up.
	//Doing this check helps make sure we don't try to read too far.
	if current+size+2 != stop {
		return nil, UnparseableError{s, current, "Data payload is too short"}
	}

	switch s[current] {
	case '<':
		if s[stop-1] != '>' {
			return nil, UnparseableError{s, stop - 1, "No matching >"}
		}
		return Data(s[current+1 : stop-1]), nil

	case '[':
		if s[stop-1] != ']' {
			return nil, UnparseableError{s, stop - 1, "No matching ]"}
		}

		return getArray(s, current+1, stop-1), nil

	}
	return nil, UnparseableError{s, current, "Invalid separator"}
}

func getArray(s string, start, stop int) Element {
	if s[stop] != ']' {
		return nil
	}
	return Data(s[start:stop])
}
<|endoftext|>


<commit_before>package ctx

import (
	"context"
	"testing"
	"time"

	"github.com/magiconair/properties/assert"
)

func TestBindFunc(t *testing.T) {
	f := BindFunc(func(d Doner) { panic("called") })
	assert.Panic(t, func() { f.Bind(nil) }, "called")
}

func TestDoneChan(t *testing.T) {
	ch := make(chan struct{})
	close(ch)

	select {
	case <-DoneChan(ch).Done():
	default:
		t.Error("doner did not reflect closed state of channel")
	}
}

func TestDefer(t *testing.T) {
	ch := make(chan struct{})
	close(ch)

	chT := make(chan struct{})
	Defer(Lift(ch), func() { close(chT) })

	select {
	case <-chT:
	case <-time.After(time.Millisecond * 100):
		t.Error("deferred function was not called")
	}
}

func TestLink(t *testing.T) {
	ch := make(chan struct{})
	close(ch)

	select {
	case <-Link(Lift(ch), Lift(nil)):
	case <-time.After(time.Millisecond * 100):
		t.Error("link did not fire despite a Doner having fired")
	}
}

func TestJoin(t *testing.T) {
	ch := make(chan struct{})
	close(ch)

	c, cancel := context.WithCancel(context.Background())

	d := Join(Lift(ch), c)

	select {
	case <-d.Done():
		t.Error("premature firing of join-Doner")
	default:
	}

	cancel()

	select {
	case <-d.Done():
	case <-time.After(time.Millisecond * 100):
		t.Error("join-Doner did not fire despite all constituent Doners having fired")
	}
}
<commit_msg>Change Lift to C and DoneChan to C<commit_after>package ctx

import (
	"context"
	"testing"
	"time"

	"github.com/magiconair/properties/assert"
)

func TestBindFunc(t *testing.T) {
	f := BindFunc(func(d Doner) { panic("called") })
	assert.Panic(t, func() { f.Bind(nil) }, "called")
}

func TestC(t *testing.T) {
	ch := make(chan struct{})
	close(ch)

	select {
	case <-C(ch).Done():
	default:
		t.Error("doner did not reflect closed state of channel")
	}
}

func TestDefer(t *testing.T) {
	ch := make(chan struct{})
	close(ch)

	chT := make(chan struct{})
	Defer(C(ch), func() { close(chT) })

	select {
	case <-chT:
	case <-time.After(time.Millisecond * 100):
		t.Error("deferred function was not called")
	}
}

func TestLink(t *testing.T) {
	ch := make(chan struct{})
	close(ch)

	select {
	case <-Link(C(ch), C(nil)):
	case <-time.After(time.Millisecond * 100):
		t.Error("link did not fire despite a Doner having fired")
	}
}

func TestJoin(t *testing.T) {
	ch := make(chan struct{})
	close(ch)

	c, cancel := context.WithCancel(context.Background())

	d := Join(C(ch), c)

	select {
	case <-d.Done():
		t.Error("premature firing of join-Doner")
	default:
	}

	cancel()

	select {
	case <-d.Done():
	case <-time.After(time.Millisecond * 100):
		t.Error("join-Doner did not fire despite all constituent Doners having fired")
	}
}
<|endoftext|>


<commit_before>package auth

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"strings"

	"github.com/jrperritt/rack/commandoptions"
	"github.com/jrperritt/rack/internal/github.com/Sirupsen/logrus"
	"github.com/jrperritt/rack/internal/github.com/codegangsta/cli"
	"github.com/jrperritt/rack/internal/github.com/rackspace/gophercloud"
	"github.com/jrperritt/rack/internal/github.com/rackspace/gophercloud/rackspace"
	"github.com/jrperritt/rack/util"
)

var usernameAuthErrSlice = []string{"There are some required Rackspace Cloud credentials that we couldn't find.",
	"Here's what we have:",
	"%s",
	"and here's what we're missing:",
	"%s",
	"",
	"You can set any of these credentials in the following ways:",
	"- Run `rack configure` to interactively create a configuration file,",
	"- Specify it in the command as a flag (--username, --api-key), or",
	"- Export it as an environment variable (RS_USERNAME, RS_API_KEY).",
	"",
}

var tenantIDAuthErrSlice = []string{"There are some required Rackspace Cloud credentials that we couldn't find.",
	"Here's what we have:",
	"%s",
	"and here's what we're missing:",
	"%s",
	"",
	"You can set the missing credentials with command-line flags (--auth-token, --auth-tenant-id)",
	"",
}

func Err(have map[string]commandoptions.Cred, want map[string]string, errMsg []string) error {
	haveString := ""
	for k, v := range have {
		haveString += fmt.Sprintf("%s: %s (from %s)\n", k, v.Value, v.From)
	}

	if len(want) > 0 {
		wantString := ""
		for k := range want {
			wantString += fmt.Sprintf("%s\n", k)
		}

		return fmt.Errorf(fmt.Sprintf(strings.Join(errMsg, "\n"), haveString, wantString))
	}

	return nil
}

type CredentialsResult struct {
	AuthOpts *gophercloud.AuthOptions
	Region   string
	Have     map[string]commandoptions.Cred
	Want     map[string]string
}

func findAuthOpts(c *cli.Context, have map[string]commandoptions.Cred, want map[string]string) error {
	// use command-line options if available
	commandoptions.CLIopts(c, have, want)
	// are there any unset auth variables?
	if len(want) != 0 {
		// if so, look in config file
		err := commandoptions.ConfigFile(c, have, want)
		if err != nil {
			return err
		}
		// still unset auth variables?
		if len(want) != 0 {
			// if so, look in environment variables
			envvars(have, want)
		}
	}

	return nil
}

// reauthFunc is what the ServiceClient uses to re-authenticate.
func reauthFunc(pc *gophercloud.ProviderClient, ao gophercloud.AuthOptions) func() error {
	return func() error {
		return rackspace.AuthenticateV2(pc, ao)
	}
}

// NewClient creates and returns a Rackspace client for the given service.
func NewClient(c *cli.Context, serviceType string, logger *logrus.Logger, noCache bool) (*gophercloud.ServiceClient, error) {
	// get the user's authentication credentials
	credsResult, err := Credentials(c, logger)
	if err != nil {
		return nil, err
	}

	if noCache {
		return authFromScratch(credsResult, serviceType, logger)
	}

	ao := credsResult.AuthOpts
	region := credsResult.Region

	// form the cache key
	cacheKey := CacheKey(*ao, region, serviceType)
	// initialize cache
	cache := &Cache{}
	logger.Infof("Looking in the cache for cache key: %s\n", cacheKey)
	// get the value from the cache
	creds, err := cache.Value(cacheKey)
	// if there was an error accessing the cache or there was nothing in the cache,
	// authenticate from scratch
	if err == nil && creds != nil {
		// we successfully retrieved a value from the cache
		logger.Infof("Using token from cache: %s\n", creds.TokenID)
		pc, err := rackspace.NewClient(ao.IdentityEndpoint)
		if err == nil {
			pc.TokenID = creds.TokenID
			pc.ReauthFunc = reauthFunc(pc, *ao)
			pc.UserAgent.Prepend(util.UserAgent)
			pc.HTTPClient = newHTTPClient()
			return &gophercloud.ServiceClient{
				ProviderClient: pc,
				Endpoint:       creds.ServiceEndpoint,
			}, nil
		}
	} else {
		return authFromScratch(credsResult, serviceType, logger)
	}

	return nil, nil
}

func authFromScratch(credsResult *CredentialsResult, serviceType string, logger *logrus.Logger) (*gophercloud.ServiceClient, error) {
	logger.Info("Not using cache; Authenticating from scratch.\n")

	ao := credsResult.AuthOpts
	region := credsResult.Region

	pc, err := rackspace.AuthenticatedClient(*ao)
	if err != nil {
		return nil, err
	}
	pc.HTTPClient = newHTTPClient()
	var sc *gophercloud.ServiceClient
	switch serviceType {
	case "compute":
		sc, err = rackspace.NewComputeV2(pc, gophercloud.EndpointOpts{
			Region: region,
		})
		break
	case "object-store":
		sc, err = rackspace.NewObjectStorageV1(pc, gophercloud.EndpointOpts{
			Region: region,
		})
		break
	case "blockstorage":
		sc, err = rackspace.NewBlockStorageV1(pc, gophercloud.EndpointOpts{
			Region: region,
		})
		break
	case "network":
		sc, err = rackspace.NewNetworkV2(pc, gophercloud.EndpointOpts{
			Region: region,
		})
		break
	}
	if err != nil {
		return nil, err
	}
	if sc == nil {
		return nil, fmt.Errorf("Unable to create service client: Unknown service type: %s\n", serviceType)
	}
	sc.UserAgent.Prepend(util.UserAgent)
	return sc, nil
}

// Credentials determines the appropriate authentication method for the user.
// It returns a gophercloud.AuthOptions object and a region.
//
// It will use command-line authentication parameters if available, then it will
// look for any unset parameters in the config file, and then finally in
// environment variables.
func Credentials(c *cli.Context, logger *logrus.Logger) (*CredentialsResult, error) {
	ao := &gophercloud.AuthOptions{
		AllowReauth: true,
	}

	have := make(map[string]commandoptions.Cred)

	// let's looks for a region and identity endpoint
	want := map[string]string{
		"auth-url": "",
		"region":   "",
	}

	err := findAuthOpts(c, have, want)
	if err != nil {
		return nil, err
	}

	// if the user didn't provide an auth URL, default to the Rackspace US endpoint
	if _, ok := have["auth-url"]; !ok || have["auth-url"].Value == "" {
		have["auth-url"] = commandoptions.Cred{Value: rackspace.RackspaceUSIdentity, From: "default value"}
		delete(want, "auth-url")
	}
	ao.IdentityEndpoint = have["auth-url"].Value

	// upper-case the region
	region := strings.ToUpper(have["region"].Value)
	delete(want, "region")

	// now we check for token authentication (only allowed via the command-line)
	want["auth-tenant-id"] = ""
	want["auth-token"] = ""
	commandoptions.CLIopts(c, have, want)

	// if a tenant ID was provided on the command-line, we don't bother checking for a
	// username or api key
	if have["auth-tenant-id"].Value != "" || have["auth-token"].Value != "" {
		if tenantID, ok := have["auth-tenant-id"]; ok {
			ao.TenantID = tenantID.Value
			ao.TokenID = have["auth-token"].Value
			delete(want, "auth-token")
		} else {
			return nil, Err(have, want, tenantIDAuthErrSlice)
		}
	} else {
		// otherwise, let's look for a username and API key
		want = map[string]string{
			"username": "",
			"api-key":  "",
		}
		err = findAuthOpts(c, have, want)
		if err != nil {
			return nil, err
		}
		if have["username"].Value != "" || have["api-key"].Value != "" {
			if username, ok := have["username"]; ok {
				ao.Username = username.Value
				ao.APIKey = have["api-key"].Value
				delete(want, "api-key")
			} else {
				return nil, Err(have, want, usernameAuthErrSlice)
			}
		} else {
			return nil, Err(have, want, usernameAuthErrSlice)
		}
	}

	if logger != nil {
		haveString := ""
		for k, v := range have {
			haveString += fmt.Sprintf("%s: %s (from %s)\n", k, v.Value, v.From)
		}
		logger.Infof("Authentication Credentials:\n%s\n", haveString)
	}

	credsResult := &CredentialsResult{
		AuthOpts: ao,
		Region:   region,
		Have:     have,
		Want:     want,
	}

	return credsResult, nil
}

// LogRoundTripper satisfies the http.RoundTripper interface and is used to
// customize the default Gophercloud RoundTripper to allow for logging.
type LogRoundTripper struct {
	Logger            *logrus.Logger
	rt                http.RoundTripper
	numReauthAttempts int
}

// newHTTPClient return a custom HTTP client that allows for logging relevant
// information before and after the HTTP request.
func newHTTPClient() http.Client {
	return http.Client{
		Transport: &LogRoundTripper{
			rt: http.DefaultTransport,
		},
	}
}

// RoundTrip performs a round-trip HTTP request and logs relevant information about it.
func (lrt *LogRoundTripper) RoundTrip(request *http.Request) (*http.Response, error) {
	var err error

	//fmt.Printf("request body: %+v\n", request.Body)

	if lrt.Logger.Level == logrus.DebugLevel && request.Body != nil {
		fmt.Println("logging request body")
		request.Body, err = lrt.logRequestBody(request.Body, request.Header)
		if err != nil {
			return nil, err
		}
	}

	lrt.Logger.Infof("Request URL: %s\n", request.URL)

	response, err := lrt.rt.RoundTrip(request)
	if response == nil {
		return nil, err
	}

	if response.StatusCode == http.StatusUnauthorized {
		if lrt.numReauthAttempts == 3 {
			return response, fmt.Errorf("Tried to re-authenticate 3 times with no success.")
		}
		lrt.numReauthAttempts++
	}

	lrt.Logger.Debugf("Response Status: %s\n", response.Status)

	info, err := json.MarshalIndent(response.Header, "", "  ")
	if err != nil {
		lrt.Logger.Debugf(fmt.Sprintf("Error logging request: %s\n", err))
	}
	lrt.Logger.Debugf("Response Headers: %+v\n", string(info))

	return response, err
}

func (lrt *LogRoundTripper) logRequestBody(original io.ReadCloser, headers http.Header) (io.ReadCloser, error) {
	defer original.Close()

	var bs bytes.Buffer
	_, err := io.Copy(&bs, original)
	if err != nil {
		return nil, err
	}

	contentType := headers.Get("Content-Type")
	if strings.HasPrefix(contentType, "application/json") {
		debugInfo := lrt.formatJSON(bs.Bytes())
		lrt.Logger.Debugf("Request Options: %s\n", debugInfo)
	} else {
		lrt.Logger.Debugf("Request Options: %s\n", bs.String())
	}

	return ioutil.NopCloser(strings.NewReader(bs.String())), nil
}

func (lrt *LogRoundTripper) formatJSON(raw []byte) string {
	var data map[string]interface{}

	err := json.Unmarshal(raw, &data)
	if err != nil {
		lrt.Logger.Debugf("Unable to parse JSON: %s\n\n", err)
		return string(raw)
	}

	pretty, err := json.MarshalIndent(data, "", "  ")
	if err != nil {
		lrt.Logger.Debugf("Unable to re-marshal JSON: %s\n", err)
		return string(raw)
	}

	return string(pretty)
}
<commit_msg>remove commented-out code<commit_after>package auth

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"strings"

	"github.com/jrperritt/rack/commandoptions"
	"github.com/jrperritt/rack/internal/github.com/Sirupsen/logrus"
	"github.com/jrperritt/rack/internal/github.com/codegangsta/cli"
	"github.com/jrperritt/rack/internal/github.com/rackspace/gophercloud"
	"github.com/jrperritt/rack/internal/github.com/rackspace/gophercloud/rackspace"
	"github.com/jrperritt/rack/util"
)

var usernameAuthErrSlice = []string{"There are some required Rackspace Cloud credentials that we couldn't find.",
	"Here's what we have:",
	"%s",
	"and here's what we're missing:",
	"%s",
	"",
	"You can set any of these credentials in the following ways:",
	"- Run `rack configure` to interactively create a configuration file,",
	"- Specify it in the command as a flag (--username, --api-key), or",
	"- Export it as an environment variable (RS_USERNAME, RS_API_KEY).",
	"",
}

var tenantIDAuthErrSlice = []string{"There are some required Rackspace Cloud credentials that we couldn't find.",
	"Here's what we have:",
	"%s",
	"and here's what we're missing:",
	"%s",
	"",
	"You can set the missing credentials with command-line flags (--auth-token, --auth-tenant-id)",
	"",
}

func Err(have map[string]commandoptions.Cred, want map[string]string, errMsg []string) error {
	haveString := ""
	for k, v := range have {
		haveString += fmt.Sprintf("%s: %s (from %s)\n", k, v.Value, v.From)
	}

	if len(want) > 0 {
		wantString := ""
		for k := range want {
			wantString += fmt.Sprintf("%s\n", k)
		}

		return fmt.Errorf(fmt.Sprintf(strings.Join(errMsg, "\n"), haveString, wantString))
	}

	return nil
}

type CredentialsResult struct {
	AuthOpts *gophercloud.AuthOptions
	Region   string
	Have     map[string]commandoptions.Cred
	Want     map[string]string
}

func findAuthOpts(c *cli.Context, have map[string]commandoptions.Cred, want map[string]string) error {
	// use command-line options if available
	commandoptions.CLIopts(c, have, want)
	// are there any unset auth variables?
	if len(want) != 0 {
		// if so, look in config file
		err := commandoptions.ConfigFile(c, have, want)
		if err != nil {
			return err
		}
		// still unset auth variables?
		if len(want) != 0 {
			// if so, look in environment variables
			envvars(have, want)
		}
	}

	return nil
}

// reauthFunc is what the ServiceClient uses to re-authenticate.
func reauthFunc(pc *gophercloud.ProviderClient, ao gophercloud.AuthOptions) func() error {
	return func() error {
		return rackspace.AuthenticateV2(pc, ao)
	}
}

// NewClient creates and returns a Rackspace client for the given service.
func NewClient(c *cli.Context, serviceType string, logger *logrus.Logger, noCache bool) (*gophercloud.ServiceClient, error) {
	// get the user's authentication credentials
	credsResult, err := Credentials(c, logger)
	if err != nil {
		return nil, err
	}

	if noCache {
		return authFromScratch(credsResult, serviceType, logger)
	}

	ao := credsResult.AuthOpts
	region := credsResult.Region

	// form the cache key
	cacheKey := CacheKey(*ao, region, serviceType)
	// initialize cache
	cache := &Cache{}
	logger.Infof("Looking in the cache for cache key: %s\n", cacheKey)
	// get the value from the cache
	creds, err := cache.Value(cacheKey)
	// if there was an error accessing the cache or there was nothing in the cache,
	// authenticate from scratch
	if err == nil && creds != nil {
		// we successfully retrieved a value from the cache
		logger.Infof("Using token from cache: %s\n", creds.TokenID)
		pc, err := rackspace.NewClient(ao.IdentityEndpoint)
		if err == nil {
			pc.TokenID = creds.TokenID
			pc.ReauthFunc = reauthFunc(pc, *ao)
			pc.UserAgent.Prepend(util.UserAgent)
			pc.HTTPClient = newHTTPClient()
			return &gophercloud.ServiceClient{
				ProviderClient: pc,
				Endpoint:       creds.ServiceEndpoint,
			}, nil
		}
	} else {
		return authFromScratch(credsResult, serviceType, logger)
	}

	return nil, nil
}

func authFromScratch(credsResult *CredentialsResult, serviceType string, logger *logrus.Logger) (*gophercloud.ServiceClient, error) {
	logger.Info("Not using cache; Authenticating from scratch.\n")

	ao := credsResult.AuthOpts
	region := credsResult.Region

	pc, err := rackspace.AuthenticatedClient(*ao)
	if err != nil {
		return nil, err
	}
	pc.HTTPClient = newHTTPClient()
	var sc *gophercloud.ServiceClient
	switch serviceType {
	case "compute":
		sc, err = rackspace.NewComputeV2(pc, gophercloud.EndpointOpts{
			Region: region,
		})
		break
	case "object-store":
		sc, err = rackspace.NewObjectStorageV1(pc, gophercloud.EndpointOpts{
			Region: region,
		})
		break
	case "blockstorage":
		sc, err = rackspace.NewBlockStorageV1(pc, gophercloud.EndpointOpts{
			Region: region,
		})
		break
	case "network":
		sc, err = rackspace.NewNetworkV2(pc, gophercloud.EndpointOpts{
			Region: region,
		})
		break
	}
	if err != nil {
		return nil, err
	}
	if sc == nil {
		return nil, fmt.Errorf("Unable to create service client: Unknown service type: %s\n", serviceType)
	}
	sc.UserAgent.Prepend(util.UserAgent)
	return sc, nil
}

// Credentials determines the appropriate authentication method for the user.
// It returns a gophercloud.AuthOptions object and a region.
//
// It will use command-line authentication parameters if available, then it will
// look for any unset parameters in the config file, and then finally in
// environment variables.
func Credentials(c *cli.Context, logger *logrus.Logger) (*CredentialsResult, error) {
	ao := &gophercloud.AuthOptions{
		AllowReauth: true,
	}

	have := make(map[string]commandoptions.Cred)

	// let's looks for a region and identity endpoint
	want := map[string]string{
		"auth-url": "",
		"region":   "",
	}

	err := findAuthOpts(c, have, want)
	if err != nil {
		return nil, err
	}

	// if the user didn't provide an auth URL, default to the Rackspace US endpoint
	if _, ok := have["auth-url"]; !ok || have["auth-url"].Value == "" {
		have["auth-url"] = commandoptions.Cred{Value: rackspace.RackspaceUSIdentity, From: "default value"}
		delete(want, "auth-url")
	}
	ao.IdentityEndpoint = have["auth-url"].Value

	// upper-case the region
	region := strings.ToUpper(have["region"].Value)
	delete(want, "region")

	// now we check for token authentication (only allowed via the command-line)
	want["auth-tenant-id"] = ""
	want["auth-token"] = ""
	commandoptions.CLIopts(c, have, want)

	// if a tenant ID was provided on the command-line, we don't bother checking for a
	// username or api key
	if have["auth-tenant-id"].Value != "" || have["auth-token"].Value != "" {
		if tenantID, ok := have["auth-tenant-id"]; ok {
			ao.TenantID = tenantID.Value
			ao.TokenID = have["auth-token"].Value
			delete(want, "auth-token")
		} else {
			return nil, Err(have, want, tenantIDAuthErrSlice)
		}
	} else {
		// otherwise, let's look for a username and API key
		want = map[string]string{
			"username": "",
			"api-key":  "",
		}
		err = findAuthOpts(c, have, want)
		if err != nil {
			return nil, err
		}
		if have["username"].Value != "" || have["api-key"].Value != "" {
			if username, ok := have["username"]; ok {
				ao.Username = username.Value
				ao.APIKey = have["api-key"].Value
				delete(want, "api-key")
			} else {
				return nil, Err(have, want, usernameAuthErrSlice)
			}
		} else {
			return nil, Err(have, want, usernameAuthErrSlice)
		}
	}

	if logger != nil {
		haveString := ""
		for k, v := range have {
			haveString += fmt.Sprintf("%s: %s (from %s)\n", k, v.Value, v.From)
		}
		logger.Infof("Authentication Credentials:\n%s\n", haveString)
	}

	credsResult := &CredentialsResult{
		AuthOpts: ao,
		Region:   region,
		Have:     have,
		Want:     want,
	}

	return credsResult, nil
}

// LogRoundTripper satisfies the http.RoundTripper interface and is used to
// customize the default Gophercloud RoundTripper to allow for logging.
type LogRoundTripper struct {
	Logger            *logrus.Logger
	rt                http.RoundTripper
	numReauthAttempts int
}

// newHTTPClient return a custom HTTP client that allows for logging relevant
// information before and after the HTTP request.
func newHTTPClient() http.Client {
	return http.Client{
		Transport: &LogRoundTripper{
			rt: http.DefaultTransport,
		},
	}
}

// RoundTrip performs a round-trip HTTP request and logs relevant information about it.
func (lrt *LogRoundTripper) RoundTrip(request *http.Request) (*http.Response, error) {
	var err error

	if lrt.Logger.Level == logrus.DebugLevel && request.Body != nil {
		fmt.Println("logging request body")
		request.Body, err = lrt.logRequestBody(request.Body, request.Header)
		if err != nil {
			return nil, err
		}
	}

	lrt.Logger.Infof("Request URL: %s\n", request.URL)

	response, err := lrt.rt.RoundTrip(request)
	if response == nil {
		return nil, err
	}

	if response.StatusCode == http.StatusUnauthorized {
		if lrt.numReauthAttempts == 3 {
			return response, fmt.Errorf("Tried to re-authenticate 3 times with no success.")
		}
		lrt.numReauthAttempts++
	}

	lrt.Logger.Debugf("Response Status: %s\n", response.Status)

	info, err := json.MarshalIndent(response.Header, "", "  ")
	if err != nil {
		lrt.Logger.Debugf(fmt.Sprintf("Error logging request: %s\n", err))
	}
	lrt.Logger.Debugf("Response Headers: %+v\n", string(info))

	return response, err
}

func (lrt *LogRoundTripper) logRequestBody(original io.ReadCloser, headers http.Header) (io.ReadCloser, error) {
	defer original.Close()

	var bs bytes.Buffer
	_, err := io.Copy(&bs, original)
	if err != nil {
		return nil, err
	}

	contentType := headers.Get("Content-Type")
	if strings.HasPrefix(contentType, "application/json") {
		debugInfo := lrt.formatJSON(bs.Bytes())
		lrt.Logger.Debugf("Request Options: %s\n", debugInfo)
	} else {
		lrt.Logger.Debugf("Request Options: %s\n", bs.String())
	}

	return ioutil.NopCloser(strings.NewReader(bs.String())), nil
}

func (lrt *LogRoundTripper) formatJSON(raw []byte) string {
	var data map[string]interface{}

	err := json.Unmarshal(raw, &data)
	if err != nil {
		lrt.Logger.Debugf("Unable to parse JSON: %s\n\n", err)
		return string(raw)
	}

	pretty, err := json.MarshalIndent(data, "", "  ")
	if err != nil {
		lrt.Logger.Debugf("Unable to re-marshal JSON: %s\n", err)
		return string(raw)
	}

	return string(pretty)
}
<|endoftext|>


<commit_before>// Copyright 2011 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 ogletest

import (
	"fmt"
	"github.com/jacobsa/ogletest/internal"
	"path"
	"reflect"
	"runtime"
)

// ExpectThat confirms that the supplied matcher matches the value x, adding a
// failure record to the currently running test if it does not. If additional
// parameters are supplied, the first will be used as a format string for the
// later ones, and the user-supplied error message will be added to the test
// output in the event of a failure.
//
// For example:
//
//     ExpectThat(userName, Equals("jacobsa"))
//     ExpectThat(users[i], Equals("jacobsa"), "while processing user %d", i)
//
func ExpectThat(x interface{}, m Matcher, errorParts ...interface{}) {
	// Get information about the call site.
	_, file, lineNumber, ok := runtime.Caller(1)
	if !ok {
		panic("ExpectThat: runtime.Caller")
	}

	// Assemble the user error, if any.
	userError := ""
	if len(errorParts) != 0 {
		v := reflect.ValueOf(errorParts[0])
		if v.Kind() != reflect.String {
			panic(fmt.Sprintf("ExpectThat: invalid format string type %v", v.Kind()))
		}

		userError = fmt.Sprintf(v.String(), errorParts[1:]...)
	}

	// Grab the current test state.
	state := internal.CurrentTest
	if state == nil {
		panic("ExpectThat: no test state.")
	}

	// Check whether the value matches.
	res, matcherErr := m.Matches(x)
	switch res {
	// Return immediately on success.
	case MATCH_TRUE:
		return

	// Handle errors below.
	case MATCH_FALSE:
	case MATCH_UNDEFINED:

	// Panic for invalid results.
	default:
		panic(fmt.Sprintf("ExpectThat: invalid matcher result %v.", res))
	}

	// Form an appropriate failure message. Make sure that the expected and
	// actual values align properly.
	var record internal.FailureRecord
	relativeClause := ""
	if matcherErr != nil {
		relativeClause = fmt.Sprintf(", %s", matcherErr.Error())
	}

	record.GeneratedError = fmt.Sprintf(
		"Expected: %s\nActual:   %v%s",
		m.Description(),
		x,
		relativeClause)

	// Record additional failure info.
	record.FileName = path.Base(file)
	record.LineNumber = lineNumber
	record.UserError = userError

	// Store the failure.
	state.FailureRecords = append(state.FailureRecords, record)
}
<commit_msg>Fixed some errors.<commit_after>// Copyright 2011 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 ogletest

import (
	"fmt"
	"github.com/jacobsa/oglematchers"
	"github.com/jacobsa/ogletest/internal"
	"path"
	"reflect"
	"runtime"
)

// ExpectThat confirms that the supplied matcher matches the value x, adding a
// failure record to the currently running test if it does not. If additional
// parameters are supplied, the first will be used as a format string for the
// later ones, and the user-supplied error message will be added to the test
// output in the event of a failure.
//
// For example:
//
//     ExpectThat(userName, Equals("jacobsa"))
//     ExpectThat(users[i], Equals("jacobsa"), "while processing user %d", i)
//
func ExpectThat(x interface{}, m oglematchers.Matcher, errorParts ...interface{}) {
	// Get information about the call site.
	_, file, lineNumber, ok := runtime.Caller(1)
	if !ok {
		panic("ExpectThat: runtime.Caller")
	}

	// Assemble the user error, if any.
	userError := ""
	if len(errorParts) != 0 {
		v := reflect.ValueOf(errorParts[0])
		if v.Kind() != reflect.String {
			panic(fmt.Sprintf("ExpectThat: invalid format string type %v", v.Kind()))
		}

		userError = fmt.Sprintf(v.String(), errorParts[1:]...)
	}

	// Grab the current test state.
	state := internal.CurrentTest
	if state == nil {
		panic("ExpectThat: no test state.")
	}

	// Check whether the value matches.
	res, matcherErr := m.Matches(x)
	switch res {
	// Return immediately on success.
	case oglematchers.MATCH_TRUE:
		return

	// Handle errors below.
	case oglematchers.MATCH_FALSE:
	case oglematchers.MATCH_UNDEFINED:

	// Panic for invalid results.
	default:
		panic(fmt.Sprintf("ExpectThat: invalid matcher result %v.", res))
	}

	// Form an appropriate failure message. Make sure that the expected and
	// actual values align properly.
	var record internal.FailureRecord
	relativeClause := ""
	if matcherErr != nil {
		relativeClause = fmt.Sprintf(", %s", matcherErr.Error())
	}

	record.GeneratedError = fmt.Sprintf(
		"Expected: %s\nActual:   %v%s",
		m.Description(),
		x,
		relativeClause)

	// Record additional failure info.
	record.FileName = path.Base(file)
	record.LineNumber = lineNumber
	record.UserError = userError

	// Store the failure.
	state.FailureRecords = append(state.FailureRecords, record)
}
<|endoftext|>


<commit_before>package mackerel

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/http/httptest"
	"testing"
	"io/ioutil"
)

func TestFindDashboards(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
		if req.URL.Path != "/api/v0/dashboards" {
			t.Error("request URL should be /api/v0/dashboards but :", req.URL.Path)
		}

		respJSON, _ := json.Marshal(map[string][]map[string]interface{}{
			"dashboards": []map[string]interface{}{
				map[string]interface{}{
					"id":           "2c5bLca8d",
					"title":        "My Dashboard",
					"bodyMarkDown": "# A test dashboard",
					"urlPath":      "2u4PP3TJqbu",
					"createdAt":    1439346145003,
					"updatedAt":    1439346145003,
				},
			},
		})

		res.Header()["Content-Type"] = []string{"application/json"}
		fmt.Fprint(res, string(respJSON))
	}))
	defer ts.Close()

	client, _ := NewClientWithOptions("dummy-key", ts.URL, false)
	dashboards, err := client.FindDashboards()

	if err != nil {
		t.Error("err shoud be nil but: ", err)
	}

	if dashboards[0].ID != "2c5bLca8d" {
		t.Error("request sends json including id but: ", dashboards[0])
	}

	if dashboards[0].Title != "My Dashboard" {
		t.Error("request sends json including title but: ", dashboards[0])
	}

	if dashboards[0].BodyMarkDown != "# A test dashboard" {
		t.Error("request sends json including bodyMarkDown but: ", dashboards[0])
	}

	if dashboards[0].URLPath != "2u4PP3TJqbu" {
		t.Error("request sends json including urlpath but: ", dashboards[0])
	}

	if dashboards[0].CreatedAt != 1439346145003 {
		t.Error("request sends json including createdAt but: ", dashboards[0])
	}

	if dashboards[0].UpdatedAt != 1439346145003 {
		t.Error("request sends json including updatedAt but: ", dashboards[0])
	}
}

func TestFindDashboard(t *testing.T) {

	testID := "2c5bLca8d"

	ts := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
		if req.URL.Path != fmt.Sprintf("/api/v0/dashboards/%s", testID) {
			t.Error("request URL should be /api/v0/dashboards/<ID> but :", req.URL.Path)
		}

		respJSON, _ := json.Marshal(
			map[string]interface{}{
				"id":           "2c5bLca8d",
				"title":        "My Dashboard",
				"bodyMarkDown": "# A test dashboard",
				"urlPath":      "2u4PP3TJqbu",
				"createdAt":    1439346145003,
				"updatedAt":    1439346145003,
			},
		)

		res.Header()["Content-Type"] = []string{"application/json"}
		fmt.Fprint(res, string(respJSON))
	}))
	defer ts.Close()

	client, _ := NewClientWithOptions("dummy-key", ts.URL, false)
	dashboard, err := client.FindDashboard(testID)

	if err != nil {
		t.Error("err shoud be nil but: ", err)
	}

	if dashboard.ID != "2c5bLca8d" {
		t.Error("request sends json including id but: ", dashboard)
	}

	if dashboard.Title != "My Dashboard" {
		t.Error("request sends json including title but: ", dashboard)
	}

	if dashboard.BodyMarkDown != "# A test dashboard" {
		t.Error("request sends json including bodyMarkDown but: ", dashboard)
	}

	if dashboard.URLPath != "2u4PP3TJqbu" {
		t.Error("request sends json including urlpath but: ", dashboard)
	}

	if dashboard.CreatedAt != 1439346145003 {
		t.Error("request sends json including createdAt but: ", dashboard)
	}

	if dashboard.UpdatedAt != 1439346145003 {
		t.Error("request sends json including updatedAt but: ", dashboard)
	}
}

func TestCreateDashboard(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
		if req.URL.Path != "/api/v0/dashboards" {
			t.Error("request URL should be /api/v0/dashboards but: ", req.URL.Path)
		}

		if req.Method != "POST" {
			t.Error("request method should be POST but: ", req.Method)
		}

		body, _ := ioutil.ReadAll(req.Body)

		var data struct {
			ID           string `json:"id"`
			Title        string `json:"title"`
			BodyMarkDown string `json:"bodyMarkdown"`
			URLPath      string `json:"urlPath"`
			CreatedAt    int64  `json:"createdAt"`
			UpdatedAt    int64  `json:"updatedAt"`
		}

		err := json.Unmarshal(body, &data)
		if err != nil {
			t.Fatal("request body should be decoded as json", string(body))
		}

		respJSON, _ := json.Marshal(map[string]interface{}{
			"id":           "2c5bLca8d",
			"title":        "My Dashboard",
			"bodyMarkDown": "# A test dashboard",
			"urlPath":      "2u4PP3TJqbu",
			"createdAt":    1439346145003,
			"updatedAt":    1439346145003,
		})

		res.Header()["Content-Type"] = []string{"application/json"}
		fmt.Fprint(res, string(respJSON))
	}))
	defer ts.Close()

	client, _ := NewClientWithOptions("dummy-key", ts.URL, false)

	dashboard, err := client.CreateDashboard(&Dashboard{
		Title:          "My Dashboard",
		BodyMarkDown:   "# A test dashboard",
		URLPath:        "2u4PP3TJqbu",
	})

	if err != nil {
		t.Error("err shoud be nil but: ", err)
	}

	if dashboard.ID != "2c5bLca8d" {
		t.Error("request sends json including id but: ", dashboard)
	}

	if dashboard.Title != "My Dashboard" {
		t.Error("request sends json including title but: ", dashboard)
	}

	if dashboard.BodyMarkDown != "# A test dashboard" {
		t.Error("request sends json including bodyMarkDown but: ", dashboard)
	}

	if dashboard.URLPath != "2u4PP3TJqbu" {
		t.Error("request sends json including urlpath but: ", dashboard)
	}

	if dashboard.CreatedAt != 1439346145003 {
		t.Error("request sends json including createdAt but: ", dashboard)
	}

	if dashboard.UpdatedAt != 1439346145003 {
		t.Error("request sends json including updatedAt but: ", dashboard)
	}
}

func TestUpdateDashboard(t *testing.T) {

	testID := "2c5bLca8d"

	ts := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
		if req.URL.Path != fmt.Sprintf("/api/v0/dashboards/%s", testID) {
			t.Error("request URL should be /api/v0/dashboards/<ID> but :", req.URL.Path)
		}

		if req.Method != "PUT" {
			t.Error("request method should be PUT but: ", req.Method)
		}

		body, _ := ioutil.ReadAll(req.Body)

		var data struct {
			ID           string `json:"id"`
			Title        string `json:"title"`
			BodyMarkDown string `json:"bodyMarkdown"`
			URLPath      string `json:"urlPath"`
			CreatedAt    int64  `json:"createdAt"`
			UpdatedAt    int64  `json:"updatedAt"`
		}

		err := json.Unmarshal(body, &data)
		if err != nil {
			t.Fatal("request body should be decoded as json", string(body))
		}

		respJSON, _ := json.Marshal(map[string]interface{}{
			"id":           "2c5bLca8d",
			"title":        "My Dashboard",
			"bodyMarkDown": "# A test dashboard",
			"urlPath":      "2u4PP3TJqbu",
			"createdAt":    1439346145003,
			"updatedAt":    1439346145003,
		})

		res.Header()["Content-Type"] = []string{"application/json"}
		fmt.Fprint(res, string(respJSON))
	}))
	defer ts.Close()

	client, _ := NewClientWithOptions("dummy-key", ts.URL, false)

	dashboard, err := client.UpdateDashboard(testID, &Dashboard{
		Title:          "My Dashboard",
		BodyMarkDown:   "# A test dashboard",
	})

	if err != nil {
		t.Error("err shoud be nil but: ", err)
	}

	if dashboard.ID != "2c5bLca8d" {
		t.Error("request sends json including id but: ", dashboard)
	}

	if dashboard.Title != "My Dashboard" {
		t.Error("request sends json including title but: ", dashboard)
	}

	if dashboard.BodyMarkDown != "# A test dashboard" {
		t.Error("request sends json including bodyMarkDown but: ", dashboard)
	}

	if dashboard.URLPath != "2u4PP3TJqbu" {
		t.Error("request sends json including urlpath but: ", dashboard)
	}

	if dashboard.CreatedAt != 1439346145003 {
		t.Error("request sends json including createdAt but: ", dashboard)
	}

	if dashboard.UpdatedAt != 1439346145003 {
		t.Error("request sends json including updatedAt but: ", dashboard)
	}
}

func TestDeleteDashboard(t *testing.T) {

	testID := "2c5bLca8d"

	ts := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
		if req.URL.Path != fmt.Sprintf("/api/v0/dashboards/%s", testID) {
			t.Error("request URL should be /api/v0/dashboards/<ID> but :", req.URL.Path)
		}

		if req.Method != "DELETE" {
			t.Error("request method should be DELETE but: ", req.Method)
		}

		respJSON, _ := json.Marshal(map[string]interface{}{
			"id":           "2c5bLca8d",
			"title":        "My Dashboard",
			"bodyMarkDown": "# A test dashboard",
			"urlPath":      "2u4PP3TJqbu",
			"createdAt":    1439346145003,
			"updatedAt":    1439346145003,
		})

		res.Header()["Content-Type"] = []string{"application/json"}
		fmt.Fprint(res, string(respJSON))
	}))
	defer ts.Close()

	client, _ := NewClientWithOptions("dummy-key", ts.URL, false)

	dashboard, err := client.DeleteDashboard(testID)

	if err != nil {
		t.Error("err shoud be nil but: ", err)
	}

	if dashboard.ID != "2c5bLca8d" {
		t.Error("request sends json including id but: ", dashboard)
	}

	if dashboard.Title != "My Dashboard" {
		t.Error("request sends json including title but: ", dashboard)
	}

	if dashboard.BodyMarkDown != "# A test dashboard" {
		t.Error("request sends json including bodyMarkDown but: ", dashboard)
	}

	if dashboard.URLPath != "2u4PP3TJqbu" {
		t.Error("request sends json including urlpath but: ", dashboard)
	}

	if dashboard.CreatedAt != 1439346145003 {
		t.Error("request sends json including createdAt but: ", dashboard)
	}

	if dashboard.UpdatedAt != 1439346145003 {
		t.Error("request sends json including updatedAt but: ", dashboard)
	}
}
<commit_msg>add `URLPath` parameter on dashboard test<commit_after>package mackerel

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/http/httptest"
	"testing"
	"io/ioutil"
)

func TestFindDashboards(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
		if req.URL.Path != "/api/v0/dashboards" {
			t.Error("request URL should be /api/v0/dashboards but :", req.URL.Path)
		}

		respJSON, _ := json.Marshal(map[string][]map[string]interface{}{
			"dashboards": []map[string]interface{}{
				map[string]interface{}{
					"id":           "2c5bLca8d",
					"title":        "My Dashboard",
					"bodyMarkDown": "# A test dashboard",
					"urlPath":      "2u4PP3TJqbu",
					"createdAt":    1439346145003,
					"updatedAt":    1439346145003,
				},
			},
		})

		res.Header()["Content-Type"] = []string{"application/json"}
		fmt.Fprint(res, string(respJSON))
	}))
	defer ts.Close()

	client, _ := NewClientWithOptions("dummy-key", ts.URL, false)
	dashboards, err := client.FindDashboards()

	if err != nil {
		t.Error("err shoud be nil but: ", err)
	}

	if dashboards[0].ID != "2c5bLca8d" {
		t.Error("request sends json including id but: ", dashboards[0])
	}

	if dashboards[0].Title != "My Dashboard" {
		t.Error("request sends json including title but: ", dashboards[0])
	}

	if dashboards[0].BodyMarkDown != "# A test dashboard" {
		t.Error("request sends json including bodyMarkDown but: ", dashboards[0])
	}

	if dashboards[0].URLPath != "2u4PP3TJqbu" {
		t.Error("request sends json including urlpath but: ", dashboards[0])
	}

	if dashboards[0].CreatedAt != 1439346145003 {
		t.Error("request sends json including createdAt but: ", dashboards[0])
	}

	if dashboards[0].UpdatedAt != 1439346145003 {
		t.Error("request sends json including updatedAt but: ", dashboards[0])
	}
}

func TestFindDashboard(t *testing.T) {

	testID := "2c5bLca8d"

	ts := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
		if req.URL.Path != fmt.Sprintf("/api/v0/dashboards/%s", testID) {
			t.Error("request URL should be /api/v0/dashboards/<ID> but :", req.URL.Path)
		}

		respJSON, _ := json.Marshal(
			map[string]interface{}{
				"id":           "2c5bLca8d",
				"title":        "My Dashboard",
				"bodyMarkDown": "# A test dashboard",
				"urlPath":      "2u4PP3TJqbu",
				"createdAt":    1439346145003,
				"updatedAt":    1439346145003,
			},
		)

		res.Header()["Content-Type"] = []string{"application/json"}
		fmt.Fprint(res, string(respJSON))
	}))
	defer ts.Close()

	client, _ := NewClientWithOptions("dummy-key", ts.URL, false)
	dashboard, err := client.FindDashboard(testID)

	if err != nil {
		t.Error("err shoud be nil but: ", err)
	}

	if dashboard.ID != "2c5bLca8d" {
		t.Error("request sends json including id but: ", dashboard)
	}

	if dashboard.Title != "My Dashboard" {
		t.Error("request sends json including title but: ", dashboard)
	}

	if dashboard.BodyMarkDown != "# A test dashboard" {
		t.Error("request sends json including bodyMarkDown but: ", dashboard)
	}

	if dashboard.URLPath != "2u4PP3TJqbu" {
		t.Error("request sends json including urlpath but: ", dashboard)
	}

	if dashboard.CreatedAt != 1439346145003 {
		t.Error("request sends json including createdAt but: ", dashboard)
	}

	if dashboard.UpdatedAt != 1439346145003 {
		t.Error("request sends json including updatedAt but: ", dashboard)
	}
}

func TestCreateDashboard(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
		if req.URL.Path != "/api/v0/dashboards" {
			t.Error("request URL should be /api/v0/dashboards but: ", req.URL.Path)
		}

		if req.Method != "POST" {
			t.Error("request method should be POST but: ", req.Method)
		}

		body, _ := ioutil.ReadAll(req.Body)

		var data struct {
			ID           string `json:"id"`
			Title        string `json:"title"`
			BodyMarkDown string `json:"bodyMarkdown"`
			URLPath      string `json:"urlPath"`
			CreatedAt    int64  `json:"createdAt"`
			UpdatedAt    int64  `json:"updatedAt"`
		}

		err := json.Unmarshal(body, &data)
		if err != nil {
			t.Fatal("request body should be decoded as json", string(body))
		}

		respJSON, _ := json.Marshal(map[string]interface{}{
			"id":           "2c5bLca8d",
			"title":        "My Dashboard",
			"bodyMarkDown": "# A test dashboard",
			"urlPath":      "2u4PP3TJqbu",
			"createdAt":    1439346145003,
			"updatedAt":    1439346145003,
		})

		res.Header()["Content-Type"] = []string{"application/json"}
		fmt.Fprint(res, string(respJSON))
	}))
	defer ts.Close()

	client, _ := NewClientWithOptions("dummy-key", ts.URL, false)

	dashboard, err := client.CreateDashboard(&Dashboard{
		Title:          "My Dashboard",
		BodyMarkDown:   "# A test dashboard",
		URLPath:        "2u4PP3TJqbu",
	})

	if err != nil {
		t.Error("err shoud be nil but: ", err)
	}

	if dashboard.ID != "2c5bLca8d" {
		t.Error("request sends json including id but: ", dashboard)
	}

	if dashboard.Title != "My Dashboard" {
		t.Error("request sends json including title but: ", dashboard)
	}

	if dashboard.BodyMarkDown != "# A test dashboard" {
		t.Error("request sends json including bodyMarkDown but: ", dashboard)
	}

	if dashboard.URLPath != "2u4PP3TJqbu" {
		t.Error("request sends json including urlpath but: ", dashboard)
	}

	if dashboard.CreatedAt != 1439346145003 {
		t.Error("request sends json including createdAt but: ", dashboard)
	}

	if dashboard.UpdatedAt != 1439346145003 {
		t.Error("request sends json including updatedAt but: ", dashboard)
	}
}

func TestUpdateDashboard(t *testing.T) {

	testID := "2c5bLca8d"

	ts := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
		if req.URL.Path != fmt.Sprintf("/api/v0/dashboards/%s", testID) {
			t.Error("request URL should be /api/v0/dashboards/<ID> but :", req.URL.Path)
		}

		if req.Method != "PUT" {
			t.Error("request method should be PUT but: ", req.Method)
		}

		body, _ := ioutil.ReadAll(req.Body)

		var data struct {
			ID           string `json:"id"`
			Title        string `json:"title"`
			BodyMarkDown string `json:"bodyMarkdown"`
			URLPath      string `json:"urlPath"`
			CreatedAt    int64  `json:"createdAt"`
			UpdatedAt    int64  `json:"updatedAt"`
		}

		err := json.Unmarshal(body, &data)
		if err != nil {
			t.Fatal("request body should be decoded as json", string(body))
		}

		respJSON, _ := json.Marshal(map[string]interface{}{
			"id":           "2c5bLca8d",
			"title":        "My Dashboard",
			"bodyMarkDown": "# A test dashboard",
			"urlPath":      "2u4PP3TJqbu",
			"createdAt":    1439346145003,
			"updatedAt":    1439346145003,
		})

		res.Header()["Content-Type"] = []string{"application/json"}
		fmt.Fprint(res, string(respJSON))
	}))
	defer ts.Close()

	client, _ := NewClientWithOptions("dummy-key", ts.URL, false)

	dashboard, err := client.UpdateDashboard(testID, &Dashboard{
		Title:          "My Dashboard",
		BodyMarkDown:   "# A test dashboard",
		URLPath:        "2u4PP3TJqbu",
	})

	if err != nil {
		t.Error("err shoud be nil but: ", err)
	}

	if dashboard.ID != "2c5bLca8d" {
		t.Error("request sends json including id but: ", dashboard)
	}

	if dashboard.Title != "My Dashboard" {
		t.Error("request sends json including title but: ", dashboard)
	}

	if dashboard.BodyMarkDown != "# A test dashboard" {
		t.Error("request sends json including bodyMarkDown but: ", dashboard)
	}

	if dashboard.URLPath != "2u4PP3TJqbu" {
		t.Error("request sends json including urlpath but: ", dashboard)
	}

	if dashboard.CreatedAt != 1439346145003 {
		t.Error("request sends json including createdAt but: ", dashboard)
	}

	if dashboard.UpdatedAt != 1439346145003 {
		t.Error("request sends json including updatedAt but: ", dashboard)
	}
}

func TestDeleteDashboard(t *testing.T) {

	testID := "2c5bLca8d"

	ts := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
		if req.URL.Path != fmt.Sprintf("/api/v0/dashboards/%s", testID) {
			t.Error("request URL should be /api/v0/dashboards/<ID> but :", req.URL.Path)
		}

		if req.Method != "DELETE" {
			t.Error("request method should be DELETE but: ", req.Method)
		}

		respJSON, _ := json.Marshal(map[string]interface{}{
			"id":           "2c5bLca8d",
			"title":        "My Dashboard",
			"bodyMarkDown": "# A test dashboard",
			"urlPath":      "2u4PP3TJqbu",
			"createdAt":    1439346145003,
			"updatedAt":    1439346145003,
		})

		res.Header()["Content-Type"] = []string{"application/json"}
		fmt.Fprint(res, string(respJSON))
	}))
	defer ts.Close()

	client, _ := NewClientWithOptions("dummy-key", ts.URL, false)

	dashboard, err := client.DeleteDashboard(testID)

	if err != nil {
		t.Error("err shoud be nil but: ", err)
	}

	if dashboard.ID != "2c5bLca8d" {
		t.Error("request sends json including id but: ", dashboard)
	}

	if dashboard.Title != "My Dashboard" {
		t.Error("request sends json including title but: ", dashboard)
	}

	if dashboard.BodyMarkDown != "# A test dashboard" {
		t.Error("request sends json including bodyMarkDown but: ", dashboard)
	}

	if dashboard.URLPath != "2u4PP3TJqbu" {
		t.Error("request sends json including urlpath but: ", dashboard)
	}

	if dashboard.CreatedAt != 1439346145003 {
		t.Error("request sends json including createdAt but: ", dashboard)
	}

	if dashboard.UpdatedAt != 1439346145003 {
		t.Error("request sends json including updatedAt but: ", dashboard)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"os"
)

var master string
var workerDir string
var jobInputs []string

func main() {
	master = os.Args[1]
	workerDir = os.Args[2]
	jobInputs = os.Args[3:]

	CreateJobPack()
	Post(master)
	Cleanup()
}
<commit_msg>jobpack: Fail early if there is not enough arguments to the jobpack.<commit_after>package main

import (
	"fmt"
	"os"
)

var master string
var workerDir string
var jobInputs []string

func main() {
	if len(os.Args) < 3 {
		fmt.Println("Usage: jobpack master_url worker_dir input(s)")
		os.Exit(1)
	}
	master = os.Args[1]
	workerDir = os.Args[2]
	jobInputs = os.Args[3:]

	CreateJobPack()
	Post(master)
	Cleanup()
}
<|endoftext|>


<commit_before><commit_msg>fix resp race<commit_after><|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"image"
	"image/color"
	"image/draw"
	_ "image/jpeg"
	"image/png"
	"log"
	"math"
	"os"
	"sort"
)

var (
	kernX = [][]int{
		[]int{-1, +0, +1},
		[]int{-2, +0, +2},
		[]int{-1, +0, +1},
	}
	kernY = [][]int{
		[]int{+1, +2, +1},
		[]int{+0, +0, +0},
		[]int{-1, -2, -1},
	}
	kernR = image.Rect(-1, -1, 2, 2)

	thresh  = flag.Int("t", 0, "threshold for the sobel filter")
	compute = flag.Bool("compute", false, "compute best threshold and exit")
)

type pixim struct {
	*image.RGBA
	region []int
}

func (p *pixim) Len() int {
	b := p.Bounds()
	return b.Dx() * b.Dy()
}

func (p *pixim) Less(i, j int) bool {
	ri, rj := region(p.region, i), region(p.region, j)
	if ri != rj {
		return ri < rj
	}

	b := p.Bounds()
	c1, c2 := p.At(b.Min.X+i, b.Min.Y).(color.RGBA), p.At(b.Min.X+j, b.Min.Y).(color.RGBA)
	dist1 := uint32(c1.R)*uint32(c1.R) + uint32(c1.G)*uint32(c1.G) + uint32(c1.B)*uint32(c1.B)
	dist2 := uint32(c2.R)*uint32(c2.R) + uint32(c2.G)*uint32(c2.G) + uint32(c2.B)*uint32(c2.B)
	return dist1 < dist2
}

func (p *pixim) Swap(i, j int) {
	b := p.Bounds()
	pi := p.PixOffset(b.Min.X+i, b.Min.Y)
	pj := p.PixOffset(b.Min.X+j, b.Min.Y)
	p.Pix[pi+0], p.Pix[pj+0] = p.Pix[pj+0], p.Pix[pi+0]
	p.Pix[pi+1], p.Pix[pj+1] = p.Pix[pj+1], p.Pix[pi+1]
	p.Pix[pi+2], p.Pix[pj+2] = p.Pix[pj+2], p.Pix[pi+2]
	p.Pix[pi+3], p.Pix[pj+3] = p.Pix[pj+3], p.Pix[pi+3]
}

func convolve(m *image.Gray, kernX, kernY [][]int, r image.Rectangle) uint8 {
	d := r.Sub(kernR.Min)
	b := m.Bounds()

	magx := int(0)
	magy := int(0)
	for y := d.Min.Y; y < d.Max.Y; y++ {
		for x := d.Min.X; x < d.Max.X; x++ {
			if (kernX[y][x] == 0) && (kernY[y][x] == 0) {
				continue
			}
			v := m.At(b.Min.X+x, b.Min.Y+y).(color.Gray)
			magx += int(v.Y) * kernX[y][x]
			magy += int(v.Y) * kernY[y][x]
		}
	}
	mag := math.Sqrt(float64(magx*magx) + float64(magy*magy))

	if mag < 0 {
		return 0
	}
	if mag > 255 {
		return 255
	}
	return uint8(mag)
}

func sobel(m *image.Gray) (*image.Gray, []int) {
	b := m.Bounds()
	im := image.NewGray(b)
	hist := make([]int, 256)

	for p := b.Min; p.Y < b.Max.Y; p.Y++ {
		for p.X = b.Min.X; p.X < b.Max.X; p.X++ {
			window := kernR.Add(p).Intersect(b)
			mag := convolve(m.SubImage(window).(*image.Gray), kernX, kernY, window.Sub(p))
			im.SetGray(p.X, p.Y, color.Gray{mag})
			hist[mag]++
		}
	}

	return im, hist
}

func threshold(m *image.Gray, t uint8) {
	b := m.Bounds()
	for y := b.Min.Y; y < b.Max.Y; y++ {
		for x := b.Min.X; x < b.Max.X; x++ {
			c := m.At(x, y).(color.Gray)
			if c.Y > t {
				c.Y = 255
			} else {
				c.Y = 0
			}
			m.Set(x, y, c)
		}
	}
}

// otsu's method
func computeThresh(hist []int, total int) int {
	sum := float64(0)
	for i := 0; i < 256; i++ {
		sum += float64(i * hist[i])
	}

	rsum := float64(0)
	bgWeight := float64(0)
	fgWeight := float64(0)
	bgMean := float64(0)
	fgMean := float64(0)

	bcMax := float64(0)
	bcBin := int(0)

	for i := 0; i < 256; i++ {
		bgWeight += float64(hist[i])
		if bgWeight == 0 {
			continue
		}
		if bgWeight == sum {
			break
		}
		rsum += float64(i) * float64(hist[i])
		fgWeight = float64(total) - bgWeight
		bgMean = rsum / bgWeight
		fgMean = (sum - rsum) / fgWeight
		bcVar := fgWeight * bgWeight * math.Pow(bgMean-fgMean, 2)
		if bcVar > bcMax {
			bcMax, bcBin = bcVar, i
		}
	}

	return bcBin
}

func edgeToRegion(m *image.Gray) [][]int {
	b := m.Bounds()
	regions := make([][]int, b.Dy())
	for i := range regions {
		for x := b.Min.X; x < b.Max.X; x++ {
			if m.Pix[m.Stride*i+x] > 0 {
				regions[i] = append(regions[i], x)
			}
		}
	}
	return regions
}

func region(regions []int, idx int) int {
	for i := range regions {
		if idx <= regions[i] {
			return i
		}
	}
	return len(regions)
}

func makeRGB(m image.Image) *image.RGBA {
	if rgb, ok := m.(*image.RGBA); ok {
		return rgb
	}
	b := m.Bounds()
	rgb := image.NewRGBA(b)
	draw.Draw(rgb, b, m, b.Min, draw.Src)
	return rgb
}

func sortimage(m image.Image, regions [][]int) image.Image {
	b := m.Bounds()
	rgb := makeRGB(m)
	for y := b.Min.Y; y < b.Max.Y; y++ {
		sub := rgb.SubImage(image.Rect(b.Min.X, b.Min.Y+y, b.Max.X, b.Min.Y+y+1))
		r := &pixim{
			sub.(*image.RGBA),
			regions[y],
		}
		sort.Sort(r)
	}
	return rgb
}

func main() {
	flag.Parse()

	if flag.NArg() < 2 {
		fmt.Fprintf(os.Stderr, "Usage: %s [options] <input image> <output image>\n", os.Args[0])
		flag.PrintDefaults()
		os.Exit(-1)
	}

	log.Println("Opening image in")
	infile, err := os.Open(flag.Arg(0))
	if err != nil {
		log.Fatal(err)
	}
	defer infile.Close()

	log.Println("Decoding image in")
	inimg, _, err := image.Decode(infile)
	if err != nil {
		log.Fatal(err)
	}

	b := inimg.Bounds()
	gray := image.NewGray(b)
	draw.Draw(gray, b, inimg, b.Min, draw.Src)

	//g, err := os.Create("gray.png")
	//png.Encode(g, gray)

	log.Println("Computing pixel gradient")
	s, hist := sobel(gray)

	if *compute {
		t := computeThresh(hist, b.Dx()*b.Dy())
		log.Printf("Best threshold = %v", t)
	}

	threshold(s, uint8(*thresh))

	if *compute {
		sout, err := os.Create(flag.Arg(1))
		if err != nil {
			log.Fatal(err)
		}
		png.Encode(sout, s)
		sout.Close()
		os.Exit(0)
	}

	log.Println("Computing regions")
	regions := edgeToRegion(s)

	log.Println("Sorting image")
	sorted := sortimage(inimg, regions)

	log.Println("Writing output")
	outfile, err := os.Create(flag.Arg(1))
	if err != nil {
		log.Fatal(err)
	}
	err = png.Encode(outfile, sorted)
	if err != nil {
		log.Fatal(err)
	}
}
<commit_msg>Add option for dumping sobel image<commit_after>package main

import (
	"flag"
	"fmt"
	"image"
	"image/color"
	"image/draw"
	_ "image/jpeg"
	"image/png"
	"log"
	"math"
	"os"
	"sort"
)

var (
	kernX = [][]int{
		[]int{-1, +0, +1},
		[]int{-2, +0, +2},
		[]int{-1, +0, +1},
	}
	kernY = [][]int{
		[]int{+1, +2, +1},
		[]int{+0, +0, +0},
		[]int{-1, -2, -1},
	}
	kernR = image.Rect(-1, -1, 2, 2)

	thresh  = flag.Int("t", 0, "threshold for the sobel filter")
	compute = flag.Bool("compute", false, "compute best threshold and exit")
	psobel  = flag.Bool("sobel", false, "only dump sobel and exit")
)

type pixim struct {
	*image.RGBA
	region []int
}

func (p *pixim) Len() int {
	b := p.Bounds()
	return b.Dx() * b.Dy()
}

func (p *pixim) Less(i, j int) bool {
	ri, rj := region(p.region, i), region(p.region, j)
	if ri != rj {
		return ri < rj
	}

	b := p.Bounds()
	c1, c2 := p.At(b.Min.X+i, b.Min.Y).(color.RGBA), p.At(b.Min.X+j, b.Min.Y).(color.RGBA)
	dist1 := uint32(c1.R)*uint32(c1.R) + uint32(c1.G)*uint32(c1.G) + uint32(c1.B)*uint32(c1.B)
	dist2 := uint32(c2.R)*uint32(c2.R) + uint32(c2.G)*uint32(c2.G) + uint32(c2.B)*uint32(c2.B)
	return dist1 < dist2
}

func (p *pixim) Swap(i, j int) {
	b := p.Bounds()
	pi := p.PixOffset(b.Min.X+i, b.Min.Y)
	pj := p.PixOffset(b.Min.X+j, b.Min.Y)
	p.Pix[pi+0], p.Pix[pj+0] = p.Pix[pj+0], p.Pix[pi+0]
	p.Pix[pi+1], p.Pix[pj+1] = p.Pix[pj+1], p.Pix[pi+1]
	p.Pix[pi+2], p.Pix[pj+2] = p.Pix[pj+2], p.Pix[pi+2]
	p.Pix[pi+3], p.Pix[pj+3] = p.Pix[pj+3], p.Pix[pi+3]
}

func convolve(m *image.Gray, kernX, kernY [][]int, r image.Rectangle) uint8 {
	d := r.Sub(kernR.Min)
	b := m.Bounds()

	magx := int(0)
	magy := int(0)
	for y := d.Min.Y; y < d.Max.Y; y++ {
		for x := d.Min.X; x < d.Max.X; x++ {
			if (kernX[y][x] == 0) && (kernY[y][x] == 0) {
				continue
			}
			v := m.At(b.Min.X+x, b.Min.Y+y).(color.Gray)
			magx += int(v.Y) * kernX[y][x]
			magy += int(v.Y) * kernY[y][x]
		}
	}
	mag := math.Sqrt(float64(magx*magx) + float64(magy*magy))

	if mag < 0 {
		return 0
	}
	if mag > 255 {
		return 255
	}
	return uint8(mag)
}

func sobel(m *image.Gray) (*image.Gray, []int) {
	b := m.Bounds()
	im := image.NewGray(b)
	hist := make([]int, 256)

	for p := b.Min; p.Y < b.Max.Y; p.Y++ {
		for p.X = b.Min.X; p.X < b.Max.X; p.X++ {
			window := kernR.Add(p).Intersect(b)
			mag := convolve(m.SubImage(window).(*image.Gray), kernX, kernY, window.Sub(p))
			im.SetGray(p.X, p.Y, color.Gray{mag})
			hist[mag]++
		}
	}

	return im, hist
}

func threshold(m *image.Gray, t uint8) {
	b := m.Bounds()
	for y := b.Min.Y; y < b.Max.Y; y++ {
		for x := b.Min.X; x < b.Max.X; x++ {
			c := m.At(x, y).(color.Gray)
			if c.Y > t {
				c.Y = 255
			} else {
				c.Y = 0
			}
			m.Set(x, y, c)
		}
	}
}

// otsu's method
func computeThresh(hist []int, total int) int {
	sum := float64(0)
	for i := 0; i < 256; i++ {
		sum += float64(i * hist[i])
	}

	rsum := float64(0)
	bgWeight := float64(0)
	fgWeight := float64(0)
	bgMean := float64(0)
	fgMean := float64(0)

	bcMax := float64(0)
	bcBin := int(0)

	for i := 0; i < 256; i++ {
		bgWeight += float64(hist[i])
		if bgWeight == 0 {
			continue
		}
		if bgWeight == sum {
			break
		}
		rsum += float64(i) * float64(hist[i])
		fgWeight = float64(total) - bgWeight
		bgMean = rsum / bgWeight
		fgMean = (sum - rsum) / fgWeight
		bcVar := fgWeight * bgWeight * math.Pow(bgMean-fgMean, 2)
		if bcVar > bcMax {
			bcMax, bcBin = bcVar, i
		}
	}

	return bcBin
}

func edgeToRegion(m *image.Gray) [][]int {
	b := m.Bounds()
	regions := make([][]int, b.Dy())
	for i := range regions {
		for x := b.Min.X; x < b.Max.X; x++ {
			if m.Pix[m.Stride*i+x] > 0 {
				regions[i] = append(regions[i], x)
			}
		}
	}
	return regions
}

func region(regions []int, idx int) int {
	for i := range regions {
		if idx <= regions[i] {
			return i
		}
	}
	return len(regions)
}

func makeRGB(m image.Image) *image.RGBA {
	if rgb, ok := m.(*image.RGBA); ok {
		return rgb
	}
	b := m.Bounds()
	rgb := image.NewRGBA(b)
	draw.Draw(rgb, b, m, b.Min, draw.Src)
	return rgb
}

func sortimage(m image.Image, regions [][]int) image.Image {
	b := m.Bounds()
	rgb := makeRGB(m)
	for y := b.Min.Y; y < b.Max.Y; y++ {
		sub := rgb.SubImage(image.Rect(b.Min.X, b.Min.Y+y, b.Max.X, b.Min.Y+y+1))
		r := &pixim{
			sub.(*image.RGBA),
			regions[y],
		}
		sort.Sort(r)
	}
	return rgb
}

func main() {
	flag.Parse()

	if flag.NArg() < 2 {
		fmt.Fprintf(os.Stderr, "Usage: %s [options] <input image> <output image>\n", os.Args[0])
		flag.PrintDefaults()
		os.Exit(-1)
	}

	log.Println("Opening image in")
	infile, err := os.Open(flag.Arg(0))
	if err != nil {
		log.Fatal(err)
	}
	defer infile.Close()

	log.Println("Decoding image in")
	inimg, _, err := image.Decode(infile)
	if err != nil {
		log.Fatal(err)
	}

	b := inimg.Bounds()
	gray := image.NewGray(b)
	draw.Draw(gray, b, inimg, b.Min, draw.Src)

	//g, err := os.Create("gray.png")
	//png.Encode(g, gray)

	log.Println("Computing pixel gradient")
	s, hist := sobel(gray)

	if *compute {
		t := computeThresh(hist, b.Dx()*b.Dy())
		log.Printf("Best threshold = %v", t)

		threshold(s, uint8(t))

		sout, err := os.Create(flag.Arg(1))
		if err != nil {
			log.Fatal(err)
		}
		png.Encode(sout, s)
		sout.Close()
		os.Exit(0)
	}

	threshold(s, uint8(*thresh))

	if *psobel {
		sout, err := os.Create(flag.Arg(1))
		if err != nil {
			log.Fatal(err)
		}
		png.Encode(sout, s)
		sout.Close()
		os.Exit(0)
	}

	log.Println("Computing regions")
	regions := edgeToRegion(s)

	log.Println("Sorting image")
	sorted := sortimage(inimg, regions)

	log.Println("Writing output")
	outfile, err := os.Create(flag.Arg(1))
	if err != nil {
		log.Fatal(err)
	}
	err = png.Encode(outfile, sorted)
	if err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2019 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package executor

import (
	"context"
	"sync"
	"sync/atomic"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"gopkg.in/guregu/null.v3"

	"github.com/loadimpact/k6/lib"
	"github.com/loadimpact/k6/lib/types"
)

func getTestExternallyControlledConfig() ExternallyControlledConfig {
	return ExternallyControlledConfig{
		ExternallyControlledConfigParams: ExternallyControlledConfigParams{
			VUs:      null.IntFrom(2),
			MaxVUs:   null.IntFrom(10),
			Duration: types.NullDurationFrom(3 * time.Second),
		},
	}
}

func TestExternallyControlledRun(t *testing.T) {
	t.Parallel()
	doneIters := new(uint64)
	et, err := lib.NewExecutionTuple(nil, nil)
	require.NoError(t, err)
	es := lib.NewExecutionState(lib.Options{}, et, 10, 50)
	var ctx, cancel, executor, _ = setupExecutor(
		t, getTestExternallyControlledConfig(), es,
		simpleRunner(func(ctx context.Context) error {
			time.Sleep(200 * time.Millisecond)
			atomic.AddUint64(doneIters, 1)
			return nil
		}),
	)
	defer cancel()

	var (
		wg            sync.WaitGroup
		errCh         = make(chan error, 1)
		doneCh        = make(chan struct{})
		resultVUCount [][]int64
	)
	wg.Add(1)
	go func() {
		defer wg.Done()
		errCh <- executor.Run(ctx, nil)
		close(doneCh)
	}()

	updateConfig := func(vus, maxVUs int) {
		newConfig := ExternallyControlledConfigParams{
			VUs:      null.IntFrom(int64(vus)),
			MaxVUs:   null.IntFrom(int64(maxVUs)),
			Duration: types.NullDurationFrom(3 * time.Second),
		}
		err := executor.(*ExternallyControlled).UpdateConfig(ctx, newConfig)
		assert.NoError(t, err)
	}

	snapshot := func() {
		resultVUCount = append(resultVUCount,
			[]int64{es.GetCurrentlyActiveVUsCount(), es.GetInitializedVUsCount()})
	}

	wg.Add(1)
	go func() {
		defer wg.Done()
		es.MarkStarted()
		time.Sleep(150 * time.Millisecond) // wait for startup
		snapshot()
		time.Sleep(500 * time.Millisecond)
		updateConfig(4, 10)
		time.Sleep(100 * time.Millisecond)
		snapshot()
		time.Sleep(500 * time.Millisecond)
		updateConfig(8, 20)
		time.Sleep(500 * time.Millisecond)
		snapshot()
		time.Sleep(500 * time.Millisecond)
		updateConfig(4, 10)
		time.Sleep(500 * time.Millisecond)
		snapshot()
		time.Sleep(1 * time.Second)
		snapshot()
		es.MarkEnded()
	}()

	<-doneCh
	wg.Wait()
	require.NoError(t, <-errCh)
	assert.InDelta(t, uint64(75), atomic.LoadUint64(doneIters), 1)
	assert.Equal(t, [][]int64{{2, 10}, {4, 10}, {8, 20}, {4, 10}, {0, 0}}, resultVUCount)
}
<commit_msg>Rewrite TestExternallyControlledRun to hopefully fix flakiness<commit_after>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2019 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package executor

import (
	"context"
	"sync"
	"sync/atomic"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"gopkg.in/guregu/null.v3"

	"github.com/loadimpact/k6/lib"
	"github.com/loadimpact/k6/lib/types"
)

func getTestExternallyControlledConfig() ExternallyControlledConfig {
	return ExternallyControlledConfig{
		ExternallyControlledConfigParams: ExternallyControlledConfigParams{
			VUs:      null.IntFrom(2),
			MaxVUs:   null.IntFrom(10),
			Duration: types.NullDurationFrom(2 * time.Second),
		},
	}
}

func TestExternallyControlledRun(t *testing.T) {
	t.Parallel()

	et, err := lib.NewExecutionTuple(nil, nil)
	require.NoError(t, err)
	es := lib.NewExecutionState(lib.Options{}, et, 10, 50)

	doneIters := new(uint64)
	var ctx, cancel, executor, _ = setupExecutor(
		t, getTestExternallyControlledConfig(), es,
		simpleRunner(func(ctx context.Context) error {
			time.Sleep(200 * time.Millisecond)
			atomic.AddUint64(doneIters, 1)
			return nil
		}),
	)
	defer cancel()

	var (
		wg     sync.WaitGroup
		errCh  = make(chan error, 1)
		doneCh = make(chan struct{})
	)
	wg.Add(1)
	go func() {
		defer wg.Done()
		es.MarkStarted()
		errCh <- executor.Run(ctx, nil)
		es.MarkEnded()
		close(doneCh)
	}()

	updateConfig := func(vus, maxVUs int) {
		newConfig := ExternallyControlledConfigParams{
			VUs:      null.IntFrom(int64(vus)),
			MaxVUs:   null.IntFrom(int64(maxVUs)),
			Duration: types.NullDurationFrom(2 * time.Second),
		}
		err := executor.(*ExternallyControlled).UpdateConfig(ctx, newConfig)
		assert.NoError(t, err)
	}

	var resultVUCount [][]int64
	snapshot := func() {
		resultVUCount = append(resultVUCount,
			[]int64{es.GetCurrentlyActiveVUsCount(), es.GetInitializedVUsCount()})
	}

	wg.Add(1)
	go func() {
		defer wg.Done()
		snapshotTicker := time.NewTicker(500 * time.Millisecond)
		ticks := 0
		for {
			select {
			case <-snapshotTicker.C:
				snapshot()
				switch ticks {
				case 0, 2:
					updateConfig(4, 10)
				case 1:
					updateConfig(8, 20)
				}
				ticks++
			case <-doneCh:
				snapshotTicker.Stop()
				snapshot()
				return
			}
		}
	}()

	wg.Wait()
	require.NoError(t, <-errCh)
	assert.Equal(t, uint64(48), atomic.LoadUint64(doneIters))
	assert.Equal(t, [][]int64{{2, 10}, {4, 10}, {8, 20}, {4, 10}, {0, 0}}, resultVUCount)
}
<|endoftext|>


<commit_before>package openstack

import (
	"fmt"
	"launchpad.net/goose/nova"
	"launchpad.net/goose/swift"
	"launchpad.net/juju-core/environs"
	"launchpad.net/juju-core/state"
	"launchpad.net/juju-core/trivial"
	"net/http"
)

func init() {
	http.DefaultTransport.(*http.Transport).RegisterProtocol("file", http.NewFileTransport(http.Dir("testdata")))
}

var origMetadataHost = metadataHost

func UseTestMetadata(local bool) {
	if local {
		metadataHost = "file:"
	} else {
		metadataHost = origMetadataHost
	}
}

var origMetadataJSON = metadataJSON

func UseMetadataJSON(path string) {
	if path != "" {
		metadataJSON = path
	} else {
		metadataJSON = origMetadataJSON
	}
}

var originalShortAttempt = shortAttempt
var originalLongAttempt = longAttempt

// ShortTimeouts sets the timeouts to a short period as we
// know that the testing server doesn't get better with time,
// and this reduces the test time from 30s to 3s.
func ShortTimeouts(short bool) {
	if short {
		shortAttempt = trivial.AttemptStrategy{
			Total: 0.25e9,
			Delay: 0.01e9,
		}
		longAttempt = shortAttempt
	} else {
		shortAttempt = originalShortAttempt
		longAttempt = originalLongAttempt
	}
}

var ShortAttempt = &shortAttempt

func DeleteStorageContent(s environs.Storage) error {
	return s.(*storage).deleteAll()
}

// WritablePublicStorage returns a Storage instance which is authorised to write to the PublicStorage bucket.
// It is used by tests which need to upload files.
func WritablePublicStorage(e environs.Environ) environs.Storage {
	ecfg := e.(*environ).ecfg()
	authModeCfg := AuthMode(ecfg.authMode())
	writablePublicStorage := &storage{
		containerName: ecfg.publicBucket(),
		swift:         swift.New(e.(*environ).client(ecfg, authModeCfg)),
	}

	// Ensure the container exists.
	err := writablePublicStorage.makeContainer(ecfg.publicBucket(), swift.PublicRead)
	if err != nil {
		panic(fmt.Errorf("cannot create writable public container: %v", err))
	}
	return writablePublicStorage
}
func InstanceAddress(addresses map[string][]nova.IPAddress) (string, error) {
	return instanceAddress(addresses)
}

func FindInstanceSpec(e environs.Environ, series, arch, flavor string) (imageId, flavorId string, err error) {
	env := e.(*environ)
	spec, err := findInstanceSpec(env, &instanceConstraint{
		series: series,
		arch:   arch,
		region: env.ecfg().region(),
		flavor: flavor,
	})
	if err == nil {
		imageId = spec.imageId
		flavorId = spec.flavorId
	}
	return
}

func SetUseFloatingIP(e environs.Environ, val bool) {
	env := e.(*environ)
	env.ecfg().attrs["use-floating-ip"] = val
}

func DefaultInstanceType(e environs.Environ) string {
	ecfg := e.(*environ).ecfg()
	return ecfg.defaultInstanceType()
}

// ImageDetails specify parameters used to start a test machine for the live tests.
type ImageDetails struct {
	Flavor  string
	ImageId string
}

type BootstrapState struct {
	StateInstances []state.InstanceId
}

func LoadState(e environs.Environ) (*BootstrapState, error) {
	s, err := e.(*environ).loadState()
	if err != nil {
		return nil, err
	}
	return &BootstrapState{s.StateInstances}, nil
}
<commit_msg>Start working on a VFS version of the metadata server<commit_after>package openstack

import (
	"bytes"
	"fmt"
	"launchpad.net/goose/nova"
	"launchpad.net/goose/swift"
	"launchpad.net/juju-core/environs"
	"launchpad.net/juju-core/state"
	"launchpad.net/juju-core/trivial"
	"net/http"
	"os"
)

type VirtualFile struct {
	bytes.Reader
}

var _ http.File = (*VirtualFile)(nil)

func (f *VirtualFile) Close() error {
	return nil
}

func (f *VirtualFile) Readdir(count int) ([]os.FileInfo, error) {
	return nil, nil
}

func (f *VirtualFile) Stat() (os.FileInfo, error) {
	return nil, fmt.Errorf("Can't stat VirtualFile")
}

func init() {
	http.DefaultTransport.(*http.Transport).RegisterProtocol("file", http.NewFileTransport(http.Dir("testdata")))
}

var origMetadataHost = metadataHost

func UseTestMetadata(local bool) {
	if local {
		metadataHost = "file:"
	} else {
		metadataHost = origMetadataHost
	}
}

var origMetadataJSON = metadataJSON

func UseMetadataJSON(path string) {
	if path != "" {
		metadataJSON = path
	} else {
		metadataJSON = origMetadataJSON
	}
}

var originalShortAttempt = shortAttempt
var originalLongAttempt = longAttempt

// ShortTimeouts sets the timeouts to a short period as we
// know that the testing server doesn't get better with time,
// and this reduces the test time from 30s to 3s.
func ShortTimeouts(short bool) {
	if short {
		shortAttempt = trivial.AttemptStrategy{
			Total: 0.25e9,
			Delay: 0.01e9,
		}
		longAttempt = shortAttempt
	} else {
		shortAttempt = originalShortAttempt
		longAttempt = originalLongAttempt
	}
}

var ShortAttempt = &shortAttempt

func DeleteStorageContent(s environs.Storage) error {
	return s.(*storage).deleteAll()
}

// WritablePublicStorage returns a Storage instance which is authorised to write to the PublicStorage bucket.
// It is used by tests which need to upload files.
func WritablePublicStorage(e environs.Environ) environs.Storage {
	ecfg := e.(*environ).ecfg()
	authModeCfg := AuthMode(ecfg.authMode())
	writablePublicStorage := &storage{
		containerName: ecfg.publicBucket(),
		swift:         swift.New(e.(*environ).client(ecfg, authModeCfg)),
	}

	// Ensure the container exists.
	err := writablePublicStorage.makeContainer(ecfg.publicBucket(), swift.PublicRead)
	if err != nil {
		panic(fmt.Errorf("cannot create writable public container: %v", err))
	}
	return writablePublicStorage
}
func InstanceAddress(addresses map[string][]nova.IPAddress) (string, error) {
	return instanceAddress(addresses)
}

func FindInstanceSpec(e environs.Environ, series, arch, flavor string) (imageId, flavorId string, err error) {
	env := e.(*environ)
	spec, err := findInstanceSpec(env, &instanceConstraint{
		series: series,
		arch:   arch,
		region: env.ecfg().region(),
		flavor: flavor,
	})
	if err == nil {
		imageId = spec.imageId
		flavorId = spec.flavorId
	}
	return
}

func SetUseFloatingIP(e environs.Environ, val bool) {
	env := e.(*environ)
	env.ecfg().attrs["use-floating-ip"] = val
}

func DefaultInstanceType(e environs.Environ) string {
	ecfg := e.(*environ).ecfg()
	return ecfg.defaultInstanceType()
}

// ImageDetails specify parameters used to start a test machine for the live tests.
type ImageDetails struct {
	Flavor  string
	ImageId string
}

type BootstrapState struct {
	StateInstances []state.InstanceId
}

func LoadState(e environs.Environ) (*BootstrapState, error) {
	s, err := e.(*environ).loadState()
	if err != nil {
		return nil, err
	}
	return &BootstrapState{s.StateInstances}, nil
}
<|endoftext|>


<commit_before>/*
   Copyright (c) 2016 VMware, 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 dao

import (
	"database/sql"
	"errors"

	"github.com/vmware/harbor/models"
	"github.com/vmware/harbor/utils"

	"github.com/astaxie/beego/orm"
	"github.com/vmware/harbor/utils/log"
)

// GetUser ...
func GetUser(query models.User) (*models.User, error) {

	o := orm.NewOrm()

	sql := `select user_id, username, email, realname, comment, reset_uuid, salt,
		sysadmin_flag, creation_time, update_time
		from user u
		where deleted = 0 `
	queryParam := make([]interface{}, 1)
	if query.UserID != 0 {
		sql += ` and user_id = ? `
		queryParam = append(queryParam, query.UserID)
	}

	if query.Username != "" {
		sql += ` and username = ? `
		queryParam = append(queryParam, query.Username)
	}

	if query.ResetUUID != "" {
		sql += ` and reset_uuid = ? `
		queryParam = append(queryParam, query.ResetUUID)
	}

	var u []models.User
	n, err := o.Raw(sql, queryParam).QueryRows(&u)

	if err != nil {
		return nil, err
	}
	if n == 0 {
		return nil, nil
	}

	return &u[0], nil
}

// LoginByDb is used for user to login with database auth mode.
func LoginByDb(auth models.AuthModel) (*models.User, error) {
	o := orm.NewOrm()

	var users []models.User
	n, err := o.Raw(`select * from user where (username = ? or email = ?)`,
		auth.Principal, auth.Principal).QueryRows(&users)
	if err != nil {
		return nil, err
	}
	if n == 0 {
		return nil, nil
	}

	user := users[0]

	if user.Password != utils.Encrypt(auth.Password, user.Salt) {
		return nil, nil
	}

	return &user, nil
}

// ListUsers lists all users according to different conditions.
func ListUsers(query models.User) ([]models.User, error) {
	o := orm.NewOrm()
	u := []models.User{}
	sql := `select  user_id, username, email, realname, comment, reset_uuid, salt,
		sysadmin_flag, creation_time, update_time
		from user u
		where u.deleted = 0 and u.user_id != 1 `

	queryParam := make([]interface{}, 1)
	if query.Username != "" {
		sql += ` and username like ? `
		queryParam = append(queryParam, query.Username)
	}
	sql += ` order by user_id desc `

	_, err := o.Raw(sql, queryParam).QueryRows(&u)
	return u, err
}

// ToggleUserAdminRole gives a user admim role.
func ToggleUserAdminRole(u models.User) error {
	o := orm.NewOrm()

	var user models.User
	err := o.Raw(`select sysadmin_flag from user where user_id = ?`, u.UserID).QueryRow(&user)
	if err != nil {
		return err
	}

	var sysAdminFlag int
	if user.HasAdminRole == 0 {
		sysAdminFlag = 1
	} else {
		sysAdminFlag = 0
	}

	sql := `update user set sysadmin_flag = ? where user_id = ?`

	r, err := o.Raw(sql, sysAdminFlag, u.UserID).Exec()
	if err != nil {
		return err
	}

	if _, err := r.RowsAffected(); err != nil {
		return err
	}

	return nil
}

// ChangeUserPassword ...
func ChangeUserPassword(u models.User, oldPassword ...string) (err error) {
	o := orm.NewOrm()

	var r sql.Result
	if len(oldPassword) == 0 {
		//In some cases, it may no need to check old password, just as Linux change password policies.
		r, err = o.Raw(`update user set password=?, salt=? where user_id=?`, utils.Encrypt(u.Password, u.Salt), u.Salt, u.UserID).Exec()
		if err != nil {
			return err
		}

		c, err := r.RowsAffected()
		if err != nil {
			return err
		}

		if c == 0 {
			return errors.New("No record has been modified, change password failed.")
		}

		return nil
	}

	if len(oldPassword) == 1 {
		r, err = o.Raw(`update user set password=?, salt=? where user_id=? and password = ?`, utils.Encrypt(u.Password, u.Salt), u.Salt, u.UserID, utils.Encrypt(oldPassword[0], u.Salt)).Exec()
		if err != nil {
			return err
		}
		c, err := r.RowsAffected()
		if err != nil {
			return err
		}
		if c == 0 {
			return errors.New("No record has been modified, change password failed.")
		}

		return nil
	}

	return errors.New("Wrong numbers of params.")
}

// ResetUserPassword ...
func ResetUserPassword(u models.User) error {
	o := orm.NewOrm()
	r, err := o.Raw(`update user set password=?, reset_uuid=? where reset_uuid=?`, utils.Encrypt(u.Password, u.Salt), "", u.ResetUUID).Exec()
	if err != nil {
		return err
	}
	count, err := r.RowsAffected()
	if err != nil {
		return err
	}
	if count == 0 {
		return errors.New("No record be changed, reset password failed.")
	}
	return nil
}

// UpdateUserResetUUID ...
func UpdateUserResetUUID(u models.User) error {
	o := orm.NewOrm()
	_, err := o.Raw(`update user set reset_uuid=? where email=?`, u.ResetUUID, u.Email).Exec()
	return err
}

// CheckUserPassword checks whether the password is correct.
func CheckUserPassword(query models.User) (*models.User, error) {

	currentUser, err := GetUser(query)

	if err != nil {
		return nil, err
	}

	if currentUser == nil {
		return nil, nil
	}

	sql := `select user_id, username, salt from user where deleted = 0`

	queryParam := make([]interface{}, 1)

	if query.UserID != 0 {
		sql += ` and password = ? and user_id = ?`
		queryParam = append(queryParam, utils.Encrypt(query.Password, currentUser.Salt))
		queryParam = append(queryParam, query.UserID)
	} else {
		sql += ` and username = ? and password = ?`
		queryParam = append(queryParam, currentUser.Username)
		queryParam = append(queryParam, utils.Encrypt(query.Password, currentUser.Salt))
	}
	o := orm.NewOrm()
	var user []models.User

	n, err := o.Raw(sql, queryParam).QueryRows(&user)

	if err != nil {
		return nil, err
	}

	if n == 0 {
		log.Warning("User principal does not match password. Current:", currentUser)
		return nil, nil
	}

	return &user[0], nil
}

// DeleteUser ...
func DeleteUser(userID int) error {
	o := orm.NewOrm()
	_, err := o.Raw(`update user set deleted = 1 where user_id = ?`, userID).Exec()
	return err
}
<commit_msg>return nil if the user is deleted in LoginByDb()<commit_after>/*
   Copyright (c) 2016 VMware, 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 dao

import (
	"database/sql"
	"errors"

	"github.com/vmware/harbor/models"
	"github.com/vmware/harbor/utils"

	"github.com/astaxie/beego/orm"
	"github.com/vmware/harbor/utils/log"
)

// GetUser ...
func GetUser(query models.User) (*models.User, error) {

	o := orm.NewOrm()

	sql := `select user_id, username, email, realname, comment, reset_uuid, salt,
		sysadmin_flag, creation_time, update_time
		from user u
		where deleted = 0 `
	queryParam := make([]interface{}, 1)
	if query.UserID != 0 {
		sql += ` and user_id = ? `
		queryParam = append(queryParam, query.UserID)
	}

	if query.Username != "" {
		sql += ` and username = ? `
		queryParam = append(queryParam, query.Username)
	}

	if query.ResetUUID != "" {
		sql += ` and reset_uuid = ? `
		queryParam = append(queryParam, query.ResetUUID)
	}

	var u []models.User
	n, err := o.Raw(sql, queryParam).QueryRows(&u)

	if err != nil {
		return nil, err
	}
	if n == 0 {
		return nil, nil
	}

	return &u[0], nil
}

// LoginByDb is used for user to login with database auth mode.
func LoginByDb(auth models.AuthModel) (*models.User, error) {
	o := orm.NewOrm()

	var users []models.User
	n, err := o.Raw(`select * from user where (username = ? or email = ?) and deleted = 0`,
		auth.Principal, auth.Principal).QueryRows(&users)
	if err != nil {
		return nil, err
	}
	if n == 0 {
		return nil, nil
	}

	user := users[0]

	if user.Password != utils.Encrypt(auth.Password, user.Salt) {
		return nil, nil
	}

	return &user, nil
}

// ListUsers lists all users according to different conditions.
func ListUsers(query models.User) ([]models.User, error) {
	o := orm.NewOrm()
	u := []models.User{}
	sql := `select  user_id, username, email, realname, comment, reset_uuid, salt,
		sysadmin_flag, creation_time, update_time
		from user u
		where u.deleted = 0 and u.user_id != 1 `

	queryParam := make([]interface{}, 1)
	if query.Username != "" {
		sql += ` and username like ? `
		queryParam = append(queryParam, query.Username)
	}
	sql += ` order by user_id desc `

	_, err := o.Raw(sql, queryParam).QueryRows(&u)
	return u, err
}

// ToggleUserAdminRole gives a user admim role.
func ToggleUserAdminRole(u models.User) error {
	o := orm.NewOrm()

	var user models.User
	err := o.Raw(`select sysadmin_flag from user where user_id = ?`, u.UserID).QueryRow(&user)
	if err != nil {
		return err
	}

	var sysAdminFlag int
	if user.HasAdminRole == 0 {
		sysAdminFlag = 1
	} else {
		sysAdminFlag = 0
	}

	sql := `update user set sysadmin_flag = ? where user_id = ?`

	r, err := o.Raw(sql, sysAdminFlag, u.UserID).Exec()
	if err != nil {
		return err
	}

	if _, err := r.RowsAffected(); err != nil {
		return err
	}

	return nil
}

// ChangeUserPassword ...
func ChangeUserPassword(u models.User, oldPassword ...string) (err error) {
	o := orm.NewOrm()

	var r sql.Result
	if len(oldPassword) == 0 {
		//In some cases, it may no need to check old password, just as Linux change password policies.
		r, err = o.Raw(`update user set password=?, salt=? where user_id=?`, utils.Encrypt(u.Password, u.Salt), u.Salt, u.UserID).Exec()
		if err != nil {
			return err
		}

		c, err := r.RowsAffected()
		if err != nil {
			return err
		}

		if c == 0 {
			return errors.New("No record has been modified, change password failed.")
		}

		return nil
	}

	if len(oldPassword) == 1 {
		r, err = o.Raw(`update user set password=?, salt=? where user_id=? and password = ?`, utils.Encrypt(u.Password, u.Salt), u.Salt, u.UserID, utils.Encrypt(oldPassword[0], u.Salt)).Exec()
		if err != nil {
			return err
		}
		c, err := r.RowsAffected()
		if err != nil {
			return err
		}
		if c == 0 {
			return errors.New("No record has been modified, change password failed.")
		}

		return nil
	}

	return errors.New("Wrong numbers of params.")
}

// ResetUserPassword ...
func ResetUserPassword(u models.User) error {
	o := orm.NewOrm()
	r, err := o.Raw(`update user set password=?, reset_uuid=? where reset_uuid=?`, utils.Encrypt(u.Password, u.Salt), "", u.ResetUUID).Exec()
	if err != nil {
		return err
	}
	count, err := r.RowsAffected()
	if err != nil {
		return err
	}
	if count == 0 {
		return errors.New("No record be changed, reset password failed.")
	}
	return nil
}

// UpdateUserResetUUID ...
func UpdateUserResetUUID(u models.User) error {
	o := orm.NewOrm()
	_, err := o.Raw(`update user set reset_uuid=? where email=?`, u.ResetUUID, u.Email).Exec()
	return err
}

// CheckUserPassword checks whether the password is correct.
func CheckUserPassword(query models.User) (*models.User, error) {

	currentUser, err := GetUser(query)

	if err != nil {
		return nil, err
	}

	if currentUser == nil {
		return nil, nil
	}

	sql := `select user_id, username, salt from user where deleted = 0`

	queryParam := make([]interface{}, 1)

	if query.UserID != 0 {
		sql += ` and password = ? and user_id = ?`
		queryParam = append(queryParam, utils.Encrypt(query.Password, currentUser.Salt))
		queryParam = append(queryParam, query.UserID)
	} else {
		sql += ` and username = ? and password = ?`
		queryParam = append(queryParam, currentUser.Username)
		queryParam = append(queryParam, utils.Encrypt(query.Password, currentUser.Salt))
	}
	o := orm.NewOrm()
	var user []models.User

	n, err := o.Raw(sql, queryParam).QueryRows(&user)

	if err != nil {
		return nil, err
	}

	if n == 0 {
		log.Warning("User principal does not match password. Current:", currentUser)
		return nil, nil
	}

	return &user[0], nil
}

// DeleteUser ...
func DeleteUser(userID int) error {
	o := orm.NewOrm()
	_, err := o.Raw(`update user set deleted = 1 where user_id = ?`, userID).Exec()
	return err
}
<|endoftext|>


<commit_before>package dao

import "time"

//------------------------------------------------------------
// DAO find methods
//------------------------------------------------------------

// Finds an object from collection by given equals 'and' criteria.
// Obj must be a pointer to a struct.
func (dao *DAO) FindAs(obj interface{}, equals map[string]interface{}, fields ...string) (err error) {

	err = dao.Coll.Find(equals).Select(M{}.Select(fields...)).One(obj)
	return
}

// Finds many objects matching equals 'and' criteria.
// Objs must be a pointer to an empty array of structs.
func (dao *DAO) FindManyAs(objs interface{}, equals map[string]interface{}, fields ...string) (err error) {

	err = dao.Coll.Find(equals).Select(M{}.Select(fields...)).All(objs)
	return
}

// Finds many objects matching dateField to the specified time period.
// Objs must be a pointer to an empty array of structs.
func (dao *DAO) FindManyByPeriodAs(objs interface{}, dateField string, ps, pe time.Time, fields ...string) (err error) {

	q := M{dateField: M{"$gte": ps, "$lt": pe}}
	err = dao.Coll.Find(q).Select(M{}.Select(fields...)).All(objs)
	return
}
<commit_msg>find by period<commit_after>package dao

import "time"

//------------------------------------------------------------
// DAO find methods
//------------------------------------------------------------

// Finds an object from collection by given equals 'and' criteria.
// Obj must be a pointer to a struct.
func (dao *DAO) FindAs(obj interface{}, equals map[string]interface{}, fields ...string) (err error) {

	err = dao.Coll.Find(equals).Select(M{}.Select(fields...)).One(obj)
	return
}

// Finds many objects matching equals 'and' criteria.
// Objs must be a pointer to an empty array of structs.
func (dao *DAO) FindManyAs(objs interface{}, equals map[string]interface{}, fields ...string) (err error) {

	err = dao.Coll.Find(equals).Select(M{}.Select(fields...)).All(objs)
	return
}

// Finds many objects matching dateKey to the specified time period.
// Objs must be a pointer to an empty array of structs.
func (dao *DAO) FindManyByIntervalAs(objs interface{}, dateKey string, ps, pe time.Time, fields ...string) (err error) {

	q := M{dateKey: M{"$gte": ps, "$lt": pe}}
	err = dao.Coll.Find(q).Select(M{}.Select(fields...)).All(objs)
	return
}

// Finds many objects matching 'ps' and 'pe' field keys to be inside the specified time period.
// Objs must be a pointer to an empty array of structs.
func (dao *DAO) FindManyByPeriodAs(objs interface{}, psKey, peKey string, ps, pe time.Time, fields ...string) (err error) {

	q := M{psKey: M{"$gte": ps}, peKey: M{"$lte": pe}}
	err = dao.Coll.Find(q).Select(M{}.Select(fields...)).All(objs)
	return
}
<|endoftext|>


<commit_before>package main

type record struct {
	Amount int
	Name   string
}

type database struct {
	records []record
}

func NewDatabase() *database {
	return &database{records: make([]record, 0, 4)}
}

func (db *database) get(index int) (r record, ok bool) {
	if !db.isValidIndex(index) {
		return record{}, false
	}

	return db.records[index], true
}

func (db *database) isValidIndex(index int) bool {
	return index >= 0 && index < db.length()
}

func (db *database) length() int {
	return len(db.records)
}

func (db *database) clear() {
	db.records = make([]record, 0, 4)
}

func (db *database) remove(index int) bool {
	if !db.isValidIndex(index) {
		return false
	}

	db.records = append(db.records[:index], db.records[index+1:]...)

	return true
}

func (db *database) insert(index int, r record) bool {
	if index < 0 || index > db.length() {
		return false
	}

	db.records = append(db.records, record{})
	copy(db.records[index+1:], db.records[index:])
	db.records[index] = r

	return true
}

func (db *database) update(index int, r record) bool {
	if !db.isValidIndex(index) {
		return false
	}

	db.records[index] = r

	return true
}
<commit_msg>Add r/w locks to database<commit_after>package main

import "sync"

type record struct {
	Amount int
	Name   string
}

type database struct {
	sync.RWMutex
	records []record
}

func NewDatabase() *database {
	return &database{records: make([]record, 0, 4)}
}

func (db *database) get(index int) (r record, ok bool) {
	db.RLock()
	defer db.RUnlock()
	if !db.isValidIndex(index) {
		return record{}, false
	}

	return db.records[index], true
}

func (db *database) isValidIndex(index int) bool {
	return index >= 0 && index < db.length()
}

func (db *database) length() int {
	db.RLock()
	defer db.RUnlock()
	return len(db.records)
}

func (db *database) clear() {
	db.Lock()
	defer db.Unlock()
	db.records = make([]record, 0, 4)
}

func (db *database) remove(index int) bool {
	db.Lock()
	defer db.Unlock()
	if !db.isValidIndex(index) {
		return false
	}

	db.records = append(db.records[:index], db.records[index+1:]...)

	return true
}

func (db *database) insert(index int, r record) bool {
	db.Lock()
	defer db.Unlock()
	if index < 0 || index > db.length() {
		return false
	}

	db.records = append(db.records, record{})
	copy(db.records[index+1:], db.records[index:])
	db.records[index] = r

	return true
}

func (db *database) update(index int, r record) bool {
	db.Lock()
	defer db.Unlock()
	if !db.isValidIndex(index) {
		return false
	}

	db.records[index] = r

	return true
}
<|endoftext|>