<commit_before>package bloom_test

import (
	"encoding/binary"
	"fmt"
	"testing"

	"github.com/influxdata/influxdb/pkg/bloom"
)

// Ensure filter can insert values and verify they exist.
func TestFilter_InsertContains(t *testing.T) {
	// Short, less comprehensive test.
	testShortFilter_InsertContains(t)

	if testing.Short() {
		return // Just run the above short test
	}

	// More comprehensive test for the xxhash based Bloom Filter.

	// These parameters will result, for 10M entries, with a bloom filter
	// with 0.001 false positive rate (1 in 1000 values will be incorrectly
	// identified as being present in the set).
	filter := bloom.NewFilter(143775876, 10)
	v := make([]byte, 4, 4)
	for i := 0; i < 10000000; i++ {
		binary.BigEndian.PutUint32(v, uint32(i))
		filter.Insert(v)
	}

	// None of the values inserted should ever be considered "not possibly in
	// the filter".
	t.Run("100M", func(t *testing.T) {
		for i := 0; i < 10000000; i++ {
			binary.BigEndian.PutUint32(v, uint32(i))
			if !filter.Contains(v) {
				t.Fatalf("got false for value %q, expected true", v)
			}
		}

		// If we check for 100,000,000 values that we know are not present in the
		// filter then we might expect around 100,000 of them to be false positives.
		var fp int
		for i := 10000000; i < 110000000; i++ {
			binary.BigEndian.PutUint32(v, uint32(i))
			if filter.Contains(v) {
				fp++
			}
		}

		if fp > 1000000 {
			// If we're an order of magnitude off, then it's arguable that there
			// is a bug in the bloom filter.
			t.Fatalf("got %d false positives which is an error rate of %f, expected error rate <=0.001", fp, float64(fp)/100000000)
		}
		t.Logf("Bloom false positive error rate was %f", float64(fp)/100000000)
	})
}

func testShortFilter_InsertContains(t *testing.T) {
	t.Run("short", func(t *testing.T) {
		f := bloom.NewFilter(1000, 4)

		// Insert value and validate.
		f.Insert([]byte("Bess"))
		if !f.Contains([]byte("Bess")) {
			t.Fatal("expected true")
		}

		// Insert another value and test.
		f.Insert([]byte("Emma"))
		if !f.Contains([]byte("Emma")) {
			t.Fatal("expected true")
		}

		// Validate that a non-existent value doesn't exist.
		if f.Contains([]byte("Jane")) {
			t.Fatal("expected false")
		}
	})
}

var benchCases = []struct {
	m, k uint64
	n    int
}{
	{m: 100, k: 4, n: 1000},
	{m: 1000, k: 4, n: 1000},
	{m: 10000, k: 4, n: 1000},
	{m: 100000, k: 4, n: 1000},
	{m: 100, k: 8, n: 1000},
	{m: 1000, k: 8, n: 1000},
	{m: 10000, k: 8, n: 1000},
	{m: 100000, k: 8, n: 1000},
	{m: 100, k: 20, n: 1000},
	{m: 1000, k: 20, n: 1000},
	{m: 10000, k: 20, n: 1000},
	{m: 100000, k: 20, n: 1000},
}

func BenchmarkFilter_Insert(b *testing.B) {
	for _, c := range benchCases {
		data := make([][]byte, 0, c.n)
		for i := 0; i < c.n; i++ {
			data = append(data, []byte(fmt.Sprintf("%d", i)))
		}

		filter := bloom.NewFilter(c.m, c.k)
		b.Run(fmt.Sprintf("m=%d_k=%d_n=%d", c.m, c.k, c.n), func(b *testing.B) {
			b.ReportAllocs()
			for i := 0; i < b.N; i++ {
				for _, v := range data {
					filter.Insert(v)
				}
			}
		})

	}
}

var okResult bool

func BenchmarkFilter_Contains(b *testing.B) {
	for _, c := range benchCases {
		data := make([][]byte, 0, c.n)
		notData := make([][]byte, 0, c.n)
		for i := 0; i < c.n; i++ {
			data = append(data, []byte(fmt.Sprintf("%d", i)))
			notData = append(notData, []byte(fmt.Sprintf("%d", c.n+i)))
		}

		filter := bloom.NewFilter(c.m, c.k)
		for _, v := range data {
			filter.Insert(v)
		}

		b.Run(fmt.Sprintf("m=%d_k=%d_n=%d", c.m, c.k, c.n), func(b *testing.B) {
			b.ReportAllocs()
			for i := 0; i < b.N; i++ {
				for _, v := range data {
					okResult = filter.Contains(v)
					if !okResult {
						b.Fatalf("Filter returned negative for value %q in set", v)
					}
				}

				// And now a bunch of values that don't exist.
				for _, v := range notData {
					okResult = filter.Contains(v)
				}
			}
		})
	}
}

func BenchmarkFilter_Merge(b *testing.B) {
	for _, c := range benchCases {
		data1 := make([][]byte, 0, c.n)
		data2 := make([][]byte, 0, c.n)
		for i := 0; i < c.n; i++ {
			data1 = append(data1, []byte(fmt.Sprintf("%d", i)))
			data2 = append(data2, []byte(fmt.Sprintf("%d", c.n+i)))
		}

		filter1 := bloom.NewFilter(c.m, c.k)
		filter2 := bloom.NewFilter(c.m, c.k)
		for i := 0; i < c.n; i++ {
			filter1.Insert(data1[i])
			filter2.Insert(data2[i])
		}

		b.Run(fmt.Sprintf("m=%d_k=%d_n=%d", c.m, c.k, c.n), func(b *testing.B) {
			b.ReportAllocs()
			for i := 0; i < b.N; i++ {
				other, err := bloom.NewFilterBuffer(filter1.Bytes(), filter1.K())
				if err != nil {
					b.Fatal(err)
				}
				other.Merge(filter2)
			}
		})
	}
}
<commit_msg>Don't run test in race mode<commit_after>package bloom_test

import (
	"encoding/binary"
	"fmt"
	"os"
	"testing"

	"github.com/influxdata/influxdb/pkg/bloom"
)

// Ensure filter can insert values and verify they exist.
func TestFilter_InsertContains(t *testing.T) {
	if testing.Short() || os.Getenv("GORACE") != "" || os.Getenv("APPVEYOR") != "" {
		t.Skip("Skipping test in short, race and appveyor mode.")
	}

	// Short, less comprehensive test.
	testShortFilter_InsertContains(t)

	if testing.Short() {
		return // Just run the above short test
	}

	// More comprehensive test for the xxhash based Bloom Filter.

	// These parameters will result, for 10M entries, with a bloom filter
	// with 0.001 false positive rate (1 in 1000 values will be incorrectly
	// identified as being present in the set).
	filter := bloom.NewFilter(143775876, 10)
	v := make([]byte, 4, 4)
	for i := 0; i < 10000000; i++ {
		binary.BigEndian.PutUint32(v, uint32(i))
		filter.Insert(v)
	}

	// None of the values inserted should ever be considered "not possibly in
	// the filter".
	t.Run("100M", func(t *testing.T) {
		for i := 0; i < 10000000; i++ {
			binary.BigEndian.PutUint32(v, uint32(i))
			if !filter.Contains(v) {
				t.Fatalf("got false for value %q, expected true", v)
			}
		}

		// If we check for 100,000,000 values that we know are not present in the
		// filter then we might expect around 100,000 of them to be false positives.
		var fp int
		for i := 10000000; i < 110000000; i++ {
			binary.BigEndian.PutUint32(v, uint32(i))
			if filter.Contains(v) {
				fp++
			}
		}

		if fp > 1000000 {
			// If we're an order of magnitude off, then it's arguable that there
			// is a bug in the bloom filter.
			t.Fatalf("got %d false positives which is an error rate of %f, expected error rate <=0.001", fp, float64(fp)/100000000)
		}
		t.Logf("Bloom false positive error rate was %f", float64(fp)/100000000)
	})
}

func testShortFilter_InsertContains(t *testing.T) {
	t.Run("short", func(t *testing.T) {
		f := bloom.NewFilter(1000, 4)

		// Insert value and validate.
		f.Insert([]byte("Bess"))
		if !f.Contains([]byte("Bess")) {
			t.Fatal("expected true")
		}

		// Insert another value and test.
		f.Insert([]byte("Emma"))
		if !f.Contains([]byte("Emma")) {
			t.Fatal("expected true")
		}

		// Validate that a non-existent value doesn't exist.
		if f.Contains([]byte("Jane")) {
			t.Fatal("expected false")
		}
	})
}

var benchCases = []struct {
	m, k uint64
	n    int
}{
	{m: 100, k: 4, n: 1000},
	{m: 1000, k: 4, n: 1000},
	{m: 10000, k: 4, n: 1000},
	{m: 100000, k: 4, n: 1000},
	{m: 100, k: 8, n: 1000},
	{m: 1000, k: 8, n: 1000},
	{m: 10000, k: 8, n: 1000},
	{m: 100000, k: 8, n: 1000},
	{m: 100, k: 20, n: 1000},
	{m: 1000, k: 20, n: 1000},
	{m: 10000, k: 20, n: 1000},
	{m: 100000, k: 20, n: 1000},
}

func BenchmarkFilter_Insert(b *testing.B) {
	for _, c := range benchCases {
		data := make([][]byte, 0, c.n)
		for i := 0; i < c.n; i++ {
			data = append(data, []byte(fmt.Sprintf("%d", i)))
		}

		filter := bloom.NewFilter(c.m, c.k)
		b.Run(fmt.Sprintf("m=%d_k=%d_n=%d", c.m, c.k, c.n), func(b *testing.B) {
			b.ReportAllocs()
			for i := 0; i < b.N; i++ {
				for _, v := range data {
					filter.Insert(v)
				}
			}
		})

	}
}

var okResult bool

func BenchmarkFilter_Contains(b *testing.B) {
	for _, c := range benchCases {
		data := make([][]byte, 0, c.n)
		notData := make([][]byte, 0, c.n)
		for i := 0; i < c.n; i++ {
			data = append(data, []byte(fmt.Sprintf("%d", i)))
			notData = append(notData, []byte(fmt.Sprintf("%d", c.n+i)))
		}

		filter := bloom.NewFilter(c.m, c.k)
		for _, v := range data {
			filter.Insert(v)
		}

		b.Run(fmt.Sprintf("m=%d_k=%d_n=%d", c.m, c.k, c.n), func(b *testing.B) {
			b.ReportAllocs()
			for i := 0; i < b.N; i++ {
				for _, v := range data {
					okResult = filter.Contains(v)
					if !okResult {
						b.Fatalf("Filter returned negative for value %q in set", v)
					}
				}

				// And now a bunch of values that don't exist.
				for _, v := range notData {
					okResult = filter.Contains(v)
				}
			}
		})
	}
}

func BenchmarkFilter_Merge(b *testing.B) {
	for _, c := range benchCases {
		data1 := make([][]byte, 0, c.n)
		data2 := make([][]byte, 0, c.n)
		for i := 0; i < c.n; i++ {
			data1 = append(data1, []byte(fmt.Sprintf("%d", i)))
			data2 = append(data2, []byte(fmt.Sprintf("%d", c.n+i)))
		}

		filter1 := bloom.NewFilter(c.m, c.k)
		filter2 := bloom.NewFilter(c.m, c.k)
		for i := 0; i < c.n; i++ {
			filter1.Insert(data1[i])
			filter2.Insert(data2[i])
		}

		b.Run(fmt.Sprintf("m=%d_k=%d_n=%d", c.m, c.k, c.n), func(b *testing.B) {
			b.ReportAllocs()
			for i := 0; i < b.N; i++ {
				other, err := bloom.NewFilterBuffer(filter1.Bytes(), filter1.K())
				if err != nil {
					b.Fatal(err)
				}
				other.Merge(filter2)
			}
		})
	}
}
<|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 chartutil

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

	"k8s.io/helm/pkg/proto/hapi/chart"
)

const (
	// ChartfileName is the default Chart file name.
	ChartfileName = "Chart.yaml"
	// ValuesfileName is the default values file name.
	ValuesfileName = "values.yaml"
	// TemplatesDir is the relative directory name for templates.
	TemplatesDir = "templates"
	// ChartsDir is the relative directory name for charts dependencies.
	ChartsDir = "charts"
	// IgnorefileName is the name of the Helm ignore file.
	IgnorefileName = ".helmignore"
)

const defaultValues = `# Default values for %s.
# This is a YAML-formatted file.
# Declare name/value pairs to be passed into your templates.
# name: value
`

const defaultIgnore = `# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*~
# Various IDEs
.project
.idea/
*.tmproj
`

