<commit_before>package builtin

import (
	"log"

	"github.com/wanliu/flow/builtin/config"
	"github.com/wanliu/flow/builtin/resolves"
	"github.com/wanliu/flow/context"
)

type NewOrder struct {
	TryGetEntities
	DefTime    string
	retryCount int

	Ctx     <-chan context.Context
	Deftime <-chan string
	Out     chan<- ReplyData
	Notice  chan<- context.Context
	Timeout chan<- context.Context

	RetryOut chan<- context.Context
	RetryIn  <-chan context.Context

	RetryCount <-chan float64
}

func NewNewOrder() interface{} {
	return new(NewOrder)
}

// 默认送货时间
func (c *NewOrder) OnDeftime(t string) {
	c.DefTime = t
}

func (c *NewOrder) OnRetryCount(count float64) {
	c.retryCount = int(count)
}

func (c *NewOrder) OnCtx(ctx context.Context) {
	orderResolve := resolves.NewOrderResolve(ctx)

	if c.DefTime != "" {
		orderResolve.SetDefTime(c.DefTime)
	}

	output := ""

	if orderResolve.EmptyProducts() {
		if c.retryCount > 0 {
			log.Printf("重新获取开单产品，第1次，共%v次", c.retryCount)
			c.RetryOut <- ctx
		} else {
			output = "没有相关的产品"
			replyData := ReplyData{output, ctx}
			c.Out <- replyData
		}
	} else {
		output = orderResolve.Answer(ctx)

		if orderResolve.Resolved() {
			ctx.SetValue(config.CtxKeyLastOrder, *orderResolve)
			ctx.SetValue(config.CtxKeyOrder, nil)
		} else if orderResolve.Failed() {
			ctx.SetValue(config.CtxKeyOrder, nil)
		} else if orderResolve.MismatchQuantity() {
			ctx.SetValue(config.CtxKeyOrder, nil)
		} else {
			ctx.SetValue(config.CtxKeyOrder, *orderResolve)
		}

		// c.Notice <- ctx
		c.Timeout <- ctx

		replyData := ReplyData{output, ctx}
		c.Out <- replyData
	}
}

func (c *NewOrder) OnRetryIn(ctx context.Context) {
	orderResolve := resolves.NewOrderResolve(ctx)

	if c.DefTime != "" {
		orderResolve.SetDefTime(c.DefTime)
	}

	output := ""

	if orderResolve.EmptyProducts() {
		retriedCount := 1
		retriedCountInt := ctx.Value(config.CtxKeyRetriedCount)

		if retriedCountInt != nil {
			retriedCount = retriedCountInt.(int)
		}

		if retriedCount >= c.retryCount {
			output = "没有相关的产品"

			replyData := ReplyData{output, ctx}
			c.Out <- replyData
		} else {
			retriedCount++
			log.Printf("重新获取开单产品，第%v次，共%v次", retriedCount, c.retryCount)

			ctx.SetValue(config.CtxKeyRetriedCount, retriedCount)
			c.RetryOut <- ctx
		}
	} else {
		output = orderResolve.Answer(ctx)

		if orderResolve.Resolved() {
			ctx.SetValue(config.CtxKeyLastOrder, *orderResolve)
			ctx.SetValue(config.CtxKeyOrder, nil)
		} else if orderResolve.Failed() {
			ctx.SetValue(config.CtxKeyOrder, nil)
		} else {
			ctx.SetValue(config.CtxKeyOrder, *orderResolve)
		}

		// c.Notice <- ctx
		c.Timeout <- ctx

		replyData := ReplyData{output, ctx}
		c.Out <- replyData
	}

}
<commit_msg>mismatch when retry<commit_after>package builtin

import (
	"log"

	"github.com/wanliu/flow/builtin/config"
	"github.com/wanliu/flow/builtin/resolves"
	"github.com/wanliu/flow/context"
)

type NewOrder struct {
	TryGetEntities
	DefTime    string
	retryCount int

	Ctx     <-chan context.Context
	Deftime <-chan string
	Out     chan<- ReplyData
	Notice  chan<- context.Context
	Timeout chan<- context.Context

	RetryOut chan<- context.Context
	RetryIn  <-chan context.Context

	RetryCount <-chan float64
}

func NewNewOrder() interface{} {
	return new(NewOrder)
}

// 默认送货时间
func (c *NewOrder) OnDeftime(t string) {
	c.DefTime = t
}

func (c *NewOrder) OnRetryCount(count float64) {
	c.retryCount = int(count)
}

func (c *NewOrder) OnCtx(ctx context.Context) {
	orderResolve := resolves.NewOrderResolve(ctx)

	if c.DefTime != "" {
		orderResolve.SetDefTime(c.DefTime)
	}

	output := ""

	if orderResolve.EmptyProducts() {
		if c.retryCount > 0 {
			log.Printf("重新获取开单产品，第1次，共%v次", c.retryCount)
			c.RetryOut <- ctx
		} else {
			output = "没有相关的产品"
			replyData := ReplyData{output, ctx}
			c.Out <- replyData
		}
	} else {
		output = orderResolve.Answer(ctx)

		if orderResolve.Resolved() {
			ctx.SetValue(config.CtxKeyLastOrder, *orderResolve)
			ctx.SetValue(config.CtxKeyOrder, nil)
		} else if orderResolve.Failed() {
			ctx.SetValue(config.CtxKeyOrder, nil)
		} else if orderResolve.MismatchQuantity() {
			ctx.SetValue(config.CtxKeyOrder, nil)
		} else {
			ctx.SetValue(config.CtxKeyOrder, *orderResolve)
		}

		// c.Notice <- ctx
		c.Timeout <- ctx

		replyData := ReplyData{output, ctx}
		c.Out <- replyData
	}
}

func (c *NewOrder) OnRetryIn(ctx context.Context) {
	orderResolve := resolves.NewOrderResolve(ctx)

	if c.DefTime != "" {
		orderResolve.SetDefTime(c.DefTime)
	}

	output := ""

	if orderResolve.EmptyProducts() {
		retriedCount := 1
		retriedCountInt := ctx.Value(config.CtxKeyRetriedCount)

		if retriedCountInt != nil {
			retriedCount = retriedCountInt.(int)
		}

		if retriedCount >= c.retryCount {
			output = "没有相关的产品"

			replyData := ReplyData{output, ctx}
			c.Out <- replyData
		} else {
			retriedCount++
			log.Printf("重新获取开单产品，第%v次，共%v次", retriedCount, c.retryCount)

			ctx.SetValue(config.CtxKeyRetriedCount, retriedCount)
			c.RetryOut <- ctx
		}
	} else {
		output = orderResolve.Answer(ctx)

		if orderResolve.Resolved() {
			ctx.SetValue(config.CtxKeyLastOrder, *orderResolve)
			ctx.SetValue(config.CtxKeyOrder, nil)
		} else if orderResolve.Failed() {
			ctx.SetValue(config.CtxKeyOrder, nil)
		} else if orderResolve.MismatchQuantity() {
			ctx.SetValue(config.CtxKeyOrder, nil)
		} else {
			ctx.SetValue(config.CtxKeyOrder, *orderResolve)
		}

		// c.Notice <- ctx
		c.Timeout <- ctx

		replyData := ReplyData{output, ctx}
		c.Out <- replyData
	}

}
<|endoftext|>


<commit_before>// Copyright 2014 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.

// +build ppc64 ppc64le

package unix

const (
	getrandomTrap     uintptr = 359
	copyFileRangeTrap uintptr = 379
)
<commit_msg>internal/syscall/unix: restore ppc build tag<commit_after>// Copyright 2014 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.

// +build ppc ppc64 ppc64le

package unix

const (
	getrandomTrap     uintptr = 359
	copyFileRangeTrap uintptr = 379
)
<|endoftext|>


<commit_before>// Copyright 2017-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may
// not use this file except in compliance with the License. A copy of the
// License is located at
//
//	http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file 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 main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"time"

	docker "github.com/fsouza/go-dockerclient"
)

const (
	v2MetadataEndpoint     = "http://169.254.170.2/v2/metadata"
	v2StatsEndpoint        = "http://169.254.170.2/v2/stats"
	maxRetries             = 4
	durationBetweenRetries = time.Second
)

// TaskResponse defines the schema for the task response JSON object
type TaskResponse struct {
	Cluster       string
	TaskARN       string
	Family        string
	Revision      string
	DesiredStatus string `json:",omitempty"`
	KnownStatus   string
	Containers    []ContainerResponse `json:",omitempty"`
	Limits        LimitsResponse      `json:",omitempty"`
}

// ContainerResponse defines the schema for the container response
// JSON object
type ContainerResponse struct {
	ID            string `json:"DockerId"`
	Name          string
	DockerName    string
	Image         string
	ImageID       string
	Ports         []PortResponse    `json:",omitempty"`
	Labels        map[string]string `json:",omitempty"`
	DesiredStatus string
	KnownStatus   string
	ExitCode      *int `json:",omitempty"`
	Limits        LimitsResponse
	CreatedAt     *time.Time `json:",omitempty"`
	StartedAt     *time.Time `json:",omitempty"`
	FinishedAt    *time.Time `json:",omitempty"`
	Type          string
	Health        HealthStatus `json:"health,omitempty"`
	Networks      []Network    `json:",omitempty"`
}

type HealthStatus struct {
	Status   string     `json:"status,omitempty"`
	Since    *time.Time `json:"statusSince,omitempty"`
	ExitCode int        `json:"exitCode,omitempty"`
	Output   string     `json:"output,omitempty"`
}

// LimitsResponse defines the schema for task/cpu limits response
// JSON object
type LimitsResponse struct {
	CPU    uint
	Memory uint
}

// PortResponse defines the schema for portmapping response JSON
// object
type PortResponse struct {
	ContainerPort uint16
	Protocol      string
	HostPort      uint16 `json:",omitempty"`
}

// Network is a struct that keeps track of metadata of a network interface
type Network struct {
	NetworkMode   string   `json:"NetworkMode,omitempty"`
	IPv4Addresses []string `json:"IPv4Addresses,omitempty"`
	IPv6Addresses []string `json:"IPv6Addresses,omitempty"`
}

func taskMetadata(client *http.Client) (*TaskResponse, error) {
	body, err := metadataResponse(client, v2MetadataEndpoint, "task metadata")
	if err != nil {
		return nil, err
	}

	var taskMetadata TaskResponse
	err = json.Unmarshal(body, &taskMetadata)
	if err != nil {
		return nil, fmt.Errorf("task metadata: unable to parse response body: %v", err)
	}

	return &taskMetadata, nil
}

func containerMetadata(client *http.Client, id string) (*ContainerResponse, error) {
	body, err := metadataResponse(client, v2MetadataEndpoint+"/"+id, "container metadata")
	if err != nil {
		return nil, err
	}

	fmt.Println("Received data: %s ", string(body))

	var containerMetadata ContainerResponse
	err = json.Unmarshal(body, &containerMetadata)
	if err != nil {
		return nil, fmt.Errorf("container metadata: unable to parse response body: %v", err)
	}

	return &containerMetadata, nil
}

func taskStats(client *http.Client) (map[string]*docker.Stats, error) {
	body, err := metadataResponse(client, v2StatsEndpoint, "task stats")
	if err != nil {
		return nil, err
	}

	var taskStats map[string]*docker.Stats
	err = json.Unmarshal(body, &taskStats)
	if err != nil {
		return nil, fmt.Errorf("task stats: unable to parse response body: %v", err)
	}

	return taskStats, nil
}

