<commit_before>// Package storage provides clients for Microsoft Azure Storage Services.
package storage

import (
	"bytes"
	"encoding/base64"
	"encoding/xml"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"regexp"
	"sort"
	"strings"
)

const (
	// DefaultBaseURL is the domain name used for storage requests when a
	// default client is created.
	DefaultBaseURL = "core.windows.net"

	// DefaultAPIVersion is the  Azure Storage API version string used when a
	// basic client is created.
	DefaultAPIVersion = "2014-02-14"

	defaultUseHTTPS = true

	blobServiceName  = "blob"
	tableServiceName = "table"
	queueServiceName = "queue"
	fileServiceName  = "file"
)

// Client is the object that needs to be constructed to perform
// operations on the storage account.
type Client struct {
	accountName string
	accountKey  []byte
	useHTTPS    bool
	baseURL     string
	apiVersion  string
}

type storageResponse struct {
	statusCode int
	headers    http.Header
	body       io.ReadCloser
}

// AzureStorageServiceError contains fields of the error response from
// Azure Storage Service REST API. See https://msdn.microsoft.com/en-us/library/azure/dd179382.aspx
// Some fields might be specific to certain calls.
type AzureStorageServiceError struct {
	Code                      string `xml:"Code"`
	Message                   string `xml:"Message"`
	AuthenticationErrorDetail string `xml:"AuthenticationErrorDetail"`
	QueryParameterName        string `xml:"QueryParameterName"`
	QueryParameterValue       string `xml:"QueryParameterValue"`
	Reason                    string `xml:"Reason"`
	StatusCode                int
	RequestID                 string
}

// UnexpectedStatusCodeError is returned when a storage service responds with neither an error
// nor with an HTTP status code indicating success.
type UnexpectedStatusCodeError struct {
	allowed []int
	got     int
}

func (e UnexpectedStatusCodeError) Error() string {
	s := func(i int) string { return fmt.Sprintf("%d %s", i, http.StatusText(i)) }

	got := s(e.got)
	expected := []string{}
	for _, v := range e.allowed {
		expected = append(expected, s(v))
	}
	return fmt.Sprintf("storage: status code from service response is %s; was expecting %s", got, strings.Join(expected, " or "))
}

// Got is the actual status code returned by Azure.
func (e UnexpectedStatusCodeError) Got() int {
	return e.got
}

// NewBasicClient constructs a Client with given storage service name and
// key.
func NewBasicClient(accountName, accountKey string) (Client, error) {
	return NewClient(accountName, accountKey, DefaultBaseURL, DefaultAPIVersion, defaultUseHTTPS)
}

// NewClient constructs a Client. This should be used if the caller wants
// to specify whether to use HTTPS, a specific REST API version or a custom
// storage endpoint than Azure Public Cloud.
func NewClient(accountName, accountKey, blobServiceBaseURL, apiVersion string, useHTTPS bool) (Client, error) {
	var c Client
	if accountName == "" {
		return c, fmt.Errorf("azure: account name required")
	} else if accountKey == "" {
		return c, fmt.Errorf("azure: account key required")
	} else if blobServiceBaseURL == "" {
		return c, fmt.Errorf("azure: base storage service url required")
	}

	key, err := base64.StdEncoding.DecodeString(accountKey)
	if err != nil {
		return c, err
	}

	return Client{
		accountName: accountName,
		accountKey:  key,
		useHTTPS:    useHTTPS,
		baseURL:     blobServiceBaseURL,
		apiVersion:  apiVersion,
	}, nil
}

func (c Client) getBaseURL(service string) string {
	scheme := "http"
	if c.useHTTPS {
		scheme = "https"
	}

	host := fmt.Sprintf("%s.%s.%s", c.accountName, service, c.baseURL)

	u := &url.URL{
		Scheme: scheme,
		Host:   host}
	return u.String()
}

func (c Client) getEndpoint(service, path string, params url.Values) string {
	u, err := url.Parse(c.getBaseURL(service))
	if err != nil {
		// really should not be happening
		panic(err)
	}

	if path == "" {
		path = "/" // API doesn't accept path segments not starting with '/'
	}

	u.Path = path
	u.RawQuery = params.Encode()
	return u.String()
}

// GetBlobService returns a BlobStorageClient which can operate on the blob
// service of the storage account.
func (c Client) GetBlobService() BlobStorageClient {
	return BlobStorageClient{c}
}

// GetQueueService returns a QueueServiceClient which can operate on the queue
// service of the storage account.
func (c Client) GetQueueService() QueueServiceClient {
	return QueueServiceClient{c}
}

// GetFileService returns a FileServiceClient which can operate on the file
// service of the storage account.
func (c Client) GetFileService() FileServiceClient {
	return FileServiceClient{c}
}

func (c Client) createAuthorizationHeader(canonicalizedString string) string {
	signature := c.computeHmac256(canonicalizedString)
	return fmt.Sprintf("%s %s:%s", "SharedKey", c.accountName, signature)
}

func (c Client) getAuthorizationHeader(verb, url string, headers map[string]string) (string, error) {
	canonicalizedResource, err := c.buildCanonicalizedResource(url)
	if err != nil {
		return "", err
	}

	canonicalizedString := c.buildCanonicalizedString(verb, headers, canonicalizedResource)
	return c.createAuthorizationHeader(canonicalizedString), nil
}

func (c Client) getStandardHeaders() map[string]string {
	return map[string]string{
		"x-ms-version": c.apiVersion,
		"x-ms-date":    currentTimeRfc1123Formatted(),
	}
}

func (c Client) buildCanonicalizedHeader(headers map[string]string) string {
	cm := make(map[string]string)

	for k, v := range headers {
		headerName := strings.TrimSpace(strings.ToLower(k))
		match, _ := regexp.MatchString("x-ms-", headerName)
		if match {
			cm[headerName] = v
		}
	}

	if len(cm) == 0 {
		return ""
	}

	keys := make([]string, 0, len(cm))
	for key := range cm {
		keys = append(keys, key)
	}

	sort.Strings(keys)

	ch := ""

	for i, key := range keys {
		if i == len(keys)-1 {
			ch += fmt.Sprintf("%s:%s", key, cm[key])
		} else {
			ch += fmt.Sprintf("%s:%s\n", key, cm[key])
		}
	}
	return ch
}

func (c Client) buildCanonicalizedResource(uri string) (string, error) {
	errMsg := "buildCanonicalizedResource error: %s"
	u, err := url.Parse(uri)
	if err != nil {
		return "", fmt.Errorf(errMsg, err.Error())
	}

	cr := "/" + c.accountName
	if len(u.Path) > 0 {
		cr += u.Path
	}

	params, err := url.ParseQuery(u.RawQuery)
	if err != nil {
		return "", fmt.Errorf(errMsg, err.Error())
	}

	if len(params) > 0 {
		cr += "\n"
		keys := make([]string, 0, len(params))
		for key := range params {
			keys = append(keys, key)
		}

		sort.Strings(keys)

		for i, key := range keys {
			if len(params[key]) > 1 {
				sort.Strings(params[key])
			}

			if i == len(keys)-1 {
				cr += fmt.Sprintf("%s:%s", key, strings.Join(params[key], ","))
			} else {
				cr += fmt.Sprintf("%s:%s\n", key, strings.Join(params[key], ","))
			}
		}
	}
	return cr, nil
}

func (c Client) buildCanonicalizedString(verb string, headers map[string]string, canonicalizedResource string) string {
	canonicalizedString := fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s",
		verb,
		headers["Content-Encoding"],
		headers["Content-Language"],
		headers["Content-Length"],
		headers["Content-MD5"],
		headers["Content-Type"],
		headers["Date"],
		headers["If-Modified-Since"],
		headers["If-Match"],
		headers["If-None-Match"],
		headers["If-Unmodified-Since"],
		headers["Range"],
		c.buildCanonicalizedHeader(headers),
		canonicalizedResource)

	return canonicalizedString
}

func (c Client) exec(verb, url string, headers map[string]string, body io.Reader) (*storageResponse, error) {
	authHeader, err := c.getAuthorizationHeader(verb, url, headers)
	if err != nil {
		return nil, err
	}
	headers["Authorization"] = authHeader

	if err != nil {
		return nil, err
	}

	req, err := http.NewRequest(verb, url, body)
	for k, v := range headers {
		req.Header.Add(k, v)
	}
	httpClient := http.Client{}
	resp, err := httpClient.Do(req)
	if err != nil {
		return nil, err
	}

	statusCode := resp.StatusCode
	if statusCode >= 400 && statusCode <= 505 {
		var respBody []byte
		respBody, err = readResponseBody(resp)
		if err != nil {
			return nil, err
		}

		if len(respBody) == 0 {
			// no error in response body
			err = fmt.Errorf("storage: service returned without a response body (%s)", resp.Status)
		} else {
			// response contains storage service error object, unmarshal
			storageErr, errIn := serviceErrFromXML(respBody, resp.StatusCode, resp.Header.Get("x-ms-request-id"))
			if err != nil { // error unmarshaling the error response
				err = errIn
			}
			err = storageErr
		}
		return &storageResponse{
			statusCode: resp.StatusCode,
			headers:    resp.Header,
			body:       ioutil.NopCloser(bytes.NewReader(respBody)), /* restore the body */
		}, err
	}

	return &storageResponse{
		statusCode: resp.StatusCode,
		headers:    resp.Header,
		body:       resp.Body}, nil
}

func readResponseBody(resp *http.Response) ([]byte, error) {
	defer resp.Body.Close()
	out, err := ioutil.ReadAll(resp.Body)
	if err == io.EOF {
		err = nil
	}
	return out, err
}

func serviceErrFromXML(body []byte, statusCode int, requestID string) (AzureStorageServiceError, error) {
	var storageErr AzureStorageServiceError
	if err := xml.Unmarshal(body, &storageErr); err != nil {
		return storageErr, err
	}
	storageErr.StatusCode = statusCode
	storageErr.RequestID = requestID
	return storageErr, nil
}

func (e AzureStorageServiceError) Error() string {
	return fmt.Sprintf("storage: service returned error: StatusCode=%d, ErrorCode=%s, ErrorMessage=%s, RequestId=%s", e.StatusCode, e.Code, e.Message, e.RequestID)
}

// checkRespCode returns UnexpectedStatusError if the given response code is not
// one of the allowed status codes; otherwise nil.
func checkRespCode(respCode int, allowed []int) error {
	for _, v := range allowed {
		if respCode == v {
			return nil
		}
	}
	return UnexpectedStatusCodeError{allowed, respCode}
}
<commit_msg>Use the Content-Length header if it is set<commit_after>// Package storage provides clients for Microsoft Azure Storage Services.
package storage

import (
	"bytes"
	"encoding/base64"
	"encoding/xml"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"regexp"
	"sort"
	"strconv"
	"strings"
)

const (
	// DefaultBaseURL is the domain name used for storage requests when a
	// default client is created.
	DefaultBaseURL = "core.windows.net"

	// DefaultAPIVersion is the  Azure Storage API version string used when a
	// basic client is created.
	DefaultAPIVersion = "2014-02-14"

	defaultUseHTTPS = true

	blobServiceName  = "blob"
	tableServiceName = "table"
	queueServiceName = "queue"
	fileServiceName  = "file"
)

// Client is the object that needs to be constructed to perform
// operations on the storage account.
type Client struct {
	accountName string
	accountKey  []byte
	useHTTPS    bool
	baseURL     string
	apiVersion  string
}

type storageResponse struct {
	statusCode int
	headers    http.Header
	body       io.ReadCloser
}

// AzureStorageServiceError contains fields of the error response from
// Azure Storage Service REST API. See https://msdn.microsoft.com/en-us/library/azure/dd179382.aspx
// Some fields might be specific to certain calls.
type AzureStorageServiceError struct {
	Code                      string `xml:"Code"`
	Message                   string `xml:"Message"`
	AuthenticationErrorDetail string `xml:"AuthenticationErrorDetail"`
	QueryParameterName        string `xml:"QueryParameterName"`
	QueryParameterValue       string `xml:"QueryParameterValue"`
	Reason                    string `xml:"Reason"`
	StatusCode                int
	RequestID                 string
}

// UnexpectedStatusCodeError is returned when a storage service responds with neither an error
// nor with an HTTP status code indicating success.
type UnexpectedStatusCodeError struct {
	allowed []int
	got     int
}

func (e UnexpectedStatusCodeError) Error() string {
	s := func(i int) string { return fmt.Sprintf("%d %s", i, http.StatusText(i)) }

	got := s(e.got)
	expected := []string{}
	for _, v := range e.allowed {
		expected = append(expected, s(v))
	}
	return fmt.Sprintf("storage: status code from service response is %s; was expecting %s", got, strings.Join(expected, " or "))
}

// Got is the actual status code returned by Azure.
func (e UnexpectedStatusCodeError) Got() int {
	return e.got
}

// NewBasicClient constructs a Client with given storage service name and
// key.
func NewBasicClient(accountName, accountKey string) (Client, error) {
	return NewClient(accountName, accountKey, DefaultBaseURL, DefaultAPIVersion, defaultUseHTTPS)
}

// NewClient constructs a Client. This should be used if the caller wants
// to specify whether to use HTTPS, a specific REST API version or a custom
// storage endpoint than Azure Public Cloud.
func NewClient(accountName, accountKey, blobServiceBaseURL, apiVersion string, useHTTPS bool) (Client, error) {
	var c Client
	if accountName == "" {
		return c, fmt.Errorf("azure: account name required")
	} else if accountKey == "" {
		return c, fmt.Errorf("azure: account key required")
	} else if blobServiceBaseURL == "" {
		return c, fmt.Errorf("azure: base storage service url required")
	}

	key, err := base64.StdEncoding.DecodeString(accountKey)
	if err != nil {
		return c, err
	}

	return Client{
		accountName: accountName,
		accountKey:  key,
		useHTTPS:    useHTTPS,
		baseURL:     blobServiceBaseURL,
		apiVersion:  apiVersion,
	}, nil
}

