<commit_before>package aws

import (
	"fmt"
	"log"
	"regexp"
	"strings"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/sagemaker"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
	"github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags"
	"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/sagemaker/finder"
	"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/sagemaker/waiter"
)

func resourceAwsSagemakerImage() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsSagemakerImageCreate,
		Read:   resourceAwsSagemakerImageRead,
		Update: resourceAwsSagemakerImageUpdate,
		Delete: resourceAwsSagemakerImageDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"arn": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"image_name": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
				ValidateFunc: validation.All(
					validation.StringLenBetween(1, 63),
					validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9](-*[a-zA-Z0-9])*$`), "Valid characters are a-z, A-Z, 0-9, and - (hyphen)."),
				),
			},
			"role_arn": {
				Type:         schema.TypeString,
				Required:     true,
				ForceNew:     true,
				ValidateFunc: validateArn,
			},
			"display_name": {
				Type:         schema.TypeString,
				Optional:     true,
				ValidateFunc: validation.StringLenBetween(1, 128),
			},
			"description": {
				Type:         schema.TypeString,
				Optional:     true,
				ValidateFunc: validation.StringLenBetween(1, 512),
			},
			"tags": tagsSchema(),
		},
	}
}

func resourceAwsSagemakerImageCreate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).sagemakerconn

	name := d.Get("image_name").(string)
	input := &sagemaker.CreateImageInput{
		ImageName: aws.String(name),
		RoleArn:   aws.String(d.Get("role_arn").(string)),
	}

	if v, ok := d.GetOk("display_name"); ok {
		input.DisplayName = aws.String(v.(string))
	}

	if v, ok := d.GetOk("description"); ok {
		input.Description = aws.String(v.(string))
	}

	if v, ok := d.GetOk("tags"); ok {
		input.Tags = keyvaluetags.New(v.(map[string]interface{})).IgnoreAws().SagemakerTags()
	}

	// for some reason even if the operation is retried the same error response is given even though the role is valid. a short sleep before creation solves it.
	time.Sleep(1 * time.Minute)
	log.Printf("[DEBUG] sagemaker Image create config: %#v", *input)
	err := resource.Retry(1*time.Minute, func() *resource.RetryError {
		var err error
		_, err = conn.CreateImage(input)
		if err != nil {
			return resource.NonRetryableError(fmt.Errorf("error creating SageMaker Image: %w", err))
		}

		d.SetId(name)

		out, err := waiter.ImageCreated(conn, d.Id())

		if strings.Contains(aws.StringValue(out.FailureReason), "Unable to assume role with RoleArn") {
			return resource.RetryableError(err)
		}
		if err != nil {
			return resource.NonRetryableError(fmt.Errorf("error waiting for SageMaker Image (%s) to create: %w", d.Id(), err))
		}
		return nil
	})
	if isResourceTimeoutError(err) {
		_, err = conn.CreateImage(input)
		_, err = waiter.ImageCreated(conn, d.Id())
	}
	if err != nil {
		return fmt.Errorf("error creating SageMaker Image %s: %w", name, err)
	}

	return resourceAwsSagemakerImageRead(d, meta)
}

func resourceAwsSagemakerImageRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).sagemakerconn
	ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig

	image, err := finder.ImageByName(conn, d.Id())
	if err != nil {
		if isAWSErr(err, sagemaker.ErrCodeResourceNotFound, "No Image with the name") {
			d.SetId("")
			log.Printf("[WARN] Unable to find SageMaker Image (%s); removing from state", d.Id())
			return nil
		}
		return fmt.Errorf("error reading SageMaker Image (%s): %w", d.Id(), err)

	}

	arn := aws.StringValue(image.ImageArn)
	d.Set("image_name", image.ImageName)
	d.Set("arn", arn)
	d.Set("role_arn", image.RoleArn)
	d.Set("display_name", image.DisplayName)
	d.Set("description", image.Description)

	tags, err := keyvaluetags.SagemakerListTags(conn, arn)

	if err != nil {
		return fmt.Errorf("error listing tags for SageMaker Image (%s): %w", d.Id(), err)
	}

	if err := d.Set("tags", tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil {
		return fmt.Errorf("error setting tags: %w", err)
	}

	return nil
}

func resourceAwsSagemakerImageUpdate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).sagemakerconn
	needsUpdate := false

	input := &sagemaker.UpdateImageInput{
		ImageName: aws.String(d.Id()),
	}

	var deleteProperties []*string

	if d.HasChange("description") {
		if v, ok := d.GetOk("description"); ok {
			input.Description = aws.String(v.(string))
		} else {
			deleteProperties = append(deleteProperties, aws.String("Description"))
			input.DeleteProperties = deleteProperties
		}
		needsUpdate = true
	}

	if d.HasChange("display_name") {
		if v, ok := d.GetOk("display_name"); ok {
			input.DisplayName = aws.String(v.(string))
		} else {
			deleteProperties = append(deleteProperties, aws.String("DisplayName"))
			input.DeleteProperties = deleteProperties
		}
		needsUpdate = true
	}

	if needsUpdate {
		log.Printf("[DEBUG] sagemaker Image update config: %#v", *input)
		_, err := conn.UpdateImage(input)
		if err != nil {
			return fmt.Errorf("error updating SageMaker Image: %w", err)
		}

		if _, err := waiter.ImageCreated(conn, d.Id()); err != nil {
			return fmt.Errorf("error waiting for SageMaker Image (%s) to update: %w", d.Id(), err)
		}
	}

	if d.HasChange("tags") {
		o, n := d.GetChange("tags")

		if err := keyvaluetags.SagemakerUpdateTags(conn, d.Get("arn").(string), o, n); err != nil {
			return fmt.Errorf("error updating SageMaker Image (%s) tags: %s", d.Id(), err)
		}
	}

	return resourceAwsSagemakerImageRead(d, meta)
}

func resourceAwsSagemakerImageDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).sagemakerconn

	input := &sagemaker.DeleteImageInput{
		ImageName: aws.String(d.Id()),
	}

	if _, err := conn.DeleteImage(input); err != nil {
		if isAWSErr(err, sagemaker.ErrCodeResourceNotFound, "No Image with the name") {
			return nil
		}
		return fmt.Errorf("error deleting SageMaker Image (%s): %w", d.Id(), err)
	}

	if _, err := waiter.ImageDeleted(conn, d.Id()); err != nil {
		if isAWSErr(err, sagemaker.ErrCodeResourceNotFound, "No Image with the name") {
			return nil
		}
		return fmt.Errorf("error waiting for SageMaker Image (%s) to delete: %w", d.Id(), err)

	}

	return nil
}
<commit_msg>reduce retry logic<commit_after>package aws

import (
	"fmt"
	"log"
	"regexp"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/sagemaker"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
	"github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags"
	"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/sagemaker/finder"
	"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/sagemaker/waiter"
)

func resourceAwsSagemakerImage() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsSagemakerImageCreate,
		Read:   resourceAwsSagemakerImageRead,
		Update: resourceAwsSagemakerImageUpdate,
		Delete: resourceAwsSagemakerImageDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"arn": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"image_name": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
				ValidateFunc: validation.All(
					validation.StringLenBetween(1, 63),
					validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9](-*[a-zA-Z0-9])*$`), "Valid characters are a-z, A-Z, 0-9, and - (hyphen)."),
				),
			},
			"role_arn": {
				Type:         schema.TypeString,
				Required:     true,
				ForceNew:     true,
				ValidateFunc: validateArn,
			},
			"display_name": {
				Type:         schema.TypeString,
				Optional:     true,
				ValidateFunc: validation.StringLenBetween(1, 128),
			},
			"description": {
				Type:         schema.TypeString,
				Optional:     true,
				ValidateFunc: validation.StringLenBetween(1, 512),
			},
			"tags": tagsSchema(),
		},
	}
}

func resourceAwsSagemakerImageCreate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).sagemakerconn

	name := d.Get("image_name").(string)
	input := &sagemaker.CreateImageInput{
		ImageName: aws.String(name),
		RoleArn:   aws.String(d.Get("role_arn").(string)),
	}

	if v, ok := d.GetOk("display_name"); ok {
		input.DisplayName = aws.String(v.(string))
	}

	if v, ok := d.GetOk("description"); ok {
		input.Description = aws.String(v.(string))
	}

	if v, ok := d.GetOk("tags"); ok {
		input.Tags = keyvaluetags.New(v.(map[string]interface{})).IgnoreAws().SagemakerTags()
	}

	// for some reason even if the operation is retried the same error response is given even though the role is valid. a short sleep before creation solves it.
	time.Sleep(1 * time.Minute)
	_, err := conn.CreateImage(input)
	if err != nil {
		return fmt.Errorf("error creating SageMaker Image %s: %w", name, err)
	}

	d.SetId(name)

	if _, err := waiter.ImageCreated(conn, d.Id()); err != nil {
		return fmt.Errorf("error waiting for SageMaker Image (%s) to be created: %w", d.Id(), err)
	}

	return resourceAwsSagemakerImageRead(d, meta)
}

func resourceAwsSagemakerImageRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).sagemakerconn
	ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig

	image, err := finder.ImageByName(conn, d.Id())
	if err != nil {
		if isAWSErr(err, sagemaker.ErrCodeResourceNotFound, "No Image with the name") {
			d.SetId("")
			log.Printf("[WARN] Unable to find SageMaker Image (%s); removing from state", d.Id())
			return nil
		}
		return fmt.Errorf("error reading SageMaker Image (%s): %w", d.Id(), err)

	}

	arn := aws.StringValue(image.ImageArn)
	d.Set("image_name", image.ImageName)
	d.Set("arn", arn)
	d.Set("role_arn", image.RoleArn)
	d.Set("display_name", image.DisplayName)
	d.Set("description", image.Description)

	tags, err := keyvaluetags.SagemakerListTags(conn, arn)

	if err != nil {
		return fmt.Errorf("error listing tags for SageMaker Image (%s): %w", d.Id(), err)
	}

	if err := d.Set("tags", tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil {
		return fmt.Errorf("error setting tags: %w", err)
	}

	return nil
}

func resourceAwsSagemakerImageUpdate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).sagemakerconn
	needsUpdate := false

	input := &sagemaker.UpdateImageInput{
		ImageName: aws.String(d.Id()),
	}

	var deleteProperties []*string

	if d.HasChange("description") {
		if v, ok := d.GetOk("description"); ok {
			input.Description = aws.String(v.(string))
		} else {
			deleteProperties = append(deleteProperties, aws.String("Description"))
			input.DeleteProperties = deleteProperties
		}
		needsUpdate = true
	}

	if d.HasChange("display_name") {
		if v, ok := d.GetOk("display_name"); ok {
			input.DisplayName = aws.String(v.(string))
		} else {
			deleteProperties = append(deleteProperties, aws.String("DisplayName"))
			input.DeleteProperties = deleteProperties
		}
		needsUpdate = true
	}

	if needsUpdate {
		log.Printf("[DEBUG] sagemaker Image update config: %#v", *input)
		_, err := conn.UpdateImage(input)
		if err != nil {
			return fmt.Errorf("error updating SageMaker Image: %w", err)
		}

		if _, err := waiter.ImageCreated(conn, d.Id()); err != nil {
			return fmt.Errorf("error waiting for SageMaker Image (%s) to update: %w", d.Id(), err)
		}
	}

	if d.HasChange("tags") {
		o, n := d.GetChange("tags")

		if err := keyvaluetags.SagemakerUpdateTags(conn, d.Get("arn").(string), o, n); err != nil {
			return fmt.Errorf("error updating SageMaker Image (%s) tags: %s", d.Id(), err)
		}
	}

	return resourceAwsSagemakerImageRead(d, meta)
}

func resourceAwsSagemakerImageDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).sagemakerconn

	input := &sagemaker.DeleteImageInput{
		ImageName: aws.String(d.Id()),
	}

	if _, err := conn.DeleteImage(input); err != nil {
		if isAWSErr(err, sagemaker.ErrCodeResourceNotFound, "No Image with the name") {
			return nil
		}
		return fmt.Errorf("error deleting SageMaker Image (%s): %w", d.Id(), err)
	}

	if _, err := waiter.ImageDeleted(conn, d.Id()); err != nil {
		if isAWSErr(err, sagemaker.ErrCodeResourceNotFound, "No Image with the name") {
			return nil
		}
		return fmt.Errorf("error waiting for SageMaker Image (%s) to delete: %w", d.Id(), err)

	}

	return nil
}
<|endoftext|>


