<commit_before>package images

import (
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"sort"
	"text/tabwriter"
	"time"

	"github.com/awslabs/aws-sdk-go/aws"
	"github.com/awslabs/aws-sdk-go/aws/awsutil"
	"github.com/awslabs/aws-sdk-go/service/ec2"
	"github.com/fatih/color"
)

type AwsImages struct {
	svc *ec2.EC2

	images []*ec2.Image
}

func NewAwsImages(region string) *AwsImages {
	return &AwsImages{
		svc: ec2.New(&aws.Config{Region: region}),
	}
}

func (a *AwsImages) Fetch() error {
	input := &ec2.DescribeImagesInput{
		Owners: stringSlice("self"),
	}

	resp, err := a.svc.DescribeImages(input)
	if err != nil {
		return err
	}

	a.images = resp.Images

	// sort from oldest to newest
	if len(a.images) > 1 {
		sort.Sort(a)
	}

	return nil
}

func (a *AwsImages) Print() {
	if len(a.images) == 0 {
		fmt.Println("no images found")
		return
	}

	color.Green("AWS: Region: %s (%d images)\n\n", a.svc.Config.Region, len(a.images))

	w := new(tabwriter.Writer)
	w.Init(os.Stdout, 10, 8, 0, '\t', 0)
	defer w.Flush()

	fmt.Fprintln(w, "    Name\tID\tState\tTags")

	for i, image := range a.images {
		tags := make([]string, len(image.Tags))
		for i, tag := range image.Tags {
			tags[i] = *tag.Key + ":" + *tag.Value
		}

		fmt.Fprintf(w, "[%d] %s\t%s\t%s\t%+v\n",
			i, *image.Name, *image.ImageID, *image.State, tags)
	}
}

func (a *AwsImages) Help(command string) string {
	switch command {
	case "modify":
		return `Usage: images modify --provider aws [options]

  Modify AMI properties.

Options:

  -create-tags                  Create or override tags
  -delete-tags                  Delete tags
`
	case "list":
	}

	return "no help found for command " + command
}

func (a *AwsImages) Modify(args []string) error {
	var (
		createTags string
		deleteTags string
		imageIds   string
	)

	flagSet := flag.NewFlagSet("modify", flag.ContinueOnError)
	flagSet.StringVar(&createTags, "create-tags", "", "create tags")
	flagSet.StringVar(&deleteTags, "delete-tags", "", "delete tags")
	flagSet.StringVar(&imageIds, "image-ids", "", "delete tags")
	flagSet.Usage = func() {
		helpMsg := `Usage: images modify --provider aws [options]

  Modify AMI properties.

Options:

  -image-ids   "ami-123,..."   Images to be user with below actions

  -create-tags "key=val,..."   Create or override tags
  -delete-tags "key,..."       Delete tags
`
		fmt.Fprintf(os.Stderr, helpMsg)
	}

	flagSet.SetOutput(ioutil.Discard) // don't print anything without my permission
	if err := flagSet.Parse(args); err != nil {
		return nil // we don't return error, the usage will be printed instead
	}

	if len(args) == 0 {
		flagSet.Usage()
		return errors.New("no flags are passed")
	}

	fmt.Printf("createTags = %+v\n", createTags)
	fmt.Printf("deleteTags = %+v\n", deleteTags)
	fmt.Printf("imageIds = %+v\n", imageIds)
	return nil
}

// Add tags adds or overwrites all tags for the specified images
func (a *AwsImages) AddTags(tags map[string]string, images ...string) error {
	params := &ec2.CreateTagsInput{
		Resources: []*string{ // Required
			aws.String("String"), // Required
			// More values...
		},
		Tags: []*ec2.Tag{ // Required
			&ec2.Tag{ // Required
				Key:   aws.String("String"),
				Value: aws.String("String"),
			},
			// More values...
		},
		DryRun: aws.Boolean(true),
	}

	resp, err := a.svc.CreateTags(params)

	if awserr := aws.Error(err); awserr != nil {
		// A service error occurred.
		fmt.Println("Error:", awserr.Code, awserr.Message)
	} else if err != nil {
		// A non-service error occurred.
		panic(err)
	}

	// Pretty-print the response data.
	fmt.Println(awsutil.StringValue(resp))
	return nil
}

//
// Sort interface
//

func (a *AwsImages) Len() int {
	return len(a.images)
}

func (a *AwsImages) Less(i, j int) bool {
	it, err := time.Parse(time.RFC3339, *a.images[i].CreationDate)
	if err != nil {
		log.Println("aws: sorting err: ", err)
	}

	jt, err := time.Parse(time.RFC3339, *a.images[j].CreationDate)
	if err != nil {
		log.Println("aws: sorting err: ", err)
	}

	return it.Before(jt)
}

func (a *AwsImages) Swap(i, j int) {
	a.images[i], a.images[j] = a.images[j], a.images[i]
}

//
// Utils
//

func stringSlice(vals ...string) []*string {
	a := make([]*string, len(vals))

	for i, v := range vals {
		a[i] = aws.String(v)
	}

	return a
}
<commit_msg>images/aws: implement create-tags<commit_after>package images

import (
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"sort"
	"strings"
	"text/tabwriter"
	"time"

	"github.com/awslabs/aws-sdk-go/aws"
	"github.com/awslabs/aws-sdk-go/aws/awsutil"
	"github.com/awslabs/aws-sdk-go/service/ec2"
	"github.com/fatih/color"
)

type AwsImages struct {
	svc *ec2.EC2

	images []*ec2.Image
}

func NewAwsImages(region string) *AwsImages {
	return &AwsImages{
		svc: ec2.New(&aws.Config{Region: region}),
	}
}

func (a *AwsImages) Fetch() error {
	input := &ec2.DescribeImagesInput{
		Owners: stringSlice("self"),
	}

	resp, err := a.svc.DescribeImages(input)
	if err != nil {
		return err
	}

	a.images = resp.Images

	// sort from oldest to newest
	if len(a.images) > 1 {
		sort.Sort(a)
	}

	return nil
}

func (a *AwsImages) Print() {
	if len(a.images) == 0 {
		fmt.Println("no images found")
		return
	}

	color.Green("AWS: Region: %s (%d images)\n\n", a.svc.Config.Region, len(a.images))

	w := new(tabwriter.Writer)
	w.Init(os.Stdout, 10, 8, 0, '\t', 0)
	defer w.Flush()

	fmt.Fprintln(w, "    Name\tID\tState\tTags")

	for i, image := range a.images {
		tags := make([]string, len(image.Tags))
		for i, tag := range image.Tags {
			tags[i] = *tag.Key + ":" + *tag.Value
		}

		fmt.Fprintf(w, "[%d] %s\t%s\t%s\t%+v\n",
			i, *image.Name, *image.ImageID, *image.State, tags)
	}
}

func (a *AwsImages) Help(command string) string {
	switch command {
	case "modify":
		return `Usage: images modify --provider aws [options]

  Modify AMI properties.

Options:

  -create-tags                  Create or override tags
  -delete-tags                  Delete tags
`
	case "list":
	}

	return "no help found for command " + command
}

func (a *AwsImages) Modify(args []string) error {
	var (
		createTags string
		deleteTags string
		imageIds   string
		dryRun     bool
	)

	flagSet := flag.NewFlagSet("modify", flag.ContinueOnError)
	flagSet.StringVar(&createTags, "create-tags", "", "Create  or override tags")
	flagSet.StringVar(&deleteTags, "delete-tags", "", "Delete tags")
	flagSet.StringVar(&imageIds, "image-ids", "", "Images to be used with actions")
	flagSet.BoolVar(&dryRun, "dry-run", false, "Don't run command, but show the action")
	flagSet.Usage = func() {
		helpMsg := `Usage: images modify --provider aws [options]

  Modify AMI properties.

Options:

  -image-ids   "ami-123,..."   Images to be used with below actions

  -create-tags "key=val,..."   Create or override tags
  -delete-tags "key,..."       Delete tags
  -dry-run                     Don't run command, but show the action
`
		fmt.Fprintf(os.Stderr, helpMsg)
	}

	flagSet.SetOutput(ioutil.Discard) // don't print anything without my permission
	if err := flagSet.Parse(args); err != nil {
		return nil // we don't return error, the usage will be printed instead
	}

	if len(args) == 0 {
		flagSet.Usage()
		return errors.New("no flags are passed")
	}

	if imageIds == "" {
		return errors.New("no images are passed with [--image-ids]")
	}

	if createTags != "" && deleteTags != "" {
		return errors.New("not allowed to be used together: [--create-tags,--delete-tags]")
	}
	fmt.Printf("imageIds = %+v\n", imageIds)

	if createTags != "" {
		fmt.Printf("createTags = %+v\n", createTags)

		keyVals := make(map[string]string, 0)

		for _, keyVal := range strings.Split(createTags, ",") {
			keys := strings.Split(keyVal, "=")
			if len(keys) != 2 {
				return fmt.Errorf("malformed value passed to --create-tags: %v", keys)
			}
			keyVals[keys[0]] = keys[1]
		}

		return a.AddTags(keyVals, dryRun, strings.Split(imageIds, ",")...)
	}

	if deleteTags != "" {
		fmt.Printf("deleteTags = %+v\n", deleteTags)
	}

	return nil
}

// Add tags adds or overwrites all tags for the specified images
func (a *AwsImages) AddTags(tags map[string]string, dryRun bool, images ...string) error {
	ec2Tags := make([]*ec2.Tag, 0)
	for key, val := range tags {
		ec2Tags = append(ec2Tags, &ec2.Tag{
			Key:   aws.String(key),
			Value: aws.String(val),
		})
	}

	params := &ec2.CreateTagsInput{
		Resources: stringSlice(images...),
		Tags:      ec2Tags,
		DryRun:    aws.Boolean(dryRun),
	}

	resp, err := a.svc.CreateTags(params)
	if awserr := aws.Error(err); awserr != nil {
		// A service error occurred.
		// fmt.Println("Error:", awserr.Code, awserr.Message)
		return err
	} else if err != nil {
		// A non-service error occurred.
		return err
	}

	// Pretty-print the response data.
	fmt.Println(awsutil.StringValue(resp))
	return nil
}

//
// Sort interface
//

func (a *AwsImages) Len() int {
	return len(a.images)
}

func (a *AwsImages) Less(i, j int) bool {
	it, err := time.Parse(time.RFC3339, *a.images[i].CreationDate)
	if err != nil {
		log.Println("aws: sorting err: ", err)
	}

	jt, err := time.Parse(time.RFC3339, *a.images[j].CreationDate)
	if err != nil {
		log.Println("aws: sorting err: ", err)
	}

	return it.Before(jt)
}

func (a *AwsImages) Swap(i, j int) {
	a.images[i], a.images[j] = a.images[j], a.images[i]
}

//
// Utils
//

func stringSlice(vals ...string) []*string {
	a := make([]*string, len(vals))

	for i, v := range vals {
		a[i] = aws.String(v)
	}

	return a
}
<|endoftext|>


<commit_before>package auth

import (
	"code.google.com/p/goauth2/oauth"
	"fmt"
	"github.com/prasmussen/gdrive/util"
	"net/http"
)

// Get auth code from user
func promptUserForAuthCode(config *oauth.Config) string {
	authUrl := config.AuthCodeURL("state")
	fmt.Println("Go to the following link in your browser:")
	fmt.Printf("%v\n\n", authUrl)
	return util.Prompt("Enter verification code: ")
}

// Returns true if we have a valid cached token
func hasValidToken(cacheFile oauth.CacheFile, transport *oauth.Transport) bool {
	// Check if we have a cached token
	token, err := cacheFile.Token()
	if err != nil {
		return false
	}

	// Refresh token if its expired
	if token.Expired() {
		transport.Token = token
		err = transport.Refresh()
		if err != nil {
			fmt.Println(err)
			return false
		}
	}
	return true
}

func GetOauth2Client(clientId, clientSecret, cachePath string, promptUser bool) (*http.Client, error) {
	cacheFile := oauth.CacheFile(cachePath)

	config := &oauth.Config{
		ClientId:     clientId,
		ClientSecret: clientSecret,
		Scope:        "https://www.googleapis.com/auth/drive",
		RedirectURL:  "urn:ietf:wg:oauth:2.0:oob",
		AuthURL:      "https://accounts.google.com/o/oauth2/auth",
		TokenURL:     "https://accounts.google.com/o/oauth2/token",
		TokenCache:   cacheFile,
	}

	transport := &oauth.Transport{
		Config:    config,
		Transport: http.DefaultTransport,
	}

	// Return client if we have a valid token
	if hasValidToken(cacheFile, transport) {
		return transport.Client(), nil
	}

	// Get auth code from user and request a new token
	code := promptUserForAuthCode(config)
	_, err := transport.Exchange(code)
	if err != nil {
		return nil, err
	}
	return transport.Client(), nil
}
<commit_msg>Actually use the option to disable the interactive prompt.<commit_after>package auth

import (
	"code.google.com/p/goauth2/oauth"
	"errors"
	"fmt"
	"github.com/prasmussen/gdrive/util"
	"net/http"
)

// Get auth code from user
func promptUserForAuthCode(config *oauth.Config) string {
	authUrl := config.AuthCodeURL("state")
	fmt.Println("Go to the following link in your browser:")
	fmt.Printf("%v\n\n", authUrl)
	return util.Prompt("Enter verification code: ")
}