func (c Client) getBaseURL(service string) string {
	scheme := "http"
	if c.useHTTPS {
		scheme = "https"
	}

	host := fmt.Sprintf("%s.%s.%s", c.accountName, service, c.baseURL)

	u := &url.URL{
		Scheme: scheme,
		Host:   host}
	return u.String()
}

func (c Client) getEndpoint(service, path string, params url.Values) string {
	u, err := url.Parse(c.getBaseURL(service))
	if err != nil {
		// really should not be happening
		panic(err)
	}

	if path == "" {
		path = "/" // API doesn't accept path segments not starting with '/'
	}

	u.Path = path
	u.RawQuery = params.Encode()
	return u.String()
}

// GetBlobService returns a BlobStorageClient which can operate on the blob
// service of the storage account.
func (c Client) GetBlobService() BlobStorageClient {
	return BlobStorageClient{c}
}

// GetQueueService returns a QueueServiceClient which can operate on the queue
// service of the storage account.
func (c Client) GetQueueService() QueueServiceClient {
	return QueueServiceClient{c}
}

// GetFileService returns a FileServiceClient which can operate on the file
// service of the storage account.
func (c Client) GetFileService() FileServiceClient {
	return FileServiceClient{c}
}

func (c Client) createAuthorizationHeader(canonicalizedString string) string {
	signature := c.computeHmac256(canonicalizedString)
	return fmt.Sprintf("%s %s:%s", "SharedKey", c.accountName, signature)
}

func (c Client) getAuthorizationHeader(verb, url string, headers map[string]string) (string, error) {
	canonicalizedResource, err := c.buildCanonicalizedResource(url)
	if err != nil {
		return "", err
	}

	canonicalizedString := c.buildCanonicalizedString(verb, headers, canonicalizedResource)
	return c.createAuthorizationHeader(canonicalizedString), nil
}

func (c Client) getStandardHeaders() map[string]string {
	return map[string]string{
		"x-ms-version": c.apiVersion,
		"x-ms-date":    currentTimeRfc1123Formatted(),
	}
}

func (c Client) buildCanonicalizedHeader(headers map[string]string) string {
	cm := make(map[string]string)

	for k, v := range headers {
		headerName := strings.TrimSpace(strings.ToLower(k))
		match, _ := regexp.MatchString("x-ms-", headerName)
		if match {
			cm[headerName] = v
		}
	}

	if len(cm) == 0 {
		return ""
	}

	keys := make([]string, 0, len(cm))
	for key := range cm {
		keys = append(keys, key)
	}

	sort.Strings(keys)

	ch := ""

	for i, key := range keys {
		if i == len(keys)-1 {
			ch += fmt.Sprintf("%s:%s", key, cm[key])
		} else {
			ch += fmt.Sprintf("%s:%s\n", key, cm[key])
		}
	}
	return ch
}

func (c Client) buildCanonicalizedResource(uri string) (string, error) {
	errMsg := "buildCanonicalizedResource error: %s"
	u, err := url.Parse(uri)
	if err != nil {
		return "", fmt.Errorf(errMsg, err.Error())
	}

	cr := "/" + c.accountName
	if len(u.Path) > 0 {
		cr += u.Path
	}

	params, err := url.ParseQuery(u.RawQuery)
	if err != nil {
		return "", fmt.Errorf(errMsg, err.Error())
	}

	if len(params) > 0 {
		cr += "\n"
		keys := make([]string, 0, len(params))
		for key := range params {
			keys = append(keys, key)
		}

		sort.Strings(keys)

		for i, key := range keys {
			if len(params[key]) > 1 {
				sort.Strings(params[key])
			}

			if i == len(keys)-1 {
				cr += fmt.Sprintf("%s:%s", key, strings.Join(params[key], ","))
			} else {
				cr += fmt.Sprintf("%s:%s\n", key, strings.Join(params[key], ","))
			}
		}
	}
	return cr, nil
}

func (c Client) buildCanonicalizedString(verb string, headers map[string]string, canonicalizedResource string) string {
	canonicalizedString := fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s",
		verb,
		headers["Content-Encoding"],
		headers["Content-Language"],
		headers["Content-Length"],
		headers["Content-MD5"],
		headers["Content-Type"],
		headers["Date"],
		headers["If-Modified-Since"],
		headers["If-Match"],
		headers["If-None-Match"],
		headers["If-Unmodified-Since"],
		headers["Range"],
		c.buildCanonicalizedHeader(headers),
		canonicalizedResource)

	return canonicalizedString
}

func (c Client) exec(verb, url string, headers map[string]string, body io.Reader) (*storageResponse, error) {
	authHeader, err := c.getAuthorizationHeader(verb, url, headers)
	if err != nil {
		return nil, err
	}
	headers["Authorization"] = authHeader

	if err != nil {
		return nil, err
	}

	req, err := http.NewRequest(verb, url, body)
	if err != nil {
		return nil, errors.New("azure/storage: error creating request: " + err.Error())
	}
	if clstr, ok := headers["Content-Length"]; ok {
		// content length header is being signed, but completely ignored by golang.
		// instead we have to use the ContentLength property on the request struct
		// (see https://golang.org/src/net/http/request.go?s=18140:18370#L536 and
		// https://golang.org/src/net/http/transfer.go?s=1739:2467#L49)
		req.ContentLength, err = strconv.ParseInt(clstr, 10, 64)
		if err != nil {
			return nil, err
		}
	}
	for k, v := range headers {
		req.Header.Add(k, v)
	}
	httpClient := http.Client{}
	resp, err := httpClient.Do(req)
	if err != nil {
		return nil, err
	}

	statusCode := resp.StatusCode
	if statusCode >= 400 && statusCode <= 505 {
		var respBody []byte
		respBody, err = readResponseBody(resp)
		if err != nil {
			return nil, err
		}

		if len(respBody) == 0 {
			// no error in response body
			err = fmt.Errorf("storage: service returned without a response body (%s)", resp.Status)
		} else {
			// response contains storage service error object, unmarshal
			storageErr, errIn := serviceErrFromXML(respBody, resp.StatusCode, resp.Header.Get("x-ms-request-id"))
			if err != nil { // error unmarshaling the error response
				err = errIn
			}
			err = storageErr
		}
		return &storageResponse{
			statusCode: resp.StatusCode,
			headers:    resp.Header,
			body:       ioutil.NopCloser(bytes.NewReader(respBody)), /* restore the body */
		}, err
	}

	return &storageResponse{
		statusCode: resp.StatusCode,
		headers:    resp.Header,
		body:       resp.Body}, nil
}

func readResponseBody(resp *http.Response) ([]byte, error) {
	defer resp.Body.Close()
	out, err := ioutil.ReadAll(resp.Body)
	if err == io.EOF {
		err = nil
	}
	return out, err
}

func serviceErrFromXML(body []byte, statusCode int, requestID string) (AzureStorageServiceError, error) {
	var storageErr AzureStorageServiceError
	if err := xml.Unmarshal(body, &storageErr); err != nil {
		return storageErr, err
	}
	storageErr.StatusCode = statusCode
	storageErr.RequestID = requestID
	return storageErr, nil
}

func (e AzureStorageServiceError) Error() string {
	return fmt.Sprintf("storage: service returned error: StatusCode=%d, ErrorCode=%s, ErrorMessage=%s, RequestId=%s", e.StatusCode, e.Code, e.Message, e.RequestID)
}

// checkRespCode returns UnexpectedStatusError if the given response code is not
// one of the allowed status codes; otherwise nil.
func checkRespCode(respCode int, allowed []int) error {
	for _, v := range allowed {
		if respCode == v {
			return nil
		}
	}
	return UnexpectedStatusCodeError{allowed, respCode}
}
<|endoftext|>


<commit_before>// errchk $G $D/$F.go

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

package main

var notmain func()

func main() {
	var x = &main;		// ERROR "address of function"
	main = notmain;	// ERROR "assign to function"
}
<commit_msg>Recognize gccgo error messages:<commit_after>// errchk $G $D/$F.go

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

package main

var notmain func()

func main() {
	var x = &main;		// ERROR "address of function|invalid"
	main = notmain;	// ERROR "assign to function|invalid"
}
<|endoftext|>


<commit_before>package db

import (
	"context"
	"fmt"
	"strconv"

	"database/sql"
	"github.com/amitu/amalgam"
	"github.com/amitu/amalgam/django"
	"github.com/juju/errors"
	"time"
)

type group struct {
	DId   int64  `db:"id"`
	DName string `db:"name"`

	store *store
}

func (g *group) ID() int64 {
	return g.DId
}

func (g *group) Name() string {
	return g.DName
}

func (g *group) Permissions(ctx context.Context) ([]django.Permission, error) {
	perms := []*permission{}
	q := `
		SELECT
			auth_permission.id,
			auth_permission.name,
			auth_permission.codename
		FROM
			auth_permission
		JOIN auth_group_permissions
			ON
				(auth_permission.id = auth_group_permissions.permission_id)
		WHERE
			group_id = $1
	`

	err := amalgam.QueryIntoSlice(ctx, &perms, q, g.DId)
	if err != nil {
		return nil, errors.Trace(err)
	}

	cperms := []django.Permission{}
	for _, g := range perms {
		cperms = append(cperms, g)
	}

	return cperms, nil
}

type permission struct {
	DId   int64  `db:"id"`
	DName string `db:"name"`
	DCode string `db:"codename"`

	store *astore
}

func (p *permission) ID() int64 {
	return p.DId
}

func (p *permission) Name() string {
	return p.DName
}

func (p *permission) Code() string {
	return p.DCode
}

type user struct {
	DID     int64 `db:"id" json:"id"`
	DFields map[string]interface{}
	store   *astore
}

func (u *user) ID() int64 {
	return u.DID
}

func (u *user) Field(key string) (interface{}, bool) {
	val, ok := u.DFields[key]
	if !ok {
		return nil, false
	}

	return val, true
}

func (u *user) Email() string {
	panic("not implemented")
	return ""
}

func (u *user) CheckPassword(string) bool {
	panic("not implemented")
	return false
}

func (u *user) Roles() ([]string, error) {
	panic("not implemented")
	return nil, nil
}

func (u *user) Permissions() ([]django.Permission, error) {
	panic("not implemented")
	return nil, nil
}

func (u *user) HasRole(ctx context.Context, roleId int64) (bool, error) {
	query := "SELECT count(*) FROM " + u.store.UserGroupsTable +
		" WHERE user_id = $1 AND group_id = $2"
	num, err := amalgam.QueryIntoInt(ctx, query, u.DID, roleId)
	if err != nil {
		return false, errors.Trace(err)
	}

	return num != 0, nil
}

func (u *user) HasPermission(string) (bool, error) {
	panic("not implemented")
	return false, nil
}

func (u *user) SetName(string, bool) error {
	panic("not implemented")
	return nil
}

func (u *user) SetEmail(string, bool) error {
	panic("not implemented")
	return nil
}

func (u *user) SetPassword(string, bool) error {
	panic("not implemented")
	return nil
}

func (u *user) Save(ctx context.Context) error {
	var values string
	index := 1
	var fields []interface{}
	for k, v := range u.DFields {
		if k == "id" {
			continue
		}
		values = values + k + "=$" + strconv.Itoa(index) + ","
		fields = append(fields, v)
		index++
	}
	values = values + "id" + "=$" + strconv.Itoa(index)
	fields = append(fields, u.DFields["id"])

	query := "UPDATE " + u.store.UserTable + " SET " +
		values + "WHERE id=$" + strconv.Itoa(index) + ";"

	err := amalgam.Exec(ctx, query, fields...)
	if err != nil {
		return errors.Trace(err)
	}

	return nil
}

func (u *user) RefreshFromDB(ctx context.Context) error {
	query := "SELECT * FROM " + u.store.AuthTables.UserTable +
		" WHERE id = $1"

	userMap, err := amalgam.QueryIntoMap(ctx, query, u.DID)
	if err != nil {
		return errors.Trace(err)
	}
	u.DFields = userMap

	return nil
}

func (u *user) Deactivate(reason string) error {
	panic("not implemented")
	return nil
}

func (u *user) IsSuperUser() bool {
	panic("not implemented")
	return false
}

type AuthTables struct {
	UserTable             string
	GroupTable            string
	PermissionTable       string
	UserGroupsTable       string
	UserPermissionsTable  string
	GroupPermissionsTable string
}

func updateAuthTablesWithDefault(at *AuthTables) {
	if at.UserTable == "" {
		at.UserTable = "auth_user"
	}
	if at.UserTable == "" {
		at.GroupTable = "auth_group"
	}
	if at.PermissionTable == "" {
		at.PermissionTable = "auth_permission"
	}
	if at.UserGroupsTable == "" {
		at.UserGroupsTable = "auth_user_groups"
	}
	if at.UserPermissionsTable == "" {
		at.UserPermissionsTable = "auth_user_user_permissions"
	}
	if at.GroupPermissionsTable == "" {
		at.GroupPermissionsTable = "auth_group_permissions"
	}
}

type astore struct {
	AuthTables
}

func (s *astore) Groups(ctx context.Context) ([]django.Group, error) {
	groups := []*group{}
	query := fmt.Sprintf("SELECT * FROM %s", s.GroupTable)
	err := amalgam.QueryIntoSlice(ctx, &groups, query)
	if err != nil {
		return nil, errors.Trace(err)
	}

	cgroups := []django.Group{}
	for _, g := range groups {
		cgroups = append(cgroups, g)
	}

	return cgroups, nil
}

func (s *astore) GroupByID(ctx context.Context, id int64) (django.Group, error) {
	group := group{}
	query := fmt.Sprintf("SELECT * FROM %s WHERE id = $1", s.GroupTable)
	err := amalgam.QueryIntoStruct(ctx, &group, query, id)
	if err != nil {
		return nil, errors.Trace(err)
	}

	return &group, nil
}