func containerStats(client *http.Client, id string) (*docker.Stats, error) {
	body, err := metadataResponse(client, v2StatsEndpoint+"/"+id, "container stats")
	if err != nil {
		return nil, err
	}

	var containerStats docker.Stats
	err = json.Unmarshal(body, &containerStats)
	if err != nil {
		return nil, fmt.Errorf("container stats: unable to parse response body: %v", err)
	}

	return &containerStats, nil
}

func metadataResponse(client *http.Client, endpoint string, respType string) ([]byte, error) {
	var resp []byte
	var err error
	for i := 0; i < maxRetries; i++ {
		resp, err = metadataResponseOnce(client, endpoint, respType)
		if err == nil {
			return resp, nil
		}
		fmt.Fprintf(os.Stderr, "Attempt [%d/%d]: unable to get metadata response for '%s' from '%s': %v",
			i, maxRetries, respType, endpoint, err)
		time.Sleep(durationBetweenRetries)
	}

	return nil, err
}

func metadataResponseOnce(client *http.Client, endpoint string, respType string) ([]byte, error) {
	resp, err := client.Get(endpoint)
	if err != nil {
		return nil, fmt.Errorf("%s: unable to get response: %v", respType, err)
	}
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("%s: incorrect status code  %d", respType, resp.StatusCode)
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("task metadata: unable to read response body: %v", err)
	}

	return body, nil
}

func main() {
	client := &http.Client{
		Timeout: 5 * time.Second,
	}

	// Wait for the Health information to be ready
	time.Sleep(5 * time.Second)

	taskMetadata, err := taskMetadata(client)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to get task metadata: %v", err)
		os.Exit(1)
	}
	if len(taskMetadata.Containers) != 2 {
		fmt.Fprintf(os.Stderr,
			"Incorrect number of containers in task metadata response, expected 2: %d [%v]",
			len(taskMetadata.Containers), taskMetadata)
		os.Exit(1)
	}

	containerID := ""
	for _, container := range taskMetadata.Containers {
		if container.Type == "NORMAL" {
			containerID = container.ID
			break
		}
	}

	if containerID == "" {
		fmt.Fprintf(os.Stderr, "Container from task definition not found")
		os.Exit(1)
	}

	containerMetadata, err := containerMetadata(client, containerID)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to get container metadata for '%s': %v", containerID, err)
		os.Exit(1)
	}
	if containerMetadata.Health.Status != "HEALTHY" || containerMetadata.Health.Output != "hello\n" {
		fmt.Fprintf(os.Stderr, "Container health metadata unexpected, got: %s\n", containerMetadata.Health)
		os.Exit(1)
	}

	_, err = taskStats(client)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to get task stats: %v", err)
		os.Exit(1)
	}

	_, err = containerStats(client, containerID)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to get container stats for '%s': %v", containerID, err)
		os.Exit(1)
	}

	os.Exit(42)
}
<commit_msg>test: skip the health check in task metadata<commit_after>// Copyright 2017-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may
// not use this file except in compliance with the License. A copy of the
// License is located at
//
//	http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file 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 main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"time"

	docker "github.com/fsouza/go-dockerclient"
)

const (
	v2MetadataEndpoint     = "http://169.254.170.2/v2/metadata"
	v2StatsEndpoint        = "http://169.254.170.2/v2/stats"
	maxRetries             = 4
	durationBetweenRetries = time.Second
)

// TaskResponse defines the schema for the task response JSON object
type TaskResponse struct {
	Cluster       string
	TaskARN       string
	Family        string
	Revision      string
	DesiredStatus string `json:",omitempty"`
	KnownStatus   string
	Containers    []ContainerResponse `json:",omitempty"`
	Limits        LimitsResponse      `json:",omitempty"`
}

// ContainerResponse defines the schema for the container response
// JSON object
type ContainerResponse struct {
	ID            string `json:"DockerId"`
	Name          string
	DockerName    string
	Image         string
	ImageID       string
	Ports         []PortResponse    `json:",omitempty"`
	Labels        map[string]string `json:",omitempty"`
	DesiredStatus string
	KnownStatus   string
	ExitCode      *int `json:",omitempty"`
	Limits        LimitsResponse
	CreatedAt     *time.Time `json:",omitempty"`
	StartedAt     *time.Time `json:",omitempty"`
	FinishedAt    *time.Time `json:",omitempty"`
	Type          string
	Health        HealthStatus `json:"health,omitempty"`
	Networks      []Network    `json:",omitempty"`
}

type HealthStatus struct {
	Status   string     `json:"status,omitempty"`
	Since    *time.Time `json:"statusSince,omitempty"`
	ExitCode int        `json:"exitCode,omitempty"`
	Output   string     `json:"output,omitempty"`
}

// LimitsResponse defines the schema for task/cpu limits response
// JSON object
type LimitsResponse struct {
	CPU    uint
	Memory uint
}

// PortResponse defines the schema for portmapping response JSON
// object
type PortResponse struct {
	ContainerPort uint16
	Protocol      string
	HostPort      uint16 `json:",omitempty"`
}

// Network is a struct that keeps track of metadata of a network interface
type Network struct {
	NetworkMode   string   `json:"NetworkMode,omitempty"`
	IPv4Addresses []string `json:"IPv4Addresses,omitempty"`
	IPv6Addresses []string `json:"IPv6Addresses,omitempty"`
}

func taskMetadata(client *http.Client) (*TaskResponse, error) {
	body, err := metadataResponse(client, v2MetadataEndpoint, "task metadata")
	if err != nil {
		return nil, err
	}

	var taskMetadata TaskResponse
	err = json.Unmarshal(body, &taskMetadata)
	if err != nil {
		return nil, fmt.Errorf("task metadata: unable to parse response body: %v", err)
	}

	return &taskMetadata, nil
}

func containerMetadata(client *http.Client, id string) (*ContainerResponse, error) {
	body, err := metadataResponse(client, v2MetadataEndpoint+"/"+id, "container metadata")
	if err != nil {
		return nil, err
	}

	fmt.Println("Received data: %s ", string(body))

	var containerMetadata ContainerResponse
	err = json.Unmarshal(body, &containerMetadata)
	if err != nil {
		return nil, fmt.Errorf("container metadata: unable to parse response body: %v", err)
	}

	return &containerMetadata, nil
}

func taskStats(client *http.Client) (map[string]*docker.Stats, error) {
	body, err := metadataResponse(client, v2StatsEndpoint, "task stats")
	if err != nil {
		return nil, err
	}

	var taskStats map[string]*docker.Stats
	err = json.Unmarshal(body, &taskStats)
	if err != nil {
		return nil, fmt.Errorf("task stats: unable to parse response body: %v", err)
	}

	return taskStats, nil
}

func containerStats(client *http.Client, id string) (*docker.Stats, error) {
	body, err := metadataResponse(client, v2StatsEndpoint+"/"+id, "container stats")
	if err != nil {
		return nil, err
	}

	var containerStats docker.Stats
	err = json.Unmarshal(body, &containerStats)
	if err != nil {
		return nil, fmt.Errorf("container stats: unable to parse response body: %v", err)
	}

	return &containerStats, nil
}

func metadataResponse(client *http.Client, endpoint string, respType string) ([]byte, error) {
	var resp []byte
	var err error
	for i := 0; i < maxRetries; i++ {
		resp, err = metadataResponseOnce(client, endpoint, respType)
		if err == nil {
			return resp, nil
		}
		fmt.Fprintf(os.Stderr, "Attempt [%d/%d]: unable to get metadata response for '%s' from '%s': %v",
			i, maxRetries, respType, endpoint, err)
		time.Sleep(durationBetweenRetries)
	}

	return nil, err
}

func metadataResponseOnce(client *http.Client, endpoint string, respType string) ([]byte, error) {
	resp, err := client.Get(endpoint)
	if err != nil {
		return nil, fmt.Errorf("%s: unable to get response: %v", respType, err)
	}
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("%s: incorrect status code  %d", respType, resp.StatusCode)
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("task metadata: unable to read response body: %v", err)
	}

	return body, nil
}

func main() {
	client := &http.Client{
		Timeout: 5 * time.Second,
	}

	// Wait for the Health information to be ready
	time.Sleep(5 * time.Second)

	taskMetadata, err := taskMetadata(client)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to get task metadata: %v", err)
		os.Exit(1)
	}
	if len(taskMetadata.Containers) != 2 {
		fmt.Fprintf(os.Stderr,
			"Incorrect number of containers in task metadata response, expected 2: %d [%v]",
			len(taskMetadata.Containers), taskMetadata)
		os.Exit(1)
	}

	containerID := ""
	for _, container := range taskMetadata.Containers {
		if container.Type == "NORMAL" {
			containerID = container.ID
			break
		}
	}

	if containerID == "" {
		fmt.Fprintf(os.Stderr, "Container from task definition not found")
		os.Exit(1)
	}

	containerMetadata, err := containerMetadata(client, containerID)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to get container metadata for '%s': %v", containerID, err)
		os.Exit(1)
	}

	if containerMetadata.Health.Status != "HEALTHY" || containerMetadata.Health.Output != "hello\n" {
		fmt.Fprintf(os.Stderr, "Container health metadata unexpected, got: %s\n", containerMetadata.Health)
		// TODO uncomment this when the container health check is deployed in backend
		//		os.Exit(1)
	}

	_, err = taskStats(client)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to get task stats: %v", err)
		os.Exit(1)
	}

	_, err = containerStats(client, containerID)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to get container stats for '%s': %v", containerID, err)
		os.Exit(1)
	}

	os.Exit(42)
}
<|endoftext|>


<commit_before>//  Copyright (c) 2012 Couchbase, Inc.
//  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 channels

import (
	"github.com/sdegutis/go.assert"
	"testing"

	"github.com/couchbaselabs/sync_gateway/base"
)

const noUser = `{"name":null, "channels":[]}`

// Just verify that the calls to the channel() fn show up in the output channel list.
func TestSyncFunction(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {channel("foo", "bar"); channel("baz")}`)
	assertNoError(t, err, "Couldn't create mapper")
	res, err := mapper.callMapper(`{"channels": []}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	assert.DeepEquals(t, res.Channels, SetOf("foo", "bar", "baz"))
}

// Just verify that the calls to the access() fn show up in the output channel list.
func TestAccessFunction(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {access("foo", "bar"); access("foo", "baz")}`)
	assertNoError(t, err, "Couldn't create mapper")
	res, err := mapper.callMapper(`{}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	assert.DeepEquals(t, res.Access, AccessMap{"foo": SetOf("bar", "baz")})
}

// Just verify that the calls to the channel() fn show up in the output channel list.
func TestSyncFunctionTakesArray(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {channel(["foo", "bar","baz"])}`)
	assertNoError(t, err, "Couldn't create mapper")
	res, err := mapper.callMapper(`{"channels": []}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	assert.DeepEquals(t, res.Channels, SetOf("foo", "bar", "baz"))
}

// Calling channel() with an invalid channel name should return an error.
func TestSyncFunctionRejectsInvalidChannels(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {channel(["foo", "bad name","baz"])}`)
	assertNoError(t, err, "Couldn't create mapper")
	_, err = mapper.callMapper(`{"channels": []}`, `{}`, noUser)
	assert.True(t, err != nil)
}

// Calling access() with an invalid channel name should return an error.
func TestAccessFunctionRejectsInvalidChannels(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {access("foo", "bad name");}`)
	assertNoError(t, err, "Couldn't create mapper")
	_, err = mapper.callMapper(`{}`, `{}`, noUser)
	assert.True(t, err != nil)
}

// Just verify that the calls to the access() fn show up in the output channel list.
func TestAccessFunctionTakesArrayOfUsers(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {access(["foo","bar","baz"], "ginger")}`)
	assertNoError(t, err, "Couldn't create mapper")
	res, err := mapper.callMapper(`{}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	assert.DeepEquals(t, res.Access, AccessMap{"bar": SetOf("ginger"), "baz": SetOf("ginger"), "foo": SetOf("ginger")})
}