// Returns true if we have a valid cached token
func hasValidToken(cacheFile oauth.CacheFile, transport *oauth.Transport) bool {
	// Check if we have a cached token
	token, err := cacheFile.Token()
	if err != nil {
		return false
	}

	// Refresh token if its expired
	if token.Expired() {
		transport.Token = token
		err = transport.Refresh()
		if err != nil {
			fmt.Println(err)
			return false
		}
	}
	return true
}

func GetOauth2Client(clientId, clientSecret, cachePath string, promptUser bool) (*http.Client, error) {
	cacheFile := oauth.CacheFile(cachePath)

	config := &oauth.Config{
		ClientId:     clientId,
		ClientSecret: clientSecret,
		Scope:        "https://www.googleapis.com/auth/drive",
		RedirectURL:  "urn:ietf:wg:oauth:2.0:oob",
		AuthURL:      "https://accounts.google.com/o/oauth2/auth",
		TokenURL:     "https://accounts.google.com/o/oauth2/token",
		TokenCache:   cacheFile,
	}

	transport := &oauth.Transport{
		Config:    config,
		Transport: http.DefaultTransport,
	}

	// Return client if we have a valid token
	if hasValidToken(cacheFile, transport) {
		return transport.Client(), nil
	}

	if !promptUser {
		return nil, errors.New("no valid token found")
	}

	// Get auth code from user and request a new token
	code := promptUserForAuthCode(config)
	_, err := transport.Exchange(code)
	if err != nil {
		return nil, err
	}
	return transport.Client(), nil
}
<|endoftext|>


<commit_before>package auth

import (
	"errors"
	"fmt"
	"net/http"
	"strings"
	"time"

	"github.com/chrisolsen/fbgraphapi"
	"golang.org/x/net/context"
	"google.golang.org/appengine"
	"google.golang.org/appengine/datastore"
)

var ErrNoCookie = errors.New("no cookie found")

// GetToken returns the *Token value for the raw token value contained within the auth cookie or auth header
func GetToken(c context.Context, r *http.Request) (*Token, error) {
	uuid, err := getUUIDFromCookie(r)
	if err != nil && err != http.ErrNoCookie {
		return nil, err
	}
	if err == http.ErrNoCookie {
		uuid = getUUIDFromHeader(r)
	}
	if err != nil {
		return nil, err
	}

	tstore := NewTokenStore()
	return tstore.Get(c, uuid)
}

// Signup creates a user account and links up the credentials. Based on the request type an auth cookie
// or header token will be set with an auth token.
func Signup(c context.Context, w http.ResponseWriter, r *http.Request, creds *Credentials, account *Account) error {
	astore := NewAccountStore()
	tstore := NewTokenStore()

	accountKey, err := astore.Create(c, creds, account)
	if err != nil {
		return errors.New("failed to create account")
	}
	token, err := tstore.Create(c, accountKey)

	if accepts(r, "json") {
		setHeaderToken(w, token.UUID)
	} else {
		setAuthCookieToken(w, token.UUID)
	}

	return nil
}

// Signout deletes the token in the response to the client as well as deletes the token
// in the database to ensure it is no longer usable
func Signout(c context.Context, w http.ResponseWriter, r *http.Request) error {
	var err error
	var uuid string

	if accepts(r, "json") {
		uuid = getUUIDFromHeader(r)
		if err != nil {
			return fmt.Errorf("failed to get token from header: %v", err)
		}
		clearHeader(w)
	} else {
		uuid, err = getUUIDFromCookie(r)
		if err != nil {
			return fmt.Errorf("failed to get token from cookie: %v", err)
		}
		clearCookie(w)
	}

	store := NewTokenStore()
	token, err := store.Get(c, uuid)
	if err != nil {
		return err
	}
	err = datastore.Delete(c, token.Key)

	return err
}

// Authorize .
func Authorize(c context.Context, w http.ResponseWriter, r *http.Request, creds *Credentials) (*Token, error) {
	var token *Token
	var err error
	if len(creds.ProviderName) > 0 {
		token, err = authorizeOut(c, creds, appEngineURLGetter{Ctx: c})
	} else {
		token, err = authorizeIn(c, creds)
	}
	if err != nil {
		return nil, err
	}

	if accepts(r, "json") {
		setHeaderToken(w, token.UUID)
	} else {
		setAuthCookieToken(w, token.UUID)
	}

	return token, nil
}

func authorizeIn(c context.Context, creds *Credentials) (*Token, error) {
	accountStore := NewAccountStore()
	tokenStore := NewTokenStore()

	accountKey, err := accountStore.GetAccountKeyByCredentials(c, creds)
	if err != nil {
		return nil, fmt.Errorf("getting account key by credentials: %v", err)
	}

	token, err := tokenStore.Create(c, accountKey)
	if err != nil {
		return nil, err
	}

	return token, nil
}

func authorizeOut(c context.Context, creds *Credentials, urlGetter urlGetter) (*Token, error) {
	var err error
	tokenStore := NewTokenStore()
	accountStore := NewAccountStore()

	switch creds.ProviderName {
	case "facebook":
		err = fbgraphapi.Authenticate(creds.ProviderToken, creds.ProviderID, urlGetter)
	default:
		return nil, errors.New("unknown auth provider")
	}
	if err != nil {
		return nil, fmt.Errorf("authenticate: %v", err)
	}

	accountKey, err := accountStore.GetAccountKeyByCredentials(c, creds)
	if err != nil {
		return nil, fmt.Errorf("getting account key by credentials: %v", err)
	}

	token, err := tokenStore.Create(c, accountKey)
	if err != nil {
		return nil, err
	}

	return token, nil
}

func clearCookie(w http.ResponseWriter) {
	http.SetCookie(w, &http.Cookie{
		Name:     cookieName,
		Path:     "/",
		Expires:  time.Time{},
		HttpOnly: true,
		Value:    "",
		Secure:   !appengine.IsDevAppServer(),
	})
}

func setAuthCookieToken(w http.ResponseWriter, uuid string) {
	http.SetCookie(w, &http.Cookie{
		Name:     cookieName,
		Path:     "/",
		Expires:  time.Now().Add(time.Hour * 24 * 14),
		HttpOnly: true,
		Secure:   !appengine.IsDevAppServer(),
		Value:    uuid,
	})
}

func setHeaderToken(w http.ResponseWriter, uuid string) {
	w.Header().Set("Authorization", uuid)
}

func getUUIDFromHeader(r *http.Request) string {
	return r.Header.Get("Authorization")[len("token="):]
}

func getUUIDFromCookie(r *http.Request) (string, error) {
	cookie, err := r.Cookie(cookieName)
	if err != nil || len(cookie.Value) == 0 {
		return "", ErrNoCookie
	}

	return cookie.Value, nil
}

func clearHeader(w http.ResponseWriter) {
	w.Header().Del("Authorization")
}

func accepts(r *http.Request, t string) bool {
	return strings.Index(r.Header.Get("Accept"), t) > 0
}
<commit_msg>add verify origin middlware<commit_after>package auth

import (
	"errors"
	"fmt"
	"net/http"
	"strings"
	"time"

	"net/url"

	"github.com/chrisolsen/fbgraphapi"
	"golang.org/x/net/context"
	"google.golang.org/appengine"
	"google.golang.org/appengine/datastore"
)

var ErrNoCookie = errors.New("no cookie found")

// GetToken returns the *Token value for the raw token value contained within the auth cookie or auth header
func GetToken(c context.Context, r *http.Request) (*Token, error) {
	uuid, err := getUUIDFromCookie(r)
	if err != nil && err != http.ErrNoCookie {
		return nil, err
	}
	if err == http.ErrNoCookie {
		uuid = getUUIDFromHeader(r)
	}
	if err != nil {
		return nil, err
	}

	tstore := NewTokenStore()
	return tstore.Get(c, uuid)
}

// Signup creates a user account and links up the credentials. Based on the request type an auth cookie
// or header token will be set with an auth token.
func Signup(c context.Context, w http.ResponseWriter, r *http.Request, creds *Credentials, account *Account) error {
	astore := NewAccountStore()
	tstore := NewTokenStore()

	accountKey, err := astore.Create(c, creds, account)
	if err != nil {
		return errors.New("failed to create account")
	}
	token, err := tstore.Create(c, accountKey)

	if accepts(r, "json") {
		setHeaderToken(w, token.UUID)
	} else {
		setAuthCookieToken(w, token.UUID)
	}

	return nil
}

// Signout deletes the token in the response to the client as well as deletes the token
// in the database to ensure it is no longer usable
func Signout(c context.Context, w http.ResponseWriter, r *http.Request) error {
	var err error
	var uuid string

	if accepts(r, "json") {
		uuid = getUUIDFromHeader(r)
		if err != nil {
			return fmt.Errorf("failed to get token from header: %v", err)
		}
		clearHeader(w)
	} else {
		uuid, err = getUUIDFromCookie(r)
		if err != nil {
			return fmt.Errorf("failed to get token from cookie: %v", err)
		}
		clearCookie(w)
	}

	store := NewTokenStore()
	token, err := store.Get(c, uuid)
	if err != nil {
		return err
	}
	err = datastore.Delete(c, token.Key)

	return err
}

// Authorize .
func Authorize(c context.Context, w http.ResponseWriter, r *http.Request, creds *Credentials) (*Token, error) {
	var token *Token
	var err error
	if len(creds.ProviderName) > 0 {
		token, err = authorizeOut(c, creds, appEngineURLGetter{Ctx: c})
	} else {
		token, err = authorizeIn(c, creds)
	}
	if err != nil {
		return nil, err
	}

	if accepts(r, "json") {
		setHeaderToken(w, token.UUID)
	} else {
		setAuthCookieToken(w, token.UUID)
	}

	return token, nil
}

func authorizeIn(c context.Context, creds *Credentials) (*Token, error) {
	accountStore := NewAccountStore()
	tokenStore := NewTokenStore()

	accountKey, err := accountStore.GetAccountKeyByCredentials(c, creds)
	if err != nil {
		return nil, fmt.Errorf("getting account key by credentials: %v", err)
	}

	token, err := tokenStore.Create(c, accountKey)
	if err != nil {
		return nil, err
	}

	return token, nil
}

func authorizeOut(c context.Context, creds *Credentials, urlGetter urlGetter) (*Token, error) {
	var err error
	tokenStore := NewTokenStore()
	accountStore := NewAccountStore()

	switch creds.ProviderName {
	case "facebook":
		err = fbgraphapi.Authenticate(creds.ProviderToken, creds.ProviderID, urlGetter)
	default:
		return nil, errors.New("unknown auth provider")
	}
	if err != nil {
		return nil, fmt.Errorf("authenticate: %v", err)
	}

	accountKey, err := accountStore.GetAccountKeyByCredentials(c, creds)
	if err != nil {
		return nil, fmt.Errorf("getting account key by credentials: %v", err)
	}

	token, err := tokenStore.Create(c, accountKey)
	if err != nil {
		return nil, err
	}

	return token, nil
}

func clearCookie(w http.ResponseWriter) {
	http.SetCookie(w, &http.Cookie{
		Name:     cookieName,
		Path:     "/",
		Expires:  time.Time{},
		HttpOnly: true,
		Value:    "",
		Secure:   !appengine.IsDevAppServer(),
	})
}

func setAuthCookieToken(w http.ResponseWriter, uuid string) {
	http.SetCookie(w, &http.Cookie{
		Name:     cookieName,
		Path:     "/",
		Expires:  time.Now().Add(time.Hour * 24 * 14),
		HttpOnly: true,
		Secure:   !appengine.IsDevAppServer(),
		Value:    uuid,
	})
}

func setHeaderToken(w http.ResponseWriter, uuid string) {
	w.Header().Set("Authorization", uuid)
}

func getUUIDFromHeader(r *http.Request) string {
	return r.Header.Get("Authorization")[len("token="):]
}

func getUUIDFromCookie(r *http.Request) (string, error) {
	cookie, err := r.Cookie(cookieName)
	if err != nil || len(cookie.Value) == 0 {
		return "", ErrNoCookie
	}

	return cookie.Value, nil
}

func clearHeader(w http.ResponseWriter) {
	w.Header().Del("Authorization")
}

func accepts(r *http.Request, t string) bool {
	return strings.Index(r.Header.Get("Accept"), t) > 0
}

// VerifyReferrer middlware validates the referer header matches the request url's host
func VerifyReferrer(c context.Context, w http.ResponseWriter, r *http.Request) context.Context {
	if r.Method != http.MethodPost {
		return c
	}

	err := func() error {
		referrer, err := url.Parse(r.Header.Get("Referer"))
		if err != nil {
			return err
		}
		if referrer.Host != r.Host {
			return fmt.Errorf("BLOCKED: VerifyReferrer: %v - %v", referrer, r.Host)
		}
		return nil
	}()

	if err != nil {
		cc, cancel := context.WithCancel(c)
		cancel()
		return cc
	}
	return c
}
<|endoftext|>


<commit_before>// Copyright 2019 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

import (
	"runtime"
	"runtime/debug"
	"sync/atomic"
)

func init() {
	register("AsyncPreempt", AsyncPreempt)
}