func (s *astore) GroupByName(
	ctx context.Context, name string,
) (django.Group, error) {
	group := group{}
	query := fmt.Sprintf("SELECT * FROM %s WHERE name = $1", s.GroupTable)
	err := amalgam.QueryIntoStruct(ctx, &group, query, name)
	if err != nil {
		return nil, errors.Trace(err)
	}

	return &group, nil
}

func (s *astore) UserByID(ctx context.Context, id int64) (django.User, error) {
	u := &user{}
	query := "SELECT * FROM " + s.UserTable +
		" WHERE id = $1"

	userMap, err := amalgam.QueryIntoMap(ctx, query, id)
	if err != nil {
		return u, errors.Trace(err)
	}

	u.DID = userMap["id"].(int64)
	u.DFields = userMap
	u.store = s

	return u, nil
}

func (s *astore) UserByAPIKey(
	ctx context.Context, apiKey string,
) (django.User, error) {
	u := &user{}
	query := "SELECT * FROM " + s.UserTable +
		" WHERE id = (select user_id from acko_userprofile where api_key= $1)"

	userMap, err := amalgam.QueryIntoMap(ctx, query, apiKey)
	if err != nil {
		return u, errors.Trace(err)
	}

	u.DID = userMap["id"].(int64)
	u.DFields = userMap
	u.store = s

	return u, nil
}

func (s *astore) UserByPhone(
	ctx context.Context, phone string,
) (django.User, error) {
	u := &user{}
	query := "SELECT * FROM " + s.UserTable +
		" WHERE phone = $1"

	userMap, err := amalgam.QueryIntoMap(ctx, query, phone)
	if err != nil {
		return u, errors.Trace(err)
	}

	u.DID = userMap["id"].(int64)
	u.DFields = userMap
	u.store = s

	return u, nil
}

func (s *astore) GetOrCreateUser(
	ctx context.Context, details map[string]interface{},
) (django.User, error) {
	u := &user{}
	query := "SELECT * FROM " + s.UserTable +
		" WHERE phone = $1"

	phone := details["phone"].(string)
	first_name := details["first_name"].(string)
	last_name := details["first_name"].(string)

	userMap, err := amalgam.QueryIntoMap(ctx, query, phone)
	if err != nil {
		if err.Error() == sql.ErrNoRows.Error() {
			query := "INSERT INTO " +
				s.UserTable + "(" + "phone, password, is_superuser, " +
				"first_name, " + "last_name, is_staff, is_active, joined_on, " +
				"available, idle, is_online, on_call) " + "VALUES " +
				"($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)"

			err := amalgam.Exec(
				ctx, query, phone, "asd", false, first_name, last_name,
				false, false, time.Now(), false, true, false, false,
			)
			if err != nil {
				return nil, errors.Trace(err)
			}

			query = "SELECT * FROM " + s.UserTable +
				" WHERE phone = $1"

			userMap, err = amalgam.QueryIntoMap(ctx, query, phone)
		} else {
			return u, errors.Trace(err)
		}
	}

	u.DID = userMap["id"].(int64)
	u.DFields = userMap
	u.store = s

	return u, nil
}

func (s *astore) UserByEmail(context.Context, string) (django.User, error) {
	panic("not implemented")
	return nil, nil
}

func (s *astore) Authenticate(
	context.Context, string, string,
) (django.User, error) {
	panic("not implemented")
	return nil, nil
}

func (s *astore) Permissions(ctx context.Context) ([]django.Permission, error) {
	panic("not implemented")
	return nil, nil
}

func (s *astore) PermissionByID(ctx context.Context, id int64) (django.Permission, error) {
	perm := permission{}
	query := fmt.Sprintf("select * from %s where id = $1", s.PermissionTable)
	err := amalgam.QueryIntoStruct(ctx, &permission{}, query, id)
	if err != nil {
		return nil, errors.Trace(err)
	}

	return &perm, nil
}

func (s *astore) PermissionByCode(
	ctx context.Context, code string,
) (django.Permission, error) {
	perm := permission{}
	query := fmt.Sprintf("select * from %s where codename = $1", s.PermissionTable)
	err := amalgam.QueryIntoStruct(ctx, &permission{}, query, code)
	if err != nil {
		return nil, errors.Trace(err)
	}

	return &perm, nil
}

func NewCustomAuthStore(ctx context.Context, auth_tables AuthTables) (django.AuthStore, error) {
	updateAuthTablesWithDefault(&auth_tables)
	query := fmt.Sprintf("SELECT count(*) FROM %s", auth_tables.GroupTable)
	gcount, err := amalgam.QueryIntoInt(ctx, query)
	if err != nil {
		return nil, errors.Trace(err)
	}

	query = fmt.Sprintf("SELECT count(*) FROM %s", auth_tables.PermissionTable)
	pcount, err := amalgam.QueryIntoInt(ctx, query)
	if err != nil {
		return nil, errors.Trace(err)
	}

	query = fmt.Sprintf("SELECT count(*) FROM %s", auth_tables.UserTable)
	ucount, err := amalgam.QueryIntoInt(ctx, query)
	if err != nil {
		return nil, errors.Trace(err)
	}

	amalgam.LOGGER.Debug(
		"found_auth_tables", "groups", gcount,
		"permissions", pcount, "users", ucount,
	)
	return &astore{auth_tables}, nil
}

func NewAuthStore(ctx context.Context) (django.AuthStore, error) {
	auth_tables := AuthTables{}
	updateAuthTablesWithDefault(&auth_tables)
	return NewCustomAuthStore(ctx, auth_tables)
}
<commit_msg>minor<commit_after>package db

import (
	"context"
	"fmt"
	"strconv"

	"crypto/rand"
	"database/sql"
	"github.com/amitu/amalgam"
	"github.com/amitu/amalgam/django"
	"github.com/juju/errors"
	"time"
)

type group struct {
	DId   int64  `db:"id"`
	DName string `db:"name"`

	store *store
}

func (g *group) ID() int64 {
	return g.DId
}

func (g *group) Name() string {
	return g.DName
}

func (g *group) Permissions(ctx context.Context) ([]django.Permission, error) {
	perms := []*permission{}
	q := `
		SELECT
			auth_permission.id,
			auth_permission.name,
			auth_permission.codename
		FROM
			auth_permission
		JOIN auth_group_permissions
			ON
				(auth_permission.id = auth_group_permissions.permission_id)
		WHERE
			group_id = $1
	`

	err := amalgam.QueryIntoSlice(ctx, &perms, q, g.DId)
	if err != nil {
		return nil, errors.Trace(err)
	}

	cperms := []django.Permission{}
	for _, g := range perms {
		cperms = append(cperms, g)
	}

	return cperms, nil
}

type permission struct {
	DId   int64  `db:"id"`
	DName string `db:"name"`
	DCode string `db:"codename"`

	store *astore
}

func (p *permission) ID() int64 {
	return p.DId
}

func (p *permission) Name() string {
	return p.DName
}

func (p *permission) Code() string {
	return p.DCode
}

type user struct {
	DID     int64 `db:"id" json:"id"`
	DFields map[string]interface{}
	store   *astore
}

func (u *user) ID() int64 {
	return u.DID
}

func (u *user) Field(key string) (interface{}, bool) {
	val, ok := u.DFields[key]
	if !ok {
		return nil, false
	}

	return val, true
}

func (u *user) Email() string {
	panic("not implemented")
	return ""
}

func (u *user) CheckPassword(string) bool {
	panic("not implemented")
	return false
}

func (u *user) Roles() ([]string, error) {
	panic("not implemented")
	return nil, nil
}

func (u *user) Permissions() ([]django.Permission, error) {
	panic("not implemented")
	return nil, nil
}

func (u *user) HasRole(ctx context.Context, roleId int64) (bool, error) {
	query := "SELECT count(*) FROM " + u.store.UserGroupsTable +
		" WHERE user_id = $1 AND group_id = $2"
	num, err := amalgam.QueryIntoInt(ctx, query, u.DID, roleId)
	if err != nil {
		return false, errors.Trace(err)
	}

	return num != 0, nil
}

func (u *user) HasPermission(string) (bool, error) {
	panic("not implemented")
	return false, nil
}

func (u *user) SetName(string, bool) error {
	panic("not implemented")
	return nil
}

func (u *user) SetEmail(string, bool) error {
	panic("not implemented")
	return nil
}

func (u *user) SetPassword(string, bool) error {
	panic("not implemented")
	return nil
}

func (u *user) Save(ctx context.Context) error {
	var values string
	index := 1
	var fields []interface{}
	for k, v := range u.DFields {
		if k == "id" {
			continue
		}
		values = values + k + "=$" + strconv.Itoa(index) + ","
		fields = append(fields, v)
		index++
	}
	values = values + "id" + "=$" + strconv.Itoa(index)
	fields = append(fields, u.DFields["id"])

	query := "UPDATE " + u.store.UserTable + " SET " +
		values + "WHERE id=$" + strconv.Itoa(index) + ";"

	err := amalgam.Exec(ctx, query, fields...)
	if err != nil {
		return errors.Trace(err)
	}

	return nil
}

func (u *user) RefreshFromDB(ctx context.Context) error {
	query := "SELECT * FROM " + u.store.AuthTables.UserTable +
		" WHERE id = $1"

	userMap, err := amalgam.QueryIntoMap(ctx, query, u.DID)
	if err != nil {
		return errors.Trace(err)
	}
	u.DFields = userMap

	return nil
}

func (u *user) Deactivate(reason string) error {
	panic("not implemented")
	return nil
}

func (u *user) IsSuperUser() bool {
	panic("not implemented")
	return false
}

type AuthTables struct {
	UserTable             string
	GroupTable            string
	PermissionTable       string
	UserGroupsTable       string
	UserPermissionsTable  string
	GroupPermissionsTable string
}

func updateAuthTablesWithDefault(at *AuthTables) {
	if at.UserTable == "" {
		at.UserTable = "auth_user"
	}
	if at.UserTable == "" {
		at.GroupTable = "auth_group"
	}
	if at.PermissionTable == "" {
		at.PermissionTable = "auth_permission"
	}
	if at.UserGroupsTable == "" {
		at.UserGroupsTable = "auth_user_groups"
	}
	if at.UserPermissionsTable == "" {
		at.UserPermissionsTable = "auth_user_user_permissions"
	}
	if at.GroupPermissionsTable == "" {
		at.GroupPermissionsTable = "auth_group_permissions"
	}
}

type astore struct {
	AuthTables
}

func (s *astore) Groups(ctx context.Context) ([]django.Group, error) {
	groups := []*group{}
	query := fmt.Sprintf("SELECT * FROM %s", s.GroupTable)
	err := amalgam.QueryIntoSlice(ctx, &groups, query)
	if err != nil {
		return nil, errors.Trace(err)
	}

	cgroups := []django.Group{}
	for _, g := range groups {
		cgroups = append(cgroups, g)
	}

	return cgroups, nil
}

func (s *astore) GroupByID(ctx context.Context, id int64) (django.Group, error) {
	group := group{}
	query := fmt.Sprintf("SELECT * FROM %s WHERE id = $1", s.GroupTable)
	err := amalgam.QueryIntoStruct(ctx, &group, query, id)
	if err != nil {
		return nil, errors.Trace(err)
	}

	return &group, nil
}

func (s *astore) GroupByName(
	ctx context.Context, name string,
) (django.Group, error) {
	group := group{}
	query := fmt.Sprintf("SELECT * FROM %s WHERE name = $1", s.GroupTable)
	err := amalgam.QueryIntoStruct(ctx, &group, query, name)
	if err != nil {
		return nil, errors.Trace(err)
	}

	return &group, nil
}

func (s *astore) UserByID(ctx context.Context, id int64) (django.User, error) {
	u := &user{}
	query := "SELECT * FROM " + s.UserTable +
		" WHERE id = $1"

	userMap, err := amalgam.QueryIntoMap(ctx, query, id)
	if err != nil {
		return u, errors.Trace(err)
	}

	u.DID = userMap["id"].(int64)
	u.DFields = userMap
	u.store = s

	return u, nil
}

func (s *astore) UserByAPIKey(
	ctx context.Context, apiKey string,
) (django.User, error) {
	u := &user{}
	query := "SELECT * FROM " + s.UserTable +
		" WHERE id = (select user_id from acko_userprofile where api_key= $1)"

	userMap, err := amalgam.QueryIntoMap(ctx, query, apiKey)
	if err != nil {
		return u, errors.Trace(err)
	}

	u.DID = userMap["id"].(int64)
	u.DFields = userMap
	u.store = s

	return u, nil
}

func (s *astore) UserByPhone(
	ctx context.Context, phone string,
) (django.User, error) {
	u := &user{}
	query := "SELECT * FROM " + s.UserTable +
		" WHERE phone = $1"

	userMap, err := amalgam.QueryIntoMap(ctx, query, phone)
	if err != nil {
		return u, errors.Trace(err)
	}

	u.DID = userMap["id"].(int64)
	u.DFields = userMap
	u.store = s

	return u, nil
}

func (s *astore) GetOrCreateUser(
	ctx context.Context, details map[string]interface{},
) (django.User, error) {
	u := &user{}
	query := "SELECT * FROM " + s.UserTable +
		" WHERE phone = $1"

	phone := details["phone"].(string)
	first_name := details["first_name"].(string)
	last_name := details["first_name"].(string)

	userMap, err := amalgam.QueryIntoMap(ctx, query, phone)
	if err != nil {
		if err.Error() == sql.ErrNoRows.Error() {
			b := make([]byte, 8)
			if _, err := rand.Read(b); err != nil {
				panic(err)
			}
			password := fmt.Sprintf("%X", b)

			query := "INSERT INTO " +
				s.UserTable + "(" + "phone, password, is_superuser, " +
				"first_name, " + "last_name, is_staff, is_active, joined_on, " +
				"available, idle, is_online, on_call) " + "VALUES " +
				"($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)"

			err := amalgam.Exec(
				ctx, query, phone, password, false, first_name, last_name,
				false, false, time.Now(), false, true, false, false,
			)
			if err != nil {
				return nil, errors.Trace(err)
			}

			query = "SELECT * FROM " + s.UserTable +
				" WHERE phone = $1"

			userMap, err = amalgam.QueryIntoMap(ctx, query, phone)
		} else {
			return u, errors.Trace(err)
		}
	}

	u.DID = userMap["id"].(int64)
	u.DFields = userMap
	u.store = s

	return u, nil
}