// Create creates a new chart in a directory.
//
// Inside of dir, this will create a directory based on the name of
// chartfile.Name. It will then write the Chart.yaml into this directory and
// create the (empty) appropriate directories.
//
// The returned string will point to the newly created directory. It will be
// an absolute path, even if the provided base directory was relative.
//
// If dir does not exist, this will return an error.
// If Chart.yaml or any directories cannot be created, this will return an
// error. In such a case, this will attempt to clean up by removing the
// new chart directory.
func Create(chartfile *chart.Metadata, dir string) (string, error) {
	path, err := filepath.Abs(dir)
	if err != nil {
		return path, err
	}

	if fi, err := os.Stat(path); err != nil {
		return path, err
	} else if !fi.IsDir() {
		return path, fmt.Errorf("no such directory %s", path)
	}

	n := chartfile.Name
	cdir := filepath.Join(path, n)
	if fi, err := os.Stat(cdir); err == nil && !fi.IsDir() {
		return cdir, fmt.Errorf("file %s already exists and is not a directory", cdir)
	}
	if err := os.MkdirAll(cdir, 0755); err != nil {
		return cdir, err
	}

	if err := SaveChartfile(filepath.Join(cdir, ChartfileName), chartfile); err != nil {
		return cdir, err
	}

	val := []byte(fmt.Sprintf(defaultValues, chartfile.Name))
	if err := ioutil.WriteFile(filepath.Join(cdir, ValuesfileName), val, 0644); err != nil {
		return cdir, err
	}

	val = []byte(defaultIgnore)
	if err := ioutil.WriteFile(filepath.Join(cdir, IgnorefileName), val, 0644); err != nil {
		return cdir, err
	}

	for _, d := range []string{TemplatesDir, ChartsDir} {
		if err := os.MkdirAll(filepath.Join(cdir, d), 0755); err != nil {
			return cdir, err
		}
	}
	return cdir, nil
}
<commit_msg>Add deployment, service and NOTES to create<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 chartutil

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

	"k8s.io/helm/pkg/proto/hapi/chart"
)

const (
	// ChartfileName is the default Chart file name.
	ChartfileName = "Chart.yaml"
	// ValuesfileName is the default values file name.
	ValuesfileName = "values.yaml"
	// TemplatesDir is the relative directory name for templates.
	TemplatesDir = "templates"
	// ChartsDir is the relative directory name for charts dependencies.
	ChartsDir = "charts"
	// IgnorefileName is the name of the Helm ignore file.
	IgnorefileName = ".helmignore"
	// DeploymentName is the name of the example deployment file.
	DeploymentName = "deployment.yaml"
	// ServiceName is the name of the example service file.
	ServiceName = "service.yaml"
	// NotesName is the name of the example NOTES.txt file.
	NotesName = "NOTES.txt"
	// HelpersName is the name of the example NOTES.txt file.
	HelpersName = "_helpers.tpl"
)

const defaultValues = `# Default values for %s.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
replicaCount: 1
image:
  repository: nginx
  tag: stable
  pullPolicy: IfNotPresent
service:
  name: nginx
  type: ClusterIP
  externalPort: 80
  internalPort: 80
`

const defaultIgnore = `# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*~
# Various IDEs
.project
.idea/
*.tmproj
`

const defaultDeployment = `apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: {{ template "fullname" . }}
  labels:
    chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
spec:
  replicas: {{ .Values.replicaCount }}
  template:
    metadata:
      labels:
        app: {{ template "fullname" . }}
    spec:
      containers:
      - name: nginx
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
        imagePullPolicy: {{ .Values.image.pullPolicy }}
        ports:
        - containerPort: {{ .Values.service.internalPort }}
`

const defaultService = `apiVersion: v1
kind: Service
metadata:
  name: {{ template "fullname" . }}
  labels:
    chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
spec:
  type: {{ .Values.service.type }}
  ports:
  - port: {{ .Values.service.externalPort }}
    targetPort: {{ .Values.service.internalPort }}
    protocol: TCP
    name: {{ .Values.service.name }}
  selector:
    app: {{ template "fullname" . }}
`

const defaultNotes = `1. Get the application URL by running these commands:
{{- if contains "NodePort" .Values.service.type }}
  export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "fullname" . }})
  export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
  echo http://$NODE_IP:$NODE_PORT/login
{{- else if contains "LoadBalancer" .Values.service.type }}
**** NOTE: It may take a few minutes for the LoadBalancer IP to be available.                      ****
****       You can watch the status of by running 'kubectl get svc -w {{ template "fullname" . }}' ****
  export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
  echo http://$SERVICE_IP:{{ .Values.Master.ServicePort }}
{{- else if contains "ClusterIP"  .Values.service.type }}
  export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "component={{ template "fullname" . }}-master" -o jsonpath="{.items[0].metadata.name}")
  echo http://127.0.0.1:{{ .Values.service.externalPort }}
  kubectl port-forward $POD_NAME {{ .Values.service.externalPort }}:{{ .Values.service.externalPort }}
{{- end }}
`

const defaultHelpers = `{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 24 -}}
{{- end -}}

{{/*
Create a default fully qualified app name.
We truncate at 24 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
*/}}
{{- define "fullname" -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- printf "%s-%s" .Release.Name $name | trunc 24 -}}
{{- end -}}
`

// Create creates a new chart in a directory.
//
// Inside of dir, this will create a directory based on the name of
// chartfile.Name. It will then write the Chart.yaml into this directory and
// create the (empty) appropriate directories.
//
// The returned string will point to the newly created directory. It will be
// an absolute path, even if the provided base directory was relative.
//
// If dir does not exist, this will return an error.
// If Chart.yaml or any directories cannot be created, this will return an
// error. In such a case, this will attempt to clean up by removing the
// new chart directory.
func Create(chartfile *chart.Metadata, dir string) (string, error) {
	path, err := filepath.Abs(dir)
	if err != nil {
		return path, err
	}

	if fi, err := os.Stat(path); err != nil {
		return path, err
	} else if !fi.IsDir() {
		return path, fmt.Errorf("no such directory %s", path)
	}

	n := chartfile.Name
	cdir := filepath.Join(path, n)
	if fi, err := os.Stat(cdir); err == nil && !fi.IsDir() {
		return cdir, fmt.Errorf("file %s already exists and is not a directory", cdir)
	}
	if err := os.MkdirAll(cdir, 0755); err != nil {
		return cdir, err
	}

	if err := SaveChartfile(filepath.Join(cdir, ChartfileName), chartfile); err != nil {
		return cdir, err
	}

	val := []byte(fmt.Sprintf(defaultValues, chartfile.Name))
	if err := ioutil.WriteFile(filepath.Join(cdir, ValuesfileName), val, 0644); err != nil {
		return cdir, err
	}

	val = []byte(defaultIgnore)
	if err := ioutil.WriteFile(filepath.Join(cdir, IgnorefileName), val, 0644); err != nil {
		return cdir, err
	}

	for _, d := range []string{TemplatesDir, ChartsDir} {
		if err := os.MkdirAll(filepath.Join(cdir, d), 0755); err != nil {
			return cdir, err
		}
	}

	// Write out deployment.yaml
	val = []byte(defaultDeployment)
	if err := ioutil.WriteFile(filepath.Join(cdir, TemplatesDir, DeploymentName), val, 0644); err != nil {
			return cdir, err
	}

	// Write out service.yaml
	val = []byte(defaultService)
	if err := ioutil.WriteFile(filepath.Join(cdir, TemplatesDir, ServiceName), val, 0644); err != nil {
			return cdir, err
	}

	// Write out NOTES.txt
	val = []byte(defaultNotes)
	if err := ioutil.WriteFile(filepath.Join(cdir, TemplatesDir, NotesName), val, 0644); err != nil {
			return cdir, err
	}

	// Write out _helpers.tpl
	val = []byte(defaultHelpers)
	if err := ioutil.WriteFile(filepath.Join(cdir, TemplatesDir, HelpersName), val, 0644); err != nil {
			return cdir, err
	}
	return cdir, nil
}
<|endoftext|>


<commit_before>package client

import (
	"context"

	"github.com/sethvargo/go-envconfig"
)

type Env struct {
	LoginAuthURL       string `env:"TELEPRESENCE_LOGIN_AUTH_URL,default=https://auth.datawire.io/auth"`
	LoginTokenURL      string `env:"TELEPRESENCE_LOGIN_TOKEN_URL,default=https://auth.datawire.io/token"`
	LoginCompletionURL string `env:"TELEPRESENCE_LOGIN_COMPLETION_URL,default=https://auth.datawire.io/completion"`
	LoginClientID      string `env:"TELEPRESENCE_LOGIN_CLIENT_ID,default=telepresence-cli"`

	Registry string `env:"TELEPRESENCE_REGISTRY,default=docker.io/datawire"`

	SystemAHost string `env:"SYSTEMA_HOST,default="`
	SystemAPort string `env:"SYSTEMA_PORT,default="`
}

func LoadEnv(ctx context.Context) (Env, error) {
	var env Env
	err := envconfig.Process(ctx, &env)
	return env, err
}
<commit_msg>CLI: Add a SYSTEMA_ENV variable to easily adjust staging/prod<commit_after>package client

import (
	"context"
	"os"

	"github.com/sethvargo/go-envconfig"
)

type Env struct {
	LoginDomain        string `env:"TELEPRESENCE_LOGIN_DOMAIN,required"`
	LoginAuthURL       string `env:"TELEPRESENCE_LOGIN_AUTH_URL,default=https://${TELEPRESENCE_LOGIN_DOMAIN}/auth"`
	LoginTokenURL      string `env:"TELEPRESENCE_LOGIN_TOKEN_URL,default=https://${TELEPRESENCE_LOGIN_DOMAIN}/token"`
	LoginCompletionURL string `env:"TELEPRESENCE_LOGIN_COMPLETION_URL,default=https://${TELEPRESENCE_LOGIN_DOMAIN}/completion"`
	LoginClientID      string `env:"TELEPRESENCE_LOGIN_CLIENT_ID,default=telepresence-cli"`

	Registry string `env:"TELEPRESENCE_REGISTRY,default=docker.io/datawire"`

	SystemAHost string `env:"SYSTEMA_HOST,default="`
	SystemAPort string `env:"SYSTEMA_PORT,default="`
}

func maybeSetEnv(key, val string) {
	if os.Getenv(key) == "" {
		os.Setenv(key, val)
	}
}

func LoadEnv(ctx context.Context) (Env, error) {
	switch os.Getenv("SYSTEMA_ENV") {
	case "staging":
		maybeSetEnv("TELEPRESENCE_LOGIN_DOMAIN", "beta-auth.datawire.io")
		maybeSetEnv("SYSTEMA_HOST", "beta-app.datawire.io")
	default:
		maybeSetEnv("TELEPRESENCE_LOGIN_DOMAIN", "auth.datawire.io")
	}

	var env Env
	err := envconfig.Process(ctx, &env)
	return env, err
}
<|endoftext|>


<commit_before>package cmd

import (
	"errors"
	"fmt"
	"io"

	"github.com/spf13/cobra"

	"k8s.io/apimachinery/pkg/api/meta"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	kapi "k8s.io/kubernetes/pkg/api"
	kcmd "k8s.io/kubernetes/pkg/kubectl/cmd"
	kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
	"k8s.io/kubernetes/pkg/kubectl/resource"

	buildapi "github.com/openshift/origin/pkg/build/api"
	buildutil "github.com/openshift/origin/pkg/build/util"
	osclient "github.com/openshift/origin/pkg/client"
	"github.com/openshift/origin/pkg/cmd/templates"
	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
	deployapi "github.com/openshift/origin/pkg/deploy/api"
)

// LogsRecommendedCommandName is the recommended command name
// TODO: Probably move this pattern upstream?
const LogsRecommendedCommandName = "logs"

var (
	logsLong = templates.LongDesc(`
		Print the logs for a resource

		Supported resources are builds, build configs (bc), deployment configs (dc), and pods.
		When a pod is specified and has more than one container, the container name should be
		specified via -c. When a build config or deployment config is specified, you can view
		the logs for a particular version of it via --version.

		If your pod is failing to start, you may need to use the --previous option to see the
		logs of the last attempt.`)

	logsExample = templates.Examples(`
		# Start streaming the logs of the most recent build of the openldap build config.
	  %[1]s %[2]s -f bc/openldap

	  # Start streaming the logs of the latest deployment of the mysql deployment config.
	  %[1]s %[2]s -f dc/mysql

	  # Get the logs of the first deployment for the mysql deployment config. Note that logs
	  # from older deployments may not exist either because the deployment was successful
	  # or due to deployment pruning or manual deletion of the deployment.
	  %[1]s %[2]s --version=1 dc/mysql

	  # Return a snapshot of ruby-container logs from pod backend.
	  %[1]s %[2]s backend -c ruby-container

	  # Start streaming of ruby-container logs from pod backend.
	  %[1]s %[2]s -f pod/backend -c ruby-container`)
)