func AsyncPreempt() {
	// Run with just 1 GOMAXPROCS so the runtime is required to
	// use scheduler preemption.
	runtime.GOMAXPROCS(1)
	// Disable GC so we have complete control of what we're testing.
	debug.SetGCPercent(-1)

	// Start a goroutine with no sync safe-points.
	var ready, ready2 uint32
	go func() {
		for {
			atomic.StoreUint32(&ready, 1)
		}
	}()
	// Also start one with a frameless function.
	// This is an especially interesting case for
	// LR machines.
	go func() {
		atomic.StoreUint32(&ready2, 1)
		frameless()
	}()

	// Wait for the goroutine to stop passing through sync
	// safe-points.
	for atomic.LoadUint32(&ready) == 0 || atomic.LoadUint32(&ready2) == 0 {
		runtime.Gosched()
	}

	// Run a GC, which will have to stop the goroutine for STW and
	// for stack scanning. If this doesn't work, the test will
	// deadlock and timeout.
	runtime.GC()

	println("OK")
}

//go:noinline
func frameless() {
	for i := int64(0); i < 1<<62; i++ {
		out += i
	}
}

var out int64
<commit_msg>runtime: relax TestAsyncPreempt<commit_after>// Copyright 2019 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

import (
	"runtime"
	"runtime/debug"
	"sync/atomic"
)

func init() {
	register("AsyncPreempt", AsyncPreempt)
}

func AsyncPreempt() {
	// Run with just 1 GOMAXPROCS so the runtime is required to
	// use scheduler preemption.
	runtime.GOMAXPROCS(1)
	// Disable GC so we have complete control of what we're testing.
	debug.SetGCPercent(-1)

	// Start a goroutine with no sync safe-points.
	var ready, ready2 uint32
	go func() {
		for {
			atomic.StoreUint32(&ready, 1)
			dummy()
			dummy()
		}
	}()
	// Also start one with a frameless function.
	// This is an especially interesting case for
	// LR machines.
	go func() {
		atomic.StoreUint32(&ready2, 1)
		frameless()
	}()

	// Wait for the goroutine to stop passing through sync
	// safe-points.
	for atomic.LoadUint32(&ready) == 0 || atomic.LoadUint32(&ready2) == 0 {
		runtime.Gosched()
	}

	// Run a GC, which will have to stop the goroutine for STW and
	// for stack scanning. If this doesn't work, the test will
	// deadlock and timeout.
	runtime.GC()

	println("OK")
}

//go:noinline
func frameless() {
	for i := int64(0); i < 1<<62; i++ {
		out += i * i * i * i * i * 12345
	}
}

var out int64

//go:noinline
func dummy() {}
<|endoftext|>


<commit_before>package trace

import (
	"context"
	"net"
	"testing"
	"time"

	"github.com/golang/protobuf/proto"
	"github.com/stretchr/testify/assert"
	"github.com/stripe/veneur/ssf"
)

const ε = .00002

func TestStartTrace(t *testing.T) {
	const resource = "Robert'); DROP TABLE students;"
	const expectedParent int64 = 0
	start := time.Now()
	trace := StartTrace(resource)
	end := time.Now()

	between := end.After(trace.Start) && trace.Start.After(start)

	assert.Equal(t, trace.TraceID, trace.SpanID)
	assert.Equal(t, trace.ParentID, expectedParent)
	assert.Equal(t, trace.Resource, resource)
	assert.True(t, between)
}

func testRecord(t *testing.T, trace *Trace, name string, tags map[string]string) (sample *ssf.SSFSpan, end time.Time) {
	// arbitrary
	const BufferSize = 1087152

	traceAddr, err := net.ResolveUDPAddr("udp", localVeneurAddress)
	assert.NoError(t, err)
	serverConn, err := net.ListenUDP("udp", traceAddr)
	assert.NoError(t, err)
	defer serverConn.Close()

	err = serverConn.SetReadBuffer(BufferSize)
	assert.NoError(t, err)

	respChan := make(chan []byte)
	kill := make(chan struct{})

	go func() {
		buf := make([]byte, BufferSize)
		n, _, err := serverConn.ReadFrom(buf)
		assert.NoError(t, err)

		buf = buf[:n]
		respChan <- buf
	}()

	go func() {
		<-time.After(5 * time.Second)
		kill <- struct{}{}
	}()

	trace.Record(name, tags)
	end = time.Now()

	select {
	case _ = <-kill:
		assert.Fail(t, "timed out waiting for socket read")
	case resp := <-respChan:
		// Because this is marshalled using protobuf,
		// we can't expect the representation to be immutable
		// and cannot test the marshalled payload directly
		sample = &ssf.SSFSpan{}
		err := proto.Unmarshal(resp, sample)
		assert.NoError(t, err)
	}
	return
}

func TestRecord(t *testing.T) {
	const resource = "Robert'); DROP TABLE students;"
	const metricName = "veneur.trace.test"
	const serviceName = "veneur-test"
	Service = serviceName

	trace := StartTrace(resource)
	trace.Status = ssf.SSFSample_CRITICAL
	trace.error = true

	tags := map[string]string{
		"error.msg":   "an error occurred!",
		"error.type":  "type error interface",
		"error.stack": "insert\nlots\nof\nstuff",
		"resource":    resource,
		"name":        metricName,
	}

	sample, end := testRecord(t, trace, metricName, tags)

	timestamp := time.Unix(sample.StartTimestamp/1e9, 0)

	assert.Equal(t, trace.Start.Unix(), timestamp.Unix())

	duration := sample.EndTimestamp - sample.StartTimestamp

	// We don't know the exact duration, but we can assert on the interval
	assert.True(t, duration > 0, "Expected positive trace duration")
	upperBound := end.Sub(trace.Start).Nanoseconds()
	assert.True(t, duration < upperBound, "Expected trace duration (%d) to be less than upper bound %d", duration, upperBound)

	for _, metric := range sample.Metrics {
		assert.InEpsilon(t, metric.SampleRate, 0.1, ε)
	}

	assertTagEquals(t, sample, "resource", resource)
	assertTagEquals(t, sample, "name", metricName)
	assert.Equal(t, true, sample.Error)
	assert.Equal(t, serviceName, sample.Service)
	assert.Equal(t, tags, sample.Tags)
}

func TestAttach(t *testing.T) {
	const resource = "Robert'); DROP TABLE students;"
	ctx := context.Background()

	parent := ctx.Value(traceKey)
	assert.Nil(t, parent, "Expected not to find parent in context before attaching")

	trace := StartTrace(resource)
	ctx2 := trace.Attach(ctx)

	parent = ctx2.Value(traceKey).(*Trace)
	assert.NotNil(t, parent, "Expected not to find parent in context before attaching")
}

func TestSpanFromContext(t *testing.T) {
	const resource = "Robert'); DROP TABLE students;"
	trace := StartTrace(resource)

	ctx := trace.Attach(context.Background())
	child := SpanFromContext(ctx)
	// Test the *grandchild* so that we can ensure that
	// the parent ID is set independently of the trace ID
	ctx = child.Attach(context.Background())
	grandchild := SpanFromContext(ctx)

	assert.Equal(t, child.TraceID, trace.SpanID)
	assert.Equal(t, child.TraceID, trace.TraceID)
	assert.Equal(t, child.ParentID, trace.SpanID)
	assert.Equal(t, grandchild.ParentID, child.SpanID)
	assert.Equal(t, grandchild.TraceID, trace.SpanID)
}

// StartSpanFromContext should create a brand-new root span
// if the context does not contain a span
func TestSpanFromContextNoParent(t *testing.T) {
	const resource = "example"
	ctx := context.Background()

	span, _ := StartSpanFromContext(ctx, resource)

	assert.Equal(t, span.TraceID, span.SpanID)
	assert.Equal(t, int64(0), span.ParentID)
}

func TestStartChildSpan(t *testing.T) {
	const resource = "Robert'); DROP TABLE students;"
	root := StartTrace(resource)
	child := StartChildSpan(root)
	grandchild := StartChildSpan(child)

	assert.Equal(t, resource, child.Resource)
	assert.Equal(t, resource, grandchild.Resource)

	assert.Equal(t, root.SpanID, root.TraceID)
	assert.Equal(t, root.SpanID, child.TraceID)
	assert.Equal(t, root.SpanID, grandchild.TraceID)

	assert.Equal(t, root.SpanID, child.ParentID)
	assert.Equal(t, child.SpanID, grandchild.ParentID)
}

// Test that a Trace is correctly able to generate
// its spanContext representation from the point of view
// of its children
func TestTraceContextAsParent(t *testing.T) {
	const resource = "Robert'); DROP TABLE students;"
	trace := StartTrace(resource)

	ctx := trace.contextAsParent()

	assert.Equal(t, trace.TraceID, ctx.TraceID())
	assert.Equal(t, trace.SpanID, ctx.ParentID())
	assert.Equal(t, trace.Resource, ctx.Resource())
}

func TestNameTag(t *testing.T) {
	const name = "my.name.tag"
	tracer := Tracer{}
	span := tracer.StartSpan("resource", NameTag(name)).(*Span)
	assert.Equal(t, 1, len(span.Tags))
	assert.Equal(t, name, span.Tags["name"])

}

type localError struct {
	message string
}

func (le localError) Error() string {
	return le.message
}

func TestError(t *testing.T) {
	const resource = "Robert'); DROP TABLE students;"
	const errorMessage = "some error happened"
	err := localError{errorMessage}

	root := StartTrace(resource)
	root.Error(err)

	assert.Equal(t, root.Status, ssf.SSFSample_CRITICAL)
	assert.Equal(t, len(root.Tags), 3)

	for k, v := range root.Tags {
		switch k {
		case errorMessageTag:
			assert.Equal(t, v, err.Error())
		case errorTypeTag:
			assert.Equal(t, v, "localError")
		case errorStackTag:
			assert.Equal(t, v, err.Error())
		}
	}

}

func TestStripPackageName(t *testing.T) {
	type testCase struct {
		Name     string
		fname    string
		expected string
	}

	cases := []testCase{
		{
			Name:     "Method",
			fname:    "github.com/stripe/veneur.(*Server).Flush",
			expected: "veneur.(*Server).Flush",
		},
		{
			Name:     "NestedPackageMethod",
			fname:    "github.com/stripe/veneur/trace.(*Tracer).StartSpan",
			expected: "trace.(*Tracer).StartSpan",
		},
		{
			// This shouldn't be valid, but we should at least ensure we don't
			// cause a runtime panic if it's passed
			Name:     "TrailingSlash",
			fname:    "github.com/",
			expected: "github.com/",
		},
	}

	for _, tc := range cases {
		t.Run(tc.Name, func(t *testing.T) {
			assert.Equal(t, stripPackageName(tc.fname), tc.expected)
		})
	}
}

func assertTagEquals(t *testing.T, sample *ssf.SSFSpan, name, value string) {
	assert.Equal(t, value, sample.Tags[name])
}
<commit_msg>Test manually setting end time<commit_after>package trace

import (
	"context"
	"net"
	"testing"
	"time"

	"github.com/golang/protobuf/proto"
	"github.com/stretchr/testify/assert"
	"github.com/stripe/veneur/ssf"
)

const ε = .00002

func TestStartTrace(t *testing.T) {
	const resource = "Robert'); DROP TABLE students;"
	const expectedParent int64 = 0
	start := time.Now()
	trace := StartTrace(resource)
	end := time.Now()

	between := end.After(trace.Start) && trace.Start.After(start)

	assert.Equal(t, trace.TraceID, trace.SpanID)
	assert.Equal(t, trace.ParentID, expectedParent)
	assert.Equal(t, trace.Resource, resource)
	assert.True(t, between)
}

func testRecord(t *testing.T, trace *Trace, name string, tags map[string]string) (sample *ssf.SSFSpan, end time.Time) {
	// arbitrary
	const BufferSize = 1087152

	traceAddr, err := net.ResolveUDPAddr("udp", localVeneurAddress)
	assert.NoError(t, err)
	serverConn, err := net.ListenUDP("udp", traceAddr)
	assert.NoError(t, err)
	defer serverConn.Close()

	err = serverConn.SetReadBuffer(BufferSize)
	assert.NoError(t, err)

	respChan := make(chan []byte)
	kill := make(chan struct{})

	go func() {
		buf := make([]byte, BufferSize)
		n, _, err := serverConn.ReadFrom(buf)
		assert.NoError(t, err)

		buf = buf[:n]
		respChan <- buf
	}()

	go func() {
		<-time.After(5 * time.Second)
		kill <- struct{}{}
	}()

	trace.Record(name, tags)
	end = time.Now()

	select {
	case _ = <-kill:
		assert.Fail(t, "timed out waiting for socket read")
	case resp := <-respChan:
		// Because this is marshalled using protobuf,
		// we can't expect the representation to be immutable
		// and cannot test the marshalled payload directly
		sample = &ssf.SSFSpan{}
		err := proto.Unmarshal(resp, sample)
		assert.NoError(t, err)
	}
	return
}