func (s *astore) UserByEmail(context.Context, string) (django.User, error) {
	panic("not implemented")
	return nil, nil
}

func (s *astore) Authenticate(
	context.Context, string, string,
) (django.User, error) {
	panic("not implemented")
	return nil, nil
}

func (s *astore) Permissions(ctx context.Context) ([]django.Permission, error) {
	panic("not implemented")
	return nil, nil
}

func (s *astore) PermissionByID(ctx context.Context, id int64) (django.Permission, error) {
	perm := permission{}
	query := fmt.Sprintf("select * from %s where id = $1", s.PermissionTable)
	err := amalgam.QueryIntoStruct(ctx, &permission{}, query, id)
	if err != nil {
		return nil, errors.Trace(err)
	}

	return &perm, nil
}

func (s *astore) PermissionByCode(
	ctx context.Context, code string,
) (django.Permission, error) {
	perm := permission{}
	query := fmt.Sprintf("select * from %s where codename = $1", s.PermissionTable)
	err := amalgam.QueryIntoStruct(ctx, &permission{}, query, code)
	if err != nil {
		return nil, errors.Trace(err)
	}

	return &perm, nil
}

func NewCustomAuthStore(ctx context.Context, auth_tables AuthTables) (django.AuthStore, error) {
	updateAuthTablesWithDefault(&auth_tables)
	query := fmt.Sprintf("SELECT count(*) FROM %s", auth_tables.GroupTable)
	gcount, err := amalgam.QueryIntoInt(ctx, query)
	if err != nil {
		return nil, errors.Trace(err)
	}

	query = fmt.Sprintf("SELECT count(*) FROM %s", auth_tables.PermissionTable)
	pcount, err := amalgam.QueryIntoInt(ctx, query)
	if err != nil {
		return nil, errors.Trace(err)
	}

	query = fmt.Sprintf("SELECT count(*) FROM %s", auth_tables.UserTable)
	ucount, err := amalgam.QueryIntoInt(ctx, query)
	if err != nil {
		return nil, errors.Trace(err)
	}

	amalgam.LOGGER.Debug(
		"found_auth_tables", "groups", gcount,
		"permissions", pcount, "users", ucount,
	)
	return &astore{auth_tables}, nil
}

func NewAuthStore(ctx context.Context) (django.AuthStore, error) {
	auth_tables := AuthTables{}
	updateAuthTablesWithDefault(&auth_tables)
	return NewCustomAuthStore(ctx, auth_tables)
}
<|endoftext|>


<commit_before>package sms

import "encoding/json"

type NexmoSms struct {
	ApiKey    string `json:"api_key,omitempty"`
	ApiSecret string `json:"api_secret,omitempty"`
	To        string `json:"to"`
	From      string `json:"from"`
	Text      string `json:"text"`
}

func (sms *NexmoSms) EncodeNexmoSms(apiKey, apiSecret string) ([]byte, error) {
	sms.ApiKey = apiKey
	sms.ApiSecret = apiSecret

	d, err := json.Marshal(&sms)
	if err != nil {
		logger.WithField("error", err.Error()).Error("Could not encode sms as json")
		return nil, err
	}
	return d, nil
}
<commit_msg>Added client-ref<commit_after>package sms

import "encoding/json"

type NexmoSms struct {
	ApiKey    string `json:"api_key,omitempty"`
	ApiSecret string `json:"api_secret,omitempty"`
	To        string `json:"to"`
	From      string `json:"from"`
	Text      string `json:"text"`
	ClientRef string `json:"client-ref"`
}

func (sms *NexmoSms) EncodeNexmoSms(apiKey, apiSecret string) ([]byte, error) {
	sms.ApiKey = apiKey
	sms.ApiSecret = apiSecret

	d, err := json.Marshal(&sms)
	if err != nil {
		logger.WithField("error", err.Error()).Error("Could not encode sms as json")
		return nil, err
	}
	return d, nil
}
<|endoftext|>


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

package service

import (
	"github.com/globocom/tsuru/action"
	"launchpad.net/gocheck"
	"net/http"
	"net/http/httptest"
	"sync/atomic"
)

func (s *S) TestCreateServiceInstancMinParams(c *gocheck.C) {
	c.Assert(createServiceInstance.MinParams, gocheck.Equals, 2)
}

func (s *S) TestCreateServiceInstancName(c *gocheck.C) {
	c.Assert(createServiceInstance.Name, gocheck.Equals, "create-service-instance")
}

func (s *S) TestCreateServiceInstanceForward(c *gocheck.C) {
	var requests int32
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusNoContent)
		atomic.AddInt32(&requests, 1)
	}))
	defer ts.Close()
	srv := Service{Name: "mongodb", Endpoint: map[string]string{"production": ts.URL}}
	err := s.conn.Services().Insert(&srv)
	c.Assert(err, gocheck.IsNil)
	defer s.conn.Services().RemoveId(srv.Name)
	instance := ServiceInstance{Name: "mysql"}
	ctx := action.FWContext{
		Params: []interface{}{srv, instance},
	}
	r, err := createServiceInstance.Forward(ctx)
	c.Assert(err, gocheck.IsNil)
	a, ok := r.(ServiceInstance)
	c.Assert(ok, gocheck.Equals, true)
	c.Assert(a.Name, gocheck.Equals, instance.Name)
	c.Assert(atomic.LoadInt32(&requests), gocheck.Equals, int32(1))
}

func (s *S) TestCreateServiceInstanceForwardInvalidParams(c *gocheck.C) {
	var requests int32
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusNoContent)
		atomic.AddInt32(&requests, 1)
	}))
	defer ts.Close()
	srv := Service{Name: "mongodb", Endpoint: map[string]string{"production": ts.URL}}
	err := s.conn.Services().Insert(&srv)
	c.Assert(err, gocheck.IsNil)
	defer s.conn.Services().RemoveId(srv.Name)
	ctx := action.FWContext{Params: []interface{}{"", ""}}
	_, err = createServiceInstance.Forward(ctx)
	c.Assert(err, gocheck.NotNil)
	c.Assert(err.Error(), gocheck.Equals, "First parameter must be a Service.")
	ctx = action.FWContext{Params: []interface{}{srv, ""}}
	_, err = createServiceInstance.Forward(ctx)
	c.Assert(err, gocheck.NotNil)
	c.Assert(err.Error(), gocheck.Equals, "Second parameter must be a ServiceInstance.")
}

func (s *S) TestCreateServiceInstanceBackward(c *gocheck.C) {
	var requests int32
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusNoContent)
		atomic.AddInt32(&requests, 1)
	}))
	defer ts.Close()
	srv := Service{Name: "mongodb", Endpoint: map[string]string{"production": ts.URL}}
	err := s.conn.Services().Insert(&srv)
	c.Assert(err, gocheck.IsNil)
	defer s.conn.Services().RemoveId(srv.Name)
	instance := ServiceInstance{Name: "mysql"}
	ctx := action.BWContext{Params: []interface{}{srv, instance}}
	createServiceInstance.Backward(ctx)
	c.Assert(atomic.LoadInt32(&requests), gocheck.Equals, int32(1))
}
<commit_msg>service: testing create service backward params.<commit_after>// Copyright 2013 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package service

import (
	"github.com/globocom/tsuru/action"
	"launchpad.net/gocheck"
	"net/http"
	"net/http/httptest"
	"sync/atomic"
)

func (s *S) TestCreateServiceInstancMinParams(c *gocheck.C) {
	c.Assert(createServiceInstance.MinParams, gocheck.Equals, 2)
}

func (s *S) TestCreateServiceInstancName(c *gocheck.C) {
	c.Assert(createServiceInstance.Name, gocheck.Equals, "create-service-instance")
}

func (s *S) TestCreateServiceInstanceForward(c *gocheck.C) {
	var requests int32
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusNoContent)
		atomic.AddInt32(&requests, 1)
	}))
	defer ts.Close()
	srv := Service{Name: "mongodb", Endpoint: map[string]string{"production": ts.URL}}
	err := s.conn.Services().Insert(&srv)
	c.Assert(err, gocheck.IsNil)
	defer s.conn.Services().RemoveId(srv.Name)
	instance := ServiceInstance{Name: "mysql"}
	ctx := action.FWContext{
		Params: []interface{}{srv, instance},
	}
	r, err := createServiceInstance.Forward(ctx)
	c.Assert(err, gocheck.IsNil)
	a, ok := r.(ServiceInstance)
	c.Assert(ok, gocheck.Equals, true)
	c.Assert(a.Name, gocheck.Equals, instance.Name)
	c.Assert(atomic.LoadInt32(&requests), gocheck.Equals, int32(1))
}

func (s *S) TestCreateServiceInstanceForwardInvalidParams(c *gocheck.C) {
	var requests int32
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusNoContent)
		atomic.AddInt32(&requests, 1)
	}))
	defer ts.Close()
	srv := Service{Name: "mongodb", Endpoint: map[string]string{"production": ts.URL}}
	err := s.conn.Services().Insert(&srv)
	c.Assert(err, gocheck.IsNil)
	defer s.conn.Services().RemoveId(srv.Name)
	ctx := action.FWContext{Params: []interface{}{"", ""}}
	_, err = createServiceInstance.Forward(ctx)
	c.Assert(err, gocheck.NotNil)
	c.Assert(err.Error(), gocheck.Equals, "First parameter must be a Service.")
	ctx = action.FWContext{Params: []interface{}{srv, ""}}
	_, err = createServiceInstance.Forward(ctx)
	c.Assert(err, gocheck.NotNil)
	c.Assert(err.Error(), gocheck.Equals, "Second parameter must be a ServiceInstance.")
}

func (s *S) TestCreateServiceInstanceBackward(c *gocheck.C) {
	var requests int32
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusNoContent)
		atomic.AddInt32(&requests, 1)
	}))
	defer ts.Close()
	srv := Service{Name: "mongodb", Endpoint: map[string]string{"production": ts.URL}}
	err := s.conn.Services().Insert(&srv)
	c.Assert(err, gocheck.IsNil)
	defer s.conn.Services().RemoveId(srv.Name)
	instance := ServiceInstance{Name: "mysql"}
	ctx := action.BWContext{Params: []interface{}{srv, instance}}
	createServiceInstance.Backward(ctx)
	c.Assert(atomic.LoadInt32(&requests), gocheck.Equals, int32(1))
}

func (s *S) TestCreateServiceInstanceBackwardParams(c *gocheck.C) {
	var requests int32
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusNoContent)
		atomic.AddInt32(&requests, 1)
	}))
	defer ts.Close()
	srv := Service{Name: "mongodb", Endpoint: map[string]string{"production": ts.URL}}
	err := s.conn.Services().Insert(&srv)
	c.Assert(err, gocheck.IsNil)
	defer s.conn.Services().RemoveId(srv.Name)
	ctx := action.BWContext{Params: []interface{}{srv, ""}}
	createServiceInstance.Backward(ctx)
	c.Assert(atomic.LoadInt32(&requests), gocheck.Equals, int32(0))
	ctx = action.BWContext{Params: []interface{}{"", ""}}
	createServiceInstance.Backward(ctx)
	c.Assert(atomic.LoadInt32(&requests), gocheck.Equals, int32(0))
}
<|endoftext|>


<commit_before>package service_test

import (
	"fmt"
	"strings"
	"time"

	"github.com/pborman/uuid"
	"github.com/pivotal-cf/cf-redis-smoke-tests/redis"
	"github.com/pivotal-cf/cf-redis-smoke-tests/service/reporter"

	"github.com/pivotal-cf-experimental/cf-test-helpers/services"
	smokeTestCF "github.com/pivotal-cf/cf-redis-smoke-tests/cf"

	. "github.com/onsi/ginkgo"
)