// OpenShiftLogsOptions holds all the necessary options for running oc logs.
type OpenShiftLogsOptions struct {
	// Options should hold our own *LogOptions objects.
	Options runtime.Object
	// KubeLogOptions contains all the necessary options for
	// running the upstream logs command.
	KubeLogOptions *kcmd.LogsOptions
	// Client enables access to the Build object when processing
	// build logs for Jenkins Pipeline Strategy builds
	Client osclient.BuildsNamespacer
	// Namespace is a required parameter when accessing the Build object when processing
	// build logs for Jenkins Pipeline Strategy builds
	Namespace string
}

// NewCmdLogs creates a new logs command that supports OpenShift resources.
func NewCmdLogs(name, baseName string, f *clientcmd.Factory, out io.Writer) *cobra.Command {
	o := OpenShiftLogsOptions{
		KubeLogOptions: &kcmd.LogsOptions{},
	}

	cmd := kcmd.NewCmdLogs(f, out)
	cmd.Short = "Print the logs for a resource"
	cmd.Long = logsLong
	cmd.Example = fmt.Sprintf(logsExample, baseName, name)
	cmd.SuggestFor = []string{"builds", "deployments"}
	cmd.Run = func(cmd *cobra.Command, args []string) {
		kcmdutil.CheckErr(o.Complete(f, cmd, args, out))

		if err := o.Validate(); err != nil {
			kcmdutil.CheckErr(kcmdutil.UsageError(cmd, err.Error()))
		}

		kcmdutil.CheckErr(o.RunLog())
	}

	cmd.Flags().Int64("version", 0, "View the logs of a particular build or deployment by version if greater than zero")

	return cmd
}

func isPipelineBuild(obj runtime.Object) (bool, *buildapi.BuildConfig, bool, *buildapi.Build, bool) {
	bc, isBC := obj.(*buildapi.BuildConfig)
	build, isBld := obj.(*buildapi.Build)
	isPipeline := false
	switch {
	case isBC:
		isPipeline = bc.Spec.CommonSpec.Strategy.JenkinsPipelineStrategy != nil
	case isBld:
		isPipeline = build.Spec.CommonSpec.Strategy.JenkinsPipelineStrategy != nil
	}
	return isPipeline, bc, isBC, build, isBld
}

// Complete calls the upstream Complete for the logs command and then resolves the
// resource a user requested to view its logs and creates the appropriate logOptions
// object for it.
func (o *OpenShiftLogsOptions) Complete(f *clientcmd.Factory, cmd *cobra.Command, args []string, out io.Writer) error {
	if err := o.KubeLogOptions.Complete(f, out, cmd, args); err != nil {
		return err
	}
	namespace, _, err := f.DefaultNamespace()
	if err != nil {
		return err
	}
	o.Namespace = namespace

	podLogOptions := o.KubeLogOptions.Options.(*kapi.PodLogOptions)

	mapper, typer := f.Object()
	infos, err := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), kapi.Codecs.UniversalDecoder()).
		NamespaceParam(o.Namespace).DefaultNamespace().
		ResourceNames("pods", args...).
		SingleResourceType().RequireObject(false).
		Do().Infos()
	if err != nil {
		return err
	}
	if len(infos) != 1 {
		return errors.New("expected a resource")
	}

	client, _, err := f.Clients()
	if err != nil {
		return err
	}
	o.Client = client

	version := kcmdutil.GetFlagInt64(cmd, "version")
	_, resource := meta.KindToResource(infos[0].Mapping.GroupVersionKind)

	gr := resource.GroupResource()
	// TODO: podLogOptions should be included in our own logOptions objects.
	switch {
	case buildapi.IsResourceOrLegacy("build", gr), buildapi.IsResourceOrLegacy("buildconfig", gr):
		bopts := &buildapi.BuildLogOptions{
			Follow:       podLogOptions.Follow,
			Previous:     podLogOptions.Previous,
			SinceSeconds: podLogOptions.SinceSeconds,
			SinceTime:    podLogOptions.SinceTime,
			Timestamps:   podLogOptions.Timestamps,
			TailLines:    podLogOptions.TailLines,
			LimitBytes:   podLogOptions.LimitBytes,
		}
		if version != 0 {
			bopts.Version = &version
		}
		o.Options = bopts

	case deployapi.IsResourceOrLegacy("deploymentconfig", gr):
		dopts := &deployapi.DeploymentLogOptions{
			Follow:       podLogOptions.Follow,
			Previous:     podLogOptions.Previous,
			SinceSeconds: podLogOptions.SinceSeconds,
			SinceTime:    podLogOptions.SinceTime,
			Timestamps:   podLogOptions.Timestamps,
			TailLines:    podLogOptions.TailLines,
			LimitBytes:   podLogOptions.LimitBytes,
		}
		if version != 0 {
			dopts.Version = &version
		}
		o.Options = dopts
	default:
		o.Options = nil
	}

	return nil
}

// Validate runs the upstream validation for the logs command and then it
// will validate any OpenShift-specific log options.
func (o OpenShiftLogsOptions) Validate() error {
	if err := o.KubeLogOptions.Validate(); err != nil {
		return err
	}
	if o.Options == nil {
		return nil
	}
	switch t := o.Options.(type) {
	case *buildapi.BuildLogOptions:
		if t.Previous && t.Version != nil {
			return errors.New("cannot use both --previous and --version")
		}
	case *deployapi.DeploymentLogOptions:
		if t.Previous && t.Version != nil {
			return errors.New("cannot use both --previous and --version")
		}
	default:
		return errors.New("invalid log options object provided")
	}
	return nil
}

// RunLog will run the upstream logs command and may use an OpenShift
// logOptions object.
func (o OpenShiftLogsOptions) RunLog() error {
	if o.Options != nil {
		// Use our own options object.
		o.KubeLogOptions.Options = o.Options
	}
	isPipeline, bc, isBC, build, isBld := isPipelineBuild(o.KubeLogOptions.Object)
	if !isPipeline {
		return o.KubeLogOptions.RunLogs()
	}

	switch {
	case isBC:
		buildName := buildutil.BuildNameForConfigVersion(bc.ObjectMeta.Name, int(bc.Status.LastVersion))
		build, _ = o.Client.Builds(o.Namespace).Get(buildName, metav1.GetOptions{})
		if build == nil {
			return errors.New(fmt.Sprintf("The build %s for build config %s was not found", buildName, bc.ObjectMeta.Name))
		}
		fallthrough
	case isBld:
		urlString, _ := build.Annotations[buildapi.BuildJenkinsBlueOceanLogURLAnnotation]
		if len(urlString) == 0 {
			return errors.New(fmt.Sprintf("The build %s did not have the correct log URL", build.ObjectMeta.Name))
		}
		o.KubeLogOptions.Out.Write([]byte(fmt.Sprintf("info: Logs available at %s\n", urlString)))
	default:
		return errors.New(fmt.Sprintf("A pipeline strategy build log operation peformed against invalid object %#v", o.KubeLogOptions.Object))
	}

	return nil
}
<commit_msg>soften pipeline log missing annotation msg<commit_after>package cmd

import (
	"errors"
	"fmt"
	"io"

	"github.com/spf13/cobra"

	"k8s.io/apimachinery/pkg/api/meta"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	kapi "k8s.io/kubernetes/pkg/api"
	kcmd "k8s.io/kubernetes/pkg/kubectl/cmd"
	kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
	"k8s.io/kubernetes/pkg/kubectl/resource"

	buildapi "github.com/openshift/origin/pkg/build/api"
	buildutil "github.com/openshift/origin/pkg/build/util"
	osclient "github.com/openshift/origin/pkg/client"
	"github.com/openshift/origin/pkg/cmd/templates"
	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
	deployapi "github.com/openshift/origin/pkg/deploy/api"
)

// LogsRecommendedCommandName is the recommended command name
// TODO: Probably move this pattern upstream?
const LogsRecommendedCommandName = "logs"

var (
	logsLong = templates.LongDesc(`
		Print the logs for a resource

		Supported resources are builds, build configs (bc), deployment configs (dc), and pods.
		When a pod is specified and has more than one container, the container name should be
		specified via -c. When a build config or deployment config is specified, you can view
		the logs for a particular version of it via --version.

		If your pod is failing to start, you may need to use the --previous option to see the
		logs of the last attempt.`)

	logsExample = templates.Examples(`
		# Start streaming the logs of the most recent build of the openldap build config.
	  %[1]s %[2]s -f bc/openldap

	  # Start streaming the logs of the latest deployment of the mysql deployment config.
	  %[1]s %[2]s -f dc/mysql

	  # Get the logs of the first deployment for the mysql deployment config. Note that logs
	  # from older deployments may not exist either because the deployment was successful
	  # or due to deployment pruning or manual deletion of the deployment.
	  %[1]s %[2]s --version=1 dc/mysql

	  # Return a snapshot of ruby-container logs from pod backend.
	  %[1]s %[2]s backend -c ruby-container

	  # Start streaming of ruby-container logs from pod backend.
	  %[1]s %[2]s -f pod/backend -c ruby-container`)
)

// OpenShiftLogsOptions holds all the necessary options for running oc logs.
type OpenShiftLogsOptions struct {
	// Options should hold our own *LogOptions objects.
	Options runtime.Object
	// KubeLogOptions contains all the necessary options for
	// running the upstream logs command.
	KubeLogOptions *kcmd.LogsOptions
	// Client enables access to the Build object when processing
	// build logs for Jenkins Pipeline Strategy builds
	Client osclient.BuildsNamespacer
	// Namespace is a required parameter when accessing the Build object when processing
	// build logs for Jenkins Pipeline Strategy builds
	Namespace string
}

// NewCmdLogs creates a new logs command that supports OpenShift resources.
func NewCmdLogs(name, baseName string, f *clientcmd.Factory, out io.Writer) *cobra.Command {
	o := OpenShiftLogsOptions{
		KubeLogOptions: &kcmd.LogsOptions{},
	}

	cmd := kcmd.NewCmdLogs(f, out)
	cmd.Short = "Print the logs for a resource"
	cmd.Long = logsLong
	cmd.Example = fmt.Sprintf(logsExample, baseName, name)
	cmd.SuggestFor = []string{"builds", "deployments"}
	cmd.Run = func(cmd *cobra.Command, args []string) {
		kcmdutil.CheckErr(o.Complete(f, cmd, args, out))

		if err := o.Validate(); err != nil {
			kcmdutil.CheckErr(kcmdutil.UsageError(cmd, err.Error()))
		}

		kcmdutil.CheckErr(o.RunLog())
	}

	cmd.Flags().Int64("version", 0, "View the logs of a particular build or deployment by version if greater than zero")

	return cmd
}

func isPipelineBuild(obj runtime.Object) (bool, *buildapi.BuildConfig, bool, *buildapi.Build, bool) {
	bc, isBC := obj.(*buildapi.BuildConfig)
	build, isBld := obj.(*buildapi.Build)
	isPipeline := false
	switch {
	case isBC:
		isPipeline = bc.Spec.CommonSpec.Strategy.JenkinsPipelineStrategy != nil
	case isBld:
		isPipeline = build.Spec.CommonSpec.Strategy.JenkinsPipelineStrategy != nil
	}
	return isPipeline, bc, isBC, build, isBld
}

// Complete calls the upstream Complete for the logs command and then resolves the
// resource a user requested to view its logs and creates the appropriate logOptions
// object for it.
func (o *OpenShiftLogsOptions) Complete(f *clientcmd.Factory, cmd *cobra.Command, args []string, out io.Writer) error {
	if err := o.KubeLogOptions.Complete(f, out, cmd, args); err != nil {
		return err
	}
	namespace, _, err := f.DefaultNamespace()
	if err != nil {
		return err
	}
	o.Namespace = namespace

	podLogOptions := o.KubeLogOptions.Options.(*kapi.PodLogOptions)

	mapper, typer := f.Object()
	infos, err := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), kapi.Codecs.UniversalDecoder()).
		NamespaceParam(o.Namespace).DefaultNamespace().
		ResourceNames("pods", args...).
		SingleResourceType().RequireObject(false).
		Do().Infos()
	if err != nil {
		return err
	}
	if len(infos) != 1 {
		return errors.New("expected a resource")
	}

	client, _, err := f.Clients()
	if err != nil {
		return err
	}
	o.Client = client

	version := kcmdutil.GetFlagInt64(cmd, "version")
	_, resource := meta.KindToResource(infos[0].Mapping.GroupVersionKind)

	gr := resource.GroupResource()
	// TODO: podLogOptions should be included in our own logOptions objects.
	switch {
	case buildapi.IsResourceOrLegacy("build", gr), buildapi.IsResourceOrLegacy("buildconfig", gr):
		bopts := &buildapi.BuildLogOptions{
			Follow:       podLogOptions.Follow,
			Previous:     podLogOptions.Previous,
			SinceSeconds: podLogOptions.SinceSeconds,
			SinceTime:    podLogOptions.SinceTime,
			Timestamps:   podLogOptions.Timestamps,
			TailLines:    podLogOptions.TailLines,
			LimitBytes:   podLogOptions.LimitBytes,
		}
		if version != 0 {
			bopts.Version = &version
		}
		o.Options = bopts

	case deployapi.IsResourceOrLegacy("deploymentconfig", gr):
		dopts := &deployapi.DeploymentLogOptions{
			Follow:       podLogOptions.Follow,
			Previous:     podLogOptions.Previous,
			SinceSeconds: podLogOptions.SinceSeconds,
			SinceTime:    podLogOptions.SinceTime,
			Timestamps:   podLogOptions.Timestamps,
			TailLines:    podLogOptions.TailLines,
			LimitBytes:   podLogOptions.LimitBytes,
		}
		if version != 0 {
			dopts.Version = &version
		}
		o.Options = dopts
	default:
		o.Options = nil
	}

	return nil
}