func TestRecord(t *testing.T) {
	const resource = "Robert'); DROP TABLE students;"
	const metricName = "veneur.trace.test"
	const serviceName = "veneur-test"
	Service = serviceName

	trace := StartTrace(resource)
	trace.Status = ssf.SSFSample_CRITICAL
	trace.error = true

	tags := map[string]string{
		"error.msg":   "an error occurred!",
		"error.type":  "type error interface",
		"error.stack": "insert\nlots\nof\nstuff",
		"resource":    resource,
		"name":        metricName,
	}

	sample, end := testRecord(t, trace, metricName, tags)

	timestamp := time.Unix(sample.StartTimestamp/1e9, 0)

	assert.Equal(t, trace.Start.Unix(), timestamp.Unix())

	duration := sample.EndTimestamp - sample.StartTimestamp

	// We don't know the exact duration, but we can assert on the interval
	assert.True(t, duration > 0, "Expected positive trace duration")
	upperBound := end.Sub(trace.Start).Nanoseconds()
	assert.True(t, duration < upperBound, "Expected trace duration (%d) to be less than upper bound %d", duration, upperBound)

	for _, metric := range sample.Metrics {
		assert.InEpsilon(t, metric.SampleRate, 0.1, ε)
	}

	assertTagEquals(t, sample, "resource", resource)
	assertTagEquals(t, sample, "name", metricName)
	assert.Equal(t, true, sample.Error)
	assert.Equal(t, serviceName, sample.Service)
	assert.Equal(t, tags, sample.Tags)
}

func TestRecordManualTime(t *testing.T) {
	trace := StartTrace("test-resource")
	end := time.Now()
	trace.End = end
	sample, _ := testRecord(t, trace, "test-metric", map[string]string{})
	assert.Equal(t, end.UnixNano(), sample.EndTimestamp)
}

func TestAttach(t *testing.T) {
	const resource = "Robert'); DROP TABLE students;"
	ctx := context.Background()

	parent := ctx.Value(traceKey)
	assert.Nil(t, parent, "Expected not to find parent in context before attaching")

	trace := StartTrace(resource)
	ctx2 := trace.Attach(ctx)

	parent = ctx2.Value(traceKey).(*Trace)
	assert.NotNil(t, parent, "Expected not to find parent in context before attaching")
}

func TestSpanFromContext(t *testing.T) {
	const resource = "Robert'); DROP TABLE students;"
	trace := StartTrace(resource)

	ctx := trace.Attach(context.Background())
	child := SpanFromContext(ctx)
	// Test the *grandchild* so that we can ensure that
	// the parent ID is set independently of the trace ID
	ctx = child.Attach(context.Background())
	grandchild := SpanFromContext(ctx)

	assert.Equal(t, child.TraceID, trace.SpanID)
	assert.Equal(t, child.TraceID, trace.TraceID)
	assert.Equal(t, child.ParentID, trace.SpanID)
	assert.Equal(t, grandchild.ParentID, child.SpanID)
	assert.Equal(t, grandchild.TraceID, trace.SpanID)
}

// StartSpanFromContext should create a brand-new root span
// if the context does not contain a span
func TestSpanFromContextNoParent(t *testing.T) {
	const resource = "example"
	ctx := context.Background()

	span, _ := StartSpanFromContext(ctx, resource)

	assert.Equal(t, span.TraceID, span.SpanID)
	assert.Equal(t, int64(0), span.ParentID)
}

func TestStartChildSpan(t *testing.T) {
	const resource = "Robert'); DROP TABLE students;"
	root := StartTrace(resource)
	child := StartChildSpan(root)
	grandchild := StartChildSpan(child)

	assert.Equal(t, resource, child.Resource)
	assert.Equal(t, resource, grandchild.Resource)

	assert.Equal(t, root.SpanID, root.TraceID)
	assert.Equal(t, root.SpanID, child.TraceID)
	assert.Equal(t, root.SpanID, grandchild.TraceID)

	assert.Equal(t, root.SpanID, child.ParentID)
	assert.Equal(t, child.SpanID, grandchild.ParentID)
}

// Test that a Trace is correctly able to generate
// its spanContext representation from the point of view
// of its children
func TestTraceContextAsParent(t *testing.T) {
	const resource = "Robert'); DROP TABLE students;"
	trace := StartTrace(resource)

	ctx := trace.contextAsParent()

	assert.Equal(t, trace.TraceID, ctx.TraceID())
	assert.Equal(t, trace.SpanID, ctx.ParentID())
	assert.Equal(t, trace.Resource, ctx.Resource())
}

func TestNameTag(t *testing.T) {
	const name = "my.name.tag"
	tracer := Tracer{}
	span := tracer.StartSpan("resource", NameTag(name)).(*Span)
	assert.Equal(t, 1, len(span.Tags))
	assert.Equal(t, name, span.Tags["name"])

}

type localError struct {
	message string
}

func (le localError) Error() string {
	return le.message
}

func TestError(t *testing.T) {
	const resource = "Robert'); DROP TABLE students;"
	const errorMessage = "some error happened"
	err := localError{errorMessage}

	root := StartTrace(resource)
	root.Error(err)

	assert.Equal(t, root.Status, ssf.SSFSample_CRITICAL)
	assert.Equal(t, len(root.Tags), 3)

	for k, v := range root.Tags {
		switch k {
		case errorMessageTag:
			assert.Equal(t, v, err.Error())
		case errorTypeTag:
			assert.Equal(t, v, "localError")
		case errorStackTag:
			assert.Equal(t, v, err.Error())
		}
	}

}

func TestStripPackageName(t *testing.T) {
	type testCase struct {
		Name     string
		fname    string
		expected string
	}

	cases := []testCase{
		{
			Name:     "Method",
			fname:    "github.com/stripe/veneur.(*Server).Flush",
			expected: "veneur.(*Server).Flush",
		},
		{
			Name:     "NestedPackageMethod",
			fname:    "github.com/stripe/veneur/trace.(*Tracer).StartSpan",
			expected: "trace.(*Tracer).StartSpan",
		},
		{
			// This shouldn't be valid, but we should at least ensure we don't
			// cause a runtime panic if it's passed
			Name:     "TrailingSlash",
			fname:    "github.com/",
			expected: "github.com/",
		},
	}

	for _, tc := range cases {
		t.Run(tc.Name, func(t *testing.T) {
			assert.Equal(t, stripPackageName(tc.fname), tc.expected)
		})
	}
}

func assertTagEquals(t *testing.T, sample *ssf.SSFSpan, name, value string) {
	assert.Equal(t, value, sample.Tags[name])
}
<|endoftext|>


<commit_before>/*******************************************************************************
The MIT License (MIT)

Copyright (c) 2016 Hajime Nakagami

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*******************************************************************************/

package firebirdsql

import (
	"database/sql"
	"testing"
)

func TestTransaction(t *testing.T) {
	var n int
	conn, err := sql.Open("firebirdsql_createdb", "sysdba:masterkey@localhost:3050/tmp/go_test_transaction.fdb")
	if err != nil {
		t.Fatalf("Error connecting: %v", err)
	}

	// Connection (autocommit)
	conn.Exec("CREATE TABLE test_trans (s varchar(2048))")
	conn.Close()
	conn, err = sql.Open("firebirdsql", "sysdba:masterkey@localhost:3050/tmp/go_test_transaction.fdb")
	err = conn.QueryRow("SELECT Count(*) FROM test_trans").Scan(&n)
	if err != nil {
		t.Fatalf("Error SELECT: %v", err)
	}
	if n != 0 {
		t.Fatalf("Incorrect count: %v", n)
	}
	conn.Exec("INSERT INTO test_trans (s) values ('A')")
	conn, err = sql.Open("firebirdsql", "sysdba:masterkey@localhost:3050/tmp/go_test_transaction.fdb")
	err = conn.QueryRow("SELECT Count(*) FROM test_trans").Scan(&n)
	if err != nil {
		t.Fatalf("Error SELECT: %v", err)
	}
	if n != 1 {
		t.Fatalf("Incorrect count: %v", n)
	}

	// Transaction
	tx, err := conn.Begin()
	if err != nil {
		t.Fatalf("Begin: %v", err)
	}

	// Rollback
	err = tx.QueryRow("SELECT Count(*) FROM test_trans").Scan(&n)
	if err != nil {
		t.Fatalf("Error SELECT: %v", err)
	}
	if n != 1 {
		t.Fatalf("Incorrect count: %v", n)
	}
	_, err = tx.Exec("INSERT INTO test_trans (s) values ('B')")
	err = tx.QueryRow("SELECT Count(*) FROM test_trans").Scan(&n)
	if err != nil {
		t.Fatalf("Error SELECT: %v", err)
	}
	if n != 2 {
		t.Fatalf("Incorrect count: %v", n)
	}
	err = tx.Rollback()
	if err != nil {
		t.Fatalf("Error Rollback: %v", err)
	}

	tx, err = conn.Begin()
	err = tx.QueryRow("SELECT Count(*) FROM test_trans").Scan(&n)
	if err != nil {
		t.Fatalf("Error SELECT: %v", err)
	}
	if n != 1 {
		t.Fatalf("Incorrect count: %v", n)
	}

	// Commit
	_, err = tx.Exec("INSERT INTO test_trans (s) values ('C')")
	err = tx.Commit()
	if err != nil {
		t.Fatalf("Error Commit: %v", err)
	}
	tx, err = conn.Begin()
	err = tx.QueryRow("SELECT Count(*) FROM test_trans").Scan(&n)
	if err != nil {
		t.Fatalf("Error SELECT: %v", err)
	}
	if n != 2 {
		t.Fatalf("Incorrect count: %v", n)
	}

	// without Commit (Need commit manually)
	_, err = tx.Exec("INSERT INTO test_trans (s) values ('D')")
	tx, err = conn.Begin()
	err = tx.QueryRow("SELECT Count(*) FROM test_trans").Scan(&n)
	if err != nil {
		t.Fatalf("Error SELECT: %v", err)
	}
	if n != 2 {
		t.Fatalf("Incorrect count: %v", n)
	}

	// Connection (autocommit)
	conn.Exec("INSERT INTO test_trans (s) values ('E')")
	conn.Close()
	conn, err = sql.Open("firebirdsql", "sysdba:masterkey@localhost:3050/tmp/go_test_transaction.fdb")
	err = tx.QueryRow("SELECT Count(*) FROM test_trans").Scan(&n)
	if err != nil {
		t.Fatalf("Error SELECT: %v", err)
	}
	if n != 3 {
		t.Fatalf("Incorrect count: %v", n)
	}

	conn.Close()
}

func TestIssue35(t *testing.T) {
	var n int
	conn, err := sql.Open("firebirdsql_createdb", "sysdba:masterkey@localhost:3050/tmp/go_test_issue35.fdb")

	if err != nil {
		t.Fatalf("Error connecting: %v", err)
	}

	tx, err := conn.Begin()

	if err != nil {
		t.Fatalf("Error Begin: %v", err)
	}

	err = tx.Commit()

	if err != nil {
		t.Fatalf("Error Commit: %v", err)
	}

	_, err = conn.Exec("CREATE TABLE test_issue35 (s varchar(2048))")

	if err != nil {
		t.Fatalf("Error CREATE TABLE: %v", err)
	}
	conn.Close()

	conn, err = sql.Open("firebirdsql", "sysdba:masterkey@localhost:3050/tmp/go_test_issue35.fdb")
	err = conn.QueryRow("SELECT Count(*) FROM test_issue35").Scan(&n)
	if err != nil {
		t.Fatalf("Error SELECT: %v", err)
	}
	if n != 0 {
		t.Fatalf("Incorrect count: %v", n)
	}
}
<commit_msg>add test for issue #38<commit_after>/*******************************************************************************
The MIT License (MIT)

Copyright (c) 2016 Hajime Nakagami

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*******************************************************************************/

package firebirdsql

import (
	"database/sql"
	"testing"
)