var _ = Describe("Redis Service", func() {
	var (
		testCF = smokeTestCF.CF{
			ShortTimeout: time.Minute * 3,
			LongTimeout:  time.Minute * 15,
			RetryBackoff: redisConfig.Retry.Backoff(),
			MaxRetries:   redisConfig.Retry.MaxRetries(),
		}

		retryInterval = time.Second

		appPath             = "../assets/cf-redis-example-app"
		serviceInstanceName string
		appName             string
		planName            string

		context services.Context
	)

	BeforeSuite(func() {
		context = services.NewContext(cfTestConfig, "redis-test")

		createQuotaArgs := []string{
			"-m", "10G",
			"-r", "1000",
			"-s", "100",
			"--allow-paid-service-plans",
		}

		regularContext := context.RegularUserContext()

		beforeSuiteSteps := []*reporter.Step{
			reporter.NewStep(
				"Connect to CloudFoundry",
				testCF.API(cfTestConfig.ApiEndpoint, cfTestConfig.SkipSSLValidation),
			),
			reporter.NewStep(
				"Log in as admin",
				testCF.Auth(cfTestConfig.AdminUser, cfTestConfig.AdminPassword),
			),
			reporter.NewStep(
				"Create 'redis-smoke-tests' quota",
				testCF.CreateQuota("redis-smoke-test-quota", createQuotaArgs...),
			),
			reporter.NewStep(
				fmt.Sprintf("Create '%s' org", cfTestConfig.OrgName),
				testCF.CreateOrg(cfTestConfig.OrgName, "redis-smoke-test-quota"),
			),
			reporter.NewStep(
				fmt.Sprintf("Enable service access for '%s' org", cfTestConfig.OrgName),
				testCF.EnableServiceAccess(cfTestConfig.OrgName, redisConfig.ServiceName),
			),
			reporter.NewStep(
				fmt.Sprintf("Target '%s' org", cfTestConfig.OrgName),
				testCF.TargetOrg(cfTestConfig.OrgName),
			),
			reporter.NewStep(
				fmt.Sprintf("Create '%s' space", cfTestConfig.SpaceName),
				testCF.CreateSpace(cfTestConfig.SpaceName),
			),
			reporter.NewStep(
				fmt.Sprintf("Create user '%s'", regularContext.Username),
				testCF.CreateUser(regularContext.Username, regularContext.Password),
			),
			reporter.NewStep(
				fmt.Sprintf(
					"Assign user '%s' to 'SpaceManager' role for '%s'",
					regularContext.Username,
					cfTestConfig.SpaceName,
				),
				testCF.SetSpaceRole(regularContext.Username, regularContext.Org, cfTestConfig.SpaceName, "SpaceManager"),
			),
			reporter.NewStep(
				fmt.Sprintf(
					"Assign user '%s' to 'SpaceDeveloper' role for '%s'",
					regularContext.Username,
					cfTestConfig.SpaceName,
				),
				testCF.SetSpaceRole(regularContext.Username, regularContext.Org, cfTestConfig.SpaceName, "SpaceDeveloper"),
			),
			reporter.NewStep(
				fmt.Sprintf(
					"Assign user '%s' to 'SpaceAuditor' role for '%s'",
					regularContext.Username,
					cfTestConfig.SpaceName,
				),
				testCF.SetSpaceRole(regularContext.Username, regularContext.Org, cfTestConfig.SpaceName, "SpaceAuditor"),
			),
			reporter.NewStep(
				"Log out",
				testCF.Logout(),
			),
		}

		smokeTestReporter.RegisterBeforeSuiteSteps(beforeSuiteSteps)

		for _, task := range beforeSuiteSteps {
			task.Perform()
		}
	})

	BeforeEach(func() {
		regularContext := context.RegularUserContext()
		appName = randomName()
		serviceInstanceName = randomName()

		pushArgs := []string{
			"-m", "256M",
			"-p", appPath,
			"-s", "cflinuxfs2",
			"-no-start",
		}

		specSteps := []*reporter.Step{
			reporter.NewStep(
				fmt.Sprintf("Log in as %s", regularContext.Username),
				testCF.Auth(regularContext.Username, regularContext.Password),
			),
			reporter.NewStep(
				fmt.Sprintf("Target '%s' org and '%s' space", cfTestConfig.OrgName, cfTestConfig.SpaceName),
				testCF.TargetOrgAndSpace(cfTestConfig.OrgName, cfTestConfig.SpaceName),
			),
			reporter.NewStep(
				"Push the redis sample app to Cloud Foundry",
				testCF.Push(appName, pushArgs...),
			),
		}

		smokeTestReporter.ClearSpecSteps()
		smokeTestReporter.RegisterSpecSteps(specSteps)

		for _, task := range specSteps {
			task.Perform()
		}
	})

	AfterEach(func() {
		specSteps := []*reporter.Step{
			reporter.NewStep(
				fmt.Sprintf("Unbind the %q plan instance", planName),
				testCF.UnbindService(appName, serviceInstanceName),
			),
			reporter.NewStep(
				fmt.Sprintf("Delete the %q plan instance", planName),
				testCF.DeleteService(serviceInstanceName),
			),
			reporter.NewStep(
				fmt.Sprintf("Ensure service instance for plan %q has been deleted", planName),
				testCF.EnsureServiceInstanceGone(serviceInstanceName),
			),
			reporter.NewStep(
				"Delete the app",
				testCF.Delete(appName),
			),
			reporter.NewStep(
				"Log out",
				testCF.Logout(),
			),
			reporter.NewStep(
				"Log in as admin",
				testCF.Auth(cfTestConfig.AdminUser, cfTestConfig.AdminPassword),
			),
			reporter.NewStep(
				"Delete security group 'redis-smoke-tests-sg'",
				testCF.DeleteSecurityGroup("redis-smoke-tests-sg"),
			),
			reporter.NewStep(
				"Log out",
				testCF.Logout(),
			),
		}

		smokeTestReporter.RegisterSpecSteps(specSteps)

		for _, task := range specSteps {
			task.Perform()
		}
	})

	AfterSuite(func() {
		regularContext := context.RegularUserContext()

		afterSuiteSteps := []*reporter.Step{
			reporter.NewStep(
				"Connect to CloudFoundry",
				testCF.API(cfTestConfig.ApiEndpoint, cfTestConfig.SkipSSLValidation),
			),
			reporter.NewStep(
				"Log in as admin",
				testCF.Auth(cfTestConfig.AdminUser, cfTestConfig.AdminPassword),
			),
			reporter.NewStep(
				fmt.Sprintf("Target '%s' org and '%s' space", cfTestConfig.OrgName, cfTestConfig.SpaceName),
				testCF.TargetOrgAndSpace(cfTestConfig.OrgName, cfTestConfig.SpaceName),
			),
			reporter.NewStep(
				"Ensure no service-instances left",
				testCF.EnsureAllServiceInstancesGone(),
			),
			reporter.NewStep(
				fmt.Sprintf("Delete user '%s'", regularContext.Username),
				testCF.DeleteUser(regularContext.Username),
			),
			reporter.NewStep(
				fmt.Sprintf("Delete org '%s'", cfTestConfig.OrgName),
				testCF.DeleteOrg(cfTestConfig.OrgName),
			),
			reporter.NewStep(
				"Log out",
				testCF.Logout(),
			),
		}

		smokeTestReporter.RegisterAfterSuiteSteps(afterSuiteSteps)

		for _, task := range afterSuiteSteps {
			task.Perform()
		}
	})

	AssertLifeCycleBehavior := func(planName string) {
		It(strings.ToUpper(planName)+": create, bind to, write to, read from, unbind, and destroy a service instance", func() {
			regularContext := context.RegularUserContext()

			var skip bool

			uri := fmt.Sprintf("https://%s.%s", appName, cfTestConfig.AppsDomain)
			app := redis.NewApp(uri, testCF.ShortTimeout, retryInterval)

			serviceCreateStep := reporter.NewStep(
				fmt.Sprintf("Create a '%s' plan instance of Redis\n    Please refer to http://docs.pivotal.io/redis/smoke-tests.html for more help on diagnosing this issue", planName),
				testCF.CreateService(redisConfig.ServiceName, planName, serviceInstanceName, &skip),
			)

			smokeTestReporter.RegisterSpecSteps([]*reporter.Step{serviceCreateStep})

			specSteps := []*reporter.Step{
				reporter.NewStep(
					fmt.Sprintf("Bind the redis sample app to the '%s' plan instance of Redis", planName),
					testCF.BindService(appName, serviceInstanceName),
				),
				reporter.NewStep(
					"Log in as admin",
					testCF.Auth(cfTestConfig.AdminUser, cfTestConfig.AdminPassword),
				),
				reporter.NewStep(
					fmt.Sprintf("Target '%s' org and '%s' space", cfTestConfig.OrgName, cfTestConfig.SpaceName),
					testCF.TargetOrgAndSpace(cfTestConfig.OrgName, cfTestConfig.SpaceName),
				),
				reporter.NewStep(
					"Create and bind security group for running smoke tests",
					testCF.CreateAndBindSecurityGroup("redis-smoke-tests-sg", appName, cfTestConfig.OrgName, cfTestConfig.SpaceName),
				),
				reporter.NewStep(
					fmt.Sprintf("Log in as %s", regularContext.Username),
					testCF.Auth(regularContext.Username, regularContext.Password),
				),
				reporter.NewStep(
					fmt.Sprintf("Target '%s' org and '%s' space", cfTestConfig.OrgName, cfTestConfig.SpaceName),
					testCF.TargetOrgAndSpace(cfTestConfig.OrgName, cfTestConfig.SpaceName),
				),
				reporter.NewStep(
					"Start the app",
					testCF.Start(appName),
				),
				reporter.NewStep(
					"Verify that the app is responding",
					app.IsRunning(),
				),
				reporter.NewStep(
					"Write a key/value pair to Redis",
					app.Write("mykey", "myvalue"),
				),
				reporter.NewStep(
					"Read the key/value pair back",
					app.ReadAssert("mykey", "myvalue"),
				),
			}

			smokeTestReporter.RegisterSpecSteps(specSteps)

			serviceCreateStep.Perform()
			serviceCreateStep.Description = fmt.Sprintf("Create a '%s' plan instance of Redis", planName)

			if skip {
				serviceCreateStep.Result = "SKIPPED"
			} else {
				for _, task := range specSteps {
					task.Perform()
				}
			}
		})
	}

	Context("for each plan", func() {
		for _, planName = range redisConfig.PlanNames {
			AssertLifeCycleBehavior(planName)
		}
	})
})

func randomName() string {
	return uuid.NewRandom().String()
}
<commit_msg>Log for easier debugging<commit_after>package service_test

import (
	"fmt"
	"strings"
	"time"

	"github.com/pborman/uuid"
	"github.com/pivotal-cf/cf-redis-smoke-tests/redis"
	"github.com/pivotal-cf/cf-redis-smoke-tests/service/reporter"

	"github.com/pivotal-cf-experimental/cf-test-helpers/services"
	smokeTestCF "github.com/pivotal-cf/cf-redis-smoke-tests/cf"

	. "github.com/onsi/ginkgo"
)