<commit_before><commit_msg>fcs-run: update config for fcs-2.0 branch<commit_after><|endoftext|>


<commit_before><commit_msg>Explicitly close dir fds<commit_after><|endoftext|>


<commit_before>/*
Copyright 2015 The Kubernetes Authors.

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

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

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

package tests

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"net/url"
	"strings"
	"testing"
	"time"

	"github.com/stretchr/testify/require"

	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/util/httpstream"
	remotecommandconsts "k8s.io/apimachinery/pkg/util/remotecommand"
	restclient "k8s.io/client-go/rest"
	remoteclient "k8s.io/client-go/tools/remotecommand"
	"k8s.io/client-go/transport/spdy"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/testapi"
	"k8s.io/kubernetes/pkg/kubelet/server/remotecommand"
)

type fakeExecutor struct {
	t             *testing.T
	testName      string
	errorData     string
	stdoutData    string
	stderrData    string
	expectStdin   bool
	stdinReceived bytes.Buffer
	tty           bool
	messageCount  int
	command       []string
	exec          bool
}

func (ex *fakeExecutor) ExecInContainer(name string, uid types.UID, container string, cmd []string, in io.Reader, out, err io.WriteCloser, tty bool, resize <-chan remoteclient.TerminalSize, timeout time.Duration) error {
	return ex.run(name, uid, container, cmd, in, out, err, tty)
}

func (ex *fakeExecutor) AttachContainer(name string, uid types.UID, container string, in io.Reader, out, err io.WriteCloser, tty bool, resize <-chan remoteclient.TerminalSize) error {
	return ex.run(name, uid, container, nil, in, out, err, tty)
}

func (ex *fakeExecutor) run(name string, uid types.UID, container string, cmd []string, in io.Reader, out, err io.WriteCloser, tty bool) error {
	ex.command = cmd
	ex.tty = tty

	if e, a := "pod", name; e != a {
		ex.t.Errorf("%s: pod: expected %q, got %q", ex.testName, e, a)
	}
	if e, a := "uid", uid; e != string(a) {
		ex.t.Errorf("%s: uid: expected %q, got %q", ex.testName, e, a)
	}
	if ex.exec {
		if e, a := "ls /", strings.Join(ex.command, " "); e != a {
			ex.t.Errorf("%s: command: expected %q, got %q", ex.testName, e, a)
		}
	} else {
		if len(ex.command) > 0 {
			ex.t.Errorf("%s: command: expected nothing, got %v", ex.testName, ex.command)
		}
	}

	if len(ex.errorData) > 0 {
		return errors.New(ex.errorData)
	}

	if len(ex.stdoutData) > 0 {
		for i := 0; i < ex.messageCount; i++ {
			fmt.Fprint(out, ex.stdoutData)
		}
	}

	if len(ex.stderrData) > 0 {
		for i := 0; i < ex.messageCount; i++ {
			fmt.Fprint(err, ex.stderrData)
		}
	}

	if ex.expectStdin {
		io.Copy(&ex.stdinReceived, in)
	}

	return nil
}

func fakeServer(t *testing.T, testName string, exec bool, stdinData, stdoutData, stderrData, errorData string, tty bool, messageCount int, serverProtocols []string) http.HandlerFunc {
	return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		executor := &fakeExecutor{
			t:            t,
			testName:     testName,
			errorData:    errorData,
			stdoutData:   stdoutData,
			stderrData:   stderrData,
			expectStdin:  len(stdinData) > 0,
			tty:          tty,
			messageCount: messageCount,
			exec:         exec,
		}

		opts, err := remotecommand.NewOptions(req)
		require.NoError(t, err)
		if exec {
			cmd := req.URL.Query()[api.ExecCommandParam]
			remotecommand.ServeExec(w, req, executor, "pod", "uid", "container", cmd, opts, 0, 10*time.Second, serverProtocols)
		} else {
			remotecommand.ServeAttach(w, req, executor, "pod", "uid", "container", opts, 0, 10*time.Second, serverProtocols)
		}

		if e, a := strings.Repeat(stdinData, messageCount), executor.stdinReceived.String(); e != a {
			t.Errorf("%s: stdin: expected %q, got %q", testName, e, a)
		}
	})
}

func TestStream(t *testing.T) {
	testCases := []struct {
		TestName        string
		Stdin           string
		Stdout          string
		Stderr          string
		Error           string
		Tty             bool
		MessageCount    int
		ClientProtocols []string
		ServerProtocols []string
	}{
		{
			TestName:        "error",
			Error:           "bail",
			Stdout:          "a",
			ClientProtocols: []string{remotecommandconsts.StreamProtocolV2Name},
			ServerProtocols: []string{remotecommandconsts.StreamProtocolV2Name},
		},
		{
			TestName:        "in/out/err",
			Stdin:           "a",
			Stdout:          "b",
			Stderr:          "c",
			MessageCount:    100,
			ClientProtocols: []string{remotecommandconsts.StreamProtocolV2Name},
			ServerProtocols: []string{remotecommandconsts.StreamProtocolV2Name},
		},
		{
			TestName:        "in/out/tty",
			Stdin:           "a",
			Stdout:          "b",
			Tty:             true,
			MessageCount:    100,
			ClientProtocols: []string{remotecommandconsts.StreamProtocolV2Name},
			ServerProtocols: []string{remotecommandconsts.StreamProtocolV2Name},
		},
		{
			// 1.0 kubectl, 1.0 kubelet
			TestName:        "unversioned client, unversioned server",
			Stdout:          "b",
			Stderr:          "c",
			MessageCount:    1,
			ClientProtocols: []string{},
			ServerProtocols: []string{},
		},
		{
			// 1.0 kubectl, 1.1+ kubelet
			TestName:        "unversioned client, versioned server",
			Stdout:          "b",
			Stderr:          "c",
			MessageCount:    1,
			ClientProtocols: []string{},
			ServerProtocols: []string{remotecommandconsts.StreamProtocolV2Name, remotecommandconsts.StreamProtocolV1Name},
		},
		{
			// 1.1+ kubectl, 1.0 kubelet
			TestName:        "versioned client, unversioned server",
			Stdout:          "b",
			Stderr:          "c",
			MessageCount:    1,
			ClientProtocols: []string{remotecommandconsts.StreamProtocolV2Name, remotecommandconsts.StreamProtocolV1Name},
			ServerProtocols: []string{},
		},
	}

	for _, testCase := range testCases {
		for _, exec := range []bool{true, false} {
			var name string
			if exec {
				name = testCase.TestName + " (exec)"
			} else {
				name = testCase.TestName + " (attach)"
			}
			var (
				streamIn             io.Reader
				streamOut, streamErr io.Writer
			)
			localOut := &bytes.Buffer{}
			localErr := &bytes.Buffer{}

			server := httptest.NewServer(fakeServer(t, name, exec, testCase.Stdin, testCase.Stdout, testCase.Stderr, testCase.Error, testCase.Tty, testCase.MessageCount, testCase.ServerProtocols))

			url, _ := url.ParseRequestURI(server.URL)
			config := restclient.ContentConfig{
				GroupVersion:         &schema.GroupVersion{Group: "x"},
				NegotiatedSerializer: testapi.Default.NegotiatedSerializer(),
			}
			c, err := restclient.NewRESTClient(url, "", config, -1, -1, nil, nil)
			if err != nil {
				t.Fatalf("failed to create a client: %v", err)
			}
			req := c.Post().Resource("testing")

			if exec {
				req.Param("command", "ls")
				req.Param("command", "/")
			}

			if len(testCase.Stdin) > 0 {
				req.Param(api.ExecStdinParam, "1")
				streamIn = strings.NewReader(strings.Repeat(testCase.Stdin, testCase.MessageCount))
			}

			if len(testCase.Stdout) > 0 {
				req.Param(api.ExecStdoutParam, "1")
				streamOut = localOut
			}

			if testCase.Tty {
				req.Param(api.ExecTTYParam, "1")
			} else if len(testCase.Stderr) > 0 {
				req.Param(api.ExecStderrParam, "1")
				streamErr = localErr
			}

			conf := &restclient.Config{
				Host: server.URL,
			}
			e, err := remoteclient.NewSPDYExecutorForProtocols(conf, "POST", req.URL(), testCase.ClientProtocols...)
			if err != nil {
				t.Errorf("%s: unexpected error: %v", name, err)
				continue
			}
			err = e.Stream(remoteclient.StreamOptions{
				Stdin:  streamIn,
				Stdout: streamOut,
				Stderr: streamErr,
				Tty:    testCase.Tty,
			})
			hasErr := err != nil

			if len(testCase.Error) > 0 {
				if !hasErr {
					t.Errorf("%s: expected an error", name)
				} else {
					if e, a := testCase.Error, err.Error(); !strings.Contains(a, e) {
						t.Errorf("%s: expected error stream read %q, got %q", name, e, a)
					}
				}

				server.Close()
				continue
			}

			if hasErr {
				t.Errorf("%s: unexpected error: %v", name, err)
				server.Close()
				continue
			}

			if len(testCase.Stdout) > 0 {
				if e, a := strings.Repeat(testCase.Stdout, testCase.MessageCount), localOut; e != a.String() {
					t.Errorf("%s: expected stdout data %q, got %q", name, e, a)
				}
			}

			if testCase.Stderr != "" {
				if e, a := strings.Repeat(testCase.Stderr, testCase.MessageCount), localErr; e != a.String() {
					t.Errorf("%s: expected stderr data %q, got %q", name, e, a)
				}
			}

			server.Close()
		}
	}
}

type fakeUpgrader struct {
	req           *http.Request
	resp          *http.Response
	conn          httpstream.Connection
	err, connErr  error
	checkResponse bool
	called        bool

	t *testing.T
}

func (u *fakeUpgrader) RoundTrip(req *http.Request) (*http.Response, error) {
	u.called = true
	u.req = req
	return u.resp, u.err
}

func (u *fakeUpgrader) NewConnection(resp *http.Response) (httpstream.Connection, error) {
	if u.checkResponse && u.resp != resp {
		u.t.Errorf("response objects passed did not match: %#v", resp)
	}
	return u.conn, u.connErr
}

type fakeConnection struct {
	httpstream.Connection
}

// Dial is the common functionality between any stream based upgrader, regardless of protocol.
// This method ensures that someone can use a generic stream executor without being dependent
// on the core Kube client config behavior.
func TestDial(t *testing.T) {
	upgrader := &fakeUpgrader{
		t:             t,
		checkResponse: true,
		conn:          &fakeConnection{},
		resp: &http.Response{
			StatusCode: http.StatusSwitchingProtocols,
			Body:       ioutil.NopCloser(&bytes.Buffer{}),
		},
	}
	dialer := spdy.NewDialer(upgrader, &http.Client{Transport: upgrader}, "POST", &url.URL{Host: "something.com", Scheme: "https"})
	conn, protocol, err := dialer.Dial("protocol1")
	if err != nil {
		t.Fatal(err)
	}
	if conn != upgrader.conn {
		t.Errorf("unexpected connection: %#v", conn)
	}
	if !upgrader.called {
		t.Errorf("request not called")
	}
	_ = protocol
}
<commit_msg>UPSTREAM: 55974: Allow constructing spdy executor from existing transports<commit_after>/*
Copyright 2015 The Kubernetes Authors.

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

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

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

package tests

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"net/url"
	"strings"
	"testing"
	"time"

	"github.com/stretchr/testify/require"

	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/util/httpstream"
	remotecommandconsts "k8s.io/apimachinery/pkg/util/remotecommand"
	restclient "k8s.io/client-go/rest"
	remoteclient "k8s.io/client-go/tools/remotecommand"
	"k8s.io/client-go/transport/spdy"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/testapi"
	"k8s.io/kubernetes/pkg/kubelet/server/remotecommand"
)

type fakeExecutor struct {
	t             *testing.T
	testName      string
	errorData     string
	stdoutData    string
	stderrData    string
	expectStdin   bool
	stdinReceived bytes.Buffer
	tty           bool
	messageCount  int
	command       []string
	exec          bool
}

func (ex *fakeExecutor) ExecInContainer(name string, uid types.UID, container string, cmd []string, in io.Reader, out, err io.WriteCloser, tty bool, resize <-chan remoteclient.TerminalSize, timeout time.Duration) error {
	return ex.run(name, uid, container, cmd, in, out, err, tty)
}

func (ex *fakeExecutor) AttachContainer(name string, uid types.UID, container string, in io.Reader, out, err io.WriteCloser, tty bool, resize <-chan remoteclient.TerminalSize) error {
	return ex.run(name, uid, container, nil, in, out, err, tty)
}

func (ex *fakeExecutor) run(name string, uid types.UID, container string, cmd []string, in io.Reader, out, err io.WriteCloser, tty bool) error {
	ex.command = cmd
	ex.tty = tty

	if e, a := "pod", name; e != a {
		ex.t.Errorf("%s: pod: expected %q, got %q", ex.testName, e, a)
	}
	if e, a := "uid", uid; e != string(a) {
		ex.t.Errorf("%s: uid: expected %q, got %q", ex.testName, e, a)
	}
	if ex.exec {
		if e, a := "ls /", strings.Join(ex.command, " "); e != a {
			ex.t.Errorf("%s: command: expected %q, got %q", ex.testName, e, a)
		}
	} else {
		if len(ex.command) > 0 {
			ex.t.Errorf("%s: command: expected nothing, got %v", ex.testName, ex.command)
		}
	}

	if len(ex.errorData) > 0 {
		return errors.New(ex.errorData)
	}

	if len(ex.stdoutData) > 0 {
		for i := 0; i < ex.messageCount; i++ {
			fmt.Fprint(out, ex.stdoutData)
		}
	}

	if len(ex.stderrData) > 0 {
		for i := 0; i < ex.messageCount; i++ {
			fmt.Fprint(err, ex.stderrData)
		}
	}

	if ex.expectStdin {
		io.Copy(&ex.stdinReceived, in)
	}

	return nil
}

func fakeServer(t *testing.T, testName string, exec bool, stdinData, stdoutData, stderrData, errorData string, tty bool, messageCount int, serverProtocols []string) http.HandlerFunc {
	return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		executor := &fakeExecutor{
			t:            t,
			testName:     testName,
			errorData:    errorData,
			stdoutData:   stdoutData,
			stderrData:   stderrData,
			expectStdin:  len(stdinData) > 0,
			tty:          tty,
			messageCount: messageCount,
			exec:         exec,
		}

		opts, err := remotecommand.NewOptions(req)
		require.NoError(t, err)
		if exec {
			cmd := req.URL.Query()[api.ExecCommandParam]
			remotecommand.ServeExec(w, req, executor, "pod", "uid", "container", cmd, opts, 0, 10*time.Second, serverProtocols)
		} else {
			remotecommand.ServeAttach(w, req, executor, "pod", "uid", "container", opts, 0, 10*time.Second, serverProtocols)
		}

		if e, a := strings.Repeat(stdinData, messageCount), executor.stdinReceived.String(); e != a {
			t.Errorf("%s: stdin: expected %q, got %q", testName, e, a)
		}
	})
}

func TestStream(t *testing.T) {
	testCases := []struct {
		TestName        string
		Stdin           string
		Stdout          string
		Stderr          string
		Error           string
		Tty             bool
		MessageCount    int
		ClientProtocols []string
		ServerProtocols []string
	}{
		{
			TestName:        "error",
			Error:           "bail",
			Stdout:          "a",
			ClientProtocols: []string{remotecommandconsts.StreamProtocolV2Name},
			ServerProtocols: []string{remotecommandconsts.StreamProtocolV2Name},
		},
		{
			TestName:        "in/out/err",
			Stdin:           "a",
			Stdout:          "b",
			Stderr:          "c",
			MessageCount:    100,
			ClientProtocols: []string{remotecommandconsts.StreamProtocolV2Name},
			ServerProtocols: []string{remotecommandconsts.StreamProtocolV2Name},
		},
		{
			TestName:        "in/out/tty",
			Stdin:           "a",
			Stdout:          "b",
			Tty:             true,
			MessageCount:    100,
			ClientProtocols: []string{remotecommandconsts.StreamProtocolV2Name},
			ServerProtocols: []string{remotecommandconsts.StreamProtocolV2Name},
		},
		{
			// 1.0 kubectl, 1.0 kubelet
			TestName:        "unversioned client, unversioned server",
			Stdout:          "b",
			Stderr:          "c",
			MessageCount:    1,
			ClientProtocols: []string{},
			ServerProtocols: []string{},
		},
		{
			// 1.0 kubectl, 1.1+ kubelet
			TestName:        "unversioned client, versioned server",
			Stdout:          "b",
			Stderr:          "c",
			MessageCount:    1,
			ClientProtocols: []string{},
			ServerProtocols: []string{remotecommandconsts.StreamProtocolV2Name, remotecommandconsts.StreamProtocolV1Name},
		},
		{
			// 1.1+ kubectl, 1.0 kubelet
			TestName:        "versioned client, unversioned server",
			Stdout:          "b",
			Stderr:          "c",
			MessageCount:    1,
			ClientProtocols: []string{remotecommandconsts.StreamProtocolV2Name, remotecommandconsts.StreamProtocolV1Name},
			ServerProtocols: []string{},
		},
	}

	for _, testCase := range testCases {
		for _, exec := range []bool{true, false} {
			var name string
			if exec {
				name = testCase.TestName + " (exec)"
			} else {
				name = testCase.TestName + " (attach)"
			}
			var (
				streamIn             io.Reader
				streamOut, streamErr io.Writer
			)
			localOut := &bytes.Buffer{}
			localErr := &bytes.Buffer{}

			server := httptest.NewServer(fakeServer(t, name, exec, testCase.Stdin, testCase.Stdout, testCase.Stderr, testCase.Error, testCase.Tty, testCase.MessageCount, testCase.ServerProtocols))

			url, _ := url.ParseRequestURI(server.URL)
			config := restclient.ContentConfig{
				GroupVersion:         &schema.GroupVersion{Group: "x"},
				NegotiatedSerializer: testapi.Default.NegotiatedSerializer(),
			}
			c, err := restclient.NewRESTClient(url, "", config, -1, -1, nil, nil)
			if err != nil {
				t.Fatalf("failed to create a client: %v", err)
			}
			req := c.Post().Resource("testing")

			if exec {
				req.Param("command", "ls")
				req.Param("command", "/")
			}

			if len(testCase.Stdin) > 0 {
				req.Param(api.ExecStdinParam, "1")
				streamIn = strings.NewReader(strings.Repeat(testCase.Stdin, testCase.MessageCount))
			}

			if len(testCase.Stdout) > 0 {
				req.Param(api.ExecStdoutParam, "1")
				streamOut = localOut
			}

			if testCase.Tty {
				req.Param(api.ExecTTYParam, "1")
			} else if len(testCase.Stderr) > 0 {
				req.Param(api.ExecStderrParam, "1")
				streamErr = localErr
			}

			conf := &restclient.Config{
				Host: server.URL,
			}
			transport, upgradeTransport, err := spdy.RoundTripperFor(conf)
			if err != nil {
				t.Errorf("%s: unexpected error: %v", name, err)
				continue
			}
			e, err := remoteclient.NewSPDYExecutorForProtocols(transport, upgradeTransport, "POST", req.URL(), testCase.ClientProtocols...)
			if err != nil {
				t.Errorf("%s: unexpected error: %v", name, err)
				continue
			}
			err = e.Stream(remoteclient.StreamOptions{
				Stdin:  streamIn,
				Stdout: streamOut,
				Stderr: streamErr,
				Tty:    testCase.Tty,
			})
			hasErr := err != nil

			if len(testCase.Error) > 0 {
				if !hasErr {
					t.Errorf("%s: expected an error", name)
				} else {
					if e, a := testCase.Error, err.Error(); !strings.Contains(a, e) {
						t.Errorf("%s: expected error stream read %q, got %q", name, e, a)
					}
				}

				server.Close()
				continue
			}

			if hasErr {
				t.Errorf("%s: unexpected error: %v", name, err)
				server.Close()
				continue
			}

			if len(testCase.Stdout) > 0 {
				if e, a := strings.Repeat(testCase.Stdout, testCase.MessageCount), localOut; e != a.String() {
					t.Errorf("%s: expected stdout data %q, got %q", name, e, a)
				}
			}

			if testCase.Stderr != "" {
				if e, a := strings.Repeat(testCase.Stderr, testCase.MessageCount), localErr; e != a.String() {
					t.Errorf("%s: expected stderr data %q, got %q", name, e, a)
				}
			}

			server.Close()
		}
	}
}

type fakeUpgrader struct {
	req           *http.Request
	resp          *http.Response
	conn          httpstream.Connection
	err, connErr  error
	checkResponse bool
	called        bool

	t *testing.T
}

func (u *fakeUpgrader) RoundTrip(req *http.Request) (*http.Response, error) {
	u.called = true
	u.req = req
	return u.resp, u.err
}

func (u *fakeUpgrader) NewConnection(resp *http.Response) (httpstream.Connection, error) {
	if u.checkResponse && u.resp != resp {
		u.t.Errorf("response objects passed did not match: %#v", resp)
	}
	return u.conn, u.connErr
}

type fakeConnection struct {
	httpstream.Connection
}

// Dial is the common functionality between any stream based upgrader, regardless of protocol.
// This method ensures that someone can use a generic stream executor without being dependent
// on the core Kube client config behavior.
func TestDial(t *testing.T) {
	upgrader := &fakeUpgrader{
		t:             t,
		checkResponse: true,
		conn:          &fakeConnection{},
		resp: &http.Response{
			StatusCode: http.StatusSwitchingProtocols,
			Body:       ioutil.NopCloser(&bytes.Buffer{}),
		},
	}
	dialer := spdy.NewDialer(upgrader, &http.Client{Transport: upgrader}, "POST", &url.URL{Host: "something.com", Scheme: "https"})
	conn, protocol, err := dialer.Dial("protocol1")
	if err != nil {
		t.Fatal(err)
	}
	if conn != upgrader.conn {
		t.Errorf("unexpected connection: %#v", conn)
	}
	if !upgrader.called {
		t.Errorf("request not called")
	}
	_ = protocol
}
<|endoftext|>


<commit_before>package client

import (
	"errors"
	"fmt"
	"reflect"

	"github.com/ovn-org/libovsdb/ovsdb"
)

const (
	opInsert string = "insert"
	opMutate string = "mutate"
	opUpdate string = "insert"
	opDelete string = "delete"
)

// API defines basic operations to interact with the database
type API interface {
	// List populates a slice of Models objects based on their type
	// The function parameter must be a pointer to a slice of Models
	// If the slice is null, the entire cache will be copied into the slice
	// If it has a capacity != 0, only 'capacity' elements will be filled in
	List(result interface{}) error

	// Create a Conditional API from a Function that is used to filter cached data
	// The function must accept a Model implementation and return a boolean. E.g:
	// ConditionFromFunc(func(l *LogicalSwitch) bool { return l.Enabled })
	WhereCache(predicate interface{}) ConditionalAPI

	// Create a ConditionalAPI from a Model's index data or a list of Conditions
	// where operations apply to elements that match any of the conditions
	// If no condition is given, it will match the values provided in Model according
	// to the database index.
	Where(Model, ...Condition) ConditionalAPI

	// Create a ConditionalAPI from a Model's index data or a list of Conditions
	// where operations apply to elements that match all the conditions
	WhereAll(Model, ...Condition) ConditionalAPI

	// Get retrieves a model from the cache
	// The way the object will be fetch depends on the data contained in the
	// provided model and the indexes defined in the associated schema
	// For more complex ways of searching for elements in the cache, the
	// preferred way is Where({condition}).List()
	Get(Model) error

	// Create returns the operation needed to add the model(s) to the Database
	// Only fields with non-default values will be added to the transaction
	// If the field associated with column "_uuid" has some content, it will be
	// treated as named-uuid
	Create(...Model) ([]ovsdb.Operation, error)
}

// ConditionalAPI is an interface used to perform operations that require / use Conditions
type ConditionalAPI interface {
	// List uses the condition to search on the cache and populates
	// the slice of Models objects based on their type
	List(result interface{}) error

	// Mutate returns the operations needed to perform the mutation specified
	// By the model and the list of Mutation objects
	// Depending on the Condition, it might return one or many operations
	Mutate(Model, ...Mutation) ([]ovsdb.Operation, error)

	// Update returns the operations needed to update any number of rows according
	// to the data in the given model.
	// By default, all the non-default values contained in model will be updated.
	// Optional fields can be passed (pointer to fields in the model) to select the
	// the fields to be updated
	Update(Model, ...interface{}) ([]ovsdb.Operation, error)

	// Delete returns the Operations needed to delete the models seleted via the condition
	Delete() ([]ovsdb.Operation, error)
}

// Mutation is a type that represents a OVSDB Mutation
type Mutation struct {
	// Pointer to the field of the model that shall be mutated
	Field interface{}
	// String representing the mutator (as per RFC7047)
	Mutator ovsdb.Mutator
	// Value to use in the mutation
	Value interface{}
}

// Condition is a type that represents a OVSDB Condition
type Condition struct {
	// Pointer to the field of the model where the operation applies
	Field interface{}
	// Condition function
	Function ovsdb.ConditionFunction
	// Value to use in the condition
	Value interface{}
}

// InputTypeError is used to report the user provided parameter has the wrong type
type InputTypeError struct {
	inputType reflect.Type
	reason    string
}

func (e *InputTypeError) Error() string {
	return fmt.Sprintf("Wrong parameter type (%s): %s", e.inputType, e.reason)
}

// ConditionError is a wrapper around an error that is used to
// indicate the error occurred during condition creation
type ConditionError struct {
	err string
}

func (c ConditionError) Error() string {
	return fmt.Sprintf("Condition Error: %s", c.err)
}
func (c ConditionError) String() string {
	return c.Error()
}

// ErrNotFound is used to inform the object or table was not found in the cache
var ErrNotFound = errors.New("object not found")

// api struct implements both API and ConditionalAPI
// Where() can be used to create a ConditionalAPI api
type api struct {
	cache *TableCache
	cond  Conditional
}

// List populates a slice of Models given as parameter based on the configured Condition
func (a api) List(result interface{}) error {
	resultPtr := reflect.ValueOf(result)
	if resultPtr.Type().Kind() != reflect.Ptr {
		return &InputTypeError{resultPtr.Type(), "Expected pointer to slice of valid Models"}
	}

	resultVal := reflect.Indirect(resultPtr)
	if resultVal.Type().Kind() != reflect.Slice {
		return &InputTypeError{resultPtr.Type(), "Expected pointer to slice of valid Models"}
	}

	table, err := a.getTableFromModel(reflect.New(resultVal.Type().Elem()).Interface())
	if err != nil {
		return err
	}

	if a.cond != nil && a.cond.Table() != table {
		return &InputTypeError{resultPtr.Type(),
			fmt.Sprintf("Table derived from input type (%s) does not match Table from Condition (%s)", table, a.cond.Table())}
	}

	tableCache := a.cache.Table(table)
	if tableCache == nil {
		return ErrNotFound
	}

	// If given a null slice, fill it in the cache table completely, if not, just up to
	// its capability
	if resultVal.IsNil() || resultVal.Cap() == 0 {
		resultVal.Set(reflect.MakeSlice(resultVal.Type(), 0, tableCache.Len()))
	}
	i := resultVal.Len()

	for _, row := range tableCache.Rows() {
		elem := tableCache.Row(row)
		if i >= resultVal.Cap() {
			break
		}

		if a.cond != nil {
			if matches, err := a.cond.Matches(elem); err != nil {
				return err
			} else if !matches {
				continue
			}
		}

		resultVal.Set(reflect.Append(resultVal, reflect.Indirect(reflect.ValueOf(elem))))
		i++
	}
	return nil
}

// Where returns a conditionalAPI based on a Condition list
func (a api) Where(model Model, cond ...Condition) ConditionalAPI {
	return newConditionalAPI(a.cache, a.conditionFromModel(false, model, cond...))
}

// Where returns a conditionalAPI based on a Condition list
func (a api) WhereAll(model Model, cond ...Condition) ConditionalAPI {
	return newConditionalAPI(a.cache, a.conditionFromModel(true, model, cond...))
}

// Where returns a conditionalAPI based a Predicate
func (a api) WhereCache(predicate interface{}) ConditionalAPI {
	return newConditionalAPI(a.cache, a.conditionFromFunc(predicate))
}

// Conditional interface implementation
// FromFunc returns a Condition from a function
func (a api) conditionFromFunc(predicate interface{}) Conditional {
	table, err := a.getTableFromFunc(predicate)
	if err != nil {
		return newErrorConditional(err)
	}

	condition, err := newPredicateConditional(table, a.cache, predicate)
	if err != nil {
		return newErrorConditional(err)
	}
	return condition
}

// FromModel returns a Condition from a model and a list of fields
func (a api) conditionFromModel(any bool, model Model, cond ...Condition) Conditional {
	var conditional Conditional
	var err error

	tableName, err := a.getTableFromModel(model)
	if tableName == "" {
		return newErrorConditional(err)
	}

	if len(cond) == 0 {
		conditional, err = newEqualityConditional(a.cache.orm, tableName, any, model)
		if err != nil {
			conditional = newErrorConditional(err)
		}

	} else {
		conditional, err = newExplicitConditional(a.cache.orm, tableName, any, model, cond...)
		if err != nil {
			conditional = newErrorConditional(err)
		}
	}
	return conditional
}

// Get is a generic Get function capable of returning (through a provided pointer)
// a instance of any row in the cache.
// 'result' must be a pointer to an Model that exists in the DBModel
//
// The way the cache is search depends on the fields already populated in 'result'
// Any table index (including _uuid) will be used for comparison
func (a api) Get(model Model) error {
	table, err := a.getTableFromModel(model)
	if err != nil {
		return err
	}

	tableCache := a.cache.Table(table)
	if tableCache == nil {
		return ErrNotFound
	}

	// If model contains _uuid value, we can access it via cache index
	ormInfo, err := newORMInfo(a.cache.orm.schema.Table(table), model)
	if err != nil {
		return err
	}
	if uuid, err := ormInfo.fieldByColumn("_uuid"); err != nil && uuid != nil {
		if found := tableCache.Row(uuid.(string)); found == nil {
			return ErrNotFound
		} else {
			reflect.ValueOf(model).Elem().Set(reflect.Indirect(reflect.ValueOf(found)))
			return nil
		}
	}

	// Look across the entire cache for table index equality
	for _, row := range tableCache.Rows() {
		elem := tableCache.Row(row)
		equal, err := a.cache.orm.equalFields(table, model, elem.(Model))
		if err != nil {
			return err
		}
		if equal {
			reflect.ValueOf(model).Elem().Set(reflect.Indirect(reflect.ValueOf(elem)))
			return nil
		}
	}
	return ErrNotFound
}

// Create is a generic function capable of creating any row in the DB
// A valud Model (pointer to object) must be provided.
func (a api) Create(models ...Model) ([]ovsdb.Operation, error) {
	var operations []ovsdb.Operation

	for _, model := range models {
		var namedUUID string
		var err error

		tableName, err := a.getTableFromModel(model)
		if err != nil {
			return nil, err
		}

		table := a.cache.orm.schema.Table(tableName)

		// Read _uuid field, and use it as named-uuid
		info, err := newORMInfo(table, model)
		if err != nil {
			return nil, err
		}
		if uuid, err := info.fieldByColumn("_uuid"); err == nil {
			namedUUID = uuid.(string)
		} else {
			return nil, err
		}

		row, err := a.cache.orm.newRow(tableName, model)
		if err != nil {
			return nil, err
		}

		operations = append(operations, ovsdb.Operation{
			Op:       opInsert,
			Table:    tableName,
			Row:      row,
			UUIDName: namedUUID,
		})
	}
	return operations, nil
}

// Mutate returns the operations needed to transform the one Model into another one
func (a api) Mutate(model Model, mutationObjs ...Mutation) ([]ovsdb.Operation, error) {
	var mutations []interface{}
	var operations []ovsdb.Operation

	if len(mutationObjs) < 1 {
		return nil, fmt.Errorf("At least one Mutation must be provided")
	}

	tableName := a.cache.dbModel.FindTable(reflect.ValueOf(model).Type())
	table := a.cache.orm.schema.Table(tableName)
	if table == nil {
		return nil, fmt.Errorf("schema error: table not found in Database Model for type %s", reflect.TypeOf(model))
	}

	conditions, err := a.cond.Generate()
	if err != nil {
		return nil, err
	}

	info, err := newORMInfo(table, model)
	if err != nil {
		return nil, err
	}

	for _, mobj := range mutationObjs {
		col, err := info.columnByPtr(mobj.Field)
		if err != nil {
			return nil, err
		}

		mutation, err := a.cache.orm.newMutation(tableName, model, col, mobj.Mutator, mobj.Value)
		if err != nil {
			return nil, err
		}
		mutations = append(mutations, mutation)
	}
	for _, condition := range conditions {
		operations = append(operations,
			ovsdb.Operation{
				Op:        opMutate,
				Table:     tableName,
				Mutations: mutations,
				Where:     condition,
			},
		)
	}

	return operations, nil
}

// Update is a generic function capable of updating any field in any row in the database
// Additional fields can be passed (variadic opts) to indicate fields to be updated
func (a api) Update(model Model, fields ...interface{}) ([]ovsdb.Operation, error) {
	var operations []ovsdb.Operation
	table, err := a.getTableFromModel(model)
	if err != nil {
		return nil, err
	}

	conditions, err := a.cond.Generate()
	if err != nil {
		return nil, err
	}

	row, err := a.cache.orm.newRow(table, model, fields...)
	if err != nil {
		return nil, err
	}

	for _, condition := range conditions {
		operations = append(operations,
			ovsdb.Operation{
				Op:    opUpdate,
				Table: table,
				Row:   row,
				Where: condition,
			},
		)
	}
	return operations, nil
}

// Delete returns the Operation needed to delete the selected models from the database
func (a api) Delete() ([]ovsdb.Operation, error) {
	var operations []ovsdb.Operation
	conditions, err := a.cond.Generate()
	if err != nil {
		return nil, err
	}

	for _, condition := range conditions {
		operations = append(operations,
			ovsdb.Operation{
				Op:    opDelete,
				Table: a.cond.Table(),
				Where: condition,
			},
		)
	}

	return operations, nil
}

// getTableFromModel returns the table name from a Model object after performing
// type verifications on the model
func (a api) getTableFromModel(model interface{}) (string, error) {
	if _, ok := model.(Model); !ok {
		return "", &InputTypeError{reflect.TypeOf(model), "Type does not implement Model interface"}
	}

	table := a.cache.dbModel.FindTable(reflect.TypeOf(model))
	if table == "" {
		return "", &InputTypeError{reflect.TypeOf(model), "Model not found in Database Model"}
	}

	return table, nil
}

// getTableFromModel returns the table name from a the predicate after performing
// type verifications
func (a api) getTableFromFunc(predicate interface{}) (string, error) {
	predType := reflect.TypeOf(predicate)
	if predType == nil || predType.Kind() != reflect.Func {
		return "", &InputTypeError{predType, "Expected function"}
	}
	if predType.NumIn() != 1 || predType.NumOut() != 1 || predType.Out(0).Kind() != reflect.Bool {
		return "", &InputTypeError{predType, "Expected func(Model) bool"}
	}

	modelInterface := reflect.TypeOf((*Model)(nil)).Elem()
	modelType := predType.In(0)
	if !modelType.Implements(modelInterface) {
		return "", &InputTypeError{predType,
			fmt.Sprintf("Type %s does not implement Model interface", modelType.String())}
	}

	table := a.cache.dbModel.FindTable(modelType)
	if table == "" {
		return "", &InputTypeError{predType,
			fmt.Sprintf("Model %s not found in Database Model", modelType.String())}
	}
	return table, nil
}

// newAPI returns a new API to interact with the database
func newAPI(cache *TableCache) API {
	return api{
		cache: cache,
	}
}

// newConditionalAPI returns a new ConditionalAPI to interact with the database
func newConditionalAPI(cache *TableCache, cond Conditional) ConditionalAPI {
	return api{
		cache: cache,
		cond:  cond,
	}
}
<commit_msg>api: remove unused ConditionError<commit_after>package client

import (
	"errors"
	"fmt"
	"reflect"

	"github.com/ovn-org/libovsdb/ovsdb"
)

const (
	opInsert string = "insert"
	opMutate string = "mutate"
	opUpdate string = "insert"
	opDelete string = "delete"
)

// API defines basic operations to interact with the database
type API interface {
	// List populates a slice of Models objects based on their type
	// The function parameter must be a pointer to a slice of Models
	// If the slice is null, the entire cache will be copied into the slice
	// If it has a capacity != 0, only 'capacity' elements will be filled in
	List(result interface{}) error

	// Create a Conditional API from a Function that is used to filter cached data
	// The function must accept a Model implementation and return a boolean. E.g:
	// ConditionFromFunc(func(l *LogicalSwitch) bool { return l.Enabled })
	WhereCache(predicate interface{}) ConditionalAPI

	// Create a ConditionalAPI from a Model's index data or a list of Conditions
	// where operations apply to elements that match any of the conditions
	// If no condition is given, it will match the values provided in Model according
	// to the database index.
	Where(Model, ...Condition) ConditionalAPI

	// Create a ConditionalAPI from a Model's index data or a list of Conditions
	// where operations apply to elements that match all the conditions
	WhereAll(Model, ...Condition) ConditionalAPI

	// Get retrieves a model from the cache
	// The way the object will be fetch depends on the data contained in the
	// provided model and the indexes defined in the associated schema
	// For more complex ways of searching for elements in the cache, the
	// preferred way is Where({condition}).List()
	Get(Model) error

	// Create returns the operation needed to add the model(s) to the Database
	// Only fields with non-default values will be added to the transaction
	// If the field associated with column "_uuid" has some content, it will be
	// treated as named-uuid
	Create(...Model) ([]ovsdb.Operation, error)
}

// ConditionalAPI is an interface used to perform operations that require / use Conditions
type ConditionalAPI interface {
	// List uses the condition to search on the cache and populates
	// the slice of Models objects based on their type
	List(result interface{}) error

	// Mutate returns the operations needed to perform the mutation specified
	// By the model and the list of Mutation objects
	// Depending on the Condition, it might return one or many operations
	Mutate(Model, ...Mutation) ([]ovsdb.Operation, error)

	// Update returns the operations needed to update any number of rows according
	// to the data in the given model.
	// By default, all the non-default values contained in model will be updated.
	// Optional fields can be passed (pointer to fields in the model) to select the
	// the fields to be updated
	Update(Model, ...interface{}) ([]ovsdb.Operation, error)

	// Delete returns the Operations needed to delete the models seleted via the condition
	Delete() ([]ovsdb.Operation, error)
}

// Mutation is a type that represents a OVSDB Mutation
type Mutation struct {
	// Pointer to the field of the model that shall be mutated
	Field interface{}
	// String representing the mutator (as per RFC7047)
	Mutator ovsdb.Mutator
	// Value to use in the mutation
	Value interface{}
}

// Condition is a type that represents a OVSDB Condition
type Condition struct {
	// Pointer to the field of the model where the operation applies
	Field interface{}
	// Condition function
	Function ovsdb.ConditionFunction
	// Value to use in the condition
	Value interface{}
}

// InputTypeError is used to report the user provided parameter has the wrong type
type InputTypeError struct {
	inputType reflect.Type
	reason    string
}

func (e *InputTypeError) Error() string {
	return fmt.Sprintf("Wrong parameter type (%s): %s", e.inputType, e.reason)
}

// ErrNotFound is used to inform the object or table was not found in the cache
var ErrNotFound = errors.New("object not found")

// api struct implements both API and ConditionalAPI
// Where() can be used to create a ConditionalAPI api
type api struct {
	cache *TableCache
	cond  Conditional
}

// List populates a slice of Models given as parameter based on the configured Condition
func (a api) List(result interface{}) error {
	resultPtr := reflect.ValueOf(result)
	if resultPtr.Type().Kind() != reflect.Ptr {
		return &InputTypeError{resultPtr.Type(), "Expected pointer to slice of valid Models"}
	}

	resultVal := reflect.Indirect(resultPtr)
	if resultVal.Type().Kind() != reflect.Slice {
		return &InputTypeError{resultPtr.Type(), "Expected pointer to slice of valid Models"}
	}

	table, err := a.getTableFromModel(reflect.New(resultVal.Type().Elem()).Interface())
	if err != nil {
		return err
	}

	if a.cond != nil && a.cond.Table() != table {
		return &InputTypeError{resultPtr.Type(),
			fmt.Sprintf("Table derived from input type (%s) does not match Table from Condition (%s)", table, a.cond.Table())}
	}

	tableCache := a.cache.Table(table)
	if tableCache == nil {
		return ErrNotFound
	}

	// If given a null slice, fill it in the cache table completely, if not, just up to
	// its capability
	if resultVal.IsNil() || resultVal.Cap() == 0 {
		resultVal.Set(reflect.MakeSlice(resultVal.Type(), 0, tableCache.Len()))
	}
	i := resultVal.Len()

	for _, row := range tableCache.Rows() {
		elem := tableCache.Row(row)
		if i >= resultVal.Cap() {
			break
		}

		if a.cond != nil {
			if matches, err := a.cond.Matches(elem); err != nil {
				return err
			} else if !matches {
				continue
			}
		}

		resultVal.Set(reflect.Append(resultVal, reflect.Indirect(reflect.ValueOf(elem))))
		i++
	}
	return nil
}

// Where returns a conditionalAPI based on a Condition list
func (a api) Where(model Model, cond ...Condition) ConditionalAPI {
	return newConditionalAPI(a.cache, a.conditionFromModel(false, model, cond...))
}

// Where returns a conditionalAPI based on a Condition list
func (a api) WhereAll(model Model, cond ...Condition) ConditionalAPI {
	return newConditionalAPI(a.cache, a.conditionFromModel(true, model, cond...))
}

// Where returns a conditionalAPI based a Predicate
func (a api) WhereCache(predicate interface{}) ConditionalAPI {
	return newConditionalAPI(a.cache, a.conditionFromFunc(predicate))
}

// Conditional interface implementation
// FromFunc returns a Condition from a function
func (a api) conditionFromFunc(predicate interface{}) Conditional {
	table, err := a.getTableFromFunc(predicate)
	if err != nil {
		return newErrorConditional(err)
	}

	condition, err := newPredicateConditional(table, a.cache, predicate)
	if err != nil {
		return newErrorConditional(err)
	}
	return condition
}

// FromModel returns a Condition from a model and a list of fields
func (a api) conditionFromModel(any bool, model Model, cond ...Condition) Conditional {
	var conditional Conditional
	var err error

	tableName, err := a.getTableFromModel(model)
	if tableName == "" {
		return newErrorConditional(err)
	}

	if len(cond) == 0 {
		conditional, err = newEqualityConditional(a.cache.orm, tableName, any, model)
		if err != nil {
			conditional = newErrorConditional(err)
		}

	} else {
		conditional, err = newExplicitConditional(a.cache.orm, tableName, any, model, cond...)
		if err != nil {
			conditional = newErrorConditional(err)
		}
	}
	return conditional
}

// Get is a generic Get function capable of returning (through a provided pointer)
// a instance of any row in the cache.
// 'result' must be a pointer to an Model that exists in the DBModel
//
// The way the cache is search depends on the fields already populated in 'result'
// Any table index (including _uuid) will be used for comparison
func (a api) Get(model Model) error {
	table, err := a.getTableFromModel(model)
	if err != nil {
		return err
	}

	tableCache := a.cache.Table(table)
	if tableCache == nil {
		return ErrNotFound
	}

	// If model contains _uuid value, we can access it via cache index
	ormInfo, err := newORMInfo(a.cache.orm.schema.Table(table), model)
	if err != nil {
		return err
	}
	if uuid, err := ormInfo.fieldByColumn("_uuid"); err != nil && uuid != nil {
		if found := tableCache.Row(uuid.(string)); found == nil {
			return ErrNotFound
		} else {
			reflect.ValueOf(model).Elem().Set(reflect.Indirect(reflect.ValueOf(found)))
			return nil
		}
	}

	// Look across the entire cache for table index equality
	for _, row := range tableCache.Rows() {
		elem := tableCache.Row(row)
		equal, err := a.cache.orm.equalFields(table, model, elem.(Model))
		if err != nil {
			return err
		}
		if equal {
			reflect.ValueOf(model).Elem().Set(reflect.Indirect(reflect.ValueOf(elem)))
			return nil
		}
	}
	return ErrNotFound
}

// Create is a generic function capable of creating any row in the DB
// A valud Model (pointer to object) must be provided.
func (a api) Create(models ...Model) ([]ovsdb.Operation, error) {
	var operations []ovsdb.Operation

	for _, model := range models {
		var namedUUID string
		var err error

		tableName, err := a.getTableFromModel(model)
		if err != nil {
			return nil, err
		}

		table := a.cache.orm.schema.Table(tableName)

		// Read _uuid field, and use it as named-uuid
		info, err := newORMInfo(table, model)
		if err != nil {
			return nil, err
		}
		if uuid, err := info.fieldByColumn("_uuid"); err == nil {
			namedUUID = uuid.(string)
		} else {
			return nil, err
		}

		row, err := a.cache.orm.newRow(tableName, model)
		if err != nil {
			return nil, err
		}

		operations = append(operations, ovsdb.Operation{
			Op:       opInsert,
			Table:    tableName,
			Row:      row,
			UUIDName: namedUUID,
		})
	}
	return operations, nil
}

// Mutate returns the operations needed to transform the one Model into another one
func (a api) Mutate(model Model, mutationObjs ...Mutation) ([]ovsdb.Operation, error) {
	var mutations []interface{}
	var operations []ovsdb.Operation

	if len(mutationObjs) < 1 {
		return nil, fmt.Errorf("At least one Mutation must be provided")
	}

	tableName := a.cache.dbModel.FindTable(reflect.ValueOf(model).Type())
	table := a.cache.orm.schema.Table(tableName)
	if table == nil {
		return nil, fmt.Errorf("schema error: table not found in Database Model for type %s", reflect.TypeOf(model))
	}

	conditions, err := a.cond.Generate()
	if err != nil {
		return nil, err
	}

	info, err := newORMInfo(table, model)
	if err != nil {
		return nil, err
	}

	for _, mobj := range mutationObjs {
		col, err := info.columnByPtr(mobj.Field)
		if err != nil {
			return nil, err
		}

		mutation, err := a.cache.orm.newMutation(tableName, model, col, mobj.Mutator, mobj.Value)
		if err != nil {
			return nil, err
		}
		mutations = append(mutations, mutation)
	}
	for _, condition := range conditions {
		operations = append(operations,
			ovsdb.Operation{
				Op:        opMutate,
				Table:     tableName,
				Mutations: mutations,
				Where:     condition,
			},
		)
	}

	return operations, nil
}

// Update is a generic function capable of updating any field in any row in the database
// Additional fields can be passed (variadic opts) to indicate fields to be updated
func (a api) Update(model Model, fields ...interface{}) ([]ovsdb.Operation, error) {
	var operations []ovsdb.Operation
	table, err := a.getTableFromModel(model)
	if err != nil {
		return nil, err
	}

	conditions, err := a.cond.Generate()
	if err != nil {
		return nil, err
	}

	row, err := a.cache.orm.newRow(table, model, fields...)
	if err != nil {
		return nil, err
	}

	for _, condition := range conditions {
		operations = append(operations,
			ovsdb.Operation{
				Op:    opUpdate,
				Table: table,
				Row:   row,
				Where: condition,
			},
		)
	}
	return operations, nil
}

// Delete returns the Operation needed to delete the selected models from the database
func (a api) Delete() ([]ovsdb.Operation, error) {
	var operations []ovsdb.Operation
	conditions, err := a.cond.Generate()
	if err != nil {
		return nil, err
	}

	for _, condition := range conditions {
		operations = append(operations,
			ovsdb.Operation{
				Op:    opDelete,
				Table: a.cond.Table(),
				Where: condition,
			},
		)
	}

	return operations, nil
}

// getTableFromModel returns the table name from a Model object after performing
// type verifications on the model
func (a api) getTableFromModel(model interface{}) (string, error) {
	if _, ok := model.(Model); !ok {
		return "", &InputTypeError{reflect.TypeOf(model), "Type does not implement Model interface"}
	}

	table := a.cache.dbModel.FindTable(reflect.TypeOf(model))
	if table == "" {
		return "", &InputTypeError{reflect.TypeOf(model), "Model not found in Database Model"}
	}

	return table, nil
}

// getTableFromModel returns the table name from a the predicate after performing
// type verifications
func (a api) getTableFromFunc(predicate interface{}) (string, error) {
	predType := reflect.TypeOf(predicate)
	if predType == nil || predType.Kind() != reflect.Func {
		return "", &InputTypeError{predType, "Expected function"}
	}
	if predType.NumIn() != 1 || predType.NumOut() != 1 || predType.Out(0).Kind() != reflect.Bool {
		return "", &InputTypeError{predType, "Expected func(Model) bool"}
	}

	modelInterface := reflect.TypeOf((*Model)(nil)).Elem()
	modelType := predType.In(0)
	if !modelType.Implements(modelInterface) {
		return "", &InputTypeError{predType,
			fmt.Sprintf("Type %s does not implement Model interface", modelType.String())}
	}

	table := a.cache.dbModel.FindTable(modelType)
	if table == "" {
		return "", &InputTypeError{predType,
			fmt.Sprintf("Model %s not found in Database Model", modelType.String())}
	}
	return table, nil
}

// newAPI returns a new API to interact with the database
func newAPI(cache *TableCache) API {
	return api{
		cache: cache,
	}
}

// newConditionalAPI returns a new ConditionalAPI to interact with the database
func newConditionalAPI(cache *TableCache, cond Conditional) ConditionalAPI {
	return api{
		cache: cache,
		cond:  cond,
	}
}
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"
)

var DefaultTemplate string

func parseRequest(r *http.Request) (doc string, err error) {
	path := strings.Split(r.RequestURI, "/")

	if len(path) == 1 || (len(path) == 2 && strings.HasSuffix(r.RequestURI, "/")) {
		doc = "index"
	} else {
		doc = strings.Join(path[1:], "/")
		if strings.HasSuffix(doc, "/") {
			doc = doc[:len(doc)-1]
		}
	}
	return
}

func fetchAndRenderDoc(doc string) (string, error) {
	template := make(chan string)
	go func() {
		buf, err := ioutil.ReadFile("docs/template.html")
		if err != nil {
			template <- DefaultTemplate
			return
		}
		template <- string(buf)
	}()
	buf, err := ioutil.ReadFile("docs/" + doc + ".md")
	if err != nil {
		return "# Page not found", err
	}

	bodyStr := string(buf)
	url := "https://api.github.com/markdown/raw"
	if os.Getenv("ACCESS_TOKEN") != "" {
		url += "?access_token="+os.Getenv("ACCESS_TOKEN")
	}
	resp, err := http.Post(url, "text/x-markdown", strings.NewReader(bodyStr))
	if err != nil {
		return "", err
	}
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}
	output := strings.Replace(<-template, "{{CONTENT}}", string(body), 1)
	// output = strings.Replace(output, "{{NAME}}", repo, -1)
	// output = strings.Replace(output, "{{USER}}", user, -1)
	return output, nil
}

func main() {
	if os.Getenv("ACCESS_TOKEN") == "" {
		log.Println("WARNING: ACCESS_TOKEN was not found, you'll be subject to GitHub's Rate Limiting of 60 requests per hour. " +
	                "Please read http://developer.github.com/v3/#rate-limiting for more information")
	}

	port := os.Getenv("PORT")
	if port == "" {
		port = "8888"
	}

	resp, err := http.Get("https://raw.github.com/progrium/viewdocs/master/docs/template.html")
	if err != nil || resp.StatusCode == 404 {
		log.Fatal("Unable to fetch default template")
	}
	body, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	if err != nil {
		log.Fatal(err)
	}
	DefaultTemplate = string(body)

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if r.RequestURI == "/favicon.ico" {
			return
		}
		switch r.Method {
		case "GET":
			doc, err := parseRequest(r)
			if err != nil {
				w.WriteHeader(http.StatusInternalServerError)
				w.Write([]byte(err.Error()))
				return
			}
			log.Printf("Building docs for '%s'", doc)
			output, err := fetchAndRenderDoc(doc)
			if err != nil {
				w.WriteHeader(http.StatusInternalServerError)
				w.Write([]byte(err.Error()))
				return
			}
			w.Write([]byte(output))
		default:
			w.WriteHeader(http.StatusMethodNotAllowed)
		}
	})
	log.Println("Listening on port " + port)
	log.Fatal(http.ListenAndServe(":"+port, nil))
}
<commit_msg>go fmt<commit_after>package main

import (
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"
)

var DefaultTemplate string

func parseRequest(r *http.Request) (doc string, err error) {
	path := strings.Split(r.RequestURI, "/")

	if len(path) == 1 || (len(path) == 2 && strings.HasSuffix(r.RequestURI, "/")) {
		doc = "index"
	} else {
		doc = strings.Join(path[1:], "/")
		if strings.HasSuffix(doc, "/") {
			doc = doc[:len(doc)-1]
		}
	}
	return
}

func fetchAndRenderDoc(doc string) (string, error) {
	template := make(chan string)
	go func() {
		buf, err := ioutil.ReadFile("docs/template.html")
		if err != nil {
			template <- DefaultTemplate
			return
		}
		template <- string(buf)
	}()
	buf, err := ioutil.ReadFile("docs/" + doc + ".md")
	if err != nil {
		return "# Page not found", err
	}

	bodyStr := string(buf)
	url := "https://api.github.com/markdown/raw"
	if os.Getenv("ACCESS_TOKEN") != "" {
		url += "?access_token=" + os.Getenv("ACCESS_TOKEN")
	}
	resp, err := http.Post(url, "text/x-markdown", strings.NewReader(bodyStr))
	if err != nil {
		return "", err
	}
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}
	output := strings.Replace(<-template, "{{CONTENT}}", string(body), 1)
	// output = strings.Replace(output, "{{NAME}}", repo, -1)
	// output = strings.Replace(output, "{{USER}}", user, -1)
	return output, nil
}

func main() {
	if os.Getenv("ACCESS_TOKEN") == "" {
		log.Println("WARNING: ACCESS_TOKEN was not found, you'll be subject to GitHub's Rate Limiting of 60 requests per hour. " +
			"Please read http://developer.github.com/v3/#rate-limiting for more information")
	}

	port := os.Getenv("PORT")
	if port == "" {
		port = "8888"
	}

	resp, err := http.Get("https://raw.github.com/progrium/viewdocs/master/docs/template.html")
	if err != nil || resp.StatusCode == 404 {
		log.Fatal("Unable to fetch default template")
	}
	body, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	if err != nil {
		log.Fatal(err)
	}
	DefaultTemplate = string(body)

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if r.RequestURI == "/favicon.ico" {
			return
		}
		switch r.Method {
		case "GET":
			doc, err := parseRequest(r)
			if err != nil {
				w.WriteHeader(http.StatusInternalServerError)
				w.Write([]byte(err.Error()))
				return
			}
			log.Printf("Building docs for '%s'", doc)
			output, err := fetchAndRenderDoc(doc)
			if err != nil {
				w.WriteHeader(http.StatusInternalServerError)
				w.Write([]byte(err.Error()))
				return
			}
			w.Write([]byte(output))
		default:
			w.WriteHeader(http.StatusMethodNotAllowed)
		}
	})
	log.Println("Listening on port " + port)
	log.Fatal(http.ListenAndServe(":"+port, nil))
}
<|endoftext|>


<commit_before>package push

import (
	"io/ioutil"
	"os"
	"path/filepath"

	"code.cloudfoundry.org/cli/api/cloudcontroller/ccversion"
	"code.cloudfoundry.org/cli/integration/helpers"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
)

var _ = Describe("push with symlinked resources", func() {
	var (
		appName string
	)

	BeforeEach(func() {
		helpers.SkipIfVersionLessThan(ccversion.MinVersionSymlinkedFilesV2)
		appName = helpers.NewAppName()
	})

	Context("when pushing a directory", func() {
		Context("when the directory contains a symlink to a file in the directory", func() {
			Context("when the file exists", func() {
				It("should push the symlink", func() {
					helpers.WithHelloWorldApp(func(dir string) {
						targetFile := filepath.Join(dir, "targetFile")
						Expect(ioutil.WriteFile(targetFile, []byte("foo bar baz"), 0777)).ToNot(HaveOccurred())
						relativePath, err := filepath.Rel(dir, targetFile)
						Expect(err).ToNot(HaveOccurred())

						err = os.Symlink(relativePath, filepath.Join(dir, "symlinkFile"))
						Expect(err).ToNot(HaveOccurred())

						session := helpers.CustomCF(helpers.CFEnv{WorkingDirectory: dir}, PushCommandName, appName, "--no-start")

						Eventually(session).Should(Exit(0))
					})

					helpers.VerifyAppPackageContentsV2(appName, "symlinkFile", "targetFile", "Staticfile", "index.html")
				})
			})

			Context("when the file doesn't exists", func() {
				It("should push the symlink", func() {
					helpers.WithHelloWorldApp(func(dir string) {
						tempFile, err := ioutil.TempFile(dir, "tempFile")
						Expect(err).ToNot(HaveOccurred())
						tempFile.Close()
						relativePath, err := filepath.Rel(dir, tempFile.Name())
						Expect(err).ToNot(HaveOccurred())

						err = os.Symlink(relativePath, filepath.Join(dir, "symlinkFile"))
						Expect(err).ToNot(HaveOccurred())
						Expect(os.Remove(tempFile.Name()))

						session := helpers.CustomCF(helpers.CFEnv{WorkingDirectory: dir}, PushCommandName, appName, "--no-start")

						Eventually(session).Should(Exit(0))
					})

					helpers.VerifyAppPackageContentsV2(appName, "symlinkFile", "Staticfile", "index.html")
				})
			})
		})

		Context("when the directory contains a symlink to subdirectory in the directory", func() {
			It("should push the symlink", func() {
				helpers.WithHelloWorldApp(func(dir string) {
					targetDir, err := ioutil.TempDir(dir, "target-dir")
					Expect(err).ToNot(HaveOccurred())
					relativePath, err := filepath.Rel(dir, targetDir)
					Expect(err).ToNot(HaveOccurred())

					err = os.Symlink(relativePath, filepath.Join(dir, "symlinkFile"))
					Expect(err).ToNot(HaveOccurred())
					Expect(os.RemoveAll(targetDir)).ToNot(HaveOccurred())

					session := helpers.CustomCF(helpers.CFEnv{WorkingDirectory: dir}, PushCommandName, appName, "--no-start")

					Eventually(session).Should(Exit(0))
				})

				helpers.VerifyAppPackageContentsV2(appName, "symlinkFile", "Staticfile", "index.html")
			})
		})
	})

	Context("when pushing an archive", func() {
		var archive string

		AfterEach(func() {
			Expect(os.RemoveAll(archive)).ToNot(HaveOccurred())
		})

		Context("when the archive contains a symlink to a file in the directory", func() {
			BeforeEach(func() {
				helpers.WithHelloWorldApp(func(appDir string) {
					helpers.WithHelloWorldApp(func(appDir string) {
						tmpfile, err := ioutil.TempFile("", "push-archive-integration")
						Expect(err).ToNot(HaveOccurred())
						archive = tmpfile.Name()
						Expect(tmpfile.Close()).ToNot(HaveOccurred())

						targetFile := filepath.Join(appDir, "targetFile")
						Expect(ioutil.WriteFile(targetFile, []byte("some random data"), 0777)).ToNot(HaveOccurred())
						relativePath, err := filepath.Rel(appDir, targetFile)
						Expect(err).ToNot(HaveOccurred())

						err = os.Symlink(relativePath, filepath.Join(appDir, "symlinkFile"))
						Expect(err).ToNot(HaveOccurred())

						err = helpers.Zipit(appDir, archive, "")
						Expect(err).ToNot(HaveOccurred())
					})
				})
			})

			It("should push the symlink", func() {
				session := helpers.CF(PushCommandName, appName, "--no-start", "-p", archive)

				Eventually(session).Should(Exit(0))
				helpers.VerifyAppPackageContentsV2(appName, "symlinkFile", "targetFile", "Staticfile", "index.html")
			})
		})
	})
})
<commit_msg>remove unused import<commit_after>package push

import (
	"io/ioutil"
	"os"
	"path/filepath"

	"code.cloudfoundry.org/cli/api/cloudcontroller/ccversion"
	"code.cloudfoundry.org/cli/integration/helpers"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gexec"
)

var _ = Describe("push with symlinked resources", func() {
	var (
		appName string
	)

	BeforeEach(func() {
		helpers.SkipIfVersionLessThan(ccversion.MinVersionSymlinkedFilesV2)
		appName = helpers.NewAppName()
	})

	Context("when pushing a directory", func() {
		Context("when the directory contains a symlink to a file in the directory", func() {
			Context("when the file exists", func() {
				It("should push the symlink", func() {
					helpers.WithHelloWorldApp(func(dir string) {
						targetFile := filepath.Join(dir, "targetFile")
						Expect(ioutil.WriteFile(targetFile, []byte("foo bar baz"), 0777)).ToNot(HaveOccurred())
						relativePath, err := filepath.Rel(dir, targetFile)
						Expect(err).ToNot(HaveOccurred())

						err = os.Symlink(relativePath, filepath.Join(dir, "symlinkFile"))
						Expect(err).ToNot(HaveOccurred())

						session := helpers.CustomCF(helpers.CFEnv{WorkingDirectory: dir}, PushCommandName, appName, "--no-start")

						Eventually(session).Should(Exit(0))
					})

					helpers.VerifyAppPackageContentsV2(appName, "symlinkFile", "targetFile", "Staticfile", "index.html")
				})
			})

			Context("when the file doesn't exists", func() {
				It("should push the symlink", func() {
					helpers.WithHelloWorldApp(func(dir string) {
						tempFile, err := ioutil.TempFile(dir, "tempFile")
						Expect(err).ToNot(HaveOccurred())
						tempFile.Close()
						relativePath, err := filepath.Rel(dir, tempFile.Name())
						Expect(err).ToNot(HaveOccurred())

						err = os.Symlink(relativePath, filepath.Join(dir, "symlinkFile"))
						Expect(err).ToNot(HaveOccurred())
						Expect(os.Remove(tempFile.Name()))

						session := helpers.CustomCF(helpers.CFEnv{WorkingDirectory: dir}, PushCommandName, appName, "--no-start")

						Eventually(session).Should(Exit(0))
					})

					helpers.VerifyAppPackageContentsV2(appName, "symlinkFile", "Staticfile", "index.html")
				})
			})
		})

		Context("when the directory contains a symlink to subdirectory in the directory", func() {
			It("should push the symlink", func() {
				helpers.WithHelloWorldApp(func(dir string) {
					targetDir, err := ioutil.TempDir(dir, "target-dir")
					Expect(err).ToNot(HaveOccurred())
					relativePath, err := filepath.Rel(dir, targetDir)
					Expect(err).ToNot(HaveOccurred())

					err = os.Symlink(relativePath, filepath.Join(dir, "symlinkFile"))
					Expect(err).ToNot(HaveOccurred())
					Expect(os.RemoveAll(targetDir)).ToNot(HaveOccurred())

					session := helpers.CustomCF(helpers.CFEnv{WorkingDirectory: dir}, PushCommandName, appName, "--no-start")

					Eventually(session).Should(Exit(0))
				})

				helpers.VerifyAppPackageContentsV2(appName, "symlinkFile", "Staticfile", "index.html")
			})
		})
	})

	Context("when pushing an archive", func() {
		var archive string

		AfterEach(func() {
			Expect(os.RemoveAll(archive)).ToNot(HaveOccurred())
		})

		Context("when the archive contains a symlink to a file in the directory", func() {
			BeforeEach(func() {
				helpers.WithHelloWorldApp(func(appDir string) {
					helpers.WithHelloWorldApp(func(appDir string) {
						tmpfile, err := ioutil.TempFile("", "push-archive-integration")
						Expect(err).ToNot(HaveOccurred())
						archive = tmpfile.Name()
						Expect(tmpfile.Close()).ToNot(HaveOccurred())

						targetFile := filepath.Join(appDir, "targetFile")
						Expect(ioutil.WriteFile(targetFile, []byte("some random data"), 0777)).ToNot(HaveOccurred())
						relativePath, err := filepath.Rel(appDir, targetFile)
						Expect(err).ToNot(HaveOccurred())

						err = os.Symlink(relativePath, filepath.Join(appDir, "symlinkFile"))
						Expect(err).ToNot(HaveOccurred())

						err = helpers.Zipit(appDir, archive, "")
						Expect(err).ToNot(HaveOccurred())
					})
				})
			})

			It("should push the symlink", func() {
				session := helpers.CF(PushCommandName, appName, "--no-start", "-p", archive)

				Eventually(session).Should(Exit(0))
				helpers.VerifyAppPackageContentsV2(appName, "symlinkFile", "targetFile", "Staticfile", "index.html")
			})
		})
	})
})
<|endoftext|>


<commit_before>// TODO(pedge): the public vs non-public needs to go away, we need to put
// creds somewhere managed, and consistently call out to s3
package s3utils

import (
	"io"
	"path"
	"strings"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/aws/aws-sdk-go/service/s3/s3manager"
)

const (
	Private           = ACL("private")
	PublicRead        = ACL("public-read")
	PublicReadWrite   = ACL("public-read-write")
	AuthenticatedRead = ACL("authenticated-read")
	BucketOwnerRead   = ACL("bucket-owner-read")
	BucketOwnerFull   = ACL("bucket-owner-full-control")
)

type ACL string

// An s3 input looks like: s3://bucket/dir
// Where dir can be a path

// getBucket extracts the bucket from an s3 input
func GetBucket(input string) (string, error) {
	return strings.Split(strings.TrimPrefix(input, "s3://"), "/")[0], nil
}

// getPath extracts the path from an s3 input
func GetPath(input string) (string, error) {
	return path.Join(strings.Split(strings.TrimPrefix(input, "s3://"), "/")[1:]...), nil
}

func NewClient(public bool) *s3.S3 {
	if public {
		return s3.New(
			&aws.Config{
				Credentials: credentials.AnonymousCredentials,
			},
		)
	}
	return s3.New(nil)
}

// PutMulti is like a smart bucket.Put in that it will automatically do a
// multiput if the input reader has enough data that it makes sense to do so.
func PutMulti(bucketUri string, path string, r io.Reader, contType string, perm ACL) error {
	bucket, err := GetBucket(bucketUri)

	if err != nil {
		return err
	}

	uploader := s3manager.NewUploader(nil)

	_, err = uploader.Upload(&s3manager.UploadInput{
		Bucket: &bucket,
		Key:    &path,
		Body:   r,
	})
	return err
}

// Files calls `cont` on each file found at `uri` starting at marker.
// Pass `marker=""` to start from the beginning.
// Returns the marker that should be passed to pick-up where this call left off.
func ForEachFile(uri string, public bool, marker string, cont func(file string, modtime time.Time) error) error {
	inPath, err := GetPath(uri)
	if err != nil {
		return err
	}

	bucket, err := GetBucket(uri)
	if err != nil {
		return err
	}

	client := NewClient(public)
	nextMarker := aws.String(marker)

	for {
		lr, err := client.ListObjects(&s3.ListObjectsInput{
			Bucket:  aws.String(bucket),
			Prefix:  aws.String(inPath),
			Marker:  nextMarker,
			MaxKeys: aws.Long(1000),
		})

		if err != nil {
			return err
		}

		for _, key := range lr.Contents {
			err = cont(*key.Key, *key.LastModified)

			if err != nil {
				return err
			}
		}

		if !*lr.IsTruncated {
			// We've exhausted the output
			break
		}

		nextMarker = lr.Contents[len(lr.Contents)-1].Key
	}

	return nil
}
<commit_msg>fix for aws api<commit_after>// TODO(pedge): the public vs non-public needs to go away, we need to put
// creds somewhere managed, and consistently call out to s3
package s3utils

import (
	"io"
	"path"
	"strings"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/aws/aws-sdk-go/service/s3/s3manager"
)

const (
	Private           = ACL("private")
	PublicRead        = ACL("public-read")
	PublicReadWrite   = ACL("public-read-write")
	AuthenticatedRead = ACL("authenticated-read")
	BucketOwnerRead   = ACL("bucket-owner-read")
	BucketOwnerFull   = ACL("bucket-owner-full-control")
)

type ACL string

// An s3 input looks like: s3://bucket/dir
// Where dir can be a path

// getBucket extracts the bucket from an s3 input
func GetBucket(input string) (string, error) {
	return strings.Split(strings.TrimPrefix(input, "s3://"), "/")[0], nil
}

// getPath extracts the path from an s3 input
func GetPath(input string) (string, error) {
	return path.Join(strings.Split(strings.TrimPrefix(input, "s3://"), "/")[1:]...), nil
}

func NewClient(public bool) *s3.S3 {
	if public {
		return s3.New(
			&aws.Config{
				Credentials: credentials.AnonymousCredentials,
			},
		)
	}
	return s3.New(nil)
}

// PutMulti is like a smart bucket.Put in that it will automatically do a
// multiput if the input reader has enough data that it makes sense to do so.
func PutMulti(bucketUri string, path string, r io.Reader, contType string, perm ACL) error {
	bucket, err := GetBucket(bucketUri)

	if err != nil {
		return err
	}

	uploader := s3manager.NewUploader(nil)

	_, err = uploader.Upload(&s3manager.UploadInput{
		Bucket: &bucket,
		Key:    &path,
		Body:   r,
	})
	return err
}

// Files calls `cont` on each file found at `uri` starting at marker.
// Pass `marker=""` to start from the beginning.
// Returns the marker that should be passed to pick-up where this call left off.
func ForEachFile(uri string, public bool, marker string, cont func(file string, modtime time.Time) error) error {
	inPath, err := GetPath(uri)
	if err != nil {
		return err
	}

	bucket, err := GetBucket(uri)
	if err != nil {
		return err
	}

	client := NewClient(public)
	nextMarker := aws.String(marker)

	for {
		lr, err := client.ListObjects(&s3.ListObjectsInput{
			Bucket:  aws.String(bucket),
			Prefix:  aws.String(inPath),
			Marker:  nextMarker,
			MaxKeys: aws.Int64(1000),
		})

		if err != nil {
			return err
		}

		for _, key := range lr.Contents {
			err = cont(*key.Key, *key.LastModified)

			if err != nil {
				return err
			}
		}

		if !*lr.IsTruncated {
			// We've exhausted the output
			break
		}

		nextMarker = lr.Contents[len(lr.Contents)-1].Key
	}

	return nil
}
<|endoftext|>


<commit_before>package rtree

import (
	"fmt"
	"math/rand"
	"runtime"
	"testing"
)

func randf(min, max float64) float64 {
	return rand.Float64()*(max-min) + min
}

func randMinMax() (min, max []float64) {
	minX, maxX := randf(-180, 180), randf(-180, 180)
	minY, maxY := randf(-90, 90), randf(-90, 90)
	minZ, maxZ := randf(0, 1000), randf(0, 1000)
	min4, max4 := randf(0, 1000), randf(0, 1000)
	if maxX < minX {
		minX, maxX = maxX, minX
	}
	if maxY < minY {
		minY, maxY = maxY, minY
	}
	if maxZ < minZ {
		minZ, maxZ = maxZ, minZ
	}
	if max4 < min4 {
		min4, max4 = max4, min4
	}
	return []float64{minX, minY, minZ, min4}, []float64{maxX, maxY, maxZ, max4}
}

func wp(min, max []float64) *Rect {
	return &Rect{
		MinX: min[0],
		MinY: min[1],
		MaxX: max[0],
		MaxY: max[1],
	}
}
func wpp(x, y, z float64) *Rect {
	return &Rect{
		x, y, z,
		x, y, z,
	}
}
func TestA(t *testing.T) {
	tr := New()
	item1 := wp([]float64{10, 10, 10, 10}, []float64{20, 20, 20, 20})
	item2 := wp([]float64{5, 5, 5, 5}, []float64{25, 25, 25, 25})
	tr.Insert(item1)
	tr.Insert(item2)
	var itemA Item
	tr.Search(21, 20, 0, 25, 25, 0, func(item Item) bool {
		itemA = item
		return true
	})
	if tr.Count() != 2 {
		t.Fatalf("tr.Count() == %d, expect 2", tr.Count())
	}
	if itemA != item2 {
		t.Fatalf("itemA == %v, expect %v", itemA, item2)
	}
}

func TestMemory(t *testing.T) {
	rand.Seed(0)
	tr := New()
	for i := 0; i < 100000; i++ {
		min, max := randMinMax()
		tr.Insert(wp(min, max))
	}
	runtime.GC()
	var m runtime.MemStats
	runtime.ReadMemStats(&m)
	println(int(m.HeapAlloc)/tr.Count(), "bytes/rect")
}
func TestBounds(t *testing.T) {
	tr := New()
	tr.Insert(wpp(10, 10, 0))
	tr.Insert(wpp(10, 20, 0))
	tr.Insert(wpp(10, 30, 0))
	tr.Insert(wpp(20, 10, 0))
	tr.Insert(wpp(30, 10, 0))
	minX, minY, minZ, maxX, maxY, maxZ := tr.Bounds()
	if minX != 10 || minY != 10 || minZ != 0 || maxX != 30 || maxY != 30 || maxZ != 0 {
		t.Fatalf("expected 10,10,0 30,30,0, got %v,%v %v,%v\n", minX, minY, minZ, maxX, maxY, maxZ)
	}
}
func TestKNN(t *testing.T) {
	x, y, z := 20., 20., 0.
	tr := New()
	tr.Insert(wpp(5, 5, 0))
	tr.Insert(wpp(19, 19, 0))
	tr.Insert(wpp(12, 19, 0))
	tr.Insert(wpp(-5, 5, 0))
	tr.Insert(wpp(33, 21, 0))
	items := tr.NearestNeighbors(10, x, y, z)
	var res string
	for i, item := range items {
		ix, iy, _, _, _, _ := item.Rect()
		res += fmt.Sprintf("%d:%v,%v\n", i, ix, iy)
	}
	if res != "0:19,19\n1:12,19\n2:33,21\n3:5,5\n4:-5,5\n" {
		t.Fatal("invalid response")
	}
}

func BenchmarkInsert(b *testing.B) {
	rand.Seed(0)
	tr := New()
	for i := 0; i < b.N; i++ {
		min, max := randMinMax()
		tr.Insert(wp(min, max))
	}
	// count := 0
	// tr.Search([]float64{-116, 32, 20}, []float64{-114, 34, 800}, func(id int) bool {
	// 	count++
	// 	return true
	// })
	// println(count)
	// //println(tr.Count())
}
<commit_msg>update benchmark<commit_after>package rtree

import (
	"fmt"
	"math/rand"
	"runtime"
	"testing"
)

func randf(min, max float64) float64 {
	return rand.Float64()*(max-min) + min
}

func randMinMax() (min, max []float64) {
	minX, maxX := randf(-180, 180), randf(-180, 180)
	minY, maxY := randf(-90, 90), randf(-90, 90)
	minZ, maxZ := randf(0, 1000), randf(0, 1000)
	min4, max4 := randf(0, 1000), randf(0, 1000)
	if maxX < minX {
		minX, maxX = maxX, minX
	}
	if maxY < minY {
		minY, maxY = maxY, minY
	}
	if maxZ < minZ {
		minZ, maxZ = maxZ, minZ
	}
	if max4 < min4 {
		min4, max4 = max4, min4
	}
	return []float64{minX, minY, minZ, min4}, []float64{maxX, maxY, maxZ, max4}
}

func wp(min, max []float64) *Rect {
	return &Rect{
		MinX: min[0],
		MinY: min[1],
		MaxX: max[0],
		MaxY: max[1],
	}
}
func wpp(x, y, z float64) *Rect {
	return &Rect{
		x, y, z,
		x, y, z,
	}
}
func TestA(t *testing.T) {
	tr := New()
	item1 := wp([]float64{10, 10, 10, 10}, []float64{20, 20, 20, 20})
	item2 := wp([]float64{5, 5, 5, 5}, []float64{25, 25, 25, 25})
	tr.Insert(item1)
	tr.Insert(item2)
	var itemA Item
	tr.Search(21, 20, 0, 25, 25, 0, func(item Item) bool {
		itemA = item
		return true
	})
	if tr.Count() != 2 {
		t.Fatalf("tr.Count() == %d, expect 2", tr.Count())
	}
	if itemA != item2 {
		t.Fatalf("itemA == %v, expect %v", itemA, item2)
	}
}

func TestMemory(t *testing.T) {
	rand.Seed(0)
	tr := New()
	for i := 0; i < 100000; i++ {
		min, max := randMinMax()
		tr.Insert(wp(min, max))
	}
	runtime.GC()
	var m runtime.MemStats
	runtime.ReadMemStats(&m)
	println(int(m.HeapAlloc)/tr.Count(), "bytes/rect")
}
func TestBounds(t *testing.T) {
	tr := New()
	tr.Insert(wpp(10, 10, 0))
	tr.Insert(wpp(10, 20, 0))
	tr.Insert(wpp(10, 30, 0))
	tr.Insert(wpp(20, 10, 0))
	tr.Insert(wpp(30, 10, 0))
	minX, minY, minZ, maxX, maxY, maxZ := tr.Bounds()
	if minX != 10 || minY != 10 || minZ != 0 || maxX != 30 || maxY != 30 || maxZ != 0 {
		t.Fatalf("expected 10,10,0 30,30,0, got %v,%v %v,%v\n", minX, minY, minZ, maxX, maxY, maxZ)
	}
}
func TestKNN(t *testing.T) {
	x, y, z := 20., 20., 0.
	tr := New()
	tr.Insert(wpp(5, 5, 0))
	tr.Insert(wpp(19, 19, 0))
	tr.Insert(wpp(12, 19, 0))
	tr.Insert(wpp(-5, 5, 0))
	tr.Insert(wpp(33, 21, 0))
	items := tr.NearestNeighbors(10, x, y, z)
	var res string
	for i, item := range items {
		ix, iy, _, _, _, _ := item.Rect()
		res += fmt.Sprintf("%d:%v,%v\n", i, ix, iy)
	}
	if res != "0:19,19\n1:12,19\n2:33,21\n3:5,5\n4:-5,5\n" {
		t.Fatal("invalid response")
	}
}

func BenchmarkInsert(b *testing.B) {
	var rects []*Rect
	for i := 0; i < b.N; i++ {
		rects = append(rects, wp(randMinMax()))
	}
	rand.Seed(0)
	b.ReportAllocs()
	b.ResetTimer()
	tr := New()
	for i := 0; i < b.N; i++ {
		tr.Insert(rects[i])
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/bmizerany/assert"
	"os"
	"path/filepath"
	"strings"
	"testing"
)

func TestEmptyRepository(t *testing.T) {
	repo := NewRepository(t, "empty")
	repo.AddPath(filepath.Join(repo.Path, ".git"))
	repo.AddPath(filepath.Join(repo.Path, "subdir"))

	cmd := repo.Command("version")
	cmd.Output = fmt.Sprintf("git-media v%s", Version)

	cmd = repo.Command("version", "-comics")
	cmd.Output = fmt.Sprintf("git-media v%s\nNothing may see Gah Lak Tus and survive.", Version)

	cmd = repo.Command("config")
	SetConfigOutput(cmd, map[string]string{
		"Endpoint":        "https://example.com/git/media.git/info/media",
		"LocalWorkingDir": repo.Path,
		"LocalGitDir":     filepath.Join(repo.Path, ".git"),
		"LocalMediaDir":   filepath.Join(repo.Path, ".git", "media"),
		"TempDir":         filepath.Join(os.TempDir(), "git-media"),
	})

	cmd = repo.Command("init")
	cmd.Output = "Installing clean filter\n" +
		"Installing smudge filter\n" +
		"git media initialized"

	cmd.After(func() {
		configs := GlobalGitConfig(t)
		AssertIncludeString(t, "filter.media.clean=git media clean %f", configs)
		AssertIncludeString(t, "filter.media.smudge=git media smudge %f", configs)
		found := 0
		for _, line := range configs {
			if strings.HasPrefix(line, "filter.media") {
				found += 1
			}
		}
		assert.Equal(t, 2, found)
	})

	repo.Test()
}

func TestAttributesOnEmptyRepository(t *testing.T) {
	repo := NewRepository(t, "empty")

	cmd := repo.Command("path", "add", "*.gif")
	cmd.Output = "Adding path *.gif"
	cmd.After(func() {
		assert.Equal(t, "*.gif filter=media -crlf\n", repo.ReadFile(".gitattributes"))

		expected := "Listing paths\n    *.gif (.gitattributes)\n"

		assert.Equal(t, expected, repo.MediaCmd("path"))
	})

	cmd = repo.Command("path")
	cmd.Output = "Listing paths"

	repo.Test()
}
<commit_msg>Update integration tests to look for required line<commit_after>package main

import (
	"fmt"
	"github.com/bmizerany/assert"
	"os"
	"path/filepath"
	"strings"
	"testing"
)

func TestEmptyRepository(t *testing.T) {
	repo := NewRepository(t, "empty")
	repo.AddPath(filepath.Join(repo.Path, ".git"))
	repo.AddPath(filepath.Join(repo.Path, "subdir"))

	cmd := repo.Command("version")
	cmd.Output = fmt.Sprintf("git-media v%s", Version)

	cmd = repo.Command("version", "-comics")
	cmd.Output = fmt.Sprintf("git-media v%s\nNothing may see Gah Lak Tus and survive.", Version)

	cmd = repo.Command("config")
	SetConfigOutput(cmd, map[string]string{
		"Endpoint":        "https://example.com/git/media.git/info/media",
		"LocalWorkingDir": repo.Path,
		"LocalGitDir":     filepath.Join(repo.Path, ".git"),
		"LocalMediaDir":   filepath.Join(repo.Path, ".git", "media"),
		"TempDir":         filepath.Join(os.TempDir(), "git-media"),
	})

	cmd = repo.Command("init")
	cmd.Output = "Installing clean filter\n" +
		"Installing smudge filter\n" +
		"git media initialized"

	cmd.After(func() {
		configs := GlobalGitConfig(t)
		fmt.Println(configs)
		AssertIncludeString(t, "filter.media.clean=git media clean %f", configs)
		AssertIncludeString(t, "filter.media.smudge=git media smudge %f", configs)
		AssertIncludeString(t, "filter.media.required=true", configs)
		found := 0
		for _, line := range configs {
			if strings.HasPrefix(line, "filter.media") {
				found += 1
			}
		}
		assert.Equal(t, 3, found)
	})

	repo.Test()
}

func TestAttributesOnEmptyRepository(t *testing.T) {
	repo := NewRepository(t, "empty")

	cmd := repo.Command("path", "add", "*.gif")
	cmd.Output = "Adding path *.gif"
	cmd.After(func() {
		assert.Equal(t, "*.gif filter=media -crlf\n", repo.ReadFile(".gitattributes"))

		expected := "Listing paths\n    *.gif (.gitattributes)\n"

		assert.Equal(t, expected, repo.MediaCmd("path"))
	})

	cmd = repo.Command("path")
	cmd.Output = "Listing paths"

	repo.Test()
}
<|endoftext|>