func TestTransaction(t *testing.T) {
	var n int
	conn, err := sql.Open("firebirdsql_createdb", "sysdba:masterkey@localhost:3050/tmp/go_test_transaction.fdb")
	if err != nil {
		t.Fatalf("Error connecting: %v", err)
	}

	// Connection (autocommit)
	conn.Exec("CREATE TABLE test_trans (s varchar(2048))")
	conn.Close()
	conn, err = sql.Open("firebirdsql", "sysdba:masterkey@localhost:3050/tmp/go_test_transaction.fdb")
	err = conn.QueryRow("SELECT Count(*) FROM test_trans").Scan(&n)
	if err != nil {
		t.Fatalf("Error SELECT: %v", err)
	}
	if n != 0 {
		t.Fatalf("Incorrect count: %v", n)
	}
	conn.Exec("INSERT INTO test_trans (s) values ('A')")
	conn, err = sql.Open("firebirdsql", "sysdba:masterkey@localhost:3050/tmp/go_test_transaction.fdb")
	err = conn.QueryRow("SELECT Count(*) FROM test_trans").Scan(&n)
	if err != nil {
		t.Fatalf("Error SELECT: %v", err)
	}
	if n != 1 {
		t.Fatalf("Incorrect count: %v", n)
	}

	// Transaction
	tx, err := conn.Begin()
	if err != nil {
		t.Fatalf("Begin: %v", err)
	}

	// Rollback
	err = tx.QueryRow("SELECT Count(*) FROM test_trans").Scan(&n)
	if err != nil {
		t.Fatalf("Error SELECT: %v", err)
	}
	if n != 1 {
		t.Fatalf("Incorrect count: %v", n)
	}
	_, err = tx.Exec("INSERT INTO test_trans (s) values ('B')")
	err = tx.QueryRow("SELECT Count(*) FROM test_trans").Scan(&n)
	if err != nil {
		t.Fatalf("Error SELECT: %v", err)
	}
	if n != 2 {
		t.Fatalf("Incorrect count: %v", n)
	}
	err = tx.Rollback()
	if err != nil {
		t.Fatalf("Error Rollback: %v", err)
	}

	tx, err = conn.Begin()
	err = tx.QueryRow("SELECT Count(*) FROM test_trans").Scan(&n)
	if err != nil {
		t.Fatalf("Error SELECT: %v", err)
	}
	if n != 1 {
		t.Fatalf("Incorrect count: %v", n)
	}

	// Commit
	_, err = tx.Exec("INSERT INTO test_trans (s) values ('C')")
	err = tx.Commit()
	if err != nil {
		t.Fatalf("Error Commit: %v", err)
	}
	tx, err = conn.Begin()
	err = tx.QueryRow("SELECT Count(*) FROM test_trans").Scan(&n)
	if err != nil {
		t.Fatalf("Error SELECT: %v", err)
	}
	if n != 2 {
		t.Fatalf("Incorrect count: %v", n)
	}

	// without Commit (Need commit manually)
	_, err = tx.Exec("INSERT INTO test_trans (s) values ('D')")
	tx, err = conn.Begin()
	err = tx.QueryRow("SELECT Count(*) FROM test_trans").Scan(&n)
	if err != nil {
		t.Fatalf("Error SELECT: %v", err)
	}
	if n != 2 {
		t.Fatalf("Incorrect count: %v", n)
	}

	// Connection (autocommit)
	conn.Exec("INSERT INTO test_trans (s) values ('E')")
	conn.Close()
	conn, err = sql.Open("firebirdsql", "sysdba:masterkey@localhost:3050/tmp/go_test_transaction.fdb")
	err = tx.QueryRow("SELECT Count(*) FROM test_trans").Scan(&n)
	if err != nil {
		t.Fatalf("Error SELECT: %v", err)
	}
	if n != 3 {
		t.Fatalf("Incorrect count: %v", n)
	}

	conn.Close()
}

func TestIssue35(t *testing.T) {
	var n int
	conn, err := sql.Open("firebirdsql_createdb", "sysdba:masterkey@localhost:3050/tmp/go_test_issue35.fdb")

	if err != nil {
		t.Fatalf("Error connecting: %v", err)
	}

	tx, err := conn.Begin()

	if err != nil {
		t.Fatalf("Error Begin: %v", err)
	}

	err = tx.Commit()

	if err != nil {
		t.Fatalf("Error Commit: %v", err)
	}

	_, err = conn.Exec("CREATE TABLE test_issue35 (s varchar(2048))")

	if err != nil {
		t.Fatalf("Error CREATE TABLE: %v", err)
	}
	conn.Close()

	conn, err = sql.Open("firebirdsql", "sysdba:masterkey@localhost:3050/tmp/go_test_issue35.fdb")
	err = conn.QueryRow("SELECT Count(*) FROM test_issue35").Scan(&n)
	if err != nil {
		t.Fatalf("Error SELECT: %v", err)
	}
	if n != 0 {
		t.Fatalf("Incorrect count: %v", n)
	}
}

func TestIssue38(t *testing.T) {
	conn, err := sql.Open("firebirdsql_createdb", "sysdba:masterkey@localhost:3050/tmp/go_test_issue38.fdb")

	if err != nil {
		t.Fatalf("Error connecting: %v", err)
	}
	conn.Exec(`
        CREATE TABLE test_issue38 (
          id  INTEGER NOT NULL,
          key VARCHAR(64),
          value VARCHAR(64)
        )
    `)
	if err != nil {
		t.Fatalf("Error CREATE TABLE: %v", err)
	}
	conn.Close()

	conn, err = sql.Open("firebirdsql", "sysdba:masterkey@localhost:3050/tmp/go_test_issue38.fdb")
	defer conn.Close()
	tx, err := conn.Begin()

	if err != nil {
		t.Fatalf("Error Begin: %v", err)
	}

	var rowId = sql.NullInt64{}

	err = tx.QueryRow(
		"INSERT INTO test_issue38 (id, key, value) VALUES (?, ?, ?) RETURNING id", 1, "testKey", "testValue").Scan(&rowId)
	if err == nil {
		t.Fatalf("'Dynamic SQL Error' is not occuerd.")
	}
	err = tx.Rollback()
	if err != nil {
		t.Fatalf("Error Rollback: %v", err)
	}
}
<|endoftext|>


<commit_before>// Copyright 2015, David Howden
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package index

// subColFlds is a Collection wrapper which overrides the Field
// method.
type subColFlds struct {
	Collection
	flds map[string]interface{}
}

func (scf subColFlds) Field(f string) interface{} {
	if x, ok := scf.flds[f]; ok {
		return x
	}
	return scf.Collection.Field(f)
}

// subGrpFlds is a Group wrapper which overrids the Field method
type subGrpFlds struct {
	Group
	tracks []Track
	flds   map[string]interface{}
}

func (sgf subGrpFlds) Tracks() []Track {
	if sgf.tracks != nil {
		return sgf.tracks
	}
	return sgf.Group.Tracks()
}

// Field implements Group.
func (sgf subGrpFlds) Field(field string) interface{} {
	if x, ok := sgf.flds[field]; ok {
		return x
	}
	return sgf.Group.Field(field)
}

// SumGroupIntAttr recurses through the Group and assigns the field with the sum
// of fields from children (Groups or Tracks).
func SumGroupIntAttr(field string, g Group) Group {
	if c, ok := g.(Collection); ok {
		return sumCollectionIntAttr(field, c)
	}
	return sumGroupIntAttr(field, g)
}

func sumCollectionIntAttr(field string, c Collection) Collection {
	nc := subCol{
		Collection: c,
		grps:       make(map[Key]Group, len(c.Keys())),
		flds:       make(map[string]interface{}),
	}
	var total int
	for _, k := range c.Keys() {
		g := c.Get(k)
		g = SumGroupIntAttr(field, g)
		total += g.Field(field).(int)
		nc.grps[k] = g
	}
	nc.flds = map[string]interface{}{
		field: total,
	}
	return nc
}

func sumGroupIntAttr(field string, g Group) Group {
	ng := subGrpFlds{
		Group: g,
		flds:  map[string]interface{}{},
	}
	var total int
	for _, t := range g.Tracks() {
		total += t.GetInt(field)
	}
	ng.flds[field] = total
	return ng
}

// CommonGroupAttr recurses through the Group and assigns fields on all sub groups
// which are common amoungst their children (Groups or Tracks).  If there is no common
// field, then the associated Field value is not set.
func CommonGroupAttr(attrs []Attr, g Group) Group {
	if c, ok := g.(Collection); ok {
		return commonCollectionTrackAttr(attrs, c)
	}
	return commonGroupTrackAttr(attrs, g)
}

func commonCollectionTrackAttr(attrs []Attr, c Collection) Collection {
	grps := make(map[Key]Group, len(c.Keys()))
	flds := make(map[string]interface{}, len(attrs))

	keys := c.Keys()
	if len(keys) > 0 {
		k0 := keys[0]
		g0 := c.Get(k0)
		g0 = CommonGroupAttr(attrs, g0)
		grps[k0] = g0

		for _, a := range attrs {
			flds[a.Field()] = g0.Field(a.Field())
		}

		if len(keys) > 1 {
			for _, k := range keys[1:] {
				g1 := c.Get(k)
				g1 = CommonGroupAttr(attrs, g1)
				grps[k] = g1

				for _, a := range attrs {
					f := a.Field()
					v := g1.Field(f)
					if !a.eq(flds[f], v) {
						flds[f] = a.Empty()
					}
				}
			}
		}
	}

	for _, a := range attrs {
		f := a.Field()
		if v, ok := flds[f]; ok && v == a.Empty() {
			delete(flds, f)
		}
	}

	return subCol{
		Collection: c,
		grps:       grps,
		flds:       flds,
	}
}

func commonGroupTrackAttr(attrs []Attr, g Group) Group {
	flds := make(map[string]interface{}, len(attrs))
	tracks := g.Tracks()

	if len(tracks) > 0 {
		t0 := tracks[0]
		for _, a := range attrs {
			f := a.Field()
			flds[f] = a.fn(t0)
		}

		if len(tracks) > 1 {
			for _, t := range tracks[1:] {
				for _, a := range attrs {
					f := a.Field()
					if !a.eq(flds[f], a.fn(t)) {
						flds[f] = a.Empty()
					}
				}
			}
		}
	}

	for _, a := range attrs {
		f := a.Field()
		if v, ok := flds[f]; ok && a.eq(v, a.Empty()) {
			delete(flds, f)
		}
	}

	return subGrpFlds{
		Group: g,
		flds:  flds,
	}
}

// subGrpName is a Group wrapper which overrides Name.
type subGrpName struct {
	Group
	name string
}

// Name implements Group.
func (s subGrpName) Name() string {
	return s.name
}

// RemoveEmptyCollections recursively goes through each sub Collection contained
// in the Group and removes any which don't have any tracks/groups in them.
func RemoveEmptyCollections(g Group) Group {
	gc, ok := g.(Collection)
	if ok {
		keys := gc.Keys()
		if len(keys) == 1 {
			gc0 := gc.Get(keys[0])
			_, col := gc0.(Collection)
			if !col && gc0.Name() == "" {
				return subGrpName{
					name:  gc.Name(),
					Group: gc0,
				}
			}
		}
		ngc := subCol{
			Collection: gc,
			grps:       make(map[Key]Group, len(gc.Keys())),
		}
		for _, k := range keys {
			ngc.grps[k] = RemoveEmptyCollections(gc.Get(k))
		}
		return ngc
	}
	return g
}

func firstTrack(g Group) Track {
	c, ok := g.(Collection)
	if ok {
		keys := c.Keys()
		if len(keys) > 0 {
			return firstTrack(c.Get(keys[0]))
		}
		return nil
	}

	ts := g.Tracks()
	if len(ts) > 0 {
		return ts[0]
	}
	return nil
}

func fieldsGroup(m map[string]interface{}, g Group) Group {
	if c, ok := g.(Collection); ok {
		return subColFlds{
			Collection: c,
			flds:       m,
		}
	}
	return subGrpFlds{
		Group: g,
		flds:  m,
	}
}

// Attr is a type which wraps a closure to get an attribute from an implementation of the
// Attr interface.
type Attr struct {
	field string
	empty interface{}
	eq    func(x, y interface{}) bool
	fn    func(t Track) interface{}
}

// Field returns the underlying field name.
func (g Attr) Field() string {
	return g.field
}

// Empty returns the empty value of the underlying field (the empty value of the field type).
func (g Attr) Empty() interface{} {
	return g.empty
}

// StringAttr constructs an Attr which will retrieve the string field from an implementation
// of Track.
func StringAttr(field string) Attr {
	return Attr{
		field: field,
		empty: "",
		eq:    func(x, y interface{}) bool { return x == y },
		fn:    func(t Track) interface{} { return t.GetString(field) },
	}
}

// StringsAttr returns an Attr which will retrieve the strings field from an implementation of Track.
func StringsAttr(field string) Attr {
	return Attr{
		field: field,
		empty: nil,
		eq: func(x, y interface{}) bool {
			// Annoyingly we have to cater for zero values from map[string]interface{}
			// which don't have the correct type wrapping the nil.
			if x == nil || y == nil {
				return x == nil && y == nil
			}
			xs := x.([]string) // NB: panics here are acceptable: should not be called on a non-'Strings' field.
			ys := y.([]string)
			if len(xs) != len(ys) {
				return false
			}
			for i, xss := range xs {
				if ys[i] != xss {
					return false
				}
			}
			return true
		},
		fn: func(t Track) interface{} {
			return t.GetStrings(field)
		},
	}
}

// IntAttr constructs an Attr which will retrieve the int field from an implementation of Track.
func IntAttr(field string) Attr {
	return Attr{
		field: field,
		empty: 0,
		eq:    func(x, y interface{}) bool { return x == y },
		fn:    func(t Track) interface{} { return t.GetInt(field) },
	}
}

// FirstTrackAttr wraps the given Group adding a string field `field` with the value taken
// from the first track.
func FirstTrackAttr(attr Attr, g Group) Group {
	t := firstTrack(g)
	if t == nil {
		return g
	}

	v := attr.fn(t)
	if attr.eq(v, attr.Empty()) {
		return g
	}
	m := map[string]interface{}{
		attr.field: v,
	}
	return fieldsGroup(m, g)
}
<commit_msg>Implement StringSliceEqual method for GetStrings equality testing.<commit_after>// Copyright 2015, David Howden
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package index

// subColFlds is a Collection wrapper which overrides the Field
// method.
type subColFlds struct {
	Collection
	flds map[string]interface{}
}

func (scf subColFlds) Field(f string) interface{} {
	if x, ok := scf.flds[f]; ok {
		return x
	}
	return scf.Collection.Field(f)
}

// subGrpFlds is a Group wrapper which overrids the Field method
type subGrpFlds struct {
	Group
	tracks []Track
	flds   map[string]interface{}
}

func (sgf subGrpFlds) Tracks() []Track {
	if sgf.tracks != nil {
		return sgf.tracks
	}
	return sgf.Group.Tracks()
}