var _ = Describe("Redis Service", func() {
	var (
		testCF = smokeTestCF.CF{
			ShortTimeout: time.Minute * 3,
			LongTimeout:  time.Minute * 15,
			RetryBackoff: redisConfig.Retry.Backoff(),
			MaxRetries:   redisConfig.Retry.MaxRetries(),
		}

		retryInterval = time.Second

		appPath             = "../assets/cf-redis-example-app"
		serviceInstanceName string
		appName             string
		planName            string

		context services.Context
	)

	BeforeSuite(func() {
		context = services.NewContext(cfTestConfig, "redis-test")

		createQuotaArgs := []string{
			"-m", "10G",
			"-r", "1000",
			"-s", "100",
			"--allow-paid-service-plans",
		}

		regularContext := context.RegularUserContext()

		beforeSuiteSteps := []*reporter.Step{
			reporter.NewStep(
				"Connect to CloudFoundry",
				testCF.API(cfTestConfig.ApiEndpoint, cfTestConfig.SkipSSLValidation),
			),
			reporter.NewStep(
				"Log in as admin",
				testCF.Auth(cfTestConfig.AdminUser, cfTestConfig.AdminPassword),
			),
			reporter.NewStep(
				"Create 'redis-smoke-tests' quota",
				testCF.CreateQuota("redis-smoke-test-quota", createQuotaArgs...),
			),
			reporter.NewStep(
				fmt.Sprintf("Create '%s' org", cfTestConfig.OrgName),
				testCF.CreateOrg(cfTestConfig.OrgName, "redis-smoke-test-quota"),
			),
			reporter.NewStep(
				fmt.Sprintf("Enable service access for '%s' org", cfTestConfig.OrgName),
				testCF.EnableServiceAccess(cfTestConfig.OrgName, redisConfig.ServiceName),
			),
			reporter.NewStep(
				fmt.Sprintf("Target '%s' org", cfTestConfig.OrgName),
				testCF.TargetOrg(cfTestConfig.OrgName),
			),
			reporter.NewStep(
				fmt.Sprintf("Create '%s' space", cfTestConfig.SpaceName),
				testCF.CreateSpace(cfTestConfig.SpaceName),
			),
			reporter.NewStep(
				fmt.Sprintf("Create user '%s'", regularContext.Username),
				testCF.CreateUser(regularContext.Username, regularContext.Password),
			),
			reporter.NewStep(
				fmt.Sprintf(
					"Assign user '%s' to 'SpaceManager' role for '%s'",
					regularContext.Username,
					cfTestConfig.SpaceName,
				),
				testCF.SetSpaceRole(regularContext.Username, regularContext.Org, cfTestConfig.SpaceName, "SpaceManager"),
			),
			reporter.NewStep(
				fmt.Sprintf(
					"Assign user '%s' to 'SpaceDeveloper' role for '%s'",
					regularContext.Username,
					cfTestConfig.SpaceName,
				),
				testCF.SetSpaceRole(regularContext.Username, regularContext.Org, cfTestConfig.SpaceName, "SpaceDeveloper"),
			),
			reporter.NewStep(
				fmt.Sprintf(
					"Assign user '%s' to 'SpaceAuditor' role for '%s'",
					regularContext.Username,
					cfTestConfig.SpaceName,
				),
				testCF.SetSpaceRole(regularContext.Username, regularContext.Org, cfTestConfig.SpaceName, "SpaceAuditor"),
			),
			reporter.NewStep(
				"Log out",
				testCF.Logout(),
			),
		}

		smokeTestReporter.RegisterBeforeSuiteSteps(beforeSuiteSteps)

		for _, task := range beforeSuiteSteps {
			task.Perform()
		}
	})

	BeforeEach(func() {
		regularContext := context.RegularUserContext()
		appName = randomName()
		serviceInstanceName = randomName()

		pushArgs := []string{
			"-m", "256M",
			"-p", appPath,
			"-s", "cflinuxfs2",
			"-no-start",
		}

		specSteps := []*reporter.Step{
			reporter.NewStep(
				fmt.Sprintf("Log in as %s", regularContext.Username),
				testCF.Auth(regularContext.Username, regularContext.Password),
			),
			reporter.NewStep(
				fmt.Sprintf("Target '%s' org and '%s' space", cfTestConfig.OrgName, cfTestConfig.SpaceName),
				testCF.TargetOrgAndSpace(cfTestConfig.OrgName, cfTestConfig.SpaceName),
			),
			reporter.NewStep(
				"Push the redis sample app to Cloud Foundry",
				testCF.Push(appName, pushArgs...),
			),
		}

		smokeTestReporter.ClearSpecSteps()
		smokeTestReporter.RegisterSpecSteps(specSteps)

		for _, task := range specSteps {
			task.Perform()
		}
	})

	AfterEach(func() {
		specSteps := []*reporter.Step{
			reporter.NewStep(
				fmt.Sprintf("Unbind the %q plan instance", planName),
				testCF.UnbindService(appName, serviceInstanceName),
			),
			reporter.NewStep(
				fmt.Sprintf("Delete the %q plan instance", planName),
				testCF.DeleteService(serviceInstanceName),
			),
			reporter.NewStep(
				fmt.Sprintf("Ensure service instance for plan %q has been deleted", planName),
				testCF.EnsureServiceInstanceGone(serviceInstanceName),
			),
			reporter.NewStep(
				"Delete the app",
				testCF.Delete(appName),
			),
			reporter.NewStep(
				"Log out",
				testCF.Logout(),
			),
			reporter.NewStep(
				"Log in as admin",
				testCF.Auth(cfTestConfig.AdminUser, cfTestConfig.AdminPassword),
			),
			reporter.NewStep(
				"Delete security group 'redis-smoke-tests-sg'",
				testCF.DeleteSecurityGroup("redis-smoke-tests-sg"),
			),
			reporter.NewStep(
				"Log out",
				testCF.Logout(),
			),
		}

		smokeTestReporter.RegisterSpecSteps(specSteps)

		for _, task := range specSteps {
			task.Perform()
		}
	})

	AfterSuite(func() {
		regularContext := context.RegularUserContext()

		afterSuiteSteps := []*reporter.Step{
			reporter.NewStep(
				"Connect to CloudFoundry",
				testCF.API(cfTestConfig.ApiEndpoint, cfTestConfig.SkipSSLValidation),
			),
			reporter.NewStep(
				"Log in as admin",
				testCF.Auth(cfTestConfig.AdminUser, cfTestConfig.AdminPassword),
			),
			reporter.NewStep(
				fmt.Sprintf("Target '%s' org and '%s' space", cfTestConfig.OrgName, cfTestConfig.SpaceName),
				testCF.TargetOrgAndSpace(cfTestConfig.OrgName, cfTestConfig.SpaceName),
			),
			reporter.NewStep(
				"Ensure no service-instances left",
				testCF.EnsureAllServiceInstancesGone(),
			),
			reporter.NewStep(
				fmt.Sprintf("Delete user '%s'", regularContext.Username),
				testCF.DeleteUser(regularContext.Username),
			),
			reporter.NewStep(
				fmt.Sprintf("Delete org '%s'", cfTestConfig.OrgName),
				testCF.DeleteOrg(cfTestConfig.OrgName),
			),
			reporter.NewStep(
				"Log out",
				testCF.Logout(),
			),
		}

		smokeTestReporter.RegisterAfterSuiteSteps(afterSuiteSteps)

		for _, task := range afterSuiteSteps {
			task.Perform()
		}
	})

	AssertLifeCycleBehavior := func(planName string) {
		It(strings.ToUpper(planName)+": create, bind to, write to, read from, unbind, and destroy a service instance", func() {
			regularContext := context.RegularUserContext()

			var skip bool

			uri := fmt.Sprintf("https://%s.%s", appName, cfTestConfig.AppsDomain)
			app := redis.NewApp(uri, testCF.ShortTimeout, retryInterval)

			serviceCreateStep := reporter.NewStep(
				fmt.Sprintf("Create a '%s' plan instance of Redis\n    Please refer to http://docs.pivotal.io/redis/smoke-tests.html for more help on diagnosing this issue", planName),
				testCF.CreateService(redisConfig.ServiceName, planName, serviceInstanceName, &skip),
			)

			smokeTestReporter.RegisterSpecSteps([]*reporter.Step{serviceCreateStep})

			specSteps := []*reporter.Step{
				reporter.NewStep(
					fmt.Sprintf("Bind the redis sample app '%s' to the '%s' plan instance '%s' of Redis", appName, planName, serviceInstanceName),
					testCF.BindService(appName, serviceInstanceName),
				),
				reporter.NewStep(
					"Log in as admin",
					testCF.Auth(cfTestConfig.AdminUser, cfTestConfig.AdminPassword),
				),
				reporter.NewStep(
					fmt.Sprintf("Target '%s' org and '%s' space", cfTestConfig.OrgName, cfTestConfig.SpaceName),
					testCF.TargetOrgAndSpace(cfTestConfig.OrgName, cfTestConfig.SpaceName),
				),
				reporter.NewStep(
					"Create and bind security group for running smoke tests",
					testCF.CreateAndBindSecurityGroup("redis-smoke-tests-sg", appName, cfTestConfig.OrgName, cfTestConfig.SpaceName),
				),
				reporter.NewStep(
					fmt.Sprintf("Log in as %s", regularContext.Username),
					testCF.Auth(regularContext.Username, regularContext.Password),
				),
				reporter.NewStep(
					fmt.Sprintf("Target '%s' org and '%s' space", cfTestConfig.OrgName, cfTestConfig.SpaceName),
					testCF.TargetOrgAndSpace(cfTestConfig.OrgName, cfTestConfig.SpaceName),
				),
				reporter.NewStep(
					"Start the app",
					testCF.Start(appName),
				),
				reporter.NewStep(
					"Verify that the app is responding",
					app.IsRunning(),
				),
				reporter.NewStep(
					"Write a key/value pair to Redis",
					app.Write("mykey", "myvalue"),
				),
				reporter.NewStep(
					"Read the key/value pair back",
					app.ReadAssert("mykey", "myvalue"),
				),
			}

			smokeTestReporter.RegisterSpecSteps(specSteps)

			serviceCreateStep.Perform()
			serviceCreateStep.Description = fmt.Sprintf("Create a '%s' plan instance of Redis", planName)

			if skip {
				serviceCreateStep.Result = "SKIPPED"
			} else {
				for _, task := range specSteps {
					task.Perform()
				}
			}
		})
	}

	Context("for each plan", func() {
		for _, planName = range redisConfig.PlanNames {
			AssertLifeCycleBehavior(planName)
		}
	})
})

func randomName() string {
	return uuid.NewRandom().String()
}
<|endoftext|>


<commit_before>package engine

import (
	"encoding/json"
	"os"

	"github.com/concourse/atc"
	"github.com/concourse/atc/db"
	"github.com/concourse/atc/event"
	"github.com/concourse/atc/exec"
	"github.com/concourse/atc/worker"
	"github.com/pivotal-golang/lager"
	"github.com/tedsuo/ifrit"
)

type execMetadata struct {
	Plan atc.Plan
}

type execEngine struct {
	factory         exec.Factory
	delegateFactory BuildDelegateFactory
	db              EngineDB
}

func NewExecEngine(factory exec.Factory, delegateFactory BuildDelegateFactory, db EngineDB) Engine {
	return &execEngine{
		factory:         factory,
		delegateFactory: delegateFactory,
		db:              db,
	}
}

func (engine *execEngine) Name() string {
	return "exec.v1"
}

func (engine *execEngine) CreateBuild(model db.Build, plan atc.Plan) (Build, error) {
	return &execBuild{
		buildID:  model.ID,
		db:       engine.db,
		factory:  engine.factory,
		delegate: engine.delegateFactory.Delegate(model.ID),
		metadata: execMetadata{
			Plan: plan,
		},

		signals: make(chan os.Signal, 1),
	}, nil
}

func (engine *execEngine) LookupBuild(model db.Build) (Build, error) {
	var metadata execMetadata
	err := json.Unmarshal([]byte(model.EngineMetadata), &metadata)
	if err != nil {
		return nil, err
	}

	return &execBuild{
		buildID:  model.ID,
		db:       engine.db,
		factory:  engine.factory,
		delegate: engine.delegateFactory.Delegate(model.ID),
		metadata: metadata,

		signals: make(chan os.Signal, 1),
	}, nil
}

type execBuild struct {
	buildID int
	db      EngineDB

	factory  exec.Factory
	delegate BuildDelegate

	signals chan os.Signal

	metadata execMetadata
}

func (build *execBuild) Metadata() string {
	payload, err := json.Marshal(build.metadata)
	if err != nil {
		panic("failed to marshal build metadata: " + err.Error())
	}

	return string(payload)
}

func (build *execBuild) Abort() error {
	build.signals <- os.Kill
	return nil
}

func (build *execBuild) Resume(logger lager.Logger) {
	stepFactory, _ := build.buildStepFactory(logger, build.metadata.Plan, event.OriginLocation{0})
	source := stepFactory.Using(&exec.NoopStep{}, exec.NewSourceRepository())

	defer source.Release()

	process := ifrit.Background(source)

	exited := process.Wait()

	for {
		select {
		case err := <-exited:
			build.delegate.Finish(logger.Session("finish"), err)
			return

		case sig := <-build.signals:
			process.Signal(sig)

			if sig == os.Kill {
				build.delegate.Aborted(logger)
			}
		}
	}
}

func (build *execBuild) buildStepFactory(logger lager.Logger, plan atc.Plan, location event.OriginLocation) (exec.StepFactory, event.OriginLocationIncrement) {
	if plan.Aggregate != nil {
		logger = logger.Session("aggregate")

		step := exec.Aggregate{}

		var aID event.OriginLocationIncrement = 0
		for _, innerPlan := range *plan.Aggregate {
			stepFactory, locationIncrement := build.buildStepFactory(logger, innerPlan, location.Chain(uint(aID)))
			step = append(step, stepFactory)
			aID = aID + locationIncrement
		}

		return step, event.SingleIncrement
	}

	if plan.HookedCompose != nil {
		step, stepIncrement := build.buildStepFactory(logger, plan.HookedCompose.Step, location)
		failure, failureIncrement := build.buildStepFactory(logger, plan.HookedCompose.OnFailure, location.Incr(stepIncrement))
		success, successIncrement := build.buildStepFactory(logger, plan.HookedCompose.OnSuccess, location.Incr(stepIncrement+failureIncrement))
		ensure, ensureIncrement := build.buildStepFactory(logger, plan.HookedCompose.OnCompletion, location.Incr(stepIncrement+failureIncrement+successIncrement))

		nextStep, nextStepIncrement := build.buildStepFactory(logger, plan.HookedCompose.Next, location.Incr(stepIncrement+failureIncrement+successIncrement+ensureIncrement))
		return exec.HookedCompose(step, nextStep, failure, success, ensure), stepIncrement + failureIncrement + successIncrement + ensureIncrement + nextStepIncrement
	}

	if plan.Compose != nil {
		x, xLocationIncrement := build.buildStepFactory(logger, plan.Compose.A, location)
		y, yLocationIncrement := build.buildStepFactory(logger, plan.Compose.B, location.Incr(xLocationIncrement))
		return exec.Compose(x, y), xLocationIncrement + yLocationIncrement
	}

	if plan.Conditional != nil {
		logger = logger.Session("conditional", lager.Data{
			"on": plan.Conditional.Conditions,
		})

		steps, locationIncrement := build.buildStepFactory(logger, plan.Conditional.Plan, location)

		return exec.Conditional{
			Conditions:  plan.Conditional.Conditions,
			StepFactory: steps,
		}, locationIncrement
	}

	if plan.Task != nil {
		logger = logger.Session("task")

		var configSource exec.TaskConfigSource
		if plan.Task.Config != nil && plan.Task.ConfigPath != "" {
			configSource = exec.MergedConfigSource{
				A: exec.FileConfigSource{plan.Task.ConfigPath},
				B: exec.StaticConfigSource{*plan.Task.Config},
			}
		} else if plan.Task.Config != nil {
			configSource = exec.StaticConfigSource{*plan.Task.Config}
		} else if plan.Task.ConfigPath != "" {
			configSource = exec.FileConfigSource{plan.Task.ConfigPath}
		} else {
			return exec.Identity{}, event.NoIncrement
		}

		return build.factory.Task(
			exec.SourceName(plan.Task.Name),
			build.taskIdentifier(plan.Task.Name, location),
			build.delegate.ExecutionDelegate(logger, *plan.Task, location),
			exec.Privileged(plan.Task.Privileged),
			plan.Task.Tags,
			configSource,
		), event.SingleIncrement
	}

	if plan.Get != nil {
		logger = logger.Session("get", lager.Data{
			"name": plan.Get.Name,
		})

		return build.factory.Get(
			exec.SourceName(plan.Get.Name),
			build.getIdentifier(plan.Get.Name, location),
			build.delegate.InputDelegate(logger, *plan.Get, location, false),
			atc.ResourceConfig{
				Name:   plan.Get.Resource,
				Type:   plan.Get.Type,
				Source: plan.Get.Source,
			},
			plan.Get.Params,
			plan.Get.Tags,
			plan.Get.Version,
		), event.SingleIncrement
	}

	if plan.PutGet != nil {
		putPlan := plan.PutGet.Head.Put
		logger = logger.Session("put", lager.Data{
			"name": putPlan.Resource,
		})

		getPlan := putPlan.GetPlan()

		getLocation := location.Incr(1)
		restLocation := location.Incr(2)

		restOfSteps, restLocationIncrement := build.buildStepFactory(logger, plan.PutGet.Rest, restLocation)

		return exec.HookedCompose(
			build.factory.Put(
				build.putIdentifier(putPlan.Resource, location),
				build.delegate.OutputDelegate(logger, *putPlan, location),
				atc.ResourceConfig{
					Name:   putPlan.Resource,
					Type:   putPlan.Type,
					Source: putPlan.Source,
				},
				putPlan.Tags,
				putPlan.Params,
			),
			restOfSteps,
			exec.Identity{},
			build.factory.DependentGet(
				exec.SourceName(getPlan.Name),
				build.getIdentifier(getPlan.Name, getLocation),
				build.delegate.InputDelegate(logger, getPlan, getLocation, true),
				atc.ResourceConfig{
					Name:   getPlan.Resource,
					Type:   getPlan.Type,
					Source: getPlan.Source,
				},
				getPlan.Tags,
				getPlan.Params,
			),
			exec.Identity{},
		), event.OriginLocationIncrement(2) + restLocationIncrement
	}

	return exec.Identity{}, event.NoIncrement
}