// Just verify that the calls to the access() fn show up in the output channel list.
func TestAccessFunctionTakesArrayOfChannels(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {access("lee", ["ginger", "earl_grey", "green"])}`)
	assertNoError(t, err, "Couldn't create mapper")
	res, err := mapper.callMapper(`{}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	assert.DeepEquals(t, res.Access, AccessMap{"lee": SetOf("ginger", "earl_grey", "green")})
}

func TestAccessFunctionTakesArrayOfChannelsAndUsers(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {access(["lee", "nancy"], ["ginger", "earl_grey", "green"])}`)
	assertNoError(t, err, "Couldn't create mapper")
	res, err := mapper.callMapper(`{}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	assert.DeepEquals(t, res.Access["lee"], SetOf("ginger", "earl_grey", "green"))
	assert.DeepEquals(t, res.Access["nancy"], SetOf("ginger", "earl_grey", "green"))
}

func TestAccessFunctionTakesEmptyArrayUser(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {access([], ["ginger", "earl grey", "green"])}`)
	assertNoError(t, err, "Couldn't create mapper")
	res, err := mapper.callMapper(`{}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	assert.DeepEquals(t, res.Access, AccessMap{})
}

func TestAccessFunctionTakesEmptyArrayChannels(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {access("lee", [])}`)
	assertNoError(t, err, "Couldn't create mapper")
	res, err := mapper.callMapper(`{}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	assert.DeepEquals(t, res.Access, AccessMap{})
}

func TestAccessFunctionTakesNullUser(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {access(null, ["ginger", "earl grey", "green"])}`)
	assertNoError(t, err, "Couldn't create mapper")
	res, err := mapper.callMapper(`{}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	assert.DeepEquals(t, res.Access, AccessMap{})
}

func TestAccessFunctionTakesNullChannels(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {access("lee", null)}`)
	assertNoError(t, err, "Couldn't create mapper")
	res, err := mapper.callMapper(`{}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	assert.DeepEquals(t, res.Access, AccessMap{})
}

func TestAccessFunctionTakesNonChannelsInArray(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {access("lee", ["ginger", null, 5])}`)
	assertNoError(t, err, "Couldn't create mapper")
	res, err := mapper.callMapper(`{}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	assert.DeepEquals(t, res.Access, AccessMap{"lee": SetOf("ginger")})
}

func TestAccessFunctionTakesUndefinedUser(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {var x = {}; access(x.nothing, ["ginger", "earl grey", "green"])}`)
	assertNoError(t, err, "Couldn't create mapper")
	res, err := mapper.callMapper(`{}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	assert.DeepEquals(t, res.Access, AccessMap{})
}

// Now just make sure the input comes through intact
func TestInputParse(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {channel(doc.channel);}`)
	assertNoError(t, err, "Couldn't create mapper")
	res, err := mapper.callMapper(`{"channel": "foo"}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	assert.DeepEquals(t, res.Channels, SetOf("foo"))
}

// A more realistic example
func TestDefaultChannelMapper(t *testing.T) {
	mapper, err := NewDefaultChannelMapper()
	assertNoError(t, err, "Couldn't create mapper")
	res, err := mapper.callMapper(`{"channels": ["foo", "bar", "baz"]}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	assert.DeepEquals(t, res.Channels, SetOf("foo", "bar", "baz"))

	res, err = mapper.callMapper(`{"x": "y"}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	assert.DeepEquals(t, res.Channels, Set{})
}

// Empty/no-op channel mapper fn
func TestEmptyChannelMapper(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {}`)
	assertNoError(t, err, "Couldn't create mapper")
	res, err := mapper.callMapper(`{"channels": ["foo", "bar", "baz"]}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	assert.DeepEquals(t, res.Channels, Set{})
}

// Validation by calling reject()
func TestChannelMapperReject(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {reject(403, "bad");}`)
	assertNoError(t, err, "Couldn't create mapper")
	res, err := mapper.callMapper(`{"channels": ["foo", "bar", "baz"]}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	assert.DeepEquals(t, res.Rejection, &base.HTTPError{403, "bad"})
}

// Rejection by calling throw()
func TestChannelMapperThrow(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {throw({forbidden:"bad"});}`)
	assertNoError(t, err, "Couldn't create mapper")
	res, err := mapper.callMapper(`{"channels": ["foo", "bar", "baz"]}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	assert.DeepEquals(t, res.Rejection, &base.HTTPError{403, "bad"})
}

// Test other runtime exception
func TestChannelMapperException(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {(nil)[5];}`)
	assertNoError(t, err, "Couldn't create mapper")
	_, err = mapper.callMapper(`{"channels": ["foo", "bar", "baz"]}`, `{}`, noUser)
	assert.True(t, err != nil)
}

// Test the public API
func TestPublicChannelMapper(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {channel(doc.channels);}`)
	assertNoError(t, err, "Couldn't create mapper")
	output, err := mapper.MapToChannelsAndAccess(`{"channels": ["foo", "bar", "baz"]}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	assert.DeepEquals(t, output.Channels, SetOf("foo", "bar", "baz"))
	mapper.Stop()
}

// Test changing the function
func TestSetFunction(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {channel(doc.channels);}`)
	assertNoError(t, err, "Couldn't create mapper")
	output, err := mapper.MapToChannelsAndAccess(`{"channels": ["foo", "bar", "baz"]}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	changed, err := mapper.SetFunction(`function(doc) {channel("all");}`)
	assertTrue(t, changed, "SetFunction failed")
	assertNoError(t, err, "SetFunction failed")
	output, err = mapper.MapToChannelsAndAccess(`{"channels": ["foo", "bar", "baz"]}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	assert.DeepEquals(t, output.Channels, SetOf("all"))
	mapper.Stop()
}

//////// HELPERS:

func assertNoError(t *testing.T, err error, message string) {
	if err != nil {
		t.Fatalf("%s: %v", message, err)
	}
}

func assertTrue(t *testing.T, success bool, message string) {
	if !success {
		t.Fatalf("%s", message)
	}
}
<commit_msg>Added test for channel mapper fn that uses _ underscore library<commit_after>//  Copyright (c) 2012 Couchbase, Inc.
//  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 channels

import (
	"github.com/sdegutis/go.assert"
	"testing"

	"github.com/couchbaselabs/sync_gateway/base"
)

const noUser = `{"name":null, "channels":[]}`

// Just verify that the calls to the channel() fn show up in the output channel list.
func TestSyncFunction(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {channel("foo", "bar"); channel("baz")}`)
	assertNoError(t, err, "Couldn't create mapper")
	res, err := mapper.callMapper(`{"channels": []}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	assert.DeepEquals(t, res.Channels, SetOf("foo", "bar", "baz"))
}

// Just verify that the calls to the access() fn show up in the output channel list.
func TestAccessFunction(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {access("foo", "bar"); access("foo", "baz")}`)
	assertNoError(t, err, "Couldn't create mapper")
	res, err := mapper.callMapper(`{}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	assert.DeepEquals(t, res.Access, AccessMap{"foo": SetOf("bar", "baz")})
}

// Just verify that the calls to the channel() fn show up in the output channel list.
func TestSyncFunctionTakesArray(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {channel(["foo", "bar","baz"])}`)
	assertNoError(t, err, "Couldn't create mapper")
	res, err := mapper.callMapper(`{"channels": []}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	assert.DeepEquals(t, res.Channels, SetOf("foo", "bar", "baz"))
}

// Calling channel() with an invalid channel name should return an error.
func TestSyncFunctionRejectsInvalidChannels(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {channel(["foo", "bad name","baz"])}`)
	assertNoError(t, err, "Couldn't create mapper")
	_, err = mapper.callMapper(`{"channels": []}`, `{}`, noUser)
	assert.True(t, err != nil)
}

// Calling access() with an invalid channel name should return an error.
func TestAccessFunctionRejectsInvalidChannels(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {access("foo", "bad name");}`)
	assertNoError(t, err, "Couldn't create mapper")
	_, err = mapper.callMapper(`{}`, `{}`, noUser)
	assert.True(t, err != nil)
}

// Just verify that the calls to the access() fn show up in the output channel list.
func TestAccessFunctionTakesArrayOfUsers(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {access(["foo","bar","baz"], "ginger")}`)
	assertNoError(t, err, "Couldn't create mapper")
	res, err := mapper.callMapper(`{}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	assert.DeepEquals(t, res.Access, AccessMap{"bar": SetOf("ginger"), "baz": SetOf("ginger"), "foo": SetOf("ginger")})
}

// Just verify that the calls to the access() fn show up in the output channel list.
func TestAccessFunctionTakesArrayOfChannels(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {access("lee", ["ginger", "earl_grey", "green"])}`)
	assertNoError(t, err, "Couldn't create mapper")
	res, err := mapper.callMapper(`{}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	assert.DeepEquals(t, res.Access, AccessMap{"lee": SetOf("ginger", "earl_grey", "green")})
}

func TestAccessFunctionTakesArrayOfChannelsAndUsers(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {access(["lee", "nancy"], ["ginger", "earl_grey", "green"])}`)
	assertNoError(t, err, "Couldn't create mapper")
	res, err := mapper.callMapper(`{}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	assert.DeepEquals(t, res.Access["lee"], SetOf("ginger", "earl_grey", "green"))
	assert.DeepEquals(t, res.Access["nancy"], SetOf("ginger", "earl_grey", "green"))
}

func TestAccessFunctionTakesEmptyArrayUser(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {access([], ["ginger", "earl grey", "green"])}`)
	assertNoError(t, err, "Couldn't create mapper")
	res, err := mapper.callMapper(`{}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	assert.DeepEquals(t, res.Access, AccessMap{})
}

func TestAccessFunctionTakesEmptyArrayChannels(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {access("lee", [])}`)
	assertNoError(t, err, "Couldn't create mapper")
	res, err := mapper.callMapper(`{}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	assert.DeepEquals(t, res.Access, AccessMap{})
}

func TestAccessFunctionTakesNullUser(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {access(null, ["ginger", "earl grey", "green"])}`)
	assertNoError(t, err, "Couldn't create mapper")
	res, err := mapper.callMapper(`{}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	assert.DeepEquals(t, res.Access, AccessMap{})
}

func TestAccessFunctionTakesNullChannels(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {access("lee", null)}`)
	assertNoError(t, err, "Couldn't create mapper")
	res, err := mapper.callMapper(`{}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	assert.DeepEquals(t, res.Access, AccessMap{})
}

func TestAccessFunctionTakesNonChannelsInArray(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {access("lee", ["ginger", null, 5])}`)
	assertNoError(t, err, "Couldn't create mapper")
	res, err := mapper.callMapper(`{}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	assert.DeepEquals(t, res.Access, AccessMap{"lee": SetOf("ginger")})
}

func TestAccessFunctionTakesUndefinedUser(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {var x = {}; access(x.nothing, ["ginger", "earl grey", "green"])}`)
	assertNoError(t, err, "Couldn't create mapper")
	res, err := mapper.callMapper(`{}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	assert.DeepEquals(t, res.Access, AccessMap{})
}

// Now just make sure the input comes through intact
func TestInputParse(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {channel(doc.channel);}`)
	assertNoError(t, err, "Couldn't create mapper")
	res, err := mapper.callMapper(`{"channel": "foo"}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	assert.DeepEquals(t, res.Channels, SetOf("foo"))
}