// Validate runs the upstream validation for the logs command and then it
// will validate any OpenShift-specific log options.
func (o OpenShiftLogsOptions) Validate() error {
	if err := o.KubeLogOptions.Validate(); err != nil {
		return err
	}
	if o.Options == nil {
		return nil
	}
	switch t := o.Options.(type) {
	case *buildapi.BuildLogOptions:
		if t.Previous && t.Version != nil {
			return errors.New("cannot use both --previous and --version")
		}
	case *deployapi.DeploymentLogOptions:
		if t.Previous && t.Version != nil {
			return errors.New("cannot use both --previous and --version")
		}
	default:
		return errors.New("invalid log options object provided")
	}
	return nil
}

// RunLog will run the upstream logs command and may use an OpenShift
// logOptions object.
func (o OpenShiftLogsOptions) RunLog() error {
	if o.Options != nil {
		// Use our own options object.
		o.KubeLogOptions.Options = o.Options
	}
	isPipeline, bc, isBC, build, isBld := isPipelineBuild(o.KubeLogOptions.Object)
	if !isPipeline {
		return o.KubeLogOptions.RunLogs()
	}

	switch {
	case isBC:
		buildName := buildutil.BuildNameForConfigVersion(bc.ObjectMeta.Name, int(bc.Status.LastVersion))
		build, _ = o.Client.Builds(o.Namespace).Get(buildName, metav1.GetOptions{})
		if build == nil {
			return errors.New(fmt.Sprintf("The build %s for build config %s was not found", buildName, bc.ObjectMeta.Name))
		}
		fallthrough
	case isBld:
		urlString, _ := build.Annotations[buildapi.BuildJenkinsBlueOceanLogURLAnnotation]
		if len(urlString) == 0 {
			return errors.New(fmt.Sprintf("The pipeline strategy build %s does not yet contain the log URL; wait a few moments, then try again", build.ObjectMeta.Name))
		}
		o.KubeLogOptions.Out.Write([]byte(fmt.Sprintf("info: Logs available at %s\n", urlString)))
	default:
		return errors.New(fmt.Sprintf("A pipeline strategy build log operation peformed against invalid object %#v", o.KubeLogOptions.Object))
	}

	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2016 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 node

import (
	"fmt"
	"io/ioutil"
	"strings"

	unversionedcertificates "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/certificates/unversioned"
	"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
	clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
	kubeadmapi "k8s.io/kubernetes/pkg/kubeadm/api"
	kubeadmutil "k8s.io/kubernetes/pkg/kubeadm/util"
	"k8s.io/kubernetes/pkg/kubelet/util/csr"
	certutil "k8s.io/kubernetes/pkg/util/cert"
)

func getNodeName() string {
	return "TODO"
}

func PerformTLSBootstrapFromConfig(s *kubeadmapi.KubeadmConfig) (*clientcmdapi.Config, error) {
	caCert, err := ioutil.ReadFile(s.ManualFlags.CaCertFile)
	if err != nil {
		return nil, fmt.Errorf("<node/csr> failed to load CA certificate [%s]", err)
	}

	return PerformTLSBootstrap(s, strings.Split(s.ManualFlags.ApiServerURLs, ",")[0], caCert)
}

// Create a restful client for doing the certificate signing request.
func PerformTLSBootstrap(s *kubeadmapi.KubeadmConfig, apiEndpoint string, caCert []byte) (*clientcmdapi.Config, error) {
	// TODO try all the api servers until we find one that works
	bareClientConfig := kubeadmutil.CreateBasicClientConfig("kubernetes", apiEndpoint, caCert)

	nodeName := getNodeName()

	bootstrapClientConfig, err := clientcmd.NewDefaultClientConfig(
		*kubeadmutil.MakeClientConfigWithToken(
			bareClientConfig, "kubernetes", fmt.Sprintf("kubelet-%s", nodeName), s.Secrets.BearerToken,
		),
		&clientcmd.ConfigOverrides{},
	).ClientConfig()
	if err != nil {
		return nil, fmt.Errorf("<node/csr> failed to create API client configuration [%s]", err)
	}

	client, err := unversionedcertificates.NewForConfig(bootstrapClientConfig)
	if err != nil {
		return nil, fmt.Errorf("<node/csr> failed to create API client [%s]", err)
	}
	csrClient := client.CertificateSigningRequests()

	fmt.Println("<node/csr> created API client to obtain unique certificate for this node, generating keys and certificate signing request")

	key, err := certutil.MakeEllipticPrivateKeyPEM()
	if err != nil {
		return nil, fmt.Errorf("<node/csr> failed to generating private key [%s]", err)
	}

	cert, err := csr.RequestNodeCertificate(csrClient, key, nodeName)
	if err != nil {
		return nil, fmt.Errorf("<node/csr> failed to request signed certificate from the API server [%s]", err)
	}

	// TODO print some basic info about the cert
	fmt.Println("<node/csr> received signed certificate from the API server, generating kubelet configuration")

	finalConfig := kubeadmutil.MakeClientConfigWithCerts(
		bareClientConfig, "kubernetes", fmt.Sprintf("kubelet-%s", nodeName),
		key, cert,
	)

	return finalConfig, nil
}
<commit_msg>Check that sever API provides certificates capabilities<commit_after>/*
Copyright 2016 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 node

import (
	"fmt"
	"io/ioutil"
	"strings"

	"k8s.io/kubernetes/pkg/apis/certificates"
	unversionedcertificates "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/certificates/unversioned"
	"k8s.io/kubernetes/pkg/client/restclient"
	"k8s.io/kubernetes/pkg/client/typed/discovery"
	"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
	clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
	kubeadmapi "k8s.io/kubernetes/pkg/kubeadm/api"
	kubeadmutil "k8s.io/kubernetes/pkg/kubeadm/util"
	"k8s.io/kubernetes/pkg/kubelet/util/csr"
	certutil "k8s.io/kubernetes/pkg/util/cert"
)

func getNodeName() string {
	return "TODO"
}

func PerformTLSBootstrapFromConfig(s *kubeadmapi.KubeadmConfig) (*clientcmdapi.Config, error) {
	caCert, err := ioutil.ReadFile(s.ManualFlags.CaCertFile)
	if err != nil {
		return nil, fmt.Errorf("<node/csr> failed to load CA certificate [%s]", err)
	}

	return PerformTLSBootstrap(s, strings.Split(s.ManualFlags.ApiServerURLs, ",")[0], caCert)
}

// Create a restful client for doing the certificate signing request.
func PerformTLSBootstrap(s *kubeadmapi.KubeadmConfig, apiEndpoint string, caCert []byte) (*clientcmdapi.Config, error) {
	// TODO try all the api servers until we find one that works
	bareClientConfig := kubeadmutil.CreateBasicClientConfig("kubernetes", apiEndpoint, caCert)

	nodeName := getNodeName()

	bootstrapClientConfig, err := clientcmd.NewDefaultClientConfig(
		*kubeadmutil.MakeClientConfigWithToken(
			bareClientConfig, "kubernetes", fmt.Sprintf("kubelet-%s", nodeName), s.Secrets.BearerToken,
		),
		&clientcmd.ConfigOverrides{},
	).ClientConfig()
	if err != nil {
		return nil, fmt.Errorf("<node/csr> failed to create API client configuration [%s]", err)
	}

	err = checkCertsAPI(bootstrapClientConfig)

	if err != nil {
		return nil, fmt.Errorf("<node/csr> API compatibility error [%s]", err)
	}

	client, err := unversionedcertificates.NewForConfig(bootstrapClientConfig)
	if err != nil {
		return nil, fmt.Errorf("<node/csr> failed to create API client [%s]", err)
	}
	csrClient := client.CertificateSigningRequests()

	fmt.Println("<node/csr> created API client to obtain unique certificate for this node, generating keys and certificate signing request")

	key, err := certutil.MakeEllipticPrivateKeyPEM()
	if err != nil {
		return nil, fmt.Errorf("<node/csr> failed to generating private key [%s]", err)
	}

	cert, err := csr.RequestNodeCertificate(csrClient, key, nodeName)
	if err != nil {
		return nil, fmt.Errorf("<node/csr> failed to request signed certificate from the API server [%s]", err)
	}

	// TODO print some basic info about the cert
	fmt.Println("<node/csr> received signed certificate from the API server, generating kubelet configuration")

	finalConfig := kubeadmutil.MakeClientConfigWithCerts(
		bareClientConfig, "kubernetes", fmt.Sprintf("kubelet-%s", nodeName),
		key, cert,
	)

	return finalConfig, nil
}

func checkCertsAPI(config *restclient.Config) error {
	discoveryClient, err := discovery.NewDiscoveryClientForConfig(config)

	if err != nil {
		return fmt.Errorf("failed to create API discovery client [%s]", err)
	}

	serverGroups, err := discoveryClient.ServerGroups()

	if err != nil {
		return fmt.Errorf("failed to retrieve a list of supported API objects [%s]", err)
	}

	for _, group := range serverGroups.Groups {
		if group.Name == certificates.GroupName {
			return nil
		}
	}

	version, err := discoveryClient.ServerVersion()
	serverVersion := version.String()

	if err != nil {
		serverVersion = "N/A"
	}

	// Due to changes in API namespaces for certificates
	// https://github.com/kubernetes/kubernetes/pull/31887/
	// it is compatible only with versions released after v1.4.0-beta.0
	return fmt.Errorf("installed Kubernetes API server version \"%s\" does not support certificates signing request use v1.4.0 or newer", serverVersion)
}
<|endoftext|>


<commit_before>// Copyright 2016 DeepFabric, 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,
// See the License for the specific language governing permissions and
// limitations under the License.

package pdserver

import (
	"errors"
	"sync"
	"time"

	"github.com/deepfabric/elasticell/pkg/codec"
	"github.com/deepfabric/elasticell/pkg/log"
	"github.com/deepfabric/elasticell/pkg/pb/pdpb"
	"github.com/deepfabric/elasticell/pkg/util"
	"github.com/fagongzi/goetty"
)

var (
	errConnect = errors.New("not connected")
)

const (
	ready = iota
	paused
)

func cmp(a, b interface{}) bool {
	return a.(*notify).watcher == b.(*notify).watcher
}

type notify struct {
	watcher string
	offset  uint64
}

func newWatcherState(watcher string) *watcherState {
	return &watcherState{
		watcher: watcher,
		state:   ready,
		q:       util.NewOffsetQueue(),
	}
}

type watcherState struct {
	watcher          string
	state            int
	hbTimeout        *goetty.Timeout
	q                *util.OffsetQueue
	lastNotifyOffset uint64
}

func (state *watcherState) reset() {
	state.cancelTimeout()
	state.state = ready
	state.q = util.NewOffsetQueue()
	state.lastNotifyOffset = 0

	log.Debugf("notify: %s reseted", state.watcher)
}

func (state *watcherState) pause() {
	state.reset()
	state.state = paused
	log.Debugf("notify: %s reset to pause", state.watcher)
}

func (state *watcherState) isReady() bool {
	return state.state == ready
}

func (state *watcherState) isPause() bool {
	return state.state == paused
}

func (state *watcherState) addNotify(info *pdpb.Range) uint64 {
	return state.q.Add(info)
}

func (state *watcherState) cancelTimeout() {
	if state.hbTimeout != nil {
		state.hbTimeout.Stop()
		state.hbTimeout = nil
	}
}

func (state *watcherState) resetTimeout(timeout time.Duration, fn func(interface{})) {
	state.cancelTimeout()

	t, _ := util.DefaultTimeoutWheel().Schedule(timeout, fn, state.watcher)
	state.hbTimeout = &t
}

// watcherNotifier is used for notify the newest cell info to all watchers
type watcherNotifier struct {
	sync.RWMutex

	notifies *util.Queue
	pool     *goetty.AddressBasedPool
	watchers map[string]*watcherState
	timeout  time.Duration
}

func newWatcherNotifier(timeout time.Duration) *watcherNotifier {
	wn := &watcherNotifier{
		notifies: util.New(1024),
		watchers: make(map[string]*watcherState),
		timeout:  timeout,
	}

	wn.pool = goetty.NewAddressBasedPool(createConn, wn)
	return wn
}

func (wn *watcherNotifier) start() {
	go func() {
		batch := int64(64)
		items := make([]interface{}, batch, batch)

		for {
			n, err := wn.notifies.Get(int64(batch), items)
			if err != nil {
				log.Infof("stop: watcher notifier stopped")
				return
			}

			for i := int64(0); i < n; i++ {
				nt := items[i].(*notify)

				if !wn.allowNotify(nt.watcher) {
					continue
				}

				if !wn.allowSend(nt) {
					continue
				}

				conn, err := wn.pool.GetConn(nt.watcher)
				if err != nil {
					wn.pause(nt.watcher)
					log.Warnf("notify: %d to %s failed, errors:\n%+v",
						nt.offset,
						nt.watcher,
						err)
					continue
				}

				req := &pdpb.WatcherNotify{
					Offset: nt.offset,
				}
				err = conn.Write(req)
				if err != nil {
					wn.pause(nt.watcher)
					log.Warnf("notify: %d to %s failed, errors:\n%+v",
						nt.offset,
						nt.watcher,
						err)
					continue
				}
			}
		}
	}()
}

func (wn *watcherNotifier) stop() {
	wn.notifies.Dispose()
}

func (wn *watcherNotifier) removedAllWatcher() {
	wn.Lock()
	for watcher := range wn.watchers {
		wn.removeWatcher(watcher)
	}
	wn.Unlock()
}

// addWatcher add a new watcher for notify the newest cells info.
func (wn *watcherNotifier) addWatcher(addr string) {
	wn.Lock()

	if state, ok := wn.watchers[addr]; ok {
		state.cancelTimeout()
		state.reset()
	} else {
		wn.watchers[addr] = newWatcherState(addr)
	}

	wn.resetTimeout(addr)
	wn.Unlock()

	log.Warnf("notify: %s added", addr)
}

func (wn *watcherNotifier) resetTimeout(addr string) {
	wn.watchers[addr].resetTimeout(wn.timeout, wn.watcherTimeout)
}

// removeWatcher remove a watcher
func (wn *watcherNotifier) removeWatcher(addr string) {
	wn.Lock()
	delete(wn.watchers, addr)
	wn.pool.RemoveConn(addr)
	wn.Unlock()
}

// watcherHeartbeat return true if the watcher resume from pause.
func (wn *watcherNotifier) watcherHeartbeat(addr string, offset uint64) bool {
	wn.Lock()
	value := wn.resume(addr)
	if state, ok := wn.watchers[addr]; ok && !value {
		max := state.q.GetMaxOffset()
		if offset < max {
			wn.notifies.Put(&notify{
				watcher: addr,
				offset:  max,
			})
		}
	}
	wn.Unlock()
	return value
}

func (wn *watcherNotifier) watcherTimeout(arg interface{}) {
	wn.pause(arg.(string))
}

func (wn *watcherNotifier) allowNotify(addr string) bool {
	wn.Lock()
	if state, ok := wn.watchers[addr]; ok {
		allow := state.isReady()
		wn.Unlock()
		return allow
	}
	wn.Unlock()
	return false
}

func (wn *watcherNotifier) allowSend(nt *notify) bool {
	wn.Lock()
	if state, ok := wn.watchers[nt.watcher]; ok {
		allow := state.isReady() && state.lastNotifyOffset == 0 || state.lastNotifyOffset < nt.offset
		if allow {
			state.lastNotifyOffset = nt.offset
		}
		wn.Unlock()
		return allow
	}
	wn.Unlock()
	return false
}

func (wn *watcherNotifier) pause(addr string) {
	wn.Lock()
	wn.pool.RemoveConn(addr)
	if state, ok := wn.watchers[addr]; ok {
		state.pause()
	}
	wn.Unlock()
}

func (wn *watcherNotifier) resume(addr string) bool {
	if state, ok := wn.watchers[addr]; ok {
		resumeFromPause := state.isPause()

		if state.isPause() {
			state.state = ready
		}

		wn.resetTimeout(addr)
		return resumeFromPause
	}

	return false
}

func (wn *watcherNotifier) notify(info *pdpb.Range) {
	wn.Lock()

	for _, state := range wn.watchers {
		if state.isReady() {
			nt := &notify{
				watcher: state.watcher,
				offset:  state.addNotify(info),
			}
			wn.notifies.PutOrUpdate(cmp, nt)
		}
	}

	wn.Unlock()
}

func (wn *watcherNotifier) sync(addr string, offset uint64) *pdpb.WatcherNotifyRsp {
	wn.Lock()

	if state, ok := wn.watchers[addr]; ok && state.isReady() {
		items, max := state.q.Get(offset)
		rsp := new(pdpb.WatcherNotifyRsp)
		for _, item := range items {
			rsp.Ranges = append(rsp.Ranges, item.(*pdpb.Range))
		}
		rsp.Offset = max
		wn.Unlock()
		return rsp
	}

	wn.Unlock()
	return nil
}

// ConnectFailed pool status handler
func (wn *watcherNotifier) ConnectFailed(addr string, err error) {
	wn.pause(addr)
}

// Connected pool status handler
func (wn *watcherNotifier) Connected(addr string, conn goetty.IOSession) {
	go func() {
		for {
			msg, err := conn.Read()
			if err != nil {
				log.Errorf("notify: read from %s failed, errors:\n%+v", addr, err)
				wn.pause(addr)
				return
			}

			if s, ok := msg.(*pdpb.WatcherNotifySync); ok {
				err := conn.Write(wn.sync(addr, s.Offset))
				if err != nil {
					wn.pause(addr)
					return
				}
			}
		}
	}()
}

func createConn(addr string) goetty.IOSession {
	c := &goetty.Conf{
		Addr: addr,
		TimeoutConnectToServer: time.Second * 30,
	}
	return goetty.NewConnector(c, &codec.ProxyDecoder{}, &codec.ProxyEncoder{})
}
<commit_msg>fix: dead lock when connect watcher failed<commit_after>// Copyright 2016 DeepFabric, 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,
// See the License for the specific language governing permissions and
// limitations under the License.

package pdserver

import (
	"errors"
	"sync"
	"time"

	"github.com/deepfabric/elasticell/pkg/codec"
	"github.com/deepfabric/elasticell/pkg/log"
	"github.com/deepfabric/elasticell/pkg/pb/pdpb"
	"github.com/deepfabric/elasticell/pkg/util"
	"github.com/fagongzi/goetty"
)

var (
	errConnect = errors.New("not connected")
)

const (
	ready = iota
	paused
)

func cmp(a, b interface{}) bool {
	return a.(*notify).watcher == b.(*notify).watcher
}

type notify struct {
	watcher string
	offset  uint64
}

func newWatcherState(watcher string) *watcherState {
	return &watcherState{
		watcher: watcher,
		state:   ready,
		q:       util.NewOffsetQueue(),
	}
}

type watcherState struct {
	watcher          string
	state            int
	hbTimeout        *goetty.Timeout
	q                *util.OffsetQueue
	lastNotifyOffset uint64
}

func (state *watcherState) reset() {
	state.cancelTimeout()
	state.state = ready
	state.q = util.NewOffsetQueue()
	state.lastNotifyOffset = 0

	log.Debugf("notify: %s reseted", state.watcher)
}

func (state *watcherState) pause() {
	state.reset()
	state.state = paused
	log.Debugf("notify: %s reset to pause", state.watcher)
}

func (state *watcherState) isReady() bool {
	return state.state == ready
}

func (state *watcherState) isPause() bool {
	return state.state == paused
}

func (state *watcherState) addNotify(info *pdpb.Range) uint64 {
	return state.q.Add(info)
}

func (state *watcherState) cancelTimeout() {
	if state.hbTimeout != nil {
		state.hbTimeout.Stop()
		state.hbTimeout = nil
	}
}

func (state *watcherState) resetTimeout(timeout time.Duration, fn func(interface{})) {
	state.cancelTimeout()

	t, _ := util.DefaultTimeoutWheel().Schedule(timeout, fn, state.watcher)
	state.hbTimeout = &t
}

// watcherNotifier is used for notify the newest cell info to all watchers
type watcherNotifier struct {
	sync.RWMutex

	notifies *util.Queue
	pool     *goetty.AddressBasedPool
	watchers map[string]*watcherState
	timeout  time.Duration
}

func newWatcherNotifier(timeout time.Duration) *watcherNotifier {
	wn := &watcherNotifier{
		notifies: util.New(1024),
		watchers: make(map[string]*watcherState),
		timeout:  timeout,
	}

	wn.pool = goetty.NewAddressBasedPool(createConn, wn)
	return wn
}

func (wn *watcherNotifier) start() {
	go func() {
		batch := int64(64)
		items := make([]interface{}, batch, batch)

		for {
			n, err := wn.notifies.Get(int64(batch), items)
			if err != nil {
				log.Infof("stop: watcher notifier stopped")
				return
			}

			for i := int64(0); i < n; i++ {
				nt := items[i].(*notify)

				if !wn.allowNotify(nt.watcher) {
					continue
				}

				if !wn.allowSend(nt) {
					continue
				}

				conn, err := wn.pool.GetConn(nt.watcher)
				if err != nil {
					wn.pause(nt.watcher, true)
					log.Warnf("notify: %d to %s failed, errors:\n%+v",
						nt.offset,
						nt.watcher,
						err)
					continue
				}

				req := &pdpb.WatcherNotify{
					Offset: nt.offset,
				}
				err = conn.Write(req)
				if err != nil {
					wn.pause(nt.watcher, true)
					log.Warnf("notify: %d to %s failed, errors:\n%+v",
						nt.offset,
						nt.watcher,
						err)
					continue
				}
			}
		}
	}()
}

func (wn *watcherNotifier) stop() {
	wn.notifies.Dispose()
}

func (wn *watcherNotifier) removedAllWatcher() {
	wn.Lock()
	for watcher := range wn.watchers {
		wn.removeWatcher(watcher)
	}
	wn.Unlock()
}

// addWatcher add a new watcher for notify the newest cells info.
func (wn *watcherNotifier) addWatcher(addr string) {
	wn.Lock()

	if state, ok := wn.watchers[addr]; ok {
		state.cancelTimeout()
		state.reset()
	} else {
		wn.watchers[addr] = newWatcherState(addr)
	}

	wn.resetTimeout(addr)
	wn.Unlock()

	log.Warnf("notify: %s added", addr)
}

func (wn *watcherNotifier) resetTimeout(addr string) {
	wn.watchers[addr].resetTimeout(wn.timeout, wn.watcherTimeout)
}

// removeWatcher remove a watcher
func (wn *watcherNotifier) removeWatcher(addr string) {
	wn.Lock()
	delete(wn.watchers, addr)
	wn.pool.RemoveConn(addr)
	wn.Unlock()
}

// watcherHeartbeat return true if the watcher resume from pause.
func (wn *watcherNotifier) watcherHeartbeat(addr string, offset uint64) bool {
	wn.Lock()
	value := wn.resume(addr)
	if state, ok := wn.watchers[addr]; ok && !value {
		max := state.q.GetMaxOffset()
		if offset < max {
			wn.notifies.Put(&notify{
				watcher: addr,
				offset:  max,
			})
		}
	}
	wn.Unlock()
	return value
}

func (wn *watcherNotifier) watcherTimeout(arg interface{}) {
	wn.pause(arg.(string), true)
}

func (wn *watcherNotifier) allowNotify(addr string) bool {
	wn.Lock()
	if state, ok := wn.watchers[addr]; ok {
		allow := state.isReady()
		wn.Unlock()
		return allow
	}
	wn.Unlock()
	return false
}

func (wn *watcherNotifier) allowSend(nt *notify) bool {
	wn.Lock()
	if state, ok := wn.watchers[nt.watcher]; ok {
		allow := state.isReady() && state.lastNotifyOffset == 0 || state.lastNotifyOffset < nt.offset
		if allow {
			state.lastNotifyOffset = nt.offset
		}
		wn.Unlock()
		return allow
	}
	wn.Unlock()
	return false
}

func (wn *watcherNotifier) pause(addr string, remove bool) {
	wn.Lock()
	if remove {
		wn.pool.RemoveConn(addr)
	}
	if state, ok := wn.watchers[addr]; ok {
		state.pause()
	}
	wn.Unlock()
}

func (wn *watcherNotifier) resume(addr string) bool {
	if state, ok := wn.watchers[addr]; ok {
		resumeFromPause := state.isPause()

		if state.isPause() {
			state.state = ready
		}

		wn.resetTimeout(addr)
		return resumeFromPause
	}

	return false
}

func (wn *watcherNotifier) notify(info *pdpb.Range) {
	wn.Lock()

	for _, state := range wn.watchers {
		if state.isReady() {
			nt := &notify{
				watcher: state.watcher,
				offset:  state.addNotify(info),
			}
			wn.notifies.PutOrUpdate(cmp, nt)
		}
	}

	wn.Unlock()
}

func (wn *watcherNotifier) sync(addr string, offset uint64) *pdpb.WatcherNotifyRsp {
	wn.Lock()

	if state, ok := wn.watchers[addr]; ok && state.isReady() {
		items, max := state.q.Get(offset)
		rsp := new(pdpb.WatcherNotifyRsp)
		for _, item := range items {
			rsp.Ranges = append(rsp.Ranges, item.(*pdpb.Range))
		}
		rsp.Offset = max
		wn.Unlock()
		return rsp
	}

	wn.Unlock()
	return nil
}

// ConnectFailed pool status handler
func (wn *watcherNotifier) ConnectFailed(addr string, err error) {
	wn.pause(addr, false)
}

// Connected pool status handler
func (wn *watcherNotifier) Connected(addr string, conn goetty.IOSession) {
	go func() {
		for {
			msg, err := conn.Read()
			if err != nil {
				log.Errorf("notify: read from %s failed, errors:\n%+v", addr, err)
				wn.pause(addr, true)
				return
			}

			if s, ok := msg.(*pdpb.WatcherNotifySync); ok {
				err := conn.Write(wn.sync(addr, s.Offset))
				if err != nil {
					wn.pause(addr, true)
					return
				}
			}
		}
	}()
}

func createConn(addr string) goetty.IOSession {
	c := &goetty.Conf{
		Addr: addr,
		TimeoutConnectToServer: time.Second * 30,
	}
	return goetty.NewConnector(c, &codec.ProxyDecoder{}, &codec.ProxyEncoder{})
}
<|endoftext|>


<commit_before>// Copyright 2017 Google Inc. All rights reserved.

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

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

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

package v2

import (
	"fmt"

	"github.com/GoogleCloudPlatform/runtimes-common/ctc_lib"

	"github.com/GoogleContainerTools/container-structure-test/pkg/drivers"
	types "github.com/GoogleContainerTools/container-structure-test/pkg/types/unversioned"
	"github.com/GoogleContainerTools/container-structure-test/pkg/utils"
)

type CommandTest struct {
	Name           string         `yaml:"name"`
	Setup          [][]string     `yaml:"setup"`
	Teardown       [][]string     `yaml:"teardown"`
	EnvVars        []types.EnvVar `yaml:"envVars"`
	ExitCode       int            `yaml:"exitCode"`
	Command        string         `yaml:"command"`
	Args           []string       `yaml:"args"`
	ExpectedOutput []string       `yaml:"expectedOutput"`
	ExcludedOutput []string       `yaml:"excludedOutput"`
	ExpectedError  []string       `yaml:"expectedError"`
	ExcludedError  []string       `yaml:"excludedError"` // excluded error from running command
}

func (ct *CommandTest) Validate() error {
	if ct.Name == "" {
		return fmt.Errorf("Please provide a valid name for every test")
	}
	if ct.Command == "" {
		return fmt.Errorf("Please provide a valid entrypoint to run for test %s", ct.Name)
	}
	if ct.Setup != nil {
		for _, c := range ct.Setup {
			if len(c) == 0 {
				return fmt.Errorf("Error in setup command configuration encountered; please check formatting and remove all empty setup commands")
			}
		}
	}
	if ct.Teardown != nil {
		for _, c := range ct.Teardown {
			if len(c) == 0 {
				return fmt.Errorf("Error in teardown command configuration encountered; please check formatting and remove all empty teardown commands")
			}
		}
	}
	if ct.EnvVars != nil {
		for _, envVar := range ct.EnvVars {
			if envVar.Key == "" || envVar.Value == "" {
				return fmt.Errorf("Please provide non-empty keys and values for all specified env vars")
			}
		}
	}
	return nil
}

func (ct *CommandTest) LogName() string {
	return fmt.Sprintf("Command Test: %s", ct.Name)
}

func (ct *CommandTest) Run(driver drivers.Driver) *types.TestResult {
	ctc_lib.Log.Debug(ct.LogName())
	config, err := driver.GetConfig()
	if err != nil {
		ctc_lib.Log.Errorf("error retrieving image config: %s", err.Error())
	}
	fullCommand := utils.SubstituteEnvVars(append([]string{ct.Command}, ct.Args...), config.Env)
	stdout, stderr, exitcode, err := driver.ProcessCommand(ct.EnvVars, fullCommand)
	result := &types.TestResult{
		Name:   ct.LogName(),
		Pass:   true,
		Errors: make([]string, 0),
		Stderr: stderr,
		Stdout: stdout,
	}
	if err != nil {
		result.Fail()
		result.Error(err.Error())
		return result
	}

	ct.CheckOutput(result, stdout, stderr, exitcode)
	return result
}

func (ct *CommandTest) CheckOutput(result *types.TestResult, stdout string, stderr string, exitCode int) {
	for _, errStr := range ct.ExpectedError {
		if !utils.CompileAndRunRegex(errStr, stderr, true) {
			result.Errorf("Expected string '%s' not found in error", errStr)
			result.Fail()
		}
	}
	for _, errStr := range ct.ExcludedError {
		if !utils.CompileAndRunRegex(errStr, stderr, false) {
			result.Errorf("Excluded string '%s' found in error", errStr)
			result.Fail()
		}
	}
	for _, outStr := range ct.ExpectedOutput {
		if !utils.CompileAndRunRegex(outStr, stdout, true) {
			result.Errorf("Expected string '%s' not found in output", outStr)
			result.Fail()
		}
	}
	for _, outStr := range ct.ExcludedOutput {
		if !utils.CompileAndRunRegex(outStr, stdout, false) {
			result.Errorf("Excluded string '%s' found in output", outStr)
			result.Fail()
		}
	}
	if ct.ExitCode != exitCode {
		result.Errorf("Test '%s' exited with incorrect error code. Expected: %d, Actual: %d", ct.Name, ct.ExitCode, exitCode)
		result.Fail()
	}
}
<commit_msg>Update command.go (#134)<commit_after>// Copyright 2017 Google Inc. All rights reserved.

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

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

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

package v2

import (
	"fmt"

	"github.com/GoogleCloudPlatform/runtimes-common/ctc_lib"

	"github.com/GoogleContainerTools/container-structure-test/pkg/drivers"
	types "github.com/GoogleContainerTools/container-structure-test/pkg/types/unversioned"
	"github.com/GoogleContainerTools/container-structure-test/pkg/utils"
)

type CommandTest struct {
	Name           string         `yaml:"name"`
	Setup          [][]string     `yaml:"setup"`
	Teardown       [][]string     `yaml:"teardown"`
	EnvVars        []types.EnvVar `yaml:"envVars"`
	ExitCode       int            `yaml:"exitCode"`
	Command        string         `yaml:"command"`
	Args           []string       `yaml:"args"`
	ExpectedOutput []string       `yaml:"expectedOutput"`
	ExcludedOutput []string       `yaml:"excludedOutput"`
	ExpectedError  []string       `yaml:"expectedError"`
	ExcludedError  []string       `yaml:"excludedError"` // excluded error from running command
}

func (ct *CommandTest) Validate() error {
	if ct.Name == "" {
		return fmt.Errorf("Please provide a valid name for every test")
	}
	if ct.Command == "" {
		return fmt.Errorf("Please provide a valid Command to run for test %s", ct.Name)
	}
	if ct.Setup != nil {
		for _, c := range ct.Setup {
			if len(c) == 0 {
				return fmt.Errorf("Error in setup command configuration encountered; please check formatting and remove all empty setup commands")
			}
		}
	}
	if ct.Teardown != nil {
		for _, c := range ct.Teardown {
			if len(c) == 0 {
				return fmt.Errorf("Error in teardown command configuration encountered; please check formatting and remove all empty teardown commands")
			}
		}
	}
	if ct.EnvVars != nil {
		for _, envVar := range ct.EnvVars {
			if envVar.Key == "" || envVar.Value == "" {
				return fmt.Errorf("Please provide non-empty keys and values for all specified env vars")
			}
		}
	}
	return nil
}

func (ct *CommandTest) LogName() string {
	return fmt.Sprintf("Command Test: %s", ct.Name)
}

func (ct *CommandTest) Run(driver drivers.Driver) *types.TestResult {
	ctc_lib.Log.Debug(ct.LogName())
	config, err := driver.GetConfig()
	if err != nil {
		ctc_lib.Log.Errorf("error retrieving image config: %s", err.Error())
	}
	fullCommand := utils.SubstituteEnvVars(append([]string{ct.Command}, ct.Args...), config.Env)
	stdout, stderr, exitcode, err := driver.ProcessCommand(ct.EnvVars, fullCommand)
	result := &types.TestResult{
		Name:   ct.LogName(),
		Pass:   true,
		Errors: make([]string, 0),
		Stderr: stderr,
		Stdout: stdout,
	}
	if err != nil {
		result.Fail()
		result.Error(err.Error())
		return result
	}

	ct.CheckOutput(result, stdout, stderr, exitcode)
	return result
}

func (ct *CommandTest) CheckOutput(result *types.TestResult, stdout string, stderr string, exitCode int) {
	for _, errStr := range ct.ExpectedError {
		if !utils.CompileAndRunRegex(errStr, stderr, true) {
			result.Errorf("Expected string '%s' not found in error", errStr)
			result.Fail()
		}
	}
	for _, errStr := range ct.ExcludedError {
		if !utils.CompileAndRunRegex(errStr, stderr, false) {
			result.Errorf("Excluded string '%s' found in error", errStr)
			result.Fail()
		}
	}
	for _, outStr := range ct.ExpectedOutput {
		if !utils.CompileAndRunRegex(outStr, stdout, true) {
			result.Errorf("Expected string '%s' not found in output", outStr)
			result.Fail()
		}
	}
	for _, outStr := range ct.ExcludedOutput {
		if !utils.CompileAndRunRegex(outStr, stdout, false) {
			result.Errorf("Excluded string '%s' found in output", outStr)
			result.Fail()
		}
	}
	if ct.ExitCode != exitCode {
		result.Errorf("Test '%s' exited with incorrect error code. Expected: %d, Actual: %d", ct.Name, ct.ExitCode, exitCode)
		result.Fail()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/xml"
	"flag"
	"fmt"
	"net/http"
	"net/url"
	"strconv"

	"code.google.com/p/go-charset/charset"
	_ "code.google.com/p/go-charset/data"
)

type DateTimeType struct {
	Date struct {
		Day   int `xml:"day,attr"`
		Month int `xml:"month,attr"`
		Year  int `xml:"year,attr"`
	} `xml:"itdDate"`

	Time struct {
		Hour   int `xml:"hour,attr"`
		Minute int `xml:"minute,attr"`
	} `xml:"itdTime"`
}

type Line struct {
	Number    int    `xml:"number,attr"`
	Direction string `xml:"direction,attr"`
}

type Departure struct {
	Countdown int    `xml:"countdown,attr"`
	Platform  string `xml:"platform,attr"`

	DateTime    DateTimeType `xml:"itdDateTime"`
	ServingLine Line         `xml:"itdServingLine"`
}

type StopInfo struct {
	State string `xml:"state,attr"`

	IdfdStop struct {
		StopName  string `xml:",chardata"`
		MatchQlty int    `xml:"matchQuality,attr"`
		StopID    int    `xml:"stopID,attr"`
	} `xml:"odvNameElem"`
}

type XmlResult struct {
	Stop       StopInfo    `xml:"itdDepartureMonitorRequest>itdOdv>itdOdvName"`
	Departures []Departure `xml:"itdDepartureMonitorRequest>itdDepartureList>itdDeparture"`
}

func fill_width(str string, width int) string {

	orig_len := len(str)

	if orig_len < width {

		for i := 0; i < width-orig_len; i++ {
			str = str + " "
		}
	}

	return str
}

func main() {

	station_id := flag.String("stop", "Königsplatz", "id or (part of the) stop name")
	max_results := flag.Int("results", 10, "how many results to show")
	flag.Parse()

	baseULR := "http://efa.avv-augsburg.de/avv/"
	endpoint := "XML_DM_REQUEST"

	params := url.Values{
		"type_dm":              {"stop"},
		"name_dm":              {*station_id},
		"useRealtime":          {"1"},
		"locationServerActive": {"1"},
		"dmLineSelection":      {"all"},
		"limit":                {strconv.Itoa(*max_results)},
		"mode":                 {"direct"},
	}

	resp, err := http.PostForm(baseULR+endpoint, params)
	defer resp.Body.Close()

	if err != nil {
		return
	}

	var result XmlResult

	decoder := xml.NewDecoder(resp.Body)
	decoder.CharsetReader = charset.NewReader
	err = decoder.Decode(&result)

	if err != nil {
		fmt.Println(err)
		return
	}

	//fmt.Printf("%+v", result)

	if result.Stop.State != "identified" {
		fmt.Println("stop does not exist or name is not unique!")
		return
	}

	fmt.Println("selected stop: " + result.Stop.IdfdStop.StopName + " (" + strconv.Itoa(result.Stop.IdfdStop.StopID) + ")\n")

	for _, departure := range result.Departures {

		plu := ""
		if departure.Countdown != 1 {
			plu = "s"
		}

		fmt.Println("route " + fill_width(departure.ServingLine.Number, 6) + fill_width(" due in "+strconv.Itoa(departure.Countdown)+" minute"+plu, 19) + " --> " + departure.ServingLine.Direction)
	}

}
<commit_msg>use string for line number<commit_after>package main

import (
	"encoding/xml"
	"flag"
	"fmt"
	"net/http"
	"net/url"
	"strconv"

	"code.google.com/p/go-charset/charset"
	_ "code.google.com/p/go-charset/data"
)

type DateTimeType struct {
	Date struct {
		Day   int `xml:"day,attr"`
		Month int `xml:"month,attr"`
		Year  int `xml:"year,attr"`
	} `xml:"itdDate"`

	Time struct {
		Hour   int `xml:"hour,attr"`
		Minute int `xml:"minute,attr"`
	} `xml:"itdTime"`
}

type Line struct {
	Number    string `xml:"number,attr"`
	Direction string `xml:"direction,attr"`
}

type Departure struct {
	Countdown int    `xml:"countdown,attr"`
	Platform  string `xml:"platform,attr"`

	DateTime    DateTimeType `xml:"itdDateTime"`
	ServingLine Line         `xml:"itdServingLine"`
}

type StopInfo struct {
	State string `xml:"state,attr"`

	IdfdStop struct {
		StopName  string `xml:",chardata"`
		MatchQlty int    `xml:"matchQuality,attr"`
		StopID    int    `xml:"stopID,attr"`
	} `xml:"odvNameElem"`
}

type XmlResult struct {
	Stop       StopInfo    `xml:"itdDepartureMonitorRequest>itdOdv>itdOdvName"`
	Departures []Departure `xml:"itdDepartureMonitorRequest>itdDepartureList>itdDeparture"`
}

func fill_width(str string, width int) string {

	orig_len := len(str)

	if orig_len < width {

		for i := 0; i < width-orig_len; i++ {
			str = str + " "
		}
	}

	return str
}

func main() {

	station_id := flag.String("stop", "Königsplatz", "id or (part of the) stop name")
	max_results := flag.Int("results", 10, "how many results to show")
	flag.Parse()

	baseULR := "http://efa.avv-augsburg.de/avv/"
	endpoint := "XML_DM_REQUEST"

	params := url.Values{
		"type_dm":              {"stop"},
		"name_dm":              {*station_id},
		"useRealtime":          {"1"},
		"locationServerActive": {"1"},
		"dmLineSelection":      {"all"},
		"limit":                {strconv.Itoa(*max_results)},
		"mode":                 {"direct"},
	}

	resp, err := http.PostForm(baseULR+endpoint, params)
	defer resp.Body.Close()

	if err != nil {
		return
	}

	var result XmlResult

	decoder := xml.NewDecoder(resp.Body)
	decoder.CharsetReader = charset.NewReader
	err = decoder.Decode(&result)

	if err != nil {
		fmt.Println(err)
		return
	}

	//fmt.Printf("%+v", result)

	if result.Stop.State != "identified" {
		fmt.Println("stop does not exist or name is not unique!")
		return
	}

	fmt.Println("selected stop: " + result.Stop.IdfdStop.StopName + " (" + strconv.Itoa(result.Stop.IdfdStop.StopID) + ")\n")

	for _, departure := range result.Departures {

		plu := ""
		if departure.Countdown != 1 {
			plu = "s"
		}

		fmt.Println("route " + fill_width(departure.ServingLine.Number, 6) + fill_width(" due in "+strconv.Itoa(departure.Countdown)+" minute"+plu, 19) + " --> " + departure.ServingLine.Direction)
	}

}
<|endoftext|>


<commit_before>/*
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.
*/

// This file implements a go-getter wrapper for cheggaaa progress bar

// based on:
// https://github.com/hashicorp/go-getter/blob/master/cmd/go-getter/progress_tracking.go
package util

import (
	"fmt"
	"io"
	"path/filepath"
	"sync"

	"github.com/cheggaaa/pb"
	"github.com/golang/glog"
	"github.com/hashicorp/go-getter"
)

var defaultProgressBar getter.ProgressTracker = &progressBar{}

type progressBar struct {
	lock sync.Mutex
	pool *pb.Pool
	pbs  int
}

// TrackProgress instantiates a new progress bar that will
// display the progress of stream until closed.
// total can be 0.
func (cpb *progressBar) TrackProgress(src string, currentSize, totalSize int64, stream io.ReadCloser) io.ReadCloser {
	cpb.lock.Lock()
	defer cpb.lock.Unlock()

	if cpb.pool == nil {
		cpb.pool = pb.NewPool()
		if err := cpb.pool.Start(); err != nil {
			glog.Errorf("pool start: %v", err)
		}
	}

	p := pb.New64(totalSize)
	p.Set64(currentSize)
	p.SetUnits(pb.U_BYTES)
	p.Prefix(fmt.Sprintf("    %s:", filepath.Base(src)))
	p.SetWidth(78)
	cpb.pool.Add(p)
	reader := p.NewProxyReader(stream)

	cpb.pbs++
	return &readCloser{
		Reader: reader,
		close: func() error {
			cpb.lock.Lock()
			defer cpb.lock.Unlock()

			p.Finish()
			cpb.pbs--
			if cpb.pbs <= 0 {
				if err := cpb.pool.Stop(); err != nil {
					glog.Errorf("pool stop: %v", err)
				}
				cpb.pool = nil
			}
			return nil
		},
	}
}

type readCloser struct {
	io.Reader
	close func() error
}

func (c *readCloser) Close() error { return c.close() }
<commit_msg>Document 78<commit_after>/*
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.
*/

// This file implements a go-getter wrapper for cheggaaa progress bar

// based on:
// https://github.com/hashicorp/go-getter/blob/master/cmd/go-getter/progress_tracking.go
package util

import (
	"fmt"
	"io"
	"path/filepath"
	"sync"

	"github.com/cheggaaa/pb"
	"github.com/golang/glog"
	"github.com/hashicorp/go-getter"
)

var defaultProgressBar getter.ProgressTracker = &progressBar{}

type progressBar struct {
	lock sync.Mutex
	pool *pb.Pool
	pbs  int
}

// TrackProgress instantiates a new progress bar that will
// display the progress of stream until closed.
// total can be 0.
func (cpb *progressBar) TrackProgress(src string, currentSize, totalSize int64, stream io.ReadCloser) io.ReadCloser {
	cpb.lock.Lock()
	defer cpb.lock.Unlock()

	if cpb.pool == nil {
		cpb.pool = pb.NewPool()
		if err := cpb.pool.Start(); err != nil {
			glog.Errorf("pool start: %v", err)
		}
	}

	p := pb.New64(totalSize)
	p.Set64(currentSize)
	p.SetUnits(pb.U_BYTES)
	p.Prefix(fmt.Sprintf("    %s:", filepath.Base(src)))
	// Just a hair less than 80 (standard terminal width) for aesthetics & pasting into docs
	p.SetWidth(78)
	cpb.pool.Add(p)
	reader := p.NewProxyReader(stream)

	cpb.pbs++
	return &readCloser{
		Reader: reader,
		close: func() error {
			cpb.lock.Lock()
			defer cpb.lock.Unlock()

			p.Finish()
			cpb.pbs--
			if cpb.pbs <= 0 {
				if err := cpb.pool.Stop(); err != nil {
					glog.Errorf("pool stop: %v", err)
				}
				cpb.pool = nil
			}
			return nil
		},
	}
}

type readCloser struct {
	io.Reader
	close func() error
}

func (c *readCloser) Close() error { return c.close() }
<|endoftext|>


<commit_before>package utils

import "testing"

func TestWordify(t *testing.T) {
	actual := Wordify("Hello World 42 !!")
	expected := "Hello_World_42"
	if actual != expected {
		t.Errorf("returned value is invalid [actual: %s][expected: %s]", actual, expected)
	}
}

func TestTruncIf(t *testing.T) {
	actual := TruncIf("Hello World", 5, false)
	expected := "Hello World"
	if actual != expected {
		t.Errorf("returned value is invalid [actual: %s][expected: %s]", actual, expected)
	}

	actual = TruncIf("Hello World", 5, true)
	expected = "Hello"
	if actual != expected {
		t.Errorf("returned value is invalid [actual: %s][expected: %s]", actual, expected)
	}

	actual = TruncIf("Hello World", 50, false)
	expected = "Hello World"
	if actual != expected {
		t.Errorf("returned value is invalid [actual: %s][expected: %s]", actual, expected)
	}

	actual = TruncIf("Hello World", 50, true)
	expected = "Hello World"
	if actual != expected {
		t.Errorf("returned value is invalid [actual: %s][expected: %s]", actual, expected)
	}
}

func TestPathToTARPathparts(t *testing.T) {
	dir, base := PathToTARPathparts("/etc/passwd")
	expected := []string{"/etc", "passwd"}
	actual := []string{dir, base}
	if actual[0] != expected[0] || actual[1] != expected[1] {
		t.Errorf("returned value is invalid [actual: %s][expected: %s]", actual, expected)
	}

	dir, base = PathToTARPathparts("/etc")
	expected = []string{"/", "etc"}
	actual = []string{dir, base}
	if actual[0] != expected[0] || actual[1] != expected[1] {
		t.Errorf("returned value is invalid [actual: %s][expected: %s]", actual, expected)
	}

	dir, base = PathToTARPathparts("/etc/")
	expected = []string{"/", "etc"}
	actual = []string{dir, base}
	if actual[0] != expected[0] || actual[1] != expected[1] {
		t.Errorf("returned value is invalid [actual: %s][expected: %s]", actual, expected)
	}
}
<commit_msg>Converted utils tests to convey<commit_after>package utils

import (
	"testing"

	. "github.com/smartystreets/goconvey/convey"
)

func TestWordify(t *testing.T) {
	Convey("Testing Wordify()", t, func() {
		So(Wordify("Hello World 42 !!"), ShouldEqual, "Hello_World_42")
		So(Wordify("  Hello   World   42   !!  "), ShouldEqual, "Hello_World_42")
		So(Wordify("Hello_World_42"), ShouldEqual, "Hello_World_42")
		So(Wordify(""), ShouldEqual, "")
	})
}

func TestTruncIf(t *testing.T) {
	Convey("Testing TruncIf()", t, func() {
		So(TruncIf("Hello World", 5, false), ShouldEqual, "Hello World")
		So(TruncIf("Hello World", 5, true), ShouldEqual, "Hello")
		So(TruncIf("Hello World", 50, false), ShouldEqual, "Hello World")
		So(TruncIf("Hello World", 50, true), ShouldEqual, "Hello World")
	})
}

func TestPathToTARPathparts(t *testing.T) {
	Convey("Testing PathToTARPathparts()", t, func() {
		dir, base := PathToTARPathparts("/etc/passwd")
		So([]string{"/etc", "passwd"}, ShouldResemble, []string{dir, base})

		dir, base = PathToTARPathparts("/etc")
		So([]string{"/", "etc"}, ShouldResemble, []string{dir, base})

		dir, base = PathToTARPathparts("/etc/")
		So([]string{"/", "etc"}, ShouldResemble, []string{dir, base})

		dir, base = PathToTARPathparts("/long/path/to/file")
		So([]string{"/long/path/to", "file"}, ShouldResemble, []string{dir, base})

		dir, base = PathToTARPathparts("/long/path/to/dir/")
		So([]string{"/long/path/to", "dir"}, ShouldResemble, []string{dir, base})
	})
}
<|endoftext|>


<commit_before>package design

import "testing"

func TestIsPrimitive(t *testing.T) {
	var (
		primitiveUserType = &UserTypeExpr{
			AttributeExpr: &AttributeExpr{
				Type: Boolean,
			},
		}
		notPrimitiveUserType = &UserTypeExpr{
			AttributeExpr: &AttributeExpr{
				Type: &Object{},
			},
		}
		primitiveResultType = &ResultTypeExpr{
			UserTypeExpr: primitiveUserType,
		}
		notPrimitiveResultType = &ResultTypeExpr{
			UserTypeExpr: notPrimitiveUserType,
		}
	)
	cases := map[string]struct {
		dt       DataType
		expected bool
	}{
		"boolean": {
			dt:       Boolean,
			expected: true,
		},
		"int": {
			dt:       Int,
			expected: true,
		},
		"int32": {
			dt:       Int32,
			expected: true,
		},
		"int64": {
			dt:       Int64,
			expected: true,
		},
		"uint": {
			dt:       UInt,
			expected: true,
		},
		"uint32": {
			dt:       UInt32,
			expected: true,
		},
		"uint64": {
			dt:       UInt64,
			expected: true,
		},
		"float32": {
			dt:       Float32,
			expected: true,
		},
		"float64": {
			dt:       Float64,
			expected: true,
		},
		"string": {
			dt:       String,
			expected: true,
		},
		"bytes": {
			dt:       Bytes,
			expected: true,
		},
		"any": {
			dt:       Any,
			expected: true,
		},
		"primitive user type": {
			dt:       primitiveUserType,
			expected: true,
		},
		"not primitive user type": {
			dt:       notPrimitiveUserType,
			expected: false,
		},
		"primitive result type": {
			dt:       primitiveResultType,
			expected: true,
		},
		"not primitive result type": {
			dt:       notPrimitiveResultType,
			expected: false,
		},
		"object": {
			dt:       &Object{},
			expected: false,
		},
		"array": {
			dt:       &Array{},
			expected: false,
		},
		"map": {
			dt:       &Map{},
			expected: false,
		},
	}

	for k, tc := range cases {
		if actual := IsPrimitive(tc.dt); tc.expected != actual {
			t.Errorf("%s: got %#v, expected %#v", k, actual, tc.expected)
		}
	}
}

func TestPrimitiveIsCompatible(t *testing.T) {
	var (
		b    = bool(true)
		i    = int(1)
		i8   = int8(2)
		i16  = int16(3)
		i32  = int32(4)
		ui   = uint(5)
		ui8  = uint8(6)
		ui16 = uint16(7)
		ui32 = uint32(8)
		i64  = int64(9)
		ui64 = uint64(10)
		f32  = float32(10.1)
		f64  = float64(20.2)
		s    = string("string")
		bs   = []byte("bytes")
	)
	cases := map[string]struct {
		p        Primitive
		values   []interface{}
		expected bool
	}{
		"boolean compatible": {
			p:        Boolean,
			values:   []interface{}{b},
			expected: true,
		},
		"boolean not compatible": {
			p:        Boolean,
			values:   []interface{}{i, i8, i16, i32, ui, ui8, ui16, ui32, i64, ui64, f32, f64, s, bs},
			expected: false,
		},
		"int compatible": {
			p:        Int,
			values:   []interface{}{i, i8, i16, i32, ui, ui8, ui16, ui32},
			expected: true,
		},
		"int not compatible": {
			p:        Int,
			values:   []interface{}{b, i64, ui64, f32, f64, s, bs},
			expected: false,
		},
		"int32 compatible": {
			p:        Int32,
			values:   []interface{}{i, i8, i16, i32, ui, ui8, ui16, ui32},
			expected: true,
		},
		"int32 not compatible": {
			p:        Int32,
			values:   []interface{}{b, i64, ui64, f32, f64, s, bs},
			expected: false,
		},
		"int64 compatible": {
			p:        Int64,
			values:   []interface{}{i, i8, i16, i32, ui, ui8, ui16, ui32, i64, ui64},
			expected: true,
		},
		"int64 not compatible": {
			p:        Int64,
			values:   []interface{}{b, f32, f64, s, bs},
			expected: false,
		},
		"uint compatible": {
			p:        UInt,
			values:   []interface{}{i, i8, i16, i32, ui, ui8, ui16, ui32},
			expected: true,
		},
		"uint not compatible": {
			p:        UInt,
			values:   []interface{}{b, i64, ui64, f32, f64, s, bs},
			expected: false,
		},
		"uint32 compatible": {
			p:        UInt32,
			values:   []interface{}{i, i8, i16, i32, ui, ui8, ui16, ui32},
			expected: true,
		},
		"uint32 not compatible": {
			p:        UInt32,
			values:   []interface{}{b, i64, ui64, f32, f64, s, bs},
			expected: false,
		},
		"uint64 compatible": {
			p:        UInt64,
			values:   []interface{}{i, i8, i16, i32, ui, ui8, ui16, ui32, i64, ui64},
			expected: true,
		},
		"uint64 not compatible": {
			p:        UInt64,
			values:   []interface{}{b, f32, f64, s, bs},
			expected: false,
		},
		"float32 compatible": {
			p:        Float32,
			values:   []interface{}{i, i8, i16, i32, ui, ui8, ui16, ui32, i64, ui64, f32, f64},
			expected: true,
		},
		"float32 not compatible": {
			p:        Float32,
			values:   []interface{}{b, s, bs},
			expected: false,
		},
		"float64 compatible": {
			p:        Float64,
			values:   []interface{}{i, i8, i16, i32, ui, ui8, ui16, ui32, i64, ui64, f32, f64},
			expected: true,
		},
		"float64 not compatible": {
			p:        Float64,
			values:   []interface{}{b, s, bs},
			expected: false,
		},
		"string compatible": {
			p:        String,
			values:   []interface{}{s},
			expected: true,
		},
		"string not compatible": {
			p:        String,
			values:   []interface{}{b, i, i8, i16, i32, ui, ui8, ui16, ui32, i64, ui64, f32, f64, bs},
			expected: false,
		},
		"bytes compatible": {
			p:        Bytes,
			values:   []interface{}{s, bs},
			expected: true,
		},
		"bytes not compatible": {
			p:        Bytes,
			values:   []interface{}{b, i, i8, i16, i32, ui, ui8, ui16, ui32, i64, ui64, f32, f64},
			expected: false,
		},
	}

	for k, tc := range cases {
		for _, value := range tc.values {
			if actual := tc.p.IsCompatible(value); tc.expected != actual {
				t.Errorf("%s: got %#v, expected %#v", k, actual, tc.expected)
			}
		}
	}
}
<commit_msg>Add tests for design.Array.IsCompatible() (#1581)<commit_after>package design

import "testing"

func TestIsPrimitive(t *testing.T) {
	var (
		primitiveUserType = &UserTypeExpr{
			AttributeExpr: &AttributeExpr{
				Type: Boolean,
			},
		}
		notPrimitiveUserType = &UserTypeExpr{
			AttributeExpr: &AttributeExpr{
				Type: &Object{},
			},
		}
		primitiveResultType = &ResultTypeExpr{
			UserTypeExpr: primitiveUserType,
		}
		notPrimitiveResultType = &ResultTypeExpr{
			UserTypeExpr: notPrimitiveUserType,
		}
	)
	cases := map[string]struct {
		dt       DataType
		expected bool
	}{
		"boolean": {
			dt:       Boolean,
			expected: true,
		},
		"int": {
			dt:       Int,
			expected: true,
		},
		"int32": {
			dt:       Int32,
			expected: true,
		},
		"int64": {
			dt:       Int64,
			expected: true,
		},
		"uint": {
			dt:       UInt,
			expected: true,
		},
		"uint32": {
			dt:       UInt32,
			expected: true,
		},
		"uint64": {
			dt:       UInt64,
			expected: true,
		},
		"float32": {
			dt:       Float32,
			expected: true,
		},
		"float64": {
			dt:       Float64,
			expected: true,
		},
		"string": {
			dt:       String,
			expected: true,
		},
		"bytes": {
			dt:       Bytes,
			expected: true,
		},
		"any": {
			dt:       Any,
			expected: true,
		},
		"primitive user type": {
			dt:       primitiveUserType,
			expected: true,
		},
		"not primitive user type": {
			dt:       notPrimitiveUserType,
			expected: false,
		},
		"primitive result type": {
			dt:       primitiveResultType,
			expected: true,
		},
		"not primitive result type": {
			dt:       notPrimitiveResultType,
			expected: false,
		},
		"object": {
			dt:       &Object{},
			expected: false,
		},
		"array": {
			dt:       &Array{},
			expected: false,
		},
		"map": {
			dt:       &Map{},
			expected: false,
		},
	}

	for k, tc := range cases {
		if actual := IsPrimitive(tc.dt); tc.expected != actual {
			t.Errorf("%s: got %#v, expected %#v", k, actual, tc.expected)
		}
	}
}

func TestPrimitiveIsCompatible(t *testing.T) {
	var (
		b    = bool(true)
		i    = int(1)
		i8   = int8(2)
		i16  = int16(3)
		i32  = int32(4)
		ui   = uint(5)
		ui8  = uint8(6)
		ui16 = uint16(7)
		ui32 = uint32(8)
		i64  = int64(9)
		ui64 = uint64(10)
		f32  = float32(10.1)
		f64  = float64(20.2)
		s    = string("string")
		bs   = []byte("bytes")
	)
	cases := map[string]struct {
		p        Primitive
		values   []interface{}
		expected bool
	}{
		"boolean compatible": {
			p:        Boolean,
			values:   []interface{}{b},
			expected: true,
		},
		"boolean not compatible": {
			p:        Boolean,
			values:   []interface{}{i, i8, i16, i32, ui, ui8, ui16, ui32, i64, ui64, f32, f64, s, bs},
			expected: false,
		},
		"int compatible": {
			p:        Int,
			values:   []interface{}{i, i8, i16, i32, ui, ui8, ui16, ui32},
			expected: true,
		},
		"int not compatible": {
			p:        Int,
			values:   []interface{}{b, i64, ui64, f32, f64, s, bs},
			expected: false,
		},
		"int32 compatible": {
			p:        Int32,
			values:   []interface{}{i, i8, i16, i32, ui, ui8, ui16, ui32},
			expected: true,
		},
		"int32 not compatible": {
			p:        Int32,
			values:   []interface{}{b, i64, ui64, f32, f64, s, bs},
			expected: false,
		},
		"int64 compatible": {
			p:        Int64,
			values:   []interface{}{i, i8, i16, i32, ui, ui8, ui16, ui32, i64, ui64},
			expected: true,
		},
		"int64 not compatible": {
			p:        Int64,
			values:   []interface{}{b, f32, f64, s, bs},
			expected: false,
		},
		"uint compatible": {
			p:        UInt,
			values:   []interface{}{i, i8, i16, i32, ui, ui8, ui16, ui32},
			expected: true,
		},
		"uint not compatible": {
			p:        UInt,
			values:   []interface{}{b, i64, ui64, f32, f64, s, bs},
			expected: false,
		},
		"uint32 compatible": {
			p:        UInt32,
			values:   []interface{}{i, i8, i16, i32, ui, ui8, ui16, ui32},
			expected: true,
		},
		"uint32 not compatible": {
			p:        UInt32,
			values:   []interface{}{b, i64, ui64, f32, f64, s, bs},
			expected: false,
		},
		"uint64 compatible": {
			p:        UInt64,
			values:   []interface{}{i, i8, i16, i32, ui, ui8, ui16, ui32, i64, ui64},
			expected: true,
		},
		"uint64 not compatible": {
			p:        UInt64,
			values:   []interface{}{b, f32, f64, s, bs},
			expected: false,
		},
		"float32 compatible": {
			p:        Float32,
			values:   []interface{}{i, i8, i16, i32, ui, ui8, ui16, ui32, i64, ui64, f32, f64},
			expected: true,
		},
		"float32 not compatible": {
			p:        Float32,
			values:   []interface{}{b, s, bs},
			expected: false,
		},
		"float64 compatible": {
			p:        Float64,
			values:   []interface{}{i, i8, i16, i32, ui, ui8, ui16, ui32, i64, ui64, f32, f64},
			expected: true,
		},
		"float64 not compatible": {
			p:        Float64,
			values:   []interface{}{b, s, bs},
			expected: false,
		},
		"string compatible": {
			p:        String,
			values:   []interface{}{s},
			expected: true,
		},
		"string not compatible": {
			p:        String,
			values:   []interface{}{b, i, i8, i16, i32, ui, ui8, ui16, ui32, i64, ui64, f32, f64, bs},
			expected: false,
		},
		"bytes compatible": {
			p:        Bytes,
			values:   []interface{}{s, bs},
			expected: true,
		},
		"bytes not compatible": {
			p:        Bytes,
			values:   []interface{}{b, i, i8, i16, i32, ui, ui8, ui16, ui32, i64, ui64, f32, f64},
			expected: false,
		},
	}

	for k, tc := range cases {
		for _, value := range tc.values {
			if actual := tc.p.IsCompatible(value); tc.expected != actual {
				t.Errorf("%s: got %#v, expected %#v", k, actual, tc.expected)
			}
		}
	}
}

func TestArrayIsCompatible(t *testing.T) {
	var (
		b  = true
		i  = 1
		ia = [2]int{1, 2}
		is = []int{3, 4}
	)
	cases := map[string]struct {
		typ      DataType
		values   []interface{}
		expected bool
	}{
		"compatible": {
			typ:      Int,
			values:   []interface{}{ia, is},
			expected: true,
		},
		"not array and slice": {
			typ:      String,
			values:   []interface{}{b, i},
			expected: false,
		},
		"array but not compatible": {
			typ:      String,
			values:   []interface{}{ia},
			expected: false,
		},
		"slice but not compatible": {
			typ:      String,
			values:   []interface{}{is},
			expected: false,
		},
	}

	for k, tc := range cases {
		array := Array{
			ElemType: &AttributeExpr{
				Type: tc.typ,
			},
		}
		for _, value := range tc.values {
			if actual := array.IsCompatible(value); tc.expected != actual {
				t.Errorf("%s: got %#v, expected %#v", k, actual, tc.expected)
			}
		}
	}
}
<|endoftext|>