func (build *execBuild) taskIdentifier(name string, location event.OriginLocation) worker.Identifier {
	return worker.Identifier{
		BuildID: build.buildID,

		Type:         "task",
		Name:         name,
		StepLocation: location,
	}
}

func (build *execBuild) getIdentifier(name string, location event.OriginLocation) worker.Identifier {
	return worker.Identifier{
		BuildID: build.buildID,

		Type:         "get",
		Name:         name,
		StepLocation: location,
	}
}

func (build *execBuild) putIdentifier(name string, location event.OriginLocation) worker.Identifier {
	return worker.Identifier{
		BuildID: build.buildID,

		Type:         "put",
		Name:         name,
		StepLocation: location,
	}
}
<commit_msg>add in location incrementing for hooks<commit_after>package engine

import (
	"encoding/json"
	"os"

	"github.com/concourse/atc"
	"github.com/concourse/atc/db"
	"github.com/concourse/atc/event"
	"github.com/concourse/atc/exec"
	"github.com/concourse/atc/worker"
	"github.com/pivotal-golang/lager"
	"github.com/tedsuo/ifrit"
)

type execMetadata struct {
	Plan atc.Plan
}

type execEngine struct {
	factory         exec.Factory
	delegateFactory BuildDelegateFactory
	db              EngineDB
}

func NewExecEngine(factory exec.Factory, delegateFactory BuildDelegateFactory, db EngineDB) Engine {
	return &execEngine{
		factory:         factory,
		delegateFactory: delegateFactory,
		db:              db,
	}
}

func (engine *execEngine) Name() string {
	return "exec.v1"
}

func (engine *execEngine) CreateBuild(model db.Build, plan atc.Plan) (Build, error) {
	return &execBuild{
		buildID:  model.ID,
		db:       engine.db,
		factory:  engine.factory,
		delegate: engine.delegateFactory.Delegate(model.ID),
		metadata: execMetadata{
			Plan: plan,
		},

		signals: make(chan os.Signal, 1),
	}, nil
}

func (engine *execEngine) LookupBuild(model db.Build) (Build, error) {
	var metadata execMetadata
	err := json.Unmarshal([]byte(model.EngineMetadata), &metadata)
	if err != nil {
		return nil, err
	}

	return &execBuild{
		buildID:  model.ID,
		db:       engine.db,
		factory:  engine.factory,
		delegate: engine.delegateFactory.Delegate(model.ID),
		metadata: metadata,

		signals: make(chan os.Signal, 1),
	}, nil
}

type execBuild struct {
	buildID int
	db      EngineDB

	factory  exec.Factory
	delegate BuildDelegate

	signals chan os.Signal

	metadata execMetadata
}

func (build *execBuild) Metadata() string {
	payload, err := json.Marshal(build.metadata)
	if err != nil {
		panic("failed to marshal build metadata: " + err.Error())
	}

	return string(payload)
}

func (build *execBuild) Abort() error {
	build.signals <- os.Kill
	return nil
}

func (build *execBuild) Resume(logger lager.Logger) {
	stepFactory, _ := build.buildStepFactory(logger, build.metadata.Plan, event.OriginLocation{0})
	source := stepFactory.Using(&exec.NoopStep{}, exec.NewSourceRepository())

	defer source.Release()

	process := ifrit.Background(source)

	exited := process.Wait()

	for {
		select {
		case err := <-exited:
			build.delegate.Finish(logger.Session("finish"), err)
			return

		case sig := <-build.signals:
			process.Signal(sig)

			if sig == os.Kill {
				build.delegate.Aborted(logger)
			}
		}
	}
}

func (build *execBuild) buildStepFactory(logger lager.Logger, plan atc.Plan, location event.OriginLocation) (exec.StepFactory, event.OriginLocationIncrement) {
	if plan.Aggregate != nil {
		logger = logger.Session("aggregate")

		step := exec.Aggregate{}

		var aID event.OriginLocationIncrement = 0
		for _, innerPlan := range *plan.Aggregate {
			stepFactory, locationIncrement := build.buildStepFactory(logger, innerPlan, location.Chain(uint(aID)))
			step = append(step, stepFactory)
			aID = aID + locationIncrement
		}

		return step, event.SingleIncrement
	}

	if plan.HookedCompose != nil {
		step, stepIncrement := build.buildStepFactory(logger, plan.HookedCompose.Step, location)
		location = location.Incr(stepIncrement)
		failure, failureIncrement := build.buildStepFactory(logger, plan.HookedCompose.OnFailure, location.Chain(0))
		success, successIncrement := build.buildStepFactory(logger, plan.HookedCompose.OnSuccess, location.Chain(uint(failureIncrement)))
		ensure, _ := build.buildStepFactory(logger, plan.HookedCompose.OnCompletion, location.Chain(uint(failureIncrement+successIncrement)))

		nextStep, nextStepIncrement := build.buildStepFactory(logger, plan.HookedCompose.Next, location.Incr(stepIncrement))
		return exec.HookedCompose(step, nextStep, failure, success, ensure), stepIncrement + nextStepIncrement
	}

	if plan.Compose != nil {
		x, xLocationIncrement := build.buildStepFactory(logger, plan.Compose.A, location)
		y, yLocationIncrement := build.buildStepFactory(logger, plan.Compose.B, location.Incr(xLocationIncrement))
		return exec.Compose(x, y), xLocationIncrement + yLocationIncrement
	}

	if plan.Conditional != nil {
		logger = logger.Session("conditional", lager.Data{
			"on": plan.Conditional.Conditions,
		})

		steps, locationIncrement := build.buildStepFactory(logger, plan.Conditional.Plan, location)

		return exec.Conditional{
			Conditions:  plan.Conditional.Conditions,
			StepFactory: steps,
		}, locationIncrement
	}

	if plan.Task != nil {
		logger = logger.Session("task")

		var configSource exec.TaskConfigSource
		if plan.Task.Config != nil && plan.Task.ConfigPath != "" {
			configSource = exec.MergedConfigSource{
				A: exec.FileConfigSource{plan.Task.ConfigPath},
				B: exec.StaticConfigSource{*plan.Task.Config},
			}
		} else if plan.Task.Config != nil {
			configSource = exec.StaticConfigSource{*plan.Task.Config}
		} else if plan.Task.ConfigPath != "" {
			configSource = exec.FileConfigSource{plan.Task.ConfigPath}
		} else {
			return exec.Identity{}, event.NoIncrement
		}

		return build.factory.Task(
			exec.SourceName(plan.Task.Name),
			build.taskIdentifier(plan.Task.Name, location),
			build.delegate.ExecutionDelegate(logger, *plan.Task, location),
			exec.Privileged(plan.Task.Privileged),
			plan.Task.Tags,
			configSource,
		), event.SingleIncrement
	}

	if plan.Get != nil {
		logger = logger.Session("get", lager.Data{
			"name": plan.Get.Name,
		})

		return build.factory.Get(
			exec.SourceName(plan.Get.Name),
			build.getIdentifier(plan.Get.Name, location),
			build.delegate.InputDelegate(logger, *plan.Get, location, false),
			atc.ResourceConfig{
				Name:   plan.Get.Resource,
				Type:   plan.Get.Type,
				Source: plan.Get.Source,
			},
			plan.Get.Params,
			plan.Get.Tags,
			plan.Get.Version,
		), event.SingleIncrement
	}

	if plan.PutGet != nil {
		putPlan := plan.PutGet.Head.Put
		logger = logger.Session("put", lager.Data{
			"name": putPlan.Resource,
		})

		getPlan := putPlan.GetPlan()

		getLocation := location.Incr(1)
		restLocation := location.Incr(2)

		restOfSteps, restLocationIncrement := build.buildStepFactory(logger, plan.PutGet.Rest, restLocation)

		return exec.HookedCompose(
			build.factory.Put(
				build.putIdentifier(putPlan.Resource, location),
				build.delegate.OutputDelegate(logger, *putPlan, location),
				atc.ResourceConfig{
					Name:   putPlan.Resource,
					Type:   putPlan.Type,
					Source: putPlan.Source,
				},
				putPlan.Tags,
				putPlan.Params,
			),
			restOfSteps,
			exec.Identity{},
			build.factory.DependentGet(
				exec.SourceName(getPlan.Name),
				build.getIdentifier(getPlan.Name, getLocation),
				build.delegate.InputDelegate(logger, getPlan, getLocation, true),
				atc.ResourceConfig{
					Name:   getPlan.Resource,
					Type:   getPlan.Type,
					Source: getPlan.Source,
				},
				getPlan.Tags,
				getPlan.Params,
			),
			exec.Identity{},
		), event.OriginLocationIncrement(2) + restLocationIncrement
	}

	return exec.Identity{}, event.NoIncrement
}

func (build *execBuild) taskIdentifier(name string, location event.OriginLocation) worker.Identifier {
	return worker.Identifier{
		BuildID: build.buildID,

		Type:         "task",
		Name:         name,
		StepLocation: location,
	}
}

func (build *execBuild) getIdentifier(name string, location event.OriginLocation) worker.Identifier {
	return worker.Identifier{
		BuildID: build.buildID,

		Type:         "get",
		Name:         name,
		StepLocation: location,
	}
}

func (build *execBuild) putIdentifier(name string, location event.OriginLocation) worker.Identifier {
	return worker.Identifier{
		BuildID: build.buildID,

		Type:         "put",
		Name:         name,
		StepLocation: location,
	}
}
<|endoftext|>


<commit_before>package fix

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"github.com/ghthor/journal/idea"
	"io"
	"io/ioutil"
	"strings"
	"time"
)

var entryFixes []entryFix

func init() {
	entryFixes = []entryFix{
		fixAddClosedAtTimestamp{},
		FixSplitCommitMessage{},
		FixCommitMessagePrefixWithTilde{},
		FixIdeasInBody{},
	}
}

type entryFix interface {
	// Parses io.Reader for the error that can be fixed
	CanFix(io.Reader) (bool, error)

	// Returns byte slice that has been fixed
	Execute(io.Reader) ([]byte, error)
}

// Parse the opened at timestamp and add 2 mins
// then append it to the end
type fixAddClosedAtTimestamp struct{}

func (fixAddClosedAtTimestamp) CanFix(r io.Reader) (bool, error) {
	data, err := ioutil.ReadAll(r)
	if err != nil {
		return false, err
	}

	return !lastLineIsTimestamp(data), nil
}

func lastLineIsTimestamp(data []byte) bool {
	scanner := bufio.NewScanner(bytes.NewReader(data))

	// Scan to the last line
	var prevLine string
	for scanner.Scan() {
		prevLine = scanner.Text()
	}
	_, err := time.Parse(time.UnixDate, prevLine)

	return err == nil
}

func (fixAddClosedAtTimestamp) Execute(r io.Reader) ([]byte, error) {
	// For adding 2 mins and making the closed at timestamp
	var openedAt time.Time

	// For storing the fixed output
	b := bytes.NewBuffer(make([]byte, 0, 1024))

	scanner := bufio.NewScanner(r)

	// Scan in the opened at timestamp
	if scanner.Scan() {
		if time, err := time.Parse(time.UnixDate, scanner.Text()); err != nil {
			// First line wasn't a timestamp
			return nil, err
		} else {
			openedAt = time
			// Print the timestamp to the fixed buffer
			if _, err := fmt.Fprintln(b, scanner.Text()); err != nil {
				return nil, err
			}
		}
	} else {
		return nil, errors.New("error parsing opened at timestamp")
	}

	// Scan and copy lines into the fixed buffer
	for scanner.Scan() {
		if scanner.Err() != nil {
			return nil, scanner.Err()
		}

		if _, err := fmt.Fprintln(b, scanner.Text()); err != nil {
			return nil, err
		}
	}

	// Append the closed at timestamp to the end of the buffer
	closedAt := openedAt.Add(time.Minute * 2)
	if _, err := fmt.Fprintf(b, "\n%s\n", closedAt.Format(time.UnixDate)); err != nil {
		return nil, err
	}

	return b.Bytes(), nil
}

/*
	Fix a commit message with the format

		#~ Commit Msg
		# Additional Msg

	By turning it into this

		# Commit Msg | Additional Msg

*/
type FixSplitCommitMessage struct{}

func (FixSplitCommitMessage) CanFix(r io.Reader) (bool, error) {
	return hasSplitCommitMsg(r), nil
}

func hasSplitCommitMsg(r io.Reader) bool {
	scanner := bufio.NewScanner(r)
	for scanner.Scan() {
		if strings.HasPrefix(scanner.Text(), "#~ ") {
			if scanner.Scan() {
				if strings.HasPrefix(scanner.Text(), "# ") {
					return true
				}
			}
		}
	}
	return false
}

func (FixSplitCommitMessage) Execute(r io.Reader) ([]byte, error) {
	// For storing the fixed output
	b := bytes.NewBuffer(make([]byte, 0, 1024))

	scanner := bufio.NewScanner(r)

	for scanner.Scan() {
		line := scanner.Text()

		if strings.HasPrefix(line, "#~ ") {
			// We've found line 1 of the split commit message
			part1 := strings.TrimPrefix(line, "#~ ")

			if scanner.Scan() {
				// Trim line 2 of the message and put part1 and part2 together
				part2 := strings.TrimPrefix(scanner.Text(), "# ")

				if _, err := fmt.Fprintf(b, "# %s | %s\n", part1, part2); err != nil {
					return nil, err
				}
			} else {
				// Maybe this should be a panic
				return nil, errors.New("attempt to fix split commit message that doesn't exist")
			}
			break
		}

		if _, err := fmt.Fprintln(b, line); err != nil {
			return nil, err
		}
	}

	// Copy the remaining bytes into the buffer
	for scanner.Scan() {
		if _, err := fmt.Fprintln(b, scanner.Text()); err != nil {
			return nil, err
		}
	}

	return b.Bytes(), nil
}

/*
	Fix a commit message line with the #~ format

		#~ Commit Msg

	to

		# Commit Msg

*/
type FixCommitMessagePrefixWithTilde struct{}