// Field implements Group.
func (sgf subGrpFlds) Field(field string) interface{} {
	if x, ok := sgf.flds[field]; ok {
		return x
	}
	return sgf.Group.Field(field)
}

// SumGroupIntAttr recurses through the Group and assigns the field with the sum
// of fields from children (Groups or Tracks).
func SumGroupIntAttr(field string, g Group) Group {
	if c, ok := g.(Collection); ok {
		return sumCollectionIntAttr(field, c)
	}
	return sumGroupIntAttr(field, g)
}

func sumCollectionIntAttr(field string, c Collection) Collection {
	nc := subCol{
		Collection: c,
		grps:       make(map[Key]Group, len(c.Keys())),
		flds:       make(map[string]interface{}),
	}
	var total int
	for _, k := range c.Keys() {
		g := c.Get(k)
		g = SumGroupIntAttr(field, g)
		total += g.Field(field).(int)
		nc.grps[k] = g
	}
	nc.flds = map[string]interface{}{
		field: total,
	}
	return nc
}

func sumGroupIntAttr(field string, g Group) Group {
	ng := subGrpFlds{
		Group: g,
		flds:  map[string]interface{}{},
	}
	var total int
	for _, t := range g.Tracks() {
		total += t.GetInt(field)
	}
	ng.flds[field] = total
	return ng
}

// CommonGroupAttr recurses through the Group and assigns fields on all sub groups
// which are common amoungst their children (Groups or Tracks).  If there is no common
// field, then the associated Field value is not set.
func CommonGroupAttr(attrs []Attr, g Group) Group {
	if c, ok := g.(Collection); ok {
		return commonCollectionTrackAttr(attrs, c)
	}
	return commonGroupTrackAttr(attrs, g)
}

func commonCollectionTrackAttr(attrs []Attr, c Collection) Collection {
	grps := make(map[Key]Group, len(c.Keys()))
	flds := make(map[string]interface{}, len(attrs))

	keys := c.Keys()
	if len(keys) > 0 {
		k0 := keys[0]
		g0 := c.Get(k0)
		g0 = CommonGroupAttr(attrs, g0)
		grps[k0] = g0

		for _, a := range attrs {
			flds[a.Field()] = g0.Field(a.Field())
		}

		if len(keys) > 1 {
			for _, k := range keys[1:] {
				g1 := c.Get(k)
				g1 = CommonGroupAttr(attrs, g1)
				grps[k] = g1

				for _, a := range attrs {
					f := a.Field()
					v := g1.Field(f)
					if !a.eq(flds[f], v) {
						flds[f] = a.Empty()
					}
				}
			}
		}
	}

	for _, a := range attrs {
		f := a.Field()
		if v, ok := flds[f]; ok && v == a.Empty() {
			delete(flds, f)
		}
	}

	return subCol{
		Collection: c,
		grps:       grps,
		flds:       flds,
	}
}

func commonGroupTrackAttr(attrs []Attr, g Group) Group {
	flds := make(map[string]interface{}, len(attrs))
	tracks := g.Tracks()

	if len(tracks) > 0 {
		t0 := tracks[0]
		for _, a := range attrs {
			f := a.Field()
			flds[f] = a.fn(t0)
		}

		if len(tracks) > 1 {
			for _, t := range tracks[1:] {
				for _, a := range attrs {
					f := a.Field()
					if !a.eq(flds[f], a.fn(t)) {
						flds[f] = a.Empty()
					}
				}
			}
		}
	}

	for _, a := range attrs {
		f := a.Field()
		if v, ok := flds[f]; ok && a.eq(v, a.Empty()) {
			delete(flds, f)
		}
	}

	return subGrpFlds{
		Group: g,
		flds:  flds,
	}
}

// subGrpName is a Group wrapper which overrides Name.
type subGrpName struct {
	Group
	name string
}

// Name implements Group.
func (s subGrpName) Name() string {
	return s.name
}

// RemoveEmptyCollections recursively goes through each sub Collection contained
// in the Group and removes any which don't have any tracks/groups in them.
func RemoveEmptyCollections(g Group) Group {
	gc, ok := g.(Collection)
	if ok {
		keys := gc.Keys()
		if len(keys) == 1 {
			gc0 := gc.Get(keys[0])
			_, col := gc0.(Collection)
			if !col && gc0.Name() == "" {
				return subGrpName{
					name:  gc.Name(),
					Group: gc0,
				}
			}
		}
		ngc := subCol{
			Collection: gc,
			grps:       make(map[Key]Group, len(gc.Keys())),
		}
		for _, k := range keys {
			ngc.grps[k] = RemoveEmptyCollections(gc.Get(k))
		}
		return ngc
	}
	return g
}

func firstTrack(g Group) Track {
	c, ok := g.(Collection)
	if ok {
		keys := c.Keys()
		if len(keys) > 0 {
			return firstTrack(c.Get(keys[0]))
		}
		return nil
	}

	ts := g.Tracks()
	if len(ts) > 0 {
		return ts[0]
	}
	return nil
}

func fieldsGroup(m map[string]interface{}, g Group) Group {
	if c, ok := g.(Collection); ok {
		return subColFlds{
			Collection: c,
			flds:       m,
		}
	}
	return subGrpFlds{
		Group: g,
		flds:  m,
	}
}

// Attr is a type which wraps a closure to get an attribute from an implementation of the
// Attr interface.
type Attr struct {
	field string
	empty interface{}
	eq    func(x, y interface{}) bool
	fn    func(t Track) interface{}
}

// Field returns the underlying field name.
func (g Attr) Field() string {
	return g.field
}

// Empty returns the empty value of the underlying field (the empty value of the field type).
func (g Attr) Empty() interface{} {
	return g.empty
}

// StringAttr constructs an Attr which will retrieve the string field from an implementation
// of Track.
func StringAttr(field string) Attr {
	return Attr{
		field: field,
		empty: "",
		eq:    func(x, y interface{}) bool { return x == y },
		fn:    func(t Track) interface{} { return t.GetString(field) },
	}
}

// StringSliceEqual is a function used to compare two interface{} types which are assumed
// to be of type []string (or interface{}(nil)).
func StringSliceEqual(x, y interface{}) bool {
	// Annoyingly we have to cater for zero values from map[string]interface{}
	// which don't have the correct type wrapping the nil.
	if x == nil || y == nil {
		return x == nil && y == nil
	}
	xs := x.([]string) // NB: panics here are acceptable: should not be called on a non-'Strings' field.
	ys := y.([]string)
	if len(xs) != len(ys) {
		return false
	}
	for i, xss := range xs {
		if ys[i] != xss {
			return false
		}
	}
	return true
}

// StringsAttr returns an Attr which will retrieve the strings field from an implementation of Track.
func StringsAttr(field string) Attr {
	return Attr{
		field: field,
		empty: nil,
		eq:    StringSliceEqual,
		fn: func(t Track) interface{} {
			return t.GetStrings(field)
		},
	}
}

// IntAttr constructs an Attr which will retrieve the int field from an implementation of Track.
func IntAttr(field string) Attr {
	return Attr{
		field: field,
		empty: 0,
		eq:    func(x, y interface{}) bool { return x == y },
		fn:    func(t Track) interface{} { return t.GetInt(field) },
	}
}

// FirstTrackAttr wraps the given Group adding a string field `field` with the value taken
// from the first track.
func FirstTrackAttr(attr Attr, g Group) Group {
	t := firstTrack(g)
	if t == nil {
		return g
	}

	v := attr.fn(t)
	if attr.eq(v, attr.Empty()) {
		return g
	}
	m := map[string]interface{}{
		attr.field: v,
	}
	return fieldsGroup(m, g)
}
<|endoftext|>


<commit_before>package main

import "testing"
import "xogeny/gimpact/utils"
import "encoding/json"

func Test_Creation(t* testing.T) {
	dep := utils.Dependency{Name: "Foo", Version: "1.0.0"};
	version := utils.Version{
		Version: "0.1.0",
		Major: 0,
		Minor: 1,
		Patch: 0,
		Tarball: "http://modelica.org/",
		Zipball: "http://modelica.org/",
		Path: "./ThisLibrary",
		Dependencies: []utils.Dependency{dep},
		Sha: "abcdefg",
	};
	lib := utils.Library{
		Homepage: "http://mylib.modelica.org",
		Description: "A dummy library",
		Versions: map[string]utils.Version{"0.1.0": version},
	};

	index := map[string]utils.Library{"Dummy": lib}

	_, ok := index["Dummy"]
	if (!ok) { t.Fatal("Library not in index"); }
}

func Test_UnmarshallDependency(t* testing.T) {
	var ds = `{
                  "version": "3.2",
                  "name": "Modelica"
              }`
	sample := []byte(ds);
	dep := utils.Dependency{};
	err := json.Unmarshal(sample, &dep);
	if (err!=nil) { t.Fatal("Unmarshal failed"); }
	if (dep.Name!="Modelica") { t.Fatal("name mismatch"); }
	if (dep.Version!="3.2") { t.Fatal("version mismatch"); }
}

func Test_UnmarshallVersion(t* testing.T) {
	var ds = `{
                "major": 1,
                "tarball_url": "https://github.com/modelica-3rdparty/Physiolibrary/archive/v1.1.0.tar.gz",
                "patch": 0,
                "sha": "3075b23c214b65a510eb58654464f54507901378",
                "version": "1.1.0",
                "dependencies": [
                    {
                        "version": "3.2",
                        "name": "Modelica"
                    }
                ],
                "path": "Physiolibrary 1.1.0",
                "zipball_url": "https://github.com/modelica-3rdparty/Physiolibrary/archive/v1.1.0.zip",
                "minor": 1
            }`;
	sample := []byte(ds);
	dep := utils.Version{};
	err := json.Unmarshal(sample, &dep);
	if (err!=nil) { t.Fatal("Unmarshal failed"); }
	if (dep.Major!=1) { t.Fatal("major mismatch"); }
	if (dep.Minor!=1) { t.Fatal("minor mismatch"); }
	if (dep.Patch!=0) { t.Fatal("patch mismatch"); }
	if (dep.Sha!="3075b23c214b65a510eb58654464f54507901378") { t.Fatal("sha mismatch"); }
	if (dep.Version!="1.1.0") { t.Fatal("version mismatch"); }
	if (dep.Path!="Physiolibrary 1.1.0") { t.Fatal("version mismatch"); }
}

func Test_UnmarshallLibrary(t* testing.T) {
	var ds = `{
                  "homepage": "http://www.modelica.org",
                  "description": "A dummy library",
                  "versions": {}
              }`
	sample := []byte(ds);
	dep := utils.Library{};
	err := json.Unmarshal(sample, &dep);
	if (err!=nil) { t.Fatal("Unmarshal failed"); }
	if (dep.Homepage!="http://www.modelica.org") { t.Fatal("homepage mismatch"); }
	if (dep.Description!="A dummy library") { t.Fatal("description mismatch"); }
}

func Test_UnmarshallIndex(t* testing.T) {
	var ds = `{
    "SPICELib": {
        "homepage": "https://github.com/modelica-3rdparty/SPICELib",
        "description": "Free library with some of the modeling and analysis capabilities of the electric circuit simulator PSPICE.",
        "versions": {
            "1.1.0": {
                "major": 1,
                "tarball_url": "https://github.com/modelica-3rdparty/SPICELib/archive/v1.1.tar.gz",
                "patch": 0,
                "sha": "3d5738757b30192182b0b7caf46248c477d83e98",
                "version": "1.1.0",
                "dependencies": [],
                "path": "SPICELib 1.1",
                "zipball_url": "https://github.com/modelica-3rdparty/SPICELib/archive/v1.1.zip",
                "minor": 1
            },
            "1.1": {
                "major": 1,
                "tarball_url": "https://github.com/modelica-3rdparty/SPICELib/archive/v1.1.tar.gz",
                "patch": 0,
                "sha": "3d5738757b30192182b0b7caf46248c477d83e98",
                "version": "1.1.0",
                "dependencies": [],
                "path": "SPICELib 1.1",
                "zipball_url": "https://github.com/modelica-3rdparty/SPICELib/archive/v1.1.zip",
                "minor": 1
            }
        }
    },
    "FaultTriggering": {
        "homepage": "https://github.com/DLR-SR/FaultTriggering",
        "description": "Library for fault modelling in Modelica",
        "versions": {
            "0.6.2": {
                "major": 0,
                "tarball_url": "https://github.com/modelica-3rdparty/FaultTriggering/archive/v0.6.2.tar.gz",
                "patch": 2,
                "sha": "0a180687231d36540e1695523d3de6bbe10b28c5",
                "version": "0.6.2",
                "dependencies": [
                    {
                        "version": "3.2.1",
                        "name": "Modelica"
                    },
                    {
                        "version": "1.1.1",
                        "name": "ModelManagement"
                    }
                ],
                "path": "FaultTriggering",
                "zipball_url": "https://github.com/modelica-3rdparty/FaultTriggering/archive/v0.6.2.zip",
                "minor": 6
            },
            "0.5.0": {
                "major": 0,
                "tarball_url": "https://github.com/modelica-3rdparty/FaultTriggering/archive/v0.5.0.tar.gz",
                "patch": 0,
                "sha": "ad0a7ca17684753ceb3a6d5d2afd9988dc74912b",
                "version": "0.5.0",
                "dependencies": [
                    {
                        "version": "3.2.1",
                        "name": "Modelica"
                    },
                    {
                        "version": "1.1.1",
                        "name": "ModelManagement"
                    }
                ],
                "path": "FaultTriggering 0.5.0",
                "zipball_url": "https://github.com/modelica-3rdparty/FaultTriggering/archive/v0.5.0.zip",
                "minor": 5
            }
        }
    }
              }`
	sample := []byte(ds);
	dep := utils.Index{};
	err := json.Unmarshal(sample, &dep);
	if (err!=nil) { t.Fatal("Unmarshal failed"); }
}