// A more realistic example
func TestDefaultChannelMapper(t *testing.T) {
	mapper, err := NewDefaultChannelMapper()
	assertNoError(t, err, "Couldn't create mapper")
	res, err := mapper.callMapper(`{"channels": ["foo", "bar", "baz"]}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	assert.DeepEquals(t, res.Channels, SetOf("foo", "bar", "baz"))

	res, err = mapper.callMapper(`{"x": "y"}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	assert.DeepEquals(t, res.Channels, Set{})
}

// Empty/no-op channel mapper fn
func TestEmptyChannelMapper(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {}`)
	assertNoError(t, err, "Couldn't create mapper")
	res, err := mapper.callMapper(`{"channels": ["foo", "bar", "baz"]}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	assert.DeepEquals(t, res.Channels, Set{})
}

// channel mapper fn that uses _ underscore JS library
func TestChannelMapperUnderscoreLib(t *testing.T) {
        mapper, err := NewChannelMapper(`function(doc) {channel(_.first(doc.channels));}`)
        assertNoError(t, err, "Couldn't create mapper")
        res, err := mapper.callMapper(`{"channels": ["foo", "bar", "baz"]}`, `{}`, noUser)
        assertNoError(t, err, "callMapper failed")
        assert.DeepEquals(t, res.Channels, SetOf("foo"))
}

// Validation by calling reject()
func TestChannelMapperReject(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {reject(403, "bad");}`)
	assertNoError(t, err, "Couldn't create mapper")
	res, err := mapper.callMapper(`{"channels": ["foo", "bar", "baz"]}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	assert.DeepEquals(t, res.Rejection, &base.HTTPError{403, "bad"})
}

// Rejection by calling throw()
func TestChannelMapperThrow(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {throw({forbidden:"bad"});}`)
	assertNoError(t, err, "Couldn't create mapper")
	res, err := mapper.callMapper(`{"channels": ["foo", "bar", "baz"]}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	assert.DeepEquals(t, res.Rejection, &base.HTTPError{403, "bad"})
}

// Test other runtime exception
func TestChannelMapperException(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {(nil)[5];}`)
	assertNoError(t, err, "Couldn't create mapper")
	_, err = mapper.callMapper(`{"channels": ["foo", "bar", "baz"]}`, `{}`, noUser)
	assert.True(t, err != nil)
}

// Test the public API
func TestPublicChannelMapper(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {channel(doc.channels);}`)
	assertNoError(t, err, "Couldn't create mapper")
	output, err := mapper.MapToChannelsAndAccess(`{"channels": ["foo", "bar", "baz"]}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	assert.DeepEquals(t, output.Channels, SetOf("foo", "bar", "baz"))
	mapper.Stop()
}

// Test changing the function
func TestSetFunction(t *testing.T) {
	mapper, err := NewChannelMapper(`function(doc) {channel(doc.channels);}`)
	assertNoError(t, err, "Couldn't create mapper")
	output, err := mapper.MapToChannelsAndAccess(`{"channels": ["foo", "bar", "baz"]}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	changed, err := mapper.SetFunction(`function(doc) {channel("all");}`)
	assertTrue(t, changed, "SetFunction failed")
	assertNoError(t, err, "SetFunction failed")
	output, err = mapper.MapToChannelsAndAccess(`{"channels": ["foo", "bar", "baz"]}`, `{}`, noUser)
	assertNoError(t, err, "callMapper failed")
	assert.DeepEquals(t, output.Channels, SetOf("all"))
	mapper.Stop()
}

//////// HELPERS:

func assertNoError(t *testing.T, err error, message string) {
	if err != nil {
		t.Fatalf("%s: %v", message, err)
	}
}

func assertTrue(t *testing.T, success bool, message string) {
	if !success {
		t.Fatalf("%s", message)
	}
}
<|endoftext|>


<commit_before>// +build integration

/*
Copyright 2019 The Kubernetes Authors All rights reserved.

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

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

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

// a_download_only_test.go filename starts with a, for the purpose that it runs before all parallel tests and downloads the images and caches them.
package integration

import (
	"fmt"
	"testing"

	"k8s.io/minikube/pkg/minikube/constants"
)

// TestDownloadOnly downloads ISOs also tests the --download-only option
// Note this test runs before all tests (because of file name) and caches images for them
func TestDownloadOnly(t *testing.T) {
	p := profile(t)
	mk := NewMinikubeRunner(t, p)
	if !isTestNoneDriver() { // none driver doesnt need to be deleted
		defer mk.TearDown(t)
	}

	t.Run("Oldest", func(t *testing.T) {
		stdout, stderr, err := mk.Start("--download-only", fmt.Sprintf("--kubernetes-version=%s", constants.OldestKubernetesVersion))
		if err != nil {
			t.Fatalf("%s minikube --download-only failed : %v\nstdout: %s\nstderr: %s", p, err, stdout, stderr)
		}
	})

	t.Run("Newest", func(t *testing.T) {
		stdout, stderr, err := mk.Start("--download-only", fmt.Sprintf("--kubernetes-version=%s", constants.NewestKubernetesVersion))
		if err != nil {
			t.Fatalf("%s minikube --download-only failed : %v\nstdout: %s\nstderr: %s", p, err, stdout, stderr)
		}
		// TODO: add test to check if files are downloaded
	})

	// TODO: download latest binary to test data here

}

// func downloadMinikubeBinary(dest string, version string) error {
// 	// Grab latest release binary
// 	url := pkgutil.GetBinaryDownloadURL(version, runtime.GOOS)
// 	download := func() error {
// 		return getter.GetFile(dest, url)
// 	}

// 	if err := util.Retry2(download, 3*time.Second, 13); err != nil {
// 		return errors.Wrap(err, "Failed to get latest release binary")
// 	}
// 	if runtime.GOOS != "windows" {
// 		if err := os.Chmod(dest, 0700); err != nil {
// 			return err
// 		}
// 	}
// 	return nil
// }
<commit_msg>remove unsed funcs<commit_after>// +build integration

/*
Copyright 2019 The Kubernetes Authors All rights reserved.

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

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

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

// a_download_only_test.go filename starts with a, for the purpose that it runs before all parallel tests and downloads the images and caches them.
package integration

import (
	"fmt"
	"testing"

	"k8s.io/minikube/pkg/minikube/constants"
)

// TestDownloadOnly downloads ISOs also tests the --download-only option
// Note this test runs before all tests (because of file name) and caches images for them
func TestDownloadOnly(t *testing.T) {
	p := profile(t)
	mk := NewMinikubeRunner(t, p)
	if !isTestNoneDriver() { // none driver doesnt need to be deleted
		defer mk.TearDown(t)
	}

	t.Run("Oldest", func(t *testing.T) {
		stdout, stderr, err := mk.Start("--download-only", fmt.Sprintf("--kubernetes-version=%s", constants.OldestKubernetesVersion))
		if err != nil {
			t.Errorf("%s minikube --download-only failed : %v\nstdout: %s\nstderr: %s", p, err, stdout, stderr)
		}
	})

	t.Run("Newest", func(t *testing.T) {
		stdout, stderr, err := mk.Start("--download-only", fmt.Sprintf("--kubernetes-version=%s", constants.NewestKubernetesVersion))
		if err != nil {
			t.Errorf("%s minikube --download-only failed : %v\nstdout: %s\nstderr: %s", p, err, stdout, stderr)
		}
		// TODO: add test to check if files are downloaded
	})

	// TODO: download latest binary to test data here

}

// func downloadMinikubeBinary(dest string, version string) error {
// 	// Grab latest release binary
// 	url := pkgutil.GetBinaryDownloadURL(version, runtime.GOOS)
// 	download := func() error {
// 		return getter.GetFile(dest, url)
// 	}

// 	if err := util.Retry2(download, 3*time.Second, 13); err != nil {
// 		return errors.Wrap(err, "Failed to get latest release binary")
// 	}
// 	if runtime.GOOS != "windows" {
// 		if err := os.Chmod(dest, 0700); err != nil {
// 			return err
// 		}
// 	}
// 	return nil
// }
<|endoftext|>


<commit_before>package acceptance_test

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"math/rand"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

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

type fakePluginLogData struct {
	Args  []string
	Env   map[string]string
	Stdin string
}

func getConfig(index int) string {
	return fmt.Sprintf(`
{
  "cniVersion": "0.1.0",
  "name": "some-net-%d",
  "type": "plugin-%d"
}`, index, index)
}

func writeConfig(index int, outDir string) error {
	config := getConfig(index)
	outpath := filepath.Join(outDir, fmt.Sprintf("%d-plugin-%d.conf", 10*index, index))
	return ioutil.WriteFile(outpath, []byte(config), 0600)
}

var _ = Describe("Guardian CNI adapter", func() {
	var (
		command      *exec.Cmd
		cniConfigDir string
		fakePid      int
		fakeLogDir   string
	)

	BeforeEach(func() {
		var err error
		cniConfigDir, err = ioutil.TempDir("", "cni-config-")
		Expect(err).NotTo(HaveOccurred())

		fakeLogDir, err = ioutil.TempDir("", "fake-logs-")
		Expect(err).NotTo(HaveOccurred())

		command = exec.Command(pathToAdapter)
		command.Env = []string{"FAKE_LOG_DIR=" + fakeLogDir}

		fakePid = rand.Intn(30000)
		command.Stdin = strings.NewReader(fmt.Sprintf(`{ "pid": %d }`, fakePid))

		Expect(writeConfig(0, cniConfigDir)).To(Succeed())
		Expect(writeConfig(1, cniConfigDir)).To(Succeed())
		Expect(writeConfig(2, cniConfigDir)).To(Succeed())
	})

	AfterEach(func() {
		Expect(os.RemoveAll(cniConfigDir)).To(Succeed())
		Expect(os.RemoveAll(fakeLogDir)).To(Succeed())
	})

	Describe("up", func() {
		BeforeEach(func() {
			command.Args = []string{pathToAdapter,
				"--cniPluginDir", cniPluginDir,
				"--cniConfigDir", cniConfigDir,
				"--ducatiSandboxDir", "some-sandbox",
				"--daemonBaseURL", "http://example.com",
				"up",
				"--handle", "some-container-handle",
				"--network", "some-network-spec",
			}
		})

		It("should call every CNI plugin in the plugin directory with ADD", func() {
			session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
			Expect(err).NotTo(HaveOccurred())
			Eventually(session).Should(gexec.Exit(0))

			for i := 0; i < 3; i++ {
				logFileContents, err := ioutil.ReadFile(filepath.Join(fakeLogDir, fmt.Sprintf("plugin-%d.log", i)))
				Expect(err).NotTo(HaveOccurred())
				var pluginCallInfo fakePluginLogData
				Expect(json.Unmarshal(logFileContents, &pluginCallInfo)).To(Succeed())

				Expect(pluginCallInfo.Stdin).To(MatchJSON(getConfig(i)))
				Expect(pluginCallInfo.Env).To(HaveKeyWithValue("CNI_COMMAND", "ADD"))
				Expect(pluginCallInfo.Env).To(HaveKeyWithValue("CNI_CONTAINERID", "some-container-handle"))
				Expect(pluginCallInfo.Env).To(HaveKeyWithValue("CNI_IFNAME", fmt.Sprintf("eth%d", i)))
				Expect(pluginCallInfo.Env).To(HaveKeyWithValue("CNI_PATH", cniPluginDir))
				Expect(pluginCallInfo.Env).To(HaveKeyWithValue("DUCATI_OS_SANDBOX_REPO", "some-sandbox"))
				Expect(pluginCallInfo.Env).To(HaveKeyWithValue("DAEMON_BASE_URL", "http://example.com"))
			}
		})
	})

	Describe("down", func() {
		BeforeEach(func() {
			command.Args = []string{pathToAdapter,
				"down",
				"--handle", "some-container-handle",
				"--cniPluginDir", cniPluginDir,
				"--cniConfigDir", cniConfigDir,
				"--ducatiSandboxDir", "some-sandbox",
				"--daemonBaseURL", "http://example.com",
			}
		})

		It("should call every CNI plugin in the plugin directory with DEL", func() {
			session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
			Expect(err).NotTo(HaveOccurred())
			Eventually(session).Should(gexec.Exit(0))

			for i := 0; i < 3; i++ {
				logFileContents, err := ioutil.ReadFile(filepath.Join(fakeLogDir, fmt.Sprintf("plugin-%d.log", i)))
				Expect(err).NotTo(HaveOccurred())
				var pluginCallInfo fakePluginLogData
				Expect(json.Unmarshal(logFileContents, &pluginCallInfo)).To(Succeed())

				Expect(pluginCallInfo.Stdin).To(MatchJSON(getConfig(i)))
				Expect(pluginCallInfo.Env).To(HaveKeyWithValue("CNI_COMMAND", "DEL"))
				Expect(pluginCallInfo.Env).To(HaveKeyWithValue("CNI_CONTAINERID", "some-container-handle"))
				Expect(pluginCallInfo.Env).To(HaveKeyWithValue("CNI_IFNAME", fmt.Sprintf("eth%d", i)))
				Expect(pluginCallInfo.Env).To(HaveKeyWithValue("CNI_PATH", cniPluginDir))
				Expect(pluginCallInfo.Env).To(HaveKeyWithValue("DUCATI_OS_SANDBOX_REPO", "some-sandbox"))
				Expect(pluginCallInfo.Env).To(HaveKeyWithValue("DAEMON_BASE_URL", "http://example.com"))
			}
		})
	})
})
<commit_msg>Add acceptance test coverage of CNI_NETNS env var<commit_after>package acceptance_test

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"math/rand"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

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

type fakePluginLogData struct {
	Args  []string
	Env   map[string]string
	Stdin string
}

func getConfig(index int) string {
	return fmt.Sprintf(`
{
  "cniVersion": "0.1.0",
  "name": "some-net-%d",
  "type": "plugin-%d"
}`, index, index)
}

func writeConfig(index int, outDir string) error {
	config := getConfig(index)
	outpath := filepath.Join(outDir, fmt.Sprintf("%d-plugin-%d.conf", 10*index, index))
	return ioutil.WriteFile(outpath, []byte(config), 0600)
}

var _ = Describe("Guardian CNI adapter", func() {
	var (
		command           *exec.Cmd
		cniConfigDir      string
		fakePid           int
		fakeLogDir        string
		expectedNetNSPath string
	)

	BeforeEach(func() {
		var err error
		cniConfigDir, err = ioutil.TempDir("", "cni-config-")
		Expect(err).NotTo(HaveOccurred())

		fakeLogDir, err = ioutil.TempDir("", "fake-logs-")
		Expect(err).NotTo(HaveOccurred())

		command = exec.Command(pathToAdapter)
		command.Env = []string{"FAKE_LOG_DIR=" + fakeLogDir}

		fakePid = rand.Intn(30000)
		command.Stdin = strings.NewReader(fmt.Sprintf(`{ "pid": %d }`, fakePid))

		expectedNetNSPath = fmt.Sprintf("/proc/%d/ns/net", fakePid)

		Expect(writeConfig(0, cniConfigDir)).To(Succeed())
		Expect(writeConfig(1, cniConfigDir)).To(Succeed())
		Expect(writeConfig(2, cniConfigDir)).To(Succeed())
	})

	AfterEach(func() {
		Expect(os.RemoveAll(cniConfigDir)).To(Succeed())
		Expect(os.RemoveAll(fakeLogDir)).To(Succeed())
	})

	Describe("up", func() {
		BeforeEach(func() {
			command.Args = []string{pathToAdapter,
				"--cniPluginDir", cniPluginDir,
				"--cniConfigDir", cniConfigDir,
				"--ducatiSandboxDir", "some-sandbox",
				"--daemonBaseURL", "http://example.com",
				"up",
				"--handle", "some-container-handle",
				"--network", "some-network-spec",
			}
		})

		It("should call every CNI plugin in the plugin directory with ADD", func() {
			session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
			Expect(err).NotTo(HaveOccurred())
			Eventually(session).Should(gexec.Exit(0))

			for i := 0; i < 3; i++ {
				logFileContents, err := ioutil.ReadFile(filepath.Join(fakeLogDir, fmt.Sprintf("plugin-%d.log", i)))
				Expect(err).NotTo(HaveOccurred())
				var pluginCallInfo fakePluginLogData
				Expect(json.Unmarshal(logFileContents, &pluginCallInfo)).To(Succeed())

				Expect(pluginCallInfo.Stdin).To(MatchJSON(getConfig(i)))
				Expect(pluginCallInfo.Env).To(HaveKeyWithValue("CNI_COMMAND", "ADD"))
				Expect(pluginCallInfo.Env).To(HaveKeyWithValue("CNI_CONTAINERID", "some-container-handle"))
				Expect(pluginCallInfo.Env).To(HaveKeyWithValue("CNI_IFNAME", fmt.Sprintf("eth%d", i)))
				Expect(pluginCallInfo.Env).To(HaveKeyWithValue("CNI_PATH", cniPluginDir))
				Expect(pluginCallInfo.Env).To(HaveKeyWithValue("CNI_NETNS", expectedNetNSPath))
				Expect(pluginCallInfo.Env).To(HaveKeyWithValue("DUCATI_OS_SANDBOX_REPO", "some-sandbox"))
				Expect(pluginCallInfo.Env).To(HaveKeyWithValue("DAEMON_BASE_URL", "http://example.com"))
			}
		})
	})

	Describe("down", func() {
		BeforeEach(func() {
			command.Args = []string{pathToAdapter,
				"down",
				"--handle", "some-container-handle",
				"--cniPluginDir", cniPluginDir,
				"--cniConfigDir", cniConfigDir,
				"--ducatiSandboxDir", "some-sandbox",
				"--daemonBaseURL", "http://example.com",
			}
		})

		It("should call every CNI plugin in the plugin directory with DEL", func() {
			session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
			Expect(err).NotTo(HaveOccurred())
			Eventually(session).Should(gexec.Exit(0))

			for i := 0; i < 3; i++ {
				logFileContents, err := ioutil.ReadFile(filepath.Join(fakeLogDir, fmt.Sprintf("plugin-%d.log", i)))
				Expect(err).NotTo(HaveOccurred())
				var pluginCallInfo fakePluginLogData
				Expect(json.Unmarshal(logFileContents, &pluginCallInfo)).To(Succeed())

				Expect(pluginCallInfo.Stdin).To(MatchJSON(getConfig(i)))
				Expect(pluginCallInfo.Env).To(HaveKeyWithValue("CNI_COMMAND", "DEL"))
				Expect(pluginCallInfo.Env).To(HaveKeyWithValue("CNI_CONTAINERID", "some-container-handle"))
				Expect(pluginCallInfo.Env).To(HaveKeyWithValue("CNI_IFNAME", fmt.Sprintf("eth%d", i)))
				Expect(pluginCallInfo.Env).To(HaveKeyWithValue("CNI_PATH", cniPluginDir))
				Expect(pluginCallInfo.Env).To(HaveKeyWithValue("CNI_NETNS", expectedNetNSPath))
				Expect(pluginCallInfo.Env).To(HaveKeyWithValue("DUCATI_OS_SANDBOX_REPO", "some-sandbox"))
				Expect(pluginCallInfo.Env).To(HaveKeyWithValue("DAEMON_BASE_URL", "http://example.com"))
			}
		})
	})
})
<|endoftext|>


<commit_before>package state_test

import (
	. "launchpad.net/gocheck"
)

type annotator interface {
	Annotation(key string) string
	Annotations() map[string]string
	Refresh() error
	SetAnnotation(key, value string) error
}

var annotatorTests = []struct {
	about    string
	initial  map[string]string
	input    map[string]string
	expected map[string]string
	err      string
}{
	{
		about:    "test setting an annotation",
		input:    map[string]string{"mykey": "myvalue"},
		expected: map[string]string{"mykey": "myvalue"},
	},
	{
		about:    "test setting multiple annotations",
		input:    map[string]string{"key1": "value1", "key2": "value2"},
		expected: map[string]string{"key1": "value1", "key2": "value2"},
	},
	{
		about:    "test overriding annotations",
		initial:  map[string]string{"mykey": "myvalue"},
		input:    map[string]string{"mykey": "another-value"},
		expected: map[string]string{"mykey": "another-value"},
	},
	{
		about: "test setting an invalid annotation",
		input: map[string]string{"invalid.key": "myvalue"},
		err:   `invalid key "invalid.key"`,
	},
	{
		about:    "test returning a non existent annotation",
		expected: map[string]string{},
	},
	{
		about:    "test removing an annotation",
		initial:  map[string]string{"mykey": "myvalue"},
		input:    map[string]string{"mykey": ""},
		expected: map[string]string{},
	},
	{
		about:    "test removing a non existent annotation",
		input:    map[string]string{"mykey": ""},
		expected: map[string]string{},
	},
}

func testAnnotator(c *C, getEntity func() (annotator, error)) {
loop:
	for i, t := range annotatorTests {
		c.Logf("test %d. %s", i, t.about)
		entity, err := getEntity()
		c.Assert(err, IsNil)
		for key, value := range t.initial {
			err = entity.SetAnnotation(key, value)
			c.Assert(err, IsNil)
		}
		for key, value := range t.input {
			err = entity.SetAnnotation(key, value)
			if t.err != "" {
				c.Assert(err, ErrorMatches, t.err)
				continue loop
			}
		}
		c.Assert(err, IsNil)
		// Retrieving single values works as expected.
		for key, value := range t.input {
			c.Assert(entity.Annotation(key), Equals, value)
		}
		// The value stored in the annotator changed.
		c.Assert(entity.Annotations(), DeepEquals, t.expected)
		err = entity.Refresh()
		c.Assert(err, IsNil)
		// The value stored in MongoDB changed.
		c.Assert(entity.Annotations(), DeepEquals, t.expected)
		// Clean up existing annotations.
		for key := range t.expected {
			err = entity.SetAnnotation(key, "")
		}
	}
}
<commit_msg>Changes as per review.<commit_after>package state_test

import (
	. "launchpad.net/gocheck"
)

type annotator interface {
	Annotation(key string) string
	Annotations() map[string]string
	Refresh() error
	SetAnnotation(key, value string) error
}

var annotatorTests = []struct {
	about    string
	initial  map[string]string
	input    map[string]string
	expected map[string]string
	err      string
}{
	{
		about:    "test setting an annotation",
		input:    map[string]string{"mykey": "myvalue"},
		expected: map[string]string{"mykey": "myvalue"},
	},
	{
		about:    "test setting multiple annotations",
		input:    map[string]string{"key1": "value1", "key2": "value2"},
		expected: map[string]string{"key1": "value1", "key2": "value2"},
	},
	{
		about:    "test overriding annotations",
		initial:  map[string]string{"mykey": "myvalue"},
		input:    map[string]string{"mykey": "another-value"},
		expected: map[string]string{"mykey": "another-value"},
	},
	{
		about: "test setting an invalid annotation",
		input: map[string]string{"invalid.key": "myvalue"},
		err:   `invalid key "invalid.key"`,
	},
	{
		about:    "test returning a non existent annotation",
		expected: map[string]string{},
	},
	{
		about:    "test removing an annotation",
		initial:  map[string]string{"mykey": "myvalue"},
		input:    map[string]string{"mykey": ""},
		expected: map[string]string{},
	},
	{
		about:    "test removing a non existent annotation",
		input:    map[string]string{"mykey": ""},
		expected: map[string]string{},
	},
}

func testAnnotator(c *C, getEntity func() (annotator, error)) {
loop:
	for i, t := range annotatorTests {
		c.Logf("test %d. %s", i, t.about)
		entity, err := getEntity()
		c.Assert(err, IsNil)
		for key, value := range t.initial {
			err := entity.SetAnnotation(key, value)
			c.Assert(err, IsNil)
		}
		for key, value := range t.input {
			err := entity.SetAnnotation(key, value)
			if t.err != "" {
				c.Assert(err, ErrorMatches, t.err)
				continue loop
			}
		}
		c.Assert(err, IsNil)
		// Retrieving single values works as expected.
		for key, value := range t.input {
			c.Assert(entity.Annotation(key), Equals, value)
		}
		// The value stored in the annotator changed.
		c.Assert(entity.Annotations(), DeepEquals, t.expected)
		err = entity.Refresh()
		c.Assert(err, IsNil)
		// The value stored in MongoDB changed.
		c.Assert(entity.Annotations(), DeepEquals, t.expected)
		// Clean up existing annotations.
		for key := range t.expected {
			err = entity.SetAnnotation(key, "")
		}
	}
}
<|endoftext|>


<commit_before>package installer

import (
	"archive/zip"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"os/user"
	"path"
	"path/filepath"
	"runtime"
	"strings"

	"github.com/kardianos/osext"

	"github.com/wx13/genesis"
	"github.com/wx13/genesis/store"
)

var DoTags, SkipTags []string

// Installer is a wrapper around modules to provide a nice
// interface for building an installer.
type Installer struct {
	Status  bool
	Remove  bool
	Install bool
	Verbose bool
	Facts   genesis.Facts
	Dir     string
	Store   *store.Store
	Tasks   []genesis.Doer
}

// New creates a new installer object.
func New() *Installer {

	flag.Usage = func() {
		fmt.Println("")
		fmt.Println("Usage:")
		fmt.Println("./installer -h")
		fmt.Println("./installer (-status|-install|-remove)")
		fmt.Println("")
		flag.PrintDefaults()
	}

	status := flag.Bool("status", false, "Status.")
	remove := flag.Bool("remove", false, "Remove (uninstall).")
	install := flag.Bool("install", false, "Install.")
	verbose := flag.Bool("verbose", false, "Verbose")
	tmpdir := flag.String("tempdir", "", "Temp directory; empty string == default location")
	storedir := flag.String("store", "", "Storage directory for snapshots. Defaults to user's home directory.")
	dotags := flag.String("tags", "", "Specify comma-separated tags to run.  Defaults to all.")
	skipTags := flag.String("skip-tags", "", "Specify comma-separated tags to skip.  Defaults to none.")
	flag.Parse()

	inst := Installer{
		Status:  *status,
		Remove:  *remove,
		Install: *install,
		Verbose: *verbose,
		Tasks:   []genesis.Doer{},
	}

	if !(*install || *remove || *status) {
		return &inst
	}

	SkipTags = strings.Split(*skipTags, ",")
	if len(*dotags) == 0 {
		DoTags = []string{}
	} else {
		DoTags = strings.Split(*dotags, ",")
	}

	inst.Store = store.New(*storedir)
	if inst.Store == nil {
		return nil
	}

	inst.GatherFacts()
	inst.extractFiles(*tmpdir)

	return &inst

}

func (inst *Installer) extractFiles(tmpdir string) error {

	dir, err := ioutil.TempDir(tmpdir, "installer")
	if err != nil {
		return err
	}
	inst.Dir = dir

	filename, _ := osext.Executable()

	zipRdr, err := zip.OpenReader(filename)
	if err != nil {
		fmt.Println("Couldn't extract files.", err, filename)
		return err
	}
	for _, file := range zipRdr.File {
		dest := path.Join(inst.Dir, file.Name)
		if file.FileInfo().IsDir() {
			os.MkdirAll(dest, file.FileInfo().Mode().Perm())
			continue
		}
		os.MkdirAll(filepath.Dir(dest), 0755)
		perms := file.FileInfo().Mode().Perm()
		out, err := os.OpenFile(dest, os.O_CREATE|os.O_RDWR, perms)
		if err != nil {
			continue
		}
		rc, err := file.Open()
		if err != nil {
			continue
		}
		_, err = io.CopyN(out, rc, file.FileInfo().Size())
		if err != nil {
			continue
		}
		rc.Close()
		out.Close()

		mtime := file.FileInfo().ModTime()
		err = os.Chtimes(dest, mtime, mtime)
		if err != nil {
			continue
		}

	}

	return nil
}

// Done finishes up the installer process.
func (inst *Installer) Done() {

	defer inst.CleanUp()

	switch {

	case inst.Remove:
		for k := len(inst.Tasks) - 1; k >= 0; k-- {
			task := inst.Tasks[k]
			task.Undo()
		}

	case inst.Install:
		for _, task := range inst.Tasks {
			task.Do()
		}

	case inst.Status:
		for _, task := range inst.Tasks {
			task.Status()
		}

	}

}

// CleanUp removes the temporary directory.
func (inst *Installer) CleanUp() {
	fmt.Println("")
	os.RemoveAll(inst.Dir)
}

// GatherFacts learns stuff about the target system.
func (inst *Installer) GatherFacts() {

	inst.Facts = genesis.Facts{}

	inst.Facts.ArchType = runtime.GOARCH
	inst.Facts.OS = runtime.GOOS
	cmd := exec.Command("uname", "-m")
	output, err := cmd.Output()
	if err == nil {
		inst.Facts.Arch = strings.TrimSpace(string(output))
	}

	inst.Facts.Hostname, _ = os.Hostname()

	u, err := user.Current()
	if err != nil {
		inst.Facts.Username = u.Username
	}

}

func SkipID(id string) string {
	id = genesis.StringHash(id)
	for _, tag := range SkipTags {
		if id == tag {
			return "skip"
		}
	}
	if len(DoTags) == 0 {
		return "do"
	}
	for _, tag := range DoTags {
		if id == tag {
			return "do"
		}
	}
	return "pass"
}

func EmptyDoTags() []string {
	doTags := make([]string, len(DoTags))
	copy(doTags, DoTags)
	DoTags = []string{}
	return doTags
}

func RestoreDoTags(doTags []string) {
	DoTags = doTags
}

func (inst *Installer) AddTask(module genesis.Module) {
	inst.Tasks = append(inst.Tasks, Task{module})
}

func (inst *Installer) Add(task genesis.Doer) {
	inst.Tasks = append(inst.Tasks, task)
}
<commit_msg>saving command history to .genesis directory<commit_after>package installer

import (
	"archive/zip"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"os/user"
	"path"
	"path/filepath"
	"runtime"
	"strings"

	"github.com/kardianos/osext"

	"github.com/wx13/genesis"
	"github.com/wx13/genesis/store"
)

var DoTags, SkipTags []string

// Installer is a wrapper around modules to provide a nice
// interface for building an installer.
type Installer struct {
	Status  bool
	Remove  bool
	Install bool
	Verbose bool
	Facts   genesis.Facts
	Dir     string
	Store   *store.Store
	Tasks   []genesis.Doer
}

// New creates a new installer object.
func New() *Installer {

	flag.Usage = func() {
		fmt.Println("")
		fmt.Println("Usage:")
		fmt.Println("./installer -h")
		fmt.Println("./installer (-status|-install|-remove)")
		fmt.Println("")
		flag.PrintDefaults()
	}

	status := flag.Bool("status", false, "Status.")
	remove := flag.Bool("remove", false, "Remove (uninstall).")
	install := flag.Bool("install", false, "Install.")
	verbose := flag.Bool("verbose", false, "Verbose")
	tmpdir := flag.String("tempdir", "", "Temp directory; empty string == default location")
	storedir := flag.String("store", "", "Storage directory for snapshots. Defaults to user's home directory.")
	dotags := flag.String("tags", "", "Specify comma-separated tags to run.  Defaults to all.")
	skipTags := flag.String("skip-tags", "", "Specify comma-separated tags to skip.  Defaults to none.")
	flag.Parse()

	inst := Installer{
		Status:  *status,
		Remove:  *remove,
		Install: *install,
		Verbose: *verbose,
		Tasks:   []genesis.Doer{},
	}

	if !(*install || *remove || *status) {
		return &inst
	}

	SkipTags = strings.Split(*skipTags, ",")
	if len(*dotags) == 0 {
		DoTags = []string{}
	} else {
		DoTags = strings.Split(*dotags, ",")
	}

	inst.Store = store.New(*storedir)
	if inst.Store == nil {
		return nil
	}

	if inst.Install || inst.Remove {
		err := inst.History(*storedir, os.Args)
		if err != nil {
			fmt.Println("Error saving command history:", err)
		}
	}

	inst.GatherFacts()
	inst.extractFiles(*tmpdir)

	return &inst

}

func (inst *Installer) extractFiles(tmpdir string) error {

	dir, err := ioutil.TempDir(tmpdir, "installer")
	if err != nil {
		return err
	}
	inst.Dir = dir

	filename, _ := osext.Executable()

	zipRdr, err := zip.OpenReader(filename)
	if err != nil {
		fmt.Println("Couldn't extract files.", err, filename)
		return err
	}
	for _, file := range zipRdr.File {
		dest := path.Join(inst.Dir, file.Name)
		if file.FileInfo().IsDir() {
			os.MkdirAll(dest, file.FileInfo().Mode().Perm())
			continue
		}
		os.MkdirAll(filepath.Dir(dest), 0755)
		perms := file.FileInfo().Mode().Perm()
		out, err := os.OpenFile(dest, os.O_CREATE|os.O_RDWR, perms)
		if err != nil {
			continue
		}
		rc, err := file.Open()
		if err != nil {
			continue
		}
		_, err = io.CopyN(out, rc, file.FileInfo().Size())
		if err != nil {
			continue
		}
		rc.Close()
		out.Close()

		mtime := file.FileInfo().ModTime()
		err = os.Chtimes(dest, mtime, mtime)
		if err != nil {
			continue
		}

	}

	return nil
}

// Done finishes up the installer process.
func (inst *Installer) Done() {

	defer inst.CleanUp()

	switch {

	case inst.Remove:
		for k := len(inst.Tasks) - 1; k >= 0; k-- {
			task := inst.Tasks[k]
			task.Undo()
		}

	case inst.Install:
		for _, task := range inst.Tasks {
			task.Do()
		}

	case inst.Status:
		for _, task := range inst.Tasks {
			task.Status()
		}

	}

}

// CleanUp removes the temporary directory.
func (inst *Installer) CleanUp() {
	fmt.Println("")
	os.RemoveAll(inst.Dir)
}

// GatherFacts learns stuff about the target system.
func (inst *Installer) GatherFacts() {

	inst.Facts = genesis.Facts{}

	inst.Facts.ArchType = runtime.GOARCH
	inst.Facts.OS = runtime.GOOS
	cmd := exec.Command("uname", "-m")
	output, err := cmd.Output()
	if err == nil {
		inst.Facts.Arch = strings.TrimSpace(string(output))
	}

	inst.Facts.Hostname, _ = os.Hostname()

	u, err := user.Current()
	if err != nil {
		inst.Facts.Username = u.Username
	}

}

func SkipID(id string) string {
	id = genesis.StringHash(id)
	for _, tag := range SkipTags {
		if id == tag {
			return "skip"
		}
	}
	if len(DoTags) == 0 {
		return "do"
	}
	for _, tag := range DoTags {
		if id == tag {
			return "do"
		}
	}
	return "pass"
}

func EmptyDoTags() []string {
	doTags := make([]string, len(DoTags))
	copy(doTags, DoTags)
	DoTags = []string{}
	return doTags
}

func RestoreDoTags(doTags []string) {
	DoTags = doTags
}

func (inst *Installer) AddTask(module genesis.Module) {
	inst.Tasks = append(inst.Tasks, Task{module})
}

func (inst *Installer) Add(task genesis.Doer) {
	inst.Tasks = append(inst.Tasks, task)
}

func (inst *Installer) History(dir string, cmd []string) error {
	if len(dir) == 0 {
		usr, _ := user.Current()
		dir = usr.HomeDir
	}
	dir = path.Join(dir, ".genesis")
	err := os.MkdirAll(dir, 0755)
	if err != nil {
		return err
	}
	file, err := os.OpenFile(path.Join(dir, "history.txt"), os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0666)
	if err != nil {
		return err
	}
	_, err = file.WriteString(strings.Join(cmd, " ") + "\n")
	file.Close()
	return err
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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

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

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

package util

import (
	"bufio"
	"bytes"
	"context"
	"fmt"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
	"sync"
	"testing"
	"time"

	"github.com/docker/machine/libmachine/state"
	"github.com/pkg/errors"
	"k8s.io/minikube/pkg/minikube/assets"
	commonutil "k8s.io/minikube/pkg/util"
	"k8s.io/minikube/pkg/util/retry"
)

// MinikubeRunner runs a command
type MinikubeRunner struct {
	Profile      string
	T            *testing.T
	BinaryPath   string
	GlobalArgs   string
	StartArgs    string
	MountArgs    string
	Runtime      string
	TimeOutStart time.Duration // time to wait for minikube start before killing it
}

// Remove removes a file
func (m *MinikubeRunner) Remove(f assets.CopyableFile) error {
	_, err := m.SSH(fmt.Sprintf("rm -rf %s", filepath.Join(f.GetTargetDir(), f.GetTargetName())))
	return err
}

// teeRun runs a command, streaming stdout, stderr to console
func (m *MinikubeRunner) teeRun(cmd *exec.Cmd, waitForRun ...bool) (string, string, error) {
	w := true
	if waitForRun != nil {
		w = waitForRun[0]
	}

	errPipe, err := cmd.StderrPipe()
	if err != nil {
		return "", "", err
	}
	outPipe, err := cmd.StdoutPipe()
	if err != nil {
		return "", "", err
	}

	if err := cmd.Start(); err != nil {
		return "", "", err
	}
	if w {
		var outB bytes.Buffer
		var errB bytes.Buffer
		var wg sync.WaitGroup
		wg.Add(2)
		go func() {
			if err := commonutil.TeePrefix(commonutil.ErrPrefix, errPipe, &errB, Logf); err != nil {
				m.T.Logf("tee: %v", err)
			}
			wg.Done()
		}()
		go func() {
			if err := commonutil.TeePrefix(commonutil.OutPrefix, outPipe, &outB, Logf); err != nil {
				m.T.Logf("tee: %v", err)
			}
			wg.Done()
		}()
		err = cmd.Wait()
		wg.Wait()
		return outB.String(), errB.String(), err

	}
	return "", "", err
}

// RunCommand executes a command, optionally checking for error and by default waits for run to finish
func (m *MinikubeRunner) RunCommand(cmdStr string, failError bool, waitForRun ...bool) (string, string) {
	profileArg := fmt.Sprintf("-p=%s ", m.Profile)
	cmdStr = profileArg + cmdStr
	cmdArgs := strings.Split(cmdStr, " ")
	path, _ := filepath.Abs(m.BinaryPath)

	cmd := exec.Command(path, cmdArgs...)
	Logf("Run: %s", cmd.Args)
	stdout, stderr, err := m.teeRun(cmd, waitForRun...)
	if err != nil {
		errMsg := ""
		if exitError, ok := err.(*exec.ExitError); ok {
			errMsg = fmt.Sprintf("Error running command: %s %s. Output: %s Stderr: %s", cmdStr, exitError.Stderr, stdout, stderr)
		} else {
			errMsg = fmt.Sprintf("Error running command: %s %s. Output: %s", cmdStr, stderr, stdout)
		}
		if failError {
			m.T.Fatalf(errMsg)
		} else {
			m.T.Errorf(errMsg)
		}
	}
	return stdout, stderr
}

// RunCommandRetriable executes a command, returns error
// the purpose of this command is to make it retriable and
// better logging for retrying
func (m *MinikubeRunner) RunCommandRetriable(cmdStr string, waitForRun ...bool) (stdout string, stderr string, err error) {
	profileArg := fmt.Sprintf("-p=%s ", m.Profile)
	cmdStr = profileArg + cmdStr
	cmdArgs := strings.Split(cmdStr, " ")
	path, _ := filepath.Abs(m.BinaryPath)

	cmd := exec.Command(path, cmdArgs...)
	Logf("Run: %s", cmd.Args)
	stdout, stderr, err = m.teeRun(cmd, waitForRun...)
	if err != nil {
		if exitError, ok := err.(*exec.ExitError); ok {
			m.T.Logf("temporary error: running command: %s %s. Output: \n%s", cmdStr, exitError.Stderr, stdout)
		} else {
			m.T.Logf("temporary error: running command: %s %s. Output: \n%s", cmdStr, stderr, stdout)
		}
	}
	return stdout, stderr, err
}

// RunWithContext calls the minikube command with a context, useful for timeouts.
func (m *MinikubeRunner) RunWithContext(ctx context.Context, cmdStr string, wait ...bool) (string, string, error) {
	profileArg := fmt.Sprintf("-p=%s ", m.Profile)
	cmdStr = profileArg + cmdStr
	cmdArgs := strings.Split(cmdStr, " ")
	path, _ := filepath.Abs(m.BinaryPath)

	cmd := exec.CommandContext(ctx, path, cmdArgs...)
	Logf("Run: %s", cmd.Args)
	return m.teeRun(cmd, wait...)
}

// RunDaemon executes a command, returning the stdout
func (m *MinikubeRunner) RunDaemon(cmdStr string) (*exec.Cmd, *bufio.Reader) {
	profileArg := fmt.Sprintf("-p=%s ", m.Profile)
	cmdStr = profileArg + cmdStr
	cmdArgs := strings.Split(cmdStr, " ")
	path, _ := filepath.Abs(m.BinaryPath)

	cmd := exec.Command(path, cmdArgs...)
	stdoutPipe, err := cmd.StdoutPipe()
	if err != nil {
		m.T.Fatalf("stdout pipe failed: %s %v", cmdStr, err)
	}
	stderrPipe, err := cmd.StderrPipe()
	if err != nil {
		m.T.Fatalf("stderr pipe failed: %s %v", cmdStr, err)
	}

	var errB bytes.Buffer
	go func() {
		if err := commonutil.TeePrefix(commonutil.ErrPrefix, stderrPipe, &errB, Logf); err != nil {
			m.T.Logf("tee: %v", err)
		}
	}()

	err = cmd.Start()
	if err != nil {
		m.T.Fatalf("Error running command: %s %v", cmdStr, err)
	}
	return cmd, bufio.NewReader(stdoutPipe)

}

// RunDaemon2 executes a command, returning the stdout and stderr
func (m *MinikubeRunner) RunDaemon2(cmdStr string) (*exec.Cmd, *bufio.Reader, *bufio.Reader) {
	profileArg := fmt.Sprintf("-p=%s ", m.Profile)
	cmdStr = profileArg + cmdStr
	cmdArgs := strings.Split(cmdStr, " ")
	path, _ := filepath.Abs(m.BinaryPath)
	cmd := exec.Command(path, cmdArgs...)
	stdoutPipe, err := cmd.StdoutPipe()
	if err != nil {
		m.T.Fatalf("stdout pipe failed: %s %v", cmdStr, err)
	}
	stderrPipe, err := cmd.StderrPipe()
	if err != nil {
		m.T.Fatalf("stderr pipe failed: %s %v", cmdStr, err)
	}

	err = cmd.Start()
	if err != nil {
		m.T.Fatalf("Error running command: %s %v", cmdStr, err)
	}
	return cmd, bufio.NewReader(stdoutPipe), bufio.NewReader(stderrPipe)
}

// SSH returns the output of running a command using SSH
func (m *MinikubeRunner) SSH(cmdStr string) (string, error) {
	profileArg := fmt.Sprintf("-p=%s", m.Profile)
	path, _ := filepath.Abs(m.BinaryPath)

	cmd := exec.Command(path, profileArg, "ssh", cmdStr)
	Logf("SSH: %s", cmdStr)
	stdout, err := cmd.CombinedOutput()
	Logf("Output: %s", stdout)
	if err, ok := err.(*exec.ExitError); ok {
		return string(stdout), err
	}
	return string(stdout), nil
}

// Start starts the cluster
func (m *MinikubeRunner) Start(opts ...string) (stdout string, stderr string, err error) {
	cmd := fmt.Sprintf("start %s %s %s", m.StartArgs, m.GlobalArgs, strings.Join(opts, " "))
	s := func() error {
		stdout, stderr, err = m.RunCommandRetriable(cmd)
		return err
	}
	err = retry.Expo(s, 10*time.Second, m.TimeOutStart)
	return stdout, stderr, err
}

// TearDown deletes minikube without waiting for it. used to free up ram/cpu after each test
func (m *MinikubeRunner) TearDown(t *testing.T) {
	profileArg := fmt.Sprintf("-p=%s", m.Profile)
	path, _ := filepath.Abs(m.BinaryPath)
	cmd := exec.Command(path, profileArg, "delete")
	err := cmd.Start() // don't wait for it to finish
	if err != nil {
		t.Errorf("error tearing down minikube %s : %v", profileArg, err)
	}
}

// EnsureRunning makes sure the container runtime is running
func (m *MinikubeRunner) EnsureRunning(opts ...string) {
	s, _, err := m.Status()
	if err != nil {
		m.T.Errorf("error getting status for ensure running: %v", err)
	}
	if s != state.Running.String() {
		stdout, stderr, err := m.Start(opts...)
		if err != nil {
			m.T.Errorf("error starting while running EnsureRunning : %v , stdout %s stderr %s", err, stdout, stderr)
		}
	}
	m.CheckStatus(state.Running.String())
}

// ParseEnvCmdOutput parses the output of `env` (assumes bash)
func (m *MinikubeRunner) ParseEnvCmdOutput(out string) map[string]string {
	env := map[string]string{}
	re := regexp.MustCompile(`(\w+?) ?= ?"?(.+?)"?\n`)
	for _, m := range re.FindAllStringSubmatch(out, -1) {
		env[m[1]] = m[2]
	}
	return env
}

// Status returns the status of a service
func (m *MinikubeRunner) Status() (status string, stderr string, err error) {
	cmd := fmt.Sprintf("status --format={{.Host}} %s", m.GlobalArgs)
	s := func() error {
		status, stderr, err = m.RunCommandRetriable(cmd)
		status = strings.TrimRight(status, "\n")
		return err
	}
	err = retry.Expo(s, 3*time.Second, 2*time.Minute)
	if err != nil && (status == state.None.String() || status == state.Stopped.String()) {
		err = nil // because https://github.com/kubernetes/minikube/issues/4932
	}
	return status, stderr, err
}

// GetLogs returns the logs of a service
func (m *MinikubeRunner) GetLogs() string {
	// TODO: this test needs to check sterr too !
	stdout, _ := m.RunCommand(fmt.Sprintf("logs %s", m.GlobalArgs), true)
	return stdout
}

// CheckStatus makes sure the service has the desired status, or cause fatal error
func (m *MinikubeRunner) CheckStatus(desired string) {
	err := m.CheckStatusNoFail(desired)
	if err != nil { // none status returns 1 exit code
		m.T.Fatalf("%v", err)
	}
}

// CheckStatusNoFail makes sure the service has the desired status, returning error
func (m *MinikubeRunner) CheckStatusNoFail(desired string) error {
	s, stderr, err := m.Status()
	if s != desired {
		return fmt.Errorf("got state: %q, expected %q : stderr: %s err: %v ", s, desired, stderr, err)
	}

	if err != nil {
		return errors.Wrapf(err, stderr)
	}
	return nil
}
<commit_msg>remove retry start from integeration tests<commit_after>/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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

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

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

package util

import (
	"bufio"
	"bytes"
	"context"
	"fmt"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
	"sync"
	"testing"
	"time"

	"github.com/docker/machine/libmachine/state"
	"github.com/pkg/errors"
	"k8s.io/minikube/pkg/minikube/assets"
	commonutil "k8s.io/minikube/pkg/util"
	"k8s.io/minikube/pkg/util/retry"
)

// MinikubeRunner runs a command
type MinikubeRunner struct {
	Profile      string
	T            *testing.T
	BinaryPath   string
	GlobalArgs   string
	StartArgs    string
	MountArgs    string
	Runtime      string
	TimeOutStart time.Duration // time to wait for minikube start before killing it
}

// Remove removes a file
func (m *MinikubeRunner) Remove(f assets.CopyableFile) error {
	_, err := m.SSH(fmt.Sprintf("rm -rf %s", filepath.Join(f.GetTargetDir(), f.GetTargetName())))
	return err
}

// teeRun runs a command, streaming stdout, stderr to console
func (m *MinikubeRunner) teeRun(cmd *exec.Cmd, waitForRun ...bool) (string, string, error) {
	w := true
	if waitForRun != nil {
		w = waitForRun[0]
	}

	errPipe, err := cmd.StderrPipe()
	if err != nil {
		return "", "", err
	}
	outPipe, err := cmd.StdoutPipe()
	if err != nil {
		return "", "", err
	}

	if err := cmd.Start(); err != nil {
		return "", "", err
	}
	if w {
		var outB bytes.Buffer
		var errB bytes.Buffer
		var wg sync.WaitGroup
		wg.Add(2)
		go func() {
			if err := commonutil.TeePrefix(commonutil.ErrPrefix, errPipe, &errB, Logf); err != nil {
				m.T.Logf("tee: %v", err)
			}
			wg.Done()
		}()
		go func() {
			if err := commonutil.TeePrefix(commonutil.OutPrefix, outPipe, &outB, Logf); err != nil {
				m.T.Logf("tee: %v", err)
			}
			wg.Done()
		}()
		err = cmd.Wait()
		wg.Wait()
		return outB.String(), errB.String(), err

	}
	return "", "", err
}

// RunCommand executes a command, optionally checking for error and by default waits for run to finish
func (m *MinikubeRunner) RunCommand(cmdStr string, failError bool, waitForRun ...bool) (string, string) {
	profileArg := fmt.Sprintf("-p=%s ", m.Profile)
	cmdStr = profileArg + cmdStr
	cmdArgs := strings.Split(cmdStr, " ")
	path, _ := filepath.Abs(m.BinaryPath)

	cmd := exec.Command(path, cmdArgs...)
	Logf("Run: %s", cmd.Args)
	stdout, stderr, err := m.teeRun(cmd, waitForRun...)
	if err != nil {
		errMsg := ""
		if exitError, ok := err.(*exec.ExitError); ok {
			errMsg = fmt.Sprintf("Error running command: %s %s. Output: %s Stderr: %s", cmdStr, exitError.Stderr, stdout, stderr)
		} else {
			errMsg = fmt.Sprintf("Error running command: %s %s. Output: %s", cmdStr, stderr, stdout)
		}
		if failError {
			m.T.Fatalf(errMsg)
		} else {
			m.T.Errorf(errMsg)
		}
	}
	return stdout, stderr
}

// RunCommandRetriable executes a command, returns error
// the purpose of this command is to make it retriable by returning error
func (m *MinikubeRunner) RunCommandRetriable(cmdStr string, waitForRun ...bool) (stdout string, stderr string, err error) {
	profileArg := fmt.Sprintf("-p=%s ", m.Profile)
	cmdStr = profileArg + cmdStr
	cmdArgs := strings.Split(cmdStr, " ")
	path, _ := filepath.Abs(m.BinaryPath)

	cmd := exec.Command(path, cmdArgs...)
	Logf("Run: %s", cmd.Args)
	stdout, stderr, err = m.teeRun(cmd, waitForRun...)
	if err != nil {
		if exitError, ok := err.(*exec.ExitError); ok {
			m.T.Logf("temporary error: running command: %s %s. Output: \n%s", cmdStr, exitError.Stderr, stdout)
		} else {
			m.T.Logf("temporary error: running command: %s %s. Output: \n%s", cmdStr, stderr, stdout)
		}
	}
	return stdout, stderr, err
}

// RunWithContext calls the minikube command with a context, useful for timeouts.
func (m *MinikubeRunner) RunWithContext(ctx context.Context, cmdStr string, wait ...bool) (string, string, error) {
	profileArg := fmt.Sprintf("-p=%s ", m.Profile)
	cmdStr = profileArg + cmdStr
	cmdArgs := strings.Split(cmdStr, " ")
	path, _ := filepath.Abs(m.BinaryPath)

	cmd := exec.CommandContext(ctx, path, cmdArgs...)
	Logf("Run: %s", cmd.Args)
	return m.teeRun(cmd, wait...)
}

// RunDaemon executes a command, returning the stdout
func (m *MinikubeRunner) RunDaemon(cmdStr string) (*exec.Cmd, *bufio.Reader) {
	profileArg := fmt.Sprintf("-p=%s ", m.Profile)
	cmdStr = profileArg + cmdStr
	cmdArgs := strings.Split(cmdStr, " ")
	path, _ := filepath.Abs(m.BinaryPath)

	cmd := exec.Command(path, cmdArgs...)
	stdoutPipe, err := cmd.StdoutPipe()
	if err != nil {
		m.T.Fatalf("stdout pipe failed: %s %v", cmdStr, err)
	}
	stderrPipe, err := cmd.StderrPipe()
	if err != nil {
		m.T.Fatalf("stderr pipe failed: %s %v", cmdStr, err)
	}

	var errB bytes.Buffer
	go func() {
		if err := commonutil.TeePrefix(commonutil.ErrPrefix, stderrPipe, &errB, Logf); err != nil {
			m.T.Logf("tee: %v", err)
		}
	}()

	err = cmd.Start()
	if err != nil {
		m.T.Fatalf("Error running command: %s %v", cmdStr, err)
	}
	return cmd, bufio.NewReader(stdoutPipe)

}

// RunDaemon2 executes a command, returning the stdout and stderr
func (m *MinikubeRunner) RunDaemon2(cmdStr string) (*exec.Cmd, *bufio.Reader, *bufio.Reader) {
	profileArg := fmt.Sprintf("-p=%s ", m.Profile)
	cmdStr = profileArg + cmdStr
	cmdArgs := strings.Split(cmdStr, " ")
	path, _ := filepath.Abs(m.BinaryPath)
	cmd := exec.Command(path, cmdArgs...)
	stdoutPipe, err := cmd.StdoutPipe()
	if err != nil {
		m.T.Fatalf("stdout pipe failed: %s %v", cmdStr, err)
	}
	stderrPipe, err := cmd.StderrPipe()
	if err != nil {
		m.T.Fatalf("stderr pipe failed: %s %v", cmdStr, err)
	}

	err = cmd.Start()
	if err != nil {
		m.T.Fatalf("Error running command: %s %v", cmdStr, err)
	}
	return cmd, bufio.NewReader(stdoutPipe), bufio.NewReader(stderrPipe)
}

// SSH returns the output of running a command using SSH
func (m *MinikubeRunner) SSH(cmdStr string) (string, error) {
	profileArg := fmt.Sprintf("-p=%s", m.Profile)
	path, _ := filepath.Abs(m.BinaryPath)

	cmd := exec.Command(path, profileArg, "ssh", cmdStr)
	Logf("SSH: %s", cmdStr)
	stdout, err := cmd.CombinedOutput()
	Logf("Output: %s", stdout)
	if err, ok := err.(*exec.ExitError); ok {
		return string(stdout), err
	}
	return string(stdout), nil
}

// Start starts the cluster
func (m *MinikubeRunner) Start(opts ...string) (stdout string, stderr string, err error) {
	cmd := fmt.Sprintf("start %s %s %s", m.StartArgs, m.GlobalArgs, strings.Join(opts, " "))
	ctx := context.Background()
	ctx, cancel := context.WithTimeout(ctx, m.TimeOutStart)
	defer cancel()
	stdout, stderr, err = m.RunWithContext(ctx, cmd, true)
	return stdout, stderr, err
}

// TearDown deletes minikube without waiting for it. used to free up ram/cpu after each test
func (m *MinikubeRunner) TearDown(t *testing.T) {
	profileArg := fmt.Sprintf("-p=%s", m.Profile)
	path, _ := filepath.Abs(m.BinaryPath)
	cmd := exec.Command(path, profileArg, "delete")
	err := cmd.Start() // don't wait for it to finish
	if err != nil {
		t.Errorf("error tearing down minikube %s : %v", profileArg, err)
	}
}

// EnsureRunning makes sure the container runtime is running
func (m *MinikubeRunner) EnsureRunning(opts ...string) {
	s, _, err := m.Status()
	if err != nil {
		m.T.Errorf("error getting status for ensure running: %v", err)
	}
	if s != state.Running.String() {
		stdout, stderr, err := m.Start(opts...)
		if err != nil {
			m.T.Errorf("error starting while running EnsureRunning : %v , stdout %s stderr %s", err, stdout, stderr)
		}
	}
	m.CheckStatus(state.Running.String())
}

// ParseEnvCmdOutput parses the output of `env` (assumes bash)
func (m *MinikubeRunner) ParseEnvCmdOutput(out string) map[string]string {
	env := map[string]string{}
	re := regexp.MustCompile(`(\w+?) ?= ?"?(.+?)"?\n`)
	for _, m := range re.FindAllStringSubmatch(out, -1) {
		env[m[1]] = m[2]
	}
	return env
}

// Status returns the status of a service
func (m *MinikubeRunner) Status() (status string, stderr string, err error) {
	cmd := fmt.Sprintf("status --format={{.Host}} %s", m.GlobalArgs)
	s := func() error {
		status, stderr, err = m.RunCommandRetriable(cmd)
		status = strings.TrimRight(status, "\n")
		return err
	}
	err = retry.Expo(s, 3*time.Second, 2*time.Minute)
	if err != nil && (status == state.None.String() || status == state.Stopped.String()) {
		err = nil // because https://github.com/kubernetes/minikube/issues/4932
	}
	return status, stderr, err
}

// GetLogs returns the logs of a service
func (m *MinikubeRunner) GetLogs() string {
	// TODO: this test needs to check sterr too !
	stdout, _ := m.RunCommand(fmt.Sprintf("logs %s", m.GlobalArgs), true)
	return stdout
}

// CheckStatus makes sure the service has the desired status, or cause fatal error
func (m *MinikubeRunner) CheckStatus(desired string) {
	err := m.CheckStatusNoFail(desired)
	if err != nil { // none status returns 1 exit code
		m.T.Fatalf("%v", err)
	}
}

// CheckStatusNoFail makes sure the service has the desired status, returning error
func (m *MinikubeRunner) CheckStatusNoFail(desired string) error {
	s, stderr, err := m.Status()
	if s != desired {
		return fmt.Errorf("got state: %q, expected %q : stderr: %s err: %v ", s, desired, stderr, err)
	}

	if err != nil {
		return errors.Wrapf(err, stderr)
	}
	return nil
}
<|endoftext|>