func (FixCommitMessagePrefixWithTilde) CanFix(r io.Reader) (bool, error) {
	scanner := bufio.NewScanner(r)
	for scanner.Scan() {
		if strings.HasPrefix(scanner.Text(), "#~ ") {
			if scanner.Scan() {
				// Make sure this isn't a split commit message
				if !strings.HasPrefix(scanner.Text(), "# ") {
					return true, nil
				}
			}
		}
	}
	return false, nil
}

func (FixCommitMessagePrefixWithTilde) Execute(r io.Reader) ([]byte, error) {
	// For storing the fixed output
	b := bytes.NewBuffer(make([]byte, 0, 1024))

	scanner := bufio.NewScanner(r)
	for scanner.Scan() {
		line := scanner.Text()

		if strings.HasPrefix(line, "#~ ") {
			// Trim out the ~ character and place in the buffer
			if _, err := fmt.Fprintln(b, strings.Replace(line, "#~", "#", 1)); err != nil {
				return nil, err
			}
			break
		}

		if _, err := fmt.Fprintln(b, line); err != nil {
			return nil, err
		}
	}

	// Copy the remaining bytes into the buffer
	for scanner.Scan() {
		if _, err := fmt.Fprintln(b, scanner.Text()); err != nil {
			return nil, err
		}
	}

	return b.Bytes(), nil
}

/*
	Remove any idea's from the entries body.
	We assume that the ideas have already been
	parsed and saved in an earlier fix step.
*/
type FixIdeasInBody struct{}

func (FixIdeasInBody) CanFix(r io.Reader) (bool, error) {
	return idea.NewIdeaScanner(r).Scan(), nil
}

func (FixIdeasInBody) Execute(r io.Reader) ([]byte, error) {
	// For storing the fixed output
	b := bytes.NewBuffer(make([]byte, 0, 1024))

	scanner := bufio.NewScanner(r)
	for scanner.Scan() {
		if strings.HasPrefix(scanner.Text(), "## [") {
			break
		}

		if _, err := fmt.Fprintln(b, scanner.Text()); err != nil {
			return nil, err
		}
	}

	var timestampLine string

	// Look for the timestamp
	for scanner.Scan() {
		if _, err := time.Parse(time.UnixDate, scanner.Text()); err == nil {
			timestampLine = scanner.Text()
		}
	}

	// Trim what's in the buffer and append the timestamp line
	b = bytes.NewBuffer(bytes.TrimSpace(b.Bytes()))
	if _, err := fmt.Fprintf(b, "\n\n%s\n", timestampLine); err != nil {
		return nil, err
	}

	return b.Bytes(), nil
}
<commit_msg>Reducing package's public interface | gofmt -w -r="FixCommitMessagePrefixWithTilde -> fixCommitMessagePrefixWithTilde" *.go<commit_after>package fix

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"github.com/ghthor/journal/idea"
	"io"
	"io/ioutil"
	"strings"
	"time"
)

var entryFixes []entryFix

func init() {
	entryFixes = []entryFix{
		fixAddClosedAtTimestamp{},
		FixSplitCommitMessage{},
		fixCommitMessagePrefixWithTilde{},
		FixIdeasInBody{},
	}
}

type entryFix interface {
	// Parses io.Reader for the error that can be fixed
	CanFix(io.Reader) (bool, error)

	// Returns byte slice that has been fixed
	Execute(io.Reader) ([]byte, error)
}

// Parse the opened at timestamp and add 2 mins
// then append it to the end
type fixAddClosedAtTimestamp struct{}

func (fixAddClosedAtTimestamp) CanFix(r io.Reader) (bool, error) {
	data, err := ioutil.ReadAll(r)
	if err != nil {
		return false, err
	}

	return !lastLineIsTimestamp(data), nil
}

func lastLineIsTimestamp(data []byte) bool {
	scanner := bufio.NewScanner(bytes.NewReader(data))

	// Scan to the last line
	var prevLine string
	for scanner.Scan() {
		prevLine = scanner.Text()
	}
	_, err := time.Parse(time.UnixDate, prevLine)

	return err == nil
}

func (fixAddClosedAtTimestamp) Execute(r io.Reader) ([]byte, error) {
	// For adding 2 mins and making the closed at timestamp
	var openedAt time.Time

	// For storing the fixed output
	b := bytes.NewBuffer(make([]byte, 0, 1024))

	scanner := bufio.NewScanner(r)

	// Scan in the opened at timestamp
	if scanner.Scan() {
		if time, err := time.Parse(time.UnixDate, scanner.Text()); err != nil {
			// First line wasn't a timestamp
			return nil, err
		} else {
			openedAt = time
			// Print the timestamp to the fixed buffer
			if _, err := fmt.Fprintln(b, scanner.Text()); err != nil {
				return nil, err
			}
		}
	} else {
		return nil, errors.New("error parsing opened at timestamp")
	}

	// Scan and copy lines into the fixed buffer
	for scanner.Scan() {
		if scanner.Err() != nil {
			return nil, scanner.Err()
		}

		if _, err := fmt.Fprintln(b, scanner.Text()); err != nil {
			return nil, err
		}
	}

	// Append the closed at timestamp to the end of the buffer
	closedAt := openedAt.Add(time.Minute * 2)
	if _, err := fmt.Fprintf(b, "\n%s\n", closedAt.Format(time.UnixDate)); err != nil {
		return nil, err
	}

	return b.Bytes(), nil
}

/*
	Fix a commit message with the format

		#~ Commit Msg
		# Additional Msg

	By turning it into this

		# Commit Msg | Additional Msg

*/
type FixSplitCommitMessage struct{}

func (FixSplitCommitMessage) CanFix(r io.Reader) (bool, error) {
	return hasSplitCommitMsg(r), nil
}

func hasSplitCommitMsg(r io.Reader) bool {
	scanner := bufio.NewScanner(r)
	for scanner.Scan() {
		if strings.HasPrefix(scanner.Text(), "#~ ") {
			if scanner.Scan() {
				if strings.HasPrefix(scanner.Text(), "# ") {
					return true
				}
			}
		}
	}
	return false
}

func (FixSplitCommitMessage) Execute(r io.Reader) ([]byte, error) {
	// For storing the fixed output
	b := bytes.NewBuffer(make([]byte, 0, 1024))

	scanner := bufio.NewScanner(r)

	for scanner.Scan() {
		line := scanner.Text()

		if strings.HasPrefix(line, "#~ ") {
			// We've found line 1 of the split commit message
			part1 := strings.TrimPrefix(line, "#~ ")

			if scanner.Scan() {
				// Trim line 2 of the message and put part1 and part2 together
				part2 := strings.TrimPrefix(scanner.Text(), "# ")

				if _, err := fmt.Fprintf(b, "# %s | %s\n", part1, part2); err != nil {
					return nil, err
				}
			} else {
				// Maybe this should be a panic
				return nil, errors.New("attempt to fix split commit message that doesn't exist")
			}
			break
		}

		if _, err := fmt.Fprintln(b, line); err != nil {
			return nil, err
		}
	}

	// Copy the remaining bytes into the buffer
	for scanner.Scan() {
		if _, err := fmt.Fprintln(b, scanner.Text()); err != nil {
			return nil, err
		}
	}

	return b.Bytes(), nil
}

/*
	Fix a commit message line with the #~ format

		#~ Commit Msg

	to

		# Commit Msg

*/
type fixCommitMessagePrefixWithTilde struct{}

func (fixCommitMessagePrefixWithTilde) CanFix(r io.Reader) (bool, error) {
	scanner := bufio.NewScanner(r)
	for scanner.Scan() {
		if strings.HasPrefix(scanner.Text(), "#~ ") {
			if scanner.Scan() {
				// Make sure this isn't a split commit message
				if !strings.HasPrefix(scanner.Text(), "# ") {
					return true, nil
				}
			}
		}
	}
	return false, nil
}

func (fixCommitMessagePrefixWithTilde) Execute(r io.Reader) ([]byte, error) {
	// For storing the fixed output
	b := bytes.NewBuffer(make([]byte, 0, 1024))

	scanner := bufio.NewScanner(r)
	for scanner.Scan() {
		line := scanner.Text()

		if strings.HasPrefix(line, "#~ ") {
			// Trim out the ~ character and place in the buffer
			if _, err := fmt.Fprintln(b, strings.Replace(line, "#~", "#", 1)); err != nil {
				return nil, err
			}
			break
		}

		if _, err := fmt.Fprintln(b, line); err != nil {
			return nil, err
		}
	}

	// Copy the remaining bytes into the buffer
	for scanner.Scan() {
		if _, err := fmt.Fprintln(b, scanner.Text()); err != nil {
			return nil, err
		}
	}

	return b.Bytes(), nil
}

/*
	Remove any idea's from the entries body.
	We assume that the ideas have already been
	parsed and saved in an earlier fix step.
*/
type FixIdeasInBody struct{}

func (FixIdeasInBody) CanFix(r io.Reader) (bool, error) {
	return idea.NewIdeaScanner(r).Scan(), nil
}

func (FixIdeasInBody) Execute(r io.Reader) ([]byte, error) {
	// For storing the fixed output
	b := bytes.NewBuffer(make([]byte, 0, 1024))

	scanner := bufio.NewScanner(r)
	for scanner.Scan() {
		if strings.HasPrefix(scanner.Text(), "## [") {
			break
		}

		if _, err := fmt.Fprintln(b, scanner.Text()); err != nil {
			return nil, err
		}
	}

	var timestampLine string

	// Look for the timestamp
	for scanner.Scan() {
		if _, err := time.Parse(time.UnixDate, scanner.Text()); err == nil {
			timestampLine = scanner.Text()
		}
	}

	// Trim what's in the buffer and append the timestamp line
	b = bytes.NewBuffer(bytes.TrimSpace(b.Bytes()))
	if _, err := fmt.Fprintf(b, "\n\n%s\n", timestampLine); err != nil {
		return nil, err
	}

	return b.Bytes(), nil
}
<|endoftext|>


<commit_before>package main

import (
	"archive/tar"
	"context"
	"os"
	"strings"
	"time"

	kafka "github.com/segmentio/kafka-go"
)

func main() {
	// Get the connection info from the ENV vars
	host := os.Getenv("HOST")
	port := os.Getenv("PORT")
	topic := os.Getenv("TOPIC")

	// And create a new kafka reader
	reader := kafka.NewReader(kafka.ReaderConfig{
		Brokers:  []string{host + ":" + port},
		Topic:    topic,
		MinBytes: 10e1,
		MaxBytes: 10e6,
	})
	defer reader.Close()

	// Open the /pfs/out pipe with write only permissons (the pachyderm spout will be reading at the other end of this)
	// Note: it won't work if you try to open this with read, or read/write permissions
	out, err := os.OpenFile("/pfs/out", os.O_WRONLY, 0644)
	if err != nil {
		panic(err)
	}
	defer out.Close()

	// this is the file loop
	for {
		if err := func() error {
			tw := tar.NewWriter(out)
			defer tw.Close()
			// this is the message loop
			for {
				// read a message
				ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
				defer cancel()
				m, err := reader.ReadMessage(ctx)
				if err != nil {
					return nil
				}
				// give it a unique name
				name := topic + time.Now().Format(time.RFC3339Nano)
				// write the header
				for err = tw.WriteHeader(&tar.Header{
					Name: name,
					Mode: 0600,
					Size: int64(len(m.Value)),
				}); err != nil; {
					if !strings.Contains(err.Error(), "broken pipe") {
						return err
					}
					// if there's a broken pipe, just give it some time to get ready for the next message
					time.Sleep(5 * time.Millisecond)
				}
				// and the message
				for _, err = tw.Write(m.Value); err != nil; {
					if !strings.Contains(err.Error(), "broken pipe") {
						return err
					}
					// if there's a broken pipe, just give it some time to get ready for the next message
					time.Sleep(5 * time.Millisecond)
				}
				return nil
			}
		}(); err != nil {
			panic(err)
		}
	}
}
<commit_msg>fix bug in kafka example<commit_after>package main

import (
	"archive/tar"
	"context"
	"os"
	"strings"
	"time"

	kafka "github.com/segmentio/kafka-go"
)

func main() {
	// Get the connection info from the ENV vars
	host := os.Getenv("HOST")
	port := os.Getenv("PORT")
	topic := os.Getenv("TOPIC")

	// And create a new kafka reader
	reader := kafka.NewReader(kafka.ReaderConfig{
		Brokers:  []string{host + ":" + port},
		Topic:    topic,
		MinBytes: 10e1,
		MaxBytes: 10e6,
	})
	defer reader.Close()

	// Open the /pfs/out pipe with write only permissons (the pachyderm spout will be reading at the other end of this)
	// Note: it won't work if you try to open this with read, or read/write permissions
	out, err := os.OpenFile("/pfs/out", os.O_WRONLY, 0644)
	if err != nil {
		panic(err)
	}
	defer out.Close()

	// this is the file loop
	for {
		if err := func() error {
			tw := tar.NewWriter(out)
			defer tw.Close()
			// this is the message loop
			for {
				// read a message
				ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
				defer cancel()
				m, err := reader.ReadMessage(ctx)
				if err != nil {
					return err
				}
				// give it a unique name
				name := topic + time.Now().Format(time.RFC3339Nano)
				// write the header
				for err = tw.WriteHeader(&tar.Header{
					Name: name,
					Mode: 0600,
					Size: int64(len(m.Value)),
				}); err != nil; {
					if !strings.Contains(err.Error(), "broken pipe") {
						return err
					}
					// if there's a broken pipe, just give it some time to get ready for the next message
					time.Sleep(5 * time.Millisecond)
				}
				// and the message
				for _, err = tw.Write(m.Value); err != nil; {
					if !strings.Contains(err.Error(), "broken pipe") {
						return err
					}
					// if there's a broken pipe, just give it some time to get ready for the next message
					time.Sleep(5 * time.Millisecond)
				}
				return nil
			}
		}(); err != nil {
			panic(err)
		}
	}
}
<|endoftext|>