func Test_ReadFile(t* testing.T) {
	index := utils.Index{};
	err := utils.ReadIndex("sample2.json", &index);
	if (err!=nil) { t.Fatal("Error reading file: "+err.Error()); }
	_, ok := index["Physiolibrary"];
	if (!ok) { t.Fatal("Couldn't find Physiolibrary"); }
}
<commit_msg>Ooops, wrong file<commit_after>package main

import "testing"
import "xogeny/gimpact/utils"
import "encoding/json"

func Test_Creation(t* testing.T) {
	dep := utils.Dependency{Name: "Foo", Version: "1.0.0"};
	version := utils.Version{
		Version: "0.1.0",
		Major: 0,
		Minor: 1,
		Patch: 0,
		Tarball: "http://modelica.org/",
		Zipball: "http://modelica.org/",
		Path: "./ThisLibrary",
		Dependencies: []utils.Dependency{dep},
		Sha: "abcdefg",
	};
	lib := utils.Library{
		Homepage: "http://mylib.modelica.org",
		Description: "A dummy library",
		Versions: map[string]utils.Version{"0.1.0": version},
	};

	index := map[string]utils.Library{"Dummy": lib}

	_, ok := index["Dummy"]
	if (!ok) { t.Fatal("Library not in index"); }
}

func Test_UnmarshallDependency(t* testing.T) {
	var ds = `{
                  "version": "3.2",
                  "name": "Modelica"
              }`
	sample := []byte(ds);
	dep := utils.Dependency{};
	err := json.Unmarshal(sample, &dep);
	if (err!=nil) { t.Fatal("Unmarshal failed"); }
	if (dep.Name!="Modelica") { t.Fatal("name mismatch"); }
	if (dep.Version!="3.2") { t.Fatal("version mismatch"); }
}

func Test_UnmarshallVersion(t* testing.T) {
	var ds = `{
                "major": 1,
                "tarball_url": "https://github.com/modelica-3rdparty/Physiolibrary/archive/v1.1.0.tar.gz",
                "patch": 0,
                "sha": "3075b23c214b65a510eb58654464f54507901378",
                "version": "1.1.0",
                "dependencies": [
                    {
                        "version": "3.2",
                        "name": "Modelica"
                    }
                ],
                "path": "Physiolibrary 1.1.0",
                "zipball_url": "https://github.com/modelica-3rdparty/Physiolibrary/archive/v1.1.0.zip",
                "minor": 1
            }`;
	sample := []byte(ds);
	dep := utils.Version{};
	err := json.Unmarshal(sample, &dep);
	if (err!=nil) { t.Fatal("Unmarshal failed"); }
	if (dep.Major!=1) { t.Fatal("major mismatch"); }
	if (dep.Minor!=1) { t.Fatal("minor mismatch"); }
	if (dep.Patch!=0) { t.Fatal("patch mismatch"); }
	if (dep.Sha!="3075b23c214b65a510eb58654464f54507901378") { t.Fatal("sha mismatch"); }
	if (dep.Version!="1.1.0") { t.Fatal("version mismatch"); }
	if (dep.Path!="Physiolibrary 1.1.0") { t.Fatal("version mismatch"); }
}

func Test_UnmarshallLibrary(t* testing.T) {
	var ds = `{
                  "homepage": "http://www.modelica.org",
                  "description": "A dummy library",
                  "versions": {}
              }`
	sample := []byte(ds);
	dep := utils.Library{};
	err := json.Unmarshal(sample, &dep);
	if (err!=nil) { t.Fatal("Unmarshal failed"); }
	if (dep.Homepage!="http://www.modelica.org") { t.Fatal("homepage mismatch"); }
	if (dep.Description!="A dummy library") { t.Fatal("description mismatch"); }
}

func Test_UnmarshallIndex(t* testing.T) {
	var ds = `{
    "SPICELib": {
        "homepage": "https://github.com/modelica-3rdparty/SPICELib",
        "description": "Free library with some of the modeling and analysis capabilities of the electric circuit simulator PSPICE.",
        "versions": {
            "1.1.0": {
                "major": 1,
                "tarball_url": "https://github.com/modelica-3rdparty/SPICELib/archive/v1.1.tar.gz",
                "patch": 0,
                "sha": "3d5738757b30192182b0b7caf46248c477d83e98",
                "version": "1.1.0",
                "dependencies": [],
                "path": "SPICELib 1.1",
                "zipball_url": "https://github.com/modelica-3rdparty/SPICELib/archive/v1.1.zip",
                "minor": 1
            },
            "1.1": {
                "major": 1,
                "tarball_url": "https://github.com/modelica-3rdparty/SPICELib/archive/v1.1.tar.gz",
                "patch": 0,
                "sha": "3d5738757b30192182b0b7caf46248c477d83e98",
                "version": "1.1.0",
                "dependencies": [],
                "path": "SPICELib 1.1",
                "zipball_url": "https://github.com/modelica-3rdparty/SPICELib/archive/v1.1.zip",
                "minor": 1
            }
        }
    },
    "FaultTriggering": {
        "homepage": "https://github.com/DLR-SR/FaultTriggering",
        "description": "Library for fault modelling in Modelica",
        "versions": {
            "0.6.2": {
                "major": 0,
                "tarball_url": "https://github.com/modelica-3rdparty/FaultTriggering/archive/v0.6.2.tar.gz",
                "patch": 2,
                "sha": "0a180687231d36540e1695523d3de6bbe10b28c5",
                "version": "0.6.2",
                "dependencies": [
                    {
                        "version": "3.2.1",
                        "name": "Modelica"
                    },
                    {
                        "version": "1.1.1",
                        "name": "ModelManagement"
                    }
                ],
                "path": "FaultTriggering",
                "zipball_url": "https://github.com/modelica-3rdparty/FaultTriggering/archive/v0.6.2.zip",
                "minor": 6
            },
            "0.5.0": {
                "major": 0,
                "tarball_url": "https://github.com/modelica-3rdparty/FaultTriggering/archive/v0.5.0.tar.gz",
                "patch": 0,
                "sha": "ad0a7ca17684753ceb3a6d5d2afd9988dc74912b",
                "version": "0.5.0",
                "dependencies": [
                    {
                        "version": "3.2.1",
                        "name": "Modelica"
                    },
                    {
                        "version": "1.1.1",
                        "name": "ModelManagement"
                    }
                ],
                "path": "FaultTriggering 0.5.0",
                "zipball_url": "https://github.com/modelica-3rdparty/FaultTriggering/archive/v0.5.0.zip",
                "minor": 5
            }
        }
    }
              }`
	sample := []byte(ds);
	dep := utils.Index{};
	err := json.Unmarshal(sample, &dep);
	if (err!=nil) { t.Fatal("Unmarshal failed"); }
}

func Test_ReadFile(t* testing.T) {
	index := utils.Index{};
	err := utils.ReadIndex("sample.json", &index);
	if (err!=nil) { t.Fatal("Error reading file: "+err.Error()); }
	_, ok := index["Physiolibrary"];
	if (!ok) { t.Fatal("Couldn't find Physiolibrary"); }
}
<|endoftext|>


<commit_before>// +build !windows

package transport

import (
	"fmt"
	"os"
	"os/exec"

	"github.com/scrapli/scrapligo/logging"

	"github.com/creack/pty"
)

// System the "system" (pty subprocess wrapper) transport option for scrapligo.
type System struct {
	BaseTransportArgs   *BaseTransportArgs
	SystemTransportArgs *SystemTransportArgs
	fileObj             *os.File
	openCmd             []string
}

// SystemTransportArgs struct representing attributes required for the System transport.
type SystemTransportArgs struct {
	AuthPrivateKey    string
	AuthStrictKey     bool
	SSHConfigFile     string
	SSHKnownHostsFile string
}

func (t *System) buildOpenCmd() {
	// base ssh arguments; "ssh" itself passed in Open()
	// need to add user arguments could go here at some point
	t.openCmd = append(
		t.openCmd,
		t.BaseTransportArgs.Host,
		"-p",
		fmt.Sprintf("%d", t.BaseTransportArgs.Port),
		"-o",
		fmt.Sprintf("ConnectTimeout=%d", int(t.BaseTransportArgs.TimeoutSocket.Seconds())),
		"-o",
		fmt.Sprintf("ServerAliveInterval=%d", int(t.BaseTransportArgs.TimeoutTransport.Seconds())),
	)

	if t.SystemTransportArgs.AuthPrivateKey != "" {
		t.openCmd = append(
			t.openCmd,
			"-i",
			t.SystemTransportArgs.AuthPrivateKey,
		)
	}

	if t.BaseTransportArgs.AuthUsername != "" {
		t.openCmd = append(
			t.openCmd,
			"-l",
			t.BaseTransportArgs.AuthUsername,
		)
	}

	if !t.SystemTransportArgs.AuthStrictKey {
		t.openCmd = append(
			t.openCmd,
			"-o",
			"StrictHostKeyChecking=no",
			"-o",
			"UserKnownHostsFile=/dev/null",
		)
	} else {
		t.openCmd = append(
			t.openCmd,
			"-o",
			"StrictHostKeyChecking=yes",
		)

		if t.SystemTransportArgs.SSHKnownHostsFile != "" {
			t.openCmd = append(
				t.openCmd,
				"-o",
				fmt.Sprintf("UserKnownHostsFile=%s", t.SystemTransportArgs.SSHKnownHostsFile),
			)
		}
	}

	if t.SystemTransportArgs.SSHConfigFile != "" {
		t.openCmd = append(
			t.openCmd,
			"-F",
			t.SystemTransportArgs.SSHConfigFile,
		)
	} else {
		t.openCmd = append(
			t.openCmd,
			"-F",
			"/dev/null",
		)
	}
}

// Open open a standard ssh connection.
func (t *System) Open() error {
	t.buildOpenCmd()

	logging.LogDebug(
		t.FormatLogMessage(
			"debug",
			fmt.Sprintf(
				"\"attempting to open transport connection with the following command: %s",
				t.openCmd,
			),
		),
	)

	sshCommand := exec.Command("ssh", t.openCmd...)
	fileObj, err := pty.StartWithSize(
		sshCommand,
		&pty.Winsize{
			Rows: uint16(t.BaseTransportArgs.PtyHeight),
			Cols: uint16(t.BaseTransportArgs.PtyWidth),
		},
	)

	if err != nil {
		logging.LogError(t.FormatLogMessage("error", "failed opening transport connection to host"))

		return err
	}

	logging.LogDebug(t.FormatLogMessage("debug", "transport connection to host opened"))

	t.fileObj = fileObj

	return err
}

// OpenNetconf open a netconf connection.
func (t *System) OpenNetconf() error {
	t.buildOpenCmd()

	t.openCmd = append(t.openCmd,
		"-tt",
		"-s",
		"netconf",
	)

	logging.LogDebug(
		t.FormatLogMessage(
			"debug",
			fmt.Sprintf(
				"\"attempting to open netconf transport connection with the following command: %s",
				t.openCmd,
			),
		),
	)

	sshCommand := exec.Command("ssh", t.openCmd...)
	fileObj, err := pty.Start(sshCommand)

	if err != nil {
		logging.LogError(
			t.FormatLogMessage("error", "failed opening netconf transport connection to host"),
		)

		return err
	}

	logging.LogDebug(t.FormatLogMessage("debug", "netconf transport connection to host opened"))

	t.fileObj = fileObj

	return err
}

// Close close the transport connection to the device.
func (t *System) Close() error {
	err := t.fileObj.Close()
	t.fileObj = nil
	logging.LogDebug(t.FormatLogMessage("debug", "transport connection to host closed"))

	return err
}

func (t *System) read(n int) *transportResult {
	b := make([]byte, n)
	_, err := t.fileObj.Read(b)

	if err != nil {
		return &transportResult{
			result: nil,
			error:  ErrTransportFailure,
		}
	}

	return &transportResult{
		result: b,
		error:  nil,
	}
}

// Read read bytes from the transport.
func (t *System) Read() ([]byte, error) {
	b, err := transportTimeout(
		*t.BaseTransportArgs.TimeoutTransport,
		t.read,
		ReadSize,
	)

	if err != nil {
		logging.LogError(t.FormatLogMessage("error", "timed out reading from transport"))
		return b, err
	}

	return b, nil
}

// ReadN read N bytes from the transport.
func (t *System) ReadN(n int) ([]byte, error) {
	b, err := transportTimeout(
		*t.BaseTransportArgs.TimeoutTransport,
		t.read,
		n,
	)

	if err != nil {
		logging.LogError(t.FormatLogMessage("error", "timed out reading from transport"))
		return b, err
	}

	return b, nil
}

// Write write bytes to the transport.
func (t *System) Write(channelInput []byte) error {
	_, err := t.fileObj.Write(channelInput)
	if err != nil {
		return err
	}

	return nil
}

// IsAlive indicate if the transport is alive or not.
func (t *System) IsAlive() bool {
	return t.fileObj != nil
}

// FormatLogMessage formats log message payload, adding contextual info about the host.
func (t *System) FormatLogMessage(level, msg string) string {
	return logging.FormatLogMessage(level, t.BaseTransportArgs.Host, t.BaseTransportArgs.Port, msg)
}
<commit_msg>playing w/ docker exec w/ system transport<commit_after>// +build !windows

package transport

import (
	"fmt"
	"os"
	"os/exec"

	"github.com/scrapli/scrapligo/logging"

	"github.com/creack/pty"
)

// System the "system" (pty subprocess wrapper) transport option for scrapligo.
type System struct {
	BaseTransportArgs   *BaseTransportArgs
	SystemTransportArgs *SystemTransportArgs
	fileObj             *os.File
	OpenCmd             []string
	ExecCmd             string
}

// SystemTransportArgs struct representing attributes required for the System transport.
type SystemTransportArgs struct {
	AuthPrivateKey    string
	AuthStrictKey     bool
	SSHConfigFile     string
	SSHKnownHostsFile string
}

func (t *System) buildOpenCmd() {
	// base ssh arguments; "ssh" itself passed in Open()
	// need to add user arguments could go here at some point
	t.OpenCmd = append(
		t.OpenCmd,
		t.BaseTransportArgs.Host,
		"-p",
		fmt.Sprintf("%d", t.BaseTransportArgs.Port),
		"-o",
		fmt.Sprintf("ConnectTimeout=%d", int(t.BaseTransportArgs.TimeoutSocket.Seconds())),
		"-o",
		fmt.Sprintf("ServerAliveInterval=%d", int(t.BaseTransportArgs.TimeoutTransport.Seconds())),
	)

	if t.SystemTransportArgs.AuthPrivateKey != "" {
		t.OpenCmd = append(
			t.OpenCmd,
			"-i",
			t.SystemTransportArgs.AuthPrivateKey,
		)
	}

	if t.BaseTransportArgs.AuthUsername != "" {
		t.OpenCmd = append(
			t.OpenCmd,
			"-l",
			t.BaseTransportArgs.AuthUsername,
		)
	}

	if !t.SystemTransportArgs.AuthStrictKey {
		t.OpenCmd = append(
			t.OpenCmd,
			"-o",
			"StrictHostKeyChecking=no",
			"-o",
			"UserKnownHostsFile=/dev/null",
		)
	} else {
		t.OpenCmd = append(
			t.OpenCmd,
			"-o",
			"StrictHostKeyChecking=yes",
		)

		if t.SystemTransportArgs.SSHKnownHostsFile != "" {
			t.OpenCmd = append(
				t.OpenCmd,
				"-o",
				fmt.Sprintf("UserKnownHostsFile=%s", t.SystemTransportArgs.SSHKnownHostsFile),
			)
		}
	}

	if t.SystemTransportArgs.SSHConfigFile != "" {
		t.OpenCmd = append(
			t.OpenCmd,
			"-F",
			t.SystemTransportArgs.SSHConfigFile,
		)
	} else {
		t.OpenCmd = append(
			t.OpenCmd,
			"-F",
			"/dev/null",
		)
	}
}

// Open open a standard ssh connection.
func (t *System) Open() error {
	if t.OpenCmd == nil {
		t.buildOpenCmd()
	}

	if t.ExecCmd == "" {
		t.ExecCmd = "ssh"
	}

	logging.LogDebug(
		t.FormatLogMessage(
			"debug",
			fmt.Sprintf(
				"\"attempting to open transport connection with the following command: %s",
				t.OpenCmd,
			),
		),
	)

	sshCommand := exec.Command(t.ExecCmd, t.OpenCmd...)
	fileObj, err := pty.StartWithSize(
		sshCommand,
		&pty.Winsize{
			Rows: uint16(t.BaseTransportArgs.PtyHeight),
			Cols: uint16(t.BaseTransportArgs.PtyWidth),
		},
	)

	if err != nil {
		logging.LogError(t.FormatLogMessage("error", "failed opening transport connection to host"))

		return err
	}

	logging.LogDebug(t.FormatLogMessage("debug", "transport connection to host opened"))

	t.fileObj = fileObj

	return err
}

// OpenNetconf open a netconf connection.
func (t *System) OpenNetconf() error {
	t.buildOpenCmd()

	t.OpenCmd = append(t.OpenCmd,
		"-tt",
		"-s",
		"netconf",
	)

	logging.LogDebug(
		t.FormatLogMessage(
			"debug",
			fmt.Sprintf(
				"\"attempting to open netconf transport connection with the following command: %s",
				t.OpenCmd,
			),
		),
	)

	sshCommand := exec.Command("ssh", t.OpenCmd...)
	fileObj, err := pty.Start(sshCommand)

	if err != nil {
		logging.LogError(
			t.FormatLogMessage("error", "failed opening netconf transport connection to host"),
		)

		return err
	}

	logging.LogDebug(t.FormatLogMessage("debug", "netconf transport connection to host opened"))

	t.fileObj = fileObj

	return err
}

// Close close the transport connection to the device.
func (t *System) Close() error {
	err := t.fileObj.Close()
	t.fileObj = nil
	logging.LogDebug(t.FormatLogMessage("debug", "transport connection to host closed"))

	return err
}

func (t *System) read(n int) *transportResult {
	b := make([]byte, n)
	_, err := t.fileObj.Read(b)

	if err != nil {
		return &transportResult{
			result: nil,
			error:  ErrTransportFailure,
		}
	}

	return &transportResult{
		result: b,
		error:  nil,
	}
}

// Read read bytes from the transport.
func (t *System) Read() ([]byte, error) {
	b, err := transportTimeout(
		*t.BaseTransportArgs.TimeoutTransport,
		t.read,
		ReadSize,
	)

	if err != nil {
		logging.LogError(t.FormatLogMessage("error", "timed out reading from transport"))
		return b, err
	}

	return b, nil
}

// ReadN read N bytes from the transport.
func (t *System) ReadN(n int) ([]byte, error) {
	b, err := transportTimeout(
		*t.BaseTransportArgs.TimeoutTransport,
		t.read,
		n,
	)

	if err != nil {
		logging.LogError(t.FormatLogMessage("error", "timed out reading from transport"))
		return b, err
	}

	return b, nil
}

// Write write bytes to the transport.
func (t *System) Write(channelInput []byte) error {
	_, err := t.fileObj.Write(channelInput)
	if err != nil {
		return err
	}

	return nil
}

// IsAlive indicate if the transport is alive or not.
func (t *System) IsAlive() bool {
	return t.fileObj != nil
}

// FormatLogMessage formats log message payload, adding contextual info about the host.
func (t *System) FormatLogMessage(level, msg string) string {
	return logging.FormatLogMessage(level, t.BaseTransportArgs.Host, t.BaseTransportArgs.Port, msg)
}
<|endoftext|>


<commit_before>package trdsql

import (
	"errors"
	"io"
	"strconv"

	"github.com/noborus/tbln"
)

// TBLNRead provides methods of the Reader interface.
type TBLNRead struct {
	reader    tbln.Reader
	preRead   [][]interface{}
	limitRead bool
}

// NewTBLNReader returns TBLNRead and error.
func NewTBLNReader(reader io.Reader, opts *ReadOpts) (*TBLNRead, error) {
	r := &TBLNRead{}
	r.reader = tbln.NewReader(reader)

	rec, err := r.reader.ReadRow()
	if err != nil {
		if !errors.Is(err, io.EOF) {
			return r, err
		}
		debug.Printf(err.Error())
		return r, nil
	}
	r.preRead = make([][]interface{}, 1)
	row := make([]interface{}, len(rec))
	for i, c := range rec {
		row[i] = c
	}
	r.preRead[0] = row

	r.limitRead = opts.InLimitRead

	// SetNames if there is no names header.
	d := r.reader.GetDefinition()
	names := d.Names()
	if len(names) == 0 {
		names = make([]string, len(rec))
		for i := range rec {
			names[i] = "c" + strconv.Itoa(i+1)
		}
		if err := d.SetNames(names); err != nil {
			return r, err
		}
	}

	// SetTypes if there is no types header.
	types := d.Types()
	if len(types) == 0 {
		types = make([]string, len(rec))
		for i := range rec {
			types[i] = DefaultDBType
		}

		if err := d.SetTypes(types); err != nil {
			return r, err
		}
	}

	return r, nil
}

// Names returns column names.
func (r *TBLNRead) Names() ([]string, error) {
	reader := r.reader
	if reader == nil {
		return nil, ErrNonDefinition
	}
	d := reader.GetDefinition()
	return d.Names(), nil
}

// Types returns column types.
func (r *TBLNRead) Types() ([]string, error) {
	reader := r.reader
	if reader == nil {
		return nil, ErrNonDefinition
	}
	d := reader.GetDefinition()
	return d.Types(), nil
}

// PreReadRow is returns only columns that store preread rows.
func (r *TBLNRead) PreReadRow() [][]interface{} {
	return r.preRead
}

// ReadRow is read the rest of the row.
func (r *TBLNRead) ReadRow(row []interface{}) ([]interface{}, error) {
	if r.limitRead {
		return nil, io.EOF
	}

	rec, err := r.reader.ReadRow()
	if err != nil {
		return row, err
	}
	row = make([]interface{}, len(rec))
	for i, c := range rec {
		row[i] = c
	}
	return row, nil
}
<commit_msg>Fixed tbln limit option not being enabled<commit_after>package trdsql

import (
	"errors"
	"io"
	"strconv"

	"github.com/noborus/tbln"
)

// TBLNRead provides methods of the Reader interface.
type TBLNRead struct {
	reader    tbln.Reader
	preRead   [][]interface{}
	limitRead bool
}

// NewTBLNReader returns TBLNRead and error.
func NewTBLNReader(reader io.Reader, opts *ReadOpts) (*TBLNRead, error) {
	r := &TBLNRead{}
	r.reader = tbln.NewReader(reader)
	r.limitRead = opts.InLimitRead

	rec, err := r.reader.ReadRow()
	if err != nil {
		if !errors.Is(err, io.EOF) {
			return r, err
		}
		debug.Printf(err.Error())
		return r, nil
	}

	// SetNames if there is no names header.
	d := r.reader.GetDefinition()
	names := d.Names()
	if len(names) == 0 {
		names = make([]string, len(rec))
		for i := range rec {
			names[i] = "c" + strconv.Itoa(i+1)
		}
		if err := d.SetNames(names); err != nil {
			return r, err
		}
	}

	// SetTypes if there is no types header.
	types := d.Types()
	if len(types) == 0 {
		types = make([]string, len(rec))
		for i := range rec {
			types[i] = DefaultDBType
		}

		if err := d.SetTypes(types); err != nil {
			return r, err
		}
	}

	r.preRead = make([][]interface{}, 0, opts.InPreRead)
	r.preRead = append(r.preRead, recToRow(rec))
	for n := 1; n < opts.InPreRead; n++ {
		rec, err := r.reader.ReadRow()
		if err != nil {
			if !errors.Is(err, io.EOF) {
				return r, err
			}
			debug.Printf(err.Error())
			return r, nil
		}
		r.preRead = append(r.preRead, recToRow(rec))
	}
	return r, nil
}

// Names returns column names.
func (r *TBLNRead) Names() ([]string, error) {
	reader := r.reader
	if reader == nil {
		return nil, ErrNonDefinition
	}
	d := reader.GetDefinition()
	return d.Names(), nil
}

// Types returns column types.
func (r *TBLNRead) Types() ([]string, error) {
	reader := r.reader
	if reader == nil {
		return nil, ErrNonDefinition
	}
	d := reader.GetDefinition()
	return d.Types(), nil
}

// PreReadRow is returns only columns that store preread rows.
func (r *TBLNRead) PreReadRow() [][]interface{} {
	return r.preRead
}

// ReadRow is read the rest of the row.
func (r *TBLNRead) ReadRow(row []interface{}) ([]interface{}, error) {
	if r.limitRead {
		return nil, io.EOF
	}

	rec, err := r.reader.ReadRow()
	if err != nil {
		return row, err
	}
	row = recToRow(rec)
	return row, nil
}

func recToRow(rec []string) []interface{} {
	row := make([]interface{}, len(rec))
	for i, c := range rec {
		if c != "" {
			row[i] = c
		}
	}
	return row
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/docopt/docopt.go"
    "time"
)

func main() {
	usage := "Usage: oc add <time> <time>"
	args, _ := docopt.Parse(usage, nil, true, "", false)
	fmt.Println(args)

    times := args["<time>"].([]string)

    time1, _ := time.Parse("15:04", times[0])
    time2, _ := time.Parse("15:04", times[1])

    fmt.Println(time2.Sub(time1))
}
<commit_msg>deleted debug text<commit_after>package main

import (
	"fmt"
	"github.com/docopt/docopt.go"
    "time"
)

func main() {
	usage := "Usage: oc add <time> <time>"
	args, _ := docopt.Parse(usage, nil, true, "", false)

    times := args["<time>"].([]string)

    time1, _ := time.Parse("15:04", times[0])
    time2, _ := time.Parse("15:04", times[1])

    fmt.Println(time2.Sub(time1))
}
<|endoftext|>