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

// This file implements printing of types.

package types

import (
	"bytes"
	"fmt"
)

// If GcCompatibilityMode is set, printing of types is modified
// to match the representation of some types in the gc compiler:
//
//	- byte and rune lose their alias name and simply stand for
//	  uint8 and int32 respectively
//	- embedded interfaces get flattened (the embedding info is lost,
//	  and certain recursive interface types cannot be printed anymore)
//
// This makes it easier to compare packages computed with the type-
// checker vs packages imported from gc export data.
//
// Caution: This flag affects all uses of WriteType, globally.
// It is only provided for testing in conjunction with
// gc-generated data. It may be removed at any time.
var GcCompatibilityMode bool

// TypeString returns the string representation of typ.
// Named types are printed package-qualified if they
// do not belong to this package.
func TypeString(this *Package, typ Type) string {
	var buf bytes.Buffer
	WriteType(&buf, this, typ)
	return buf.String()
}

// WriteType writes the string representation of typ to buf.
// Named types are printed package-qualified if they
// do not belong to this package.
func WriteType(buf *bytes.Buffer, this *Package, typ Type) {
	writeType(buf, this, typ, make([]Type, 8))
}

func writeType(buf *bytes.Buffer, this *Package, typ Type, visited []Type) {
	// Theoretically, this is a quadratic lookup algorithm, but in
	// practice deeply nested composite types with unnamed component
	// types are uncommon. This code is likely more efficient than
	// using a map.
	for _, t := range visited {
		if t == typ {
			fmt.Fprintf(buf, "○%T", typ) // cycle to typ
			return
		}
	}
	visited = append(visited, typ)

	switch t := typ.(type) {
	case nil:
		buf.WriteString("<nil>")

	case *Basic:
		if t.kind == UnsafePointer {
			buf.WriteString("unsafe.")
		}
		if GcCompatibilityMode {
			// forget the alias names
			switch t.kind {
			case Byte:
				t = Typ[Uint8]
			case Rune:
				t = Typ[Int32]
			}
		}
		buf.WriteString(t.name)

	case *Array:
		fmt.Fprintf(buf, "[%d]", t.len)
		writeType(buf, this, t.elem, visited)

	case *Slice:
		buf.WriteString("[]")
		writeType(buf, this, t.elem, visited)

	case *Struct:
		buf.WriteString("struct{")
		for i, f := range t.fields {
			if i > 0 {
				buf.WriteString("; ")
			}
			if !f.anonymous {
				buf.WriteString(f.name)
				buf.WriteByte(' ')
			}
			writeType(buf, this, f.typ, visited)
			if tag := t.Tag(i); tag != "" {
				fmt.Fprintf(buf, " %q", tag)
			}
		}
		buf.WriteByte('}')

	case *Pointer:
		buf.WriteByte('*')
		writeType(buf, this, t.base, visited)

	case *Tuple:
		writeTuple(buf, this, t, false, visited)

	case *Signature:
		buf.WriteString("func")
		writeSignature(buf, this, t, visited)

	case *Interface:
		// We write the source-level methods and embedded types rather
		// than the actual method set since resolved method signatures
		// may have non-printable cycles if parameters have anonymous
		// interface types that (directly or indirectly) embed the
		// current interface. For instance, consider the result type
		// of m:
		//
		//     type T interface{
		//         m() interface{ T }
		//     }
		//
		buf.WriteString("interface{")
		if GcCompatibilityMode {
			// print flattened interface
			// (useful to compare against gc-generated interfaces)
			for i, m := range t.allMethods {
				if i > 0 {
					buf.WriteString("; ")
				}
				buf.WriteString(m.name)
				writeSignature(buf, this, m.typ.(*Signature), visited)
			}
		} else {
			// print explicit interface methods and embedded types
			for i, m := range t.methods {
				if i > 0 {
					buf.WriteString("; ")
				}
				buf.WriteString(m.name)
				writeSignature(buf, this, m.typ.(*Signature), visited)
			}
			for i, typ := range t.embeddeds {
				if i > 0 || len(t.methods) > 0 {
					buf.WriteString("; ")
				}
				writeType(buf, this, typ, visited)
			}
		}
		buf.WriteByte('}')

	case *Map:
		buf.WriteString("map[")
		writeType(buf, this, t.key, visited)
		buf.WriteByte(']')
		writeType(buf, this, t.elem, visited)

	case *Chan:
		var s string
		var parens bool
		switch t.dir {
		case SendRecv:
			s = "chan "
			// chan (<-chan T) requires parentheses
			if c, _ := t.elem.(*Chan); c != nil && c.dir == RecvOnly {
				parens = true
			}
		case SendOnly:
			s = "chan<- "
		case RecvOnly:
			s = "<-chan "
		default:
			panic("unreachable")
		}
		buf.WriteString(s)
		if parens {
			buf.WriteByte('(')
		}
		writeType(buf, this, t.elem, visited)
		if parens {
			buf.WriteByte(')')
		}

	case *Named:
		s := "<Named w/o object>"
		if obj := t.obj; obj != nil {
			if obj.pkg != nil {
				if obj.pkg != this {
					buf.WriteString(obj.pkg.path)
					buf.WriteByte('.')
				}
				// TODO(gri): function-local named types should be displayed
				// differently from named types at package level to avoid
				// ambiguity.
			}
			s = t.obj.name
		}
		buf.WriteString(s)

	default:
		// For externally defined implementations of Type.
		buf.WriteString(t.String())
	}
}

func writeTuple(buf *bytes.Buffer, this *Package, tup *Tuple, variadic bool, visited []Type) {
	buf.WriteByte('(')
	if tup != nil {
		for i, v := range tup.vars {
			if i > 0 {
				buf.WriteString(", ")
			}
			if v.name != "" {
				buf.WriteString(v.name)
				buf.WriteByte(' ')
			}
			typ := v.typ
			if variadic && i == len(tup.vars)-1 {
				buf.WriteString("...")
				typ = typ.(*Slice).elem
			}
			writeType(buf, this, typ, visited)
		}
	}
	buf.WriteByte(')')
}

// WriteSignature writes the representation of the signature sig to buf,
// without a leading "func" keyword.
// Named types are printed package-qualified if they
// do not belong to this package.
func WriteSignature(buf *bytes.Buffer, this *Package, sig *Signature) {
	writeSignature(buf, this, sig, make([]Type, 8))
}

func writeSignature(buf *bytes.Buffer, this *Package, sig *Signature, visited []Type) {
	writeTuple(buf, this, sig.params, sig.variadic, visited)

	n := sig.results.Len()
	if n == 0 {
		// no result
		return
	}

	buf.WriteByte(' ')
	if n == 1 && sig.results.vars[0].name == "" {
		// single unnamed result
		writeType(buf, this, sig.results.vars[0].typ, visited)
		return
	}

	// multiple or named result(s)
	writeTuple(buf, this, sig.results, false, visited)
}
<commit_msg>go.tools/go/types: minor internal cleanup<commit_after>// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file implements printing of types.

package types

import (
	"bytes"
	"fmt"
)

// If GcCompatibilityMode is set, printing of types is modified
// to match the representation of some types in the gc compiler:
//
//	- byte and rune lose their alias name and simply stand for
//	  uint8 and int32 respectively
//	- embedded interfaces get flattened (the embedding info is lost,
//	  and certain recursive interface types cannot be printed anymore)
//
// This makes it easier to compare packages computed with the type-
// checker vs packages imported from gc export data.
//
// Caution: This flag affects all uses of WriteType, globally.
// It is only provided for testing in conjunction with
// gc-generated data. It may be removed at any time.
var GcCompatibilityMode bool

// TypeString returns the string representation of typ.
// Named types are printed package-qualified if they
// do not belong to this package.
func TypeString(this *Package, typ Type) string {
	var buf bytes.Buffer
	WriteType(&buf, this, typ)
	return buf.String()
}

// WriteType writes the string representation of typ to buf.
// Named types are printed package-qualified if they
// do not belong to this package.
func WriteType(buf *bytes.Buffer, this *Package, typ Type) {
	writeType(buf, this, typ, make([]Type, 8))
}

func writeType(buf *bytes.Buffer, this *Package, typ Type, visited []Type) {
	// Theoretically, this is a quadratic lookup algorithm, but in
	// practice deeply nested composite types with unnamed component
	// types are uncommon. This code is likely more efficient than
	// using a map.
	for _, t := range visited {
		if t == typ {
			fmt.Fprintf(buf, "○%T", typ) // cycle to typ
			return
		}
	}
	visited = append(visited, typ)

	switch t := typ.(type) {
	case nil:
		buf.WriteString("<nil>")

	case *Basic:
		if t.kind == UnsafePointer {
			buf.WriteString("unsafe.")
		}
		if GcCompatibilityMode {
			// forget the alias names
			switch t.kind {
			case Byte:
				t = Typ[Uint8]
			case Rune:
				t = Typ[Int32]
			}
		}
		buf.WriteString(t.name)

	case *Array:
		fmt.Fprintf(buf, "[%d]", t.len)
		writeType(buf, this, t.elem, visited)

	case *Slice:
		buf.WriteString("[]")
		writeType(buf, this, t.elem, visited)

	case *Struct:
		buf.WriteString("struct{")
		for i, f := range t.fields {
			if i > 0 {
				buf.WriteString("; ")
			}
			if !f.anonymous {
				buf.WriteString(f.name)
				buf.WriteByte(' ')
			}
			writeType(buf, this, f.typ, visited)
			if tag := t.Tag(i); tag != "" {
				fmt.Fprintf(buf, " %q", tag)
			}
		}
		buf.WriteByte('}')

	case *Pointer:
		buf.WriteByte('*')
		writeType(buf, this, t.base, visited)

	case *Tuple:
		writeTuple(buf, this, t, false, visited)

	case *Signature:
		buf.WriteString("func")
		writeSignature(buf, this, t, visited)

	case *Interface:
		// We write the source-level methods and embedded types rather
		// than the actual method set since resolved method signatures
		// may have non-printable cycles if parameters have anonymous
		// interface types that (directly or indirectly) embed the
		// current interface. For instance, consider the result type
		// of m:
		//
		//     type T interface{
		//         m() interface{ T }
		//     }
		//
		buf.WriteString("interface{")
		if GcCompatibilityMode {
			// print flattened interface
			// (useful to compare against gc-generated interfaces)
			for i, m := range t.allMethods {
				if i > 0 {
					buf.WriteString("; ")
				}
				buf.WriteString(m.name)
				writeSignature(buf, this, m.typ.(*Signature), visited)
			}
		} else {
			// print explicit interface methods and embedded types
			for i, m := range t.methods {
				if i > 0 {
					buf.WriteString("; ")
				}
				buf.WriteString(m.name)
				writeSignature(buf, this, m.typ.(*Signature), visited)
			}
			for i, typ := range t.embeddeds {
				if i > 0 || len(t.methods) > 0 {
					buf.WriteString("; ")
				}
				writeType(buf, this, typ, visited)
			}
		}
		buf.WriteByte('}')

	case *Map:
		buf.WriteString("map[")
		writeType(buf, this, t.key, visited)
		buf.WriteByte(']')
		writeType(buf, this, t.elem, visited)

	case *Chan:
		var s string
		var parens bool
		switch t.dir {
		case SendRecv:
			s = "chan "
			// chan (<-chan T) requires parentheses
			if c, _ := t.elem.(*Chan); c != nil && c.dir == RecvOnly {
				parens = true
			}
		case SendOnly:
			s = "chan<- "
		case RecvOnly:
			s = "<-chan "
		default:
			panic("unreachable")
		}
		buf.WriteString(s)
		if parens {
			buf.WriteByte('(')
		}
		writeType(buf, this, t.elem, visited)
		if parens {
			buf.WriteByte(')')
		}

	case *Named:
		s := "<Named w/o object>"
		if obj := t.obj; obj != nil {
			if pkg := obj.pkg; pkg != nil && pkg != this {
				buf.WriteString(pkg.path)
				buf.WriteByte('.')
			}
			// TODO(gri): function-local named types should be displayed
			// differently from named types at package level to avoid
			// ambiguity.
			s = obj.name
		}
		buf.WriteString(s)

	default:
		// For externally defined implementations of Type.
		buf.WriteString(t.String())
	}
}

func writeTuple(buf *bytes.Buffer, this *Package, tup *Tuple, variadic bool, visited []Type) {
	buf.WriteByte('(')
	if tup != nil {
		for i, v := range tup.vars {
			if i > 0 {
				buf.WriteString(", ")
			}
			if v.name != "" {
				buf.WriteString(v.name)
				buf.WriteByte(' ')
			}
			typ := v.typ
			if variadic && i == len(tup.vars)-1 {
				buf.WriteString("...")
				typ = typ.(*Slice).elem
			}
			writeType(buf, this, typ, visited)
		}
	}
	buf.WriteByte(')')
}

// WriteSignature writes the representation of the signature sig to buf,
// without a leading "func" keyword.
// Named types are printed package-qualified if they
// do not belong to this package.
func WriteSignature(buf *bytes.Buffer, this *Package, sig *Signature) {
	writeSignature(buf, this, sig, make([]Type, 8))
}

func writeSignature(buf *bytes.Buffer, this *Package, sig *Signature, visited []Type) {
	writeTuple(buf, this, sig.params, sig.variadic, visited)

	n := sig.results.Len()
	if n == 0 {
		// no result
		return
	}

	buf.WriteByte(' ')
	if n == 1 && sig.results.vars[0].name == "" {
		// single unnamed result
		writeType(buf, this, sig.results.vars[0].typ, visited)
		return
	}

	// multiple or named result(s)
	writeTuple(buf, this, sig.results, false, visited)
}
<|endoftext|>


<commit_before>// Copyright 2016, RadiantBlue Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package piazza

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
	"strings"

	"github.com/gin-gonic/gin"
)

//----------------------------------------------------------

const (
	// ContentTypeJSON is the http content-type for JSON.
	ContentTypeJSON = "application/json"

	// ContentTypeText is the http content-type for plain text.
	ContentTypeText = "text/plain"
)

//----------------------------------------------------------

// Put, because there is no http.Put.
func HTTPPut(url string, contentType string, body io.Reader) (*http.Response, error) {
	req, err := http.NewRequest("PUT", url, body)
	if err != nil {
		return nil, err
	}

	req.Header.Set("Content-Type", contentType)
	client := &http.Client{}
	return client.Do(req)
}

// Delete, because there is no http.Delete.
func HTTPDelete(url string) (*http.Response, error) {
	req, err := http.NewRequest("DELETE", url, nil)
	if err != nil {
		return nil, err
	}

	client := &http.Client{}
	return client.Do(req)
}

//---------------------------------------------------------------------

func GinReturnJson(c *gin.Context, resp *JsonResponse) {
	raw, err := json.MarshalIndent(resp, "", "  ")
	if err != nil {
		log.Fatalf("Internal Error: marshalling of %#v", resp)
	}
	c.Data(resp.StatusCode, ContentTypeJSON, raw)

	// If things get worse, try this:
	//    c.Writer.Header().Set("Content-Type", "application/json; charset=utf-8")
	//    c.Writer.Header().Set("Content-Length", str(len(raw))
}

// GetApiKey retrieves the Pz API key for the given server, in this order:
//
// (1) if $PZKEY present, use that
// (2) if ~/.pzkey exists, use that
// (3) error
//
// And no, we don't uspport Windows.
func GetApiKey(pzserver string) (string, error) {

	fileExists := func(s string) bool {
		if _, err := os.Stat(s); os.IsNotExist(err) {
			return false
		}
		return true
	}

	key := os.Getenv("PZKEY")
	if key != "" {
		key = strings.TrimSpace(key)
		return key, nil
	}

	home := os.Getenv("HOME")
	if home == "" {
		return "", errors.New("Unable read $HOME")
	}

	path := home + "/.pzkey"
	if !fileExists(path) {
		return "", errors.New("Unable to find env var $PZKEY or file $HOME/.pzkey")
	}

	raw, err := ioutil.ReadFile(path)
	if err != nil {
		return "", err
	}

	data := map[string]string{}
	err = json.Unmarshal(raw, &data)
	if err != nil {
		return "", err
	}

	key, ok := data[pzserver]
	if !ok {
		return "", fmt.Errorf("No API key for server %s", pzserver)
	}

	return key, nil
}

// GetApiServer gets the $PZSERVER host.
func GetApiServer() (string, error) {
	pzserver := os.Getenv("PZSERVER")
	if pzserver == "" {
		return "", fmt.Errorf("$PZSERVER not set")
	}
	return pzserver, nil
}

// GetExternalIP returns the "best"(?) IP address we can reasonably get.
// see: http://stackoverflow.com/a/23558495
func GetExternalIP() (string, error) {
	ifaces, err := net.Interfaces()
	if err != nil {
		return "", err
	}
	for _, iface := range ifaces {
		if iface.Flags&net.FlagUp == 0 {
			continue // interface down
		}
		if iface.Flags&net.FlagLoopback != 0 {
			continue // loopback interface
		}
		addrs, err := iface.Addrs()
		if err != nil {
			return "", err
		}
		for _, addr := range addrs {
			var ip net.IP
			switch v := addr.(type) {
			case *net.IPNet:
				ip = v.IP
			case *net.IPAddr:
				ip = v.IP
			}
			if ip == nil || ip.IsLoopback() {
				continue
			}
			ip = ip.To4()
			if ip == nil {
				continue // not an ipv4 address
			}
			return ip.String(), nil
		}
	}
	return "", errors.New("are you connected to the network?")
}
<commit_msg>simplify JSON response<commit_after>// Copyright 2016, RadiantBlue Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package piazza

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
	"strings"

	"github.com/gin-gonic/gin"
)

//----------------------------------------------------------

const (
	// ContentTypeJSON is the http content-type for JSON.
	ContentTypeJSON = "application/json"

	// ContentTypeText is the http content-type for plain text.
	ContentTypeText = "text/plain"
)

//----------------------------------------------------------

// Put, because there is no http.Put.
func HTTPPut(url string, contentType string, body io.Reader) (*http.Response, error) {
	req, err := http.NewRequest("PUT", url, body)
	if err != nil {
		return nil, err
	}

	req.Header.Set("Content-Type", contentType)
	client := &http.Client{}
	return client.Do(req)
}

// Delete, because there is no http.Delete.
func HTTPDelete(url string) (*http.Response, error) {
	req, err := http.NewRequest("DELETE", url, nil)
	if err != nil {
		return nil, err
	}

	client := &http.Client{}
	return client.Do(req)
}

//---------------------------------------------------------------------

func GinReturnJson(c *gin.Context, resp *JsonResponse) {
	// this just for error checking
	_, err := json.MarshalIndent(resp, "", "  ")
	if err != nil {
		log.Fatalf("Internal Error: marshalling of %#v", resp)
	}

	c.JSON(resp.StatusCode, resp)

	// If things get worse, try this:
	//    c.Writer.Header().Set("Content-Type", "application/json; charset=utf-8")
	//    c.Writer.Header().Set("Content-Length", fmt.Sprintf("%d", len(raw)))
}

// GetApiKey retrieves the Pz API key for the given server, in this order:
//
// (1) if $PZKEY present, use that
// (2) if ~/.pzkey exists, use that
// (3) error
//
// And no, we don't uspport Windows.
func GetApiKey(pzserver string) (string, error) {

	fileExists := func(s string) bool {
		if _, err := os.Stat(s); os.IsNotExist(err) {
			return false
		}
		return true
	}

	key := os.Getenv("PZKEY")
	if key != "" {
		key = strings.TrimSpace(key)
		return key, nil
	}

	home := os.Getenv("HOME")
	if home == "" {
		return "", errors.New("Unable read $HOME")
	}

	path := home + "/.pzkey"
	if !fileExists(path) {
		return "", errors.New("Unable to find env var $PZKEY or file $HOME/.pzkey")
	}

	raw, err := ioutil.ReadFile(path)
	if err != nil {
		return "", err
	}

	data := map[string]string{}
	err = json.Unmarshal(raw, &data)
	if err != nil {
		return "", err
	}

	key, ok := data[pzserver]
	if !ok {
		return "", fmt.Errorf("No API key for server %s", pzserver)
	}

	return key, nil
}

// GetApiServer gets the $PZSERVER host.
func GetApiServer() (string, error) {
	pzserver := os.Getenv("PZSERVER")
	if pzserver == "" {
		return "", fmt.Errorf("$PZSERVER not set")
	}
	return pzserver, nil
}

// GetExternalIP returns the "best"(?) IP address we can reasonably get.
// see: http://stackoverflow.com/a/23558495
func GetExternalIP() (string, error) {
	ifaces, err := net.Interfaces()
	if err != nil {
		return "", err
	}
	for _, iface := range ifaces {
		if iface.Flags&net.FlagUp == 0 {
			continue // interface down
		}
		if iface.Flags&net.FlagLoopback != 0 {
			continue // loopback interface
		}
		addrs, err := iface.Addrs()
		if err != nil {
			return "", err
		}
		for _, addr := range addrs {
			var ip net.IP
			switch v := addr.(type) {
			case *net.IPNet:
				ip = v.IP
			case *net.IPAddr:
				ip = v.IP
			}
			if ip == nil || ip.IsLoopback() {
				continue
			}
			ip = ip.To4()
			if ip == nil {
				continue // not an ipv4 address
			}
			return ip.String(), nil
		}
	}
	return "", errors.New("are you connected to the network?")
}
<|endoftext|>


<commit_before>/*
Copyright 2018 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 testsuites

import (
	"fmt"
	"time"

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

	"k8s.io/api/core/v1"
	storage "k8s.io/api/storage/v1"
	apierrs "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/client-go/dynamic"
	clientset "k8s.io/client-go/kubernetes"
	"k8s.io/kubernetes/test/e2e/framework"
	"k8s.io/kubernetes/test/e2e/storage/testpatterns"
)

// snapshot CRD api group
const snapshotGroup = "snapshot.storage.k8s.io"

// snapshot CRD api version
const snapshotAPIVersion = "snapshot.storage.k8s.io/v1alpha1"

var (
	snapshotGVR        = schema.GroupVersionResource{Group: snapshotGroup, Version: "v1alpha1", Resource: "volumesnapshots"}
	snapshotClassGVR   = schema.GroupVersionResource{Group: snapshotGroup, Version: "v1alpha1", Resource: "volumesnapshotclasses"}
	snapshotContentGVR = schema.GroupVersionResource{Group: snapshotGroup, Version: "v1alpha1", Resource: "volumesnapshotcontents"}
)

type SnapshotClassTest struct {
	Name                 string
	CloudProviders       []string
	Snapshotter          string
	Parameters           map[string]string
	NodeName             string
	NodeSelector         map[string]string // NodeSelector for the pod
	SnapshotContentCheck func(snapshotContent *unstructured.Unstructured) error
}

type snapshottableTestSuite struct {
	tsInfo TestSuiteInfo
}

var _ TestSuite = &snapshottableTestSuite{}

// InitSnapshottableTestSuite returns snapshottableTestSuite that implements TestSuite interface
func InitSnapshottableTestSuite() TestSuite {
	return &snapshottableTestSuite{
		tsInfo: TestSuiteInfo{
			name: "snapshottable",
			testPatterns: []testpatterns.TestPattern{
				testpatterns.DynamicSnapshot,
			},
		},
	}
}

func (s *snapshottableTestSuite) getTestSuiteInfo() TestSuiteInfo {
	return s.tsInfo
}

func (s *snapshottableTestSuite) skipUnsupportedTest(pattern testpatterns.TestPattern, driver TestDriver) {
}

func createSnapshottableTestInput(driver TestDriver, pattern testpatterns.TestPattern) (snapshottableTestResource, snapshottableTestInput) {
	// Setup test resource for driver and testpattern
	resource := snapshottableTestResource{}
	resource.setupResource(driver, pattern)

	input := snapshottableTestInput{
		testCase: SnapshotClassTest{},
		cs:       driver.GetDriverInfo().Config.Framework.ClientSet,
		dc:       driver.GetDriverInfo().Config.Framework.DynamicClient,
		pvc:      resource.pvc,
		sc:       resource.sc,
		vsc:      resource.vsc,
		dInfo:    driver.GetDriverInfo(),
	}

	if driver.GetDriverInfo().Config.ClientNodeName != "" {
		input.testCase.NodeName = driver.GetDriverInfo().Config.ClientNodeName
	}

	return resource, input
}

func (s *snapshottableTestSuite) execTest(driver TestDriver, pattern testpatterns.TestPattern) {
	Context(getTestNameStr(s, pattern), func() {
		var (
			resource     snapshottableTestResource
			input        snapshottableTestInput
			needsCleanup bool
		)

		BeforeEach(func() {
			needsCleanup = false
			// Skip unsupported tests to avoid unnecessary resource initialization
			skipUnsupportedTest(s, driver, pattern)
			needsCleanup = true

			// Create test input
			resource, input = createSnapshottableTestInput(driver, pattern)
		})

		AfterEach(func() {
			if needsCleanup {
				resource.cleanupResource(driver, pattern)
			}
		})

		// Ginkgo's "Global Shared Behaviors" require arguments for a shared function
		// to be a single struct and to be passed as a pointer.
		// Please see https://onsi.github.io/ginkgo/#global-shared-behaviors for details.
		testSnapshot(&input)
	})
}

type snapshottableTestResource struct {
	driver    TestDriver
	claimSize string

	sc  *storage.StorageClass
	pvc *v1.PersistentVolumeClaim
	// volume snapshot class
	vsc *unstructured.Unstructured
}

var _ TestResource = &snapshottableTestResource{}

func (s *snapshottableTestResource) setupResource(driver TestDriver, pattern testpatterns.TestPattern) {
	// Setup snapshottableTest resource
	switch pattern.SnapshotType {
	case testpatterns.DynamicCreatedSnapshot:
		if dDriver, ok := driver.(DynamicPVTestDriver); ok {
			s.sc = dDriver.GetDynamicProvisionStorageClass("")
			if s.sc == nil {
				framework.Skipf("Driver %q does not define Dynamic Provision StorageClass - skipping", driver.GetDriverInfo().Name)
			}
			s.driver = driver
			s.claimSize = dDriver.GetClaimSize()
			s.pvc = getClaim(s.claimSize, driver.GetDriverInfo().Config.Framework.Namespace.Name)
			s.pvc.Spec.StorageClassName = &s.sc.Name
			framework.Logf("In creating storage class object and pvc object for driver - sc: %v, pvc: %v", s.sc, s.pvc)

			if sDriver, ok := driver.(SnapshottableTestDriver); ok {
				s.vsc = sDriver.GetSnapshotClass()
			}
		}

	default:
		framework.Failf("Dynamic Snapshot test doesn't support: %s", pattern.SnapshotType)
	}
}

func (s *snapshottableTestResource) cleanupResource(driver TestDriver, pattern testpatterns.TestPattern) {
}

type snapshottableTestInput struct {
	testCase SnapshotClassTest
	cs       clientset.Interface
	dc       dynamic.Interface
	pvc      *v1.PersistentVolumeClaim
	sc       *storage.StorageClass
	// volume snapshot class
	vsc   *unstructured.Unstructured
	dInfo *DriverInfo
}

func testSnapshot(input *snapshottableTestInput) {
	It("should create snapshot with defaults", func() {
		if input.dInfo.Name == "csi-hostpath-v0" {
			framework.Skipf("skip test when using driver csi-hostpath-v0 - skipping")
		}
		TestCreateSnapshot(input.testCase, input.cs, input.dc, input.pvc, input.sc, input.vsc)
	})
}

// TestCreateSnapshot tests dynamic creating snapshot with specified SnapshotClassTest and snapshotClass
func TestCreateSnapshot(
	t SnapshotClassTest,
	client clientset.Interface,
	dynamicClient dynamic.Interface,
	claim *v1.PersistentVolumeClaim,
	class *storage.StorageClass,
	snapshotClass *unstructured.Unstructured,
) *unstructured.Unstructured {
	var err error
	if class != nil {
		By("creating a StorageClass " + class.Name)
		class, err = client.StorageV1().StorageClasses().Create(class)
		Expect(err).NotTo(HaveOccurred())
		defer func() {
			framework.Logf("deleting storage class %s", class.Name)
			framework.ExpectNoError(client.StorageV1().StorageClasses().Delete(class.Name, nil))
		}()
	}

	By("creating a claim")
	claim, err = client.CoreV1().PersistentVolumeClaims(claim.Namespace).Create(claim)
	Expect(err).NotTo(HaveOccurred())
	defer func() {
		framework.Logf("deleting claim %q/%q", claim.Namespace, claim.Name)
		// typically this claim has already been deleted
		err = client.CoreV1().PersistentVolumeClaims(claim.Namespace).Delete(claim.Name, nil)
		if err != nil && !apierrs.IsNotFound(err) {
			framework.Failf("Error deleting claim %q. Error: %v", claim.Name, err)
		}
	}()
	err = framework.WaitForPersistentVolumeClaimPhase(v1.ClaimBound, client, claim.Namespace, claim.Name, framework.Poll, framework.ClaimProvisionTimeout)
	Expect(err).NotTo(HaveOccurred())

	By("checking the claim")
	// Get new copy of the claim
	claim, err = client.CoreV1().PersistentVolumeClaims(claim.Namespace).Get(claim.Name, metav1.GetOptions{})
	Expect(err).NotTo(HaveOccurred())

	// Get the bound PV
	pv, err := client.CoreV1().PersistentVolumes().Get(claim.Spec.VolumeName, metav1.GetOptions{})
	Expect(err).NotTo(HaveOccurred())

	By("creating a SnapshotClass")
	snapshotClass, err = dynamicClient.Resource(snapshotClassGVR).Create(snapshotClass, metav1.CreateOptions{})
	Expect(err).NotTo(HaveOccurred())
	defer func() {
		framework.Logf("deleting SnapshotClass %s", snapshotClass.GetName())
		framework.ExpectNoError(dynamicClient.Resource(snapshotClassGVR).Delete(snapshotClass.GetName(), nil))
	}()

	By("creating a snapshot")
	snapshot := getSnapshot(claim.Name, claim.Namespace, snapshotClass.GetName())

	snapshot, err = dynamicClient.Resource(snapshotGVR).Namespace(snapshot.GetNamespace()).Create(snapshot, metav1.CreateOptions{})
	Expect(err).NotTo(HaveOccurred())
	defer func() {
		framework.Logf("deleting snapshot %q/%q", snapshot.GetNamespace(), snapshot.GetName())
		// typically this snapshot has already been deleted
		err = dynamicClient.Resource(snapshotGVR).Namespace(snapshot.GetNamespace()).Delete(snapshot.GetName(), nil)
		if err != nil && !apierrs.IsNotFound(err) {
			framework.Failf("Error deleting snapshot %q. Error: %v", claim.Name, err)
		}
	}()
	err = WaitForSnapshotReady(dynamicClient, snapshot.GetNamespace(), snapshot.GetName(), framework.Poll, framework.SnapshotCreateTimeout)
	Expect(err).NotTo(HaveOccurred())

	By("checking the snapshot")
	// Get new copy of the snapshot
	snapshot, err = dynamicClient.Resource(snapshotGVR).Namespace(snapshot.GetNamespace()).Get(snapshot.GetName(), metav1.GetOptions{})
	Expect(err).NotTo(HaveOccurred())

	// Get the bound snapshotContent
	snapshotSpec := snapshot.Object["spec"].(map[string]interface{})
	snapshotContentName := snapshotSpec["snapshotContentName"].(string)
	snapshotContent, err := dynamicClient.Resource(snapshotContentGVR).Get(snapshotContentName, metav1.GetOptions{})
	Expect(err).NotTo(HaveOccurred())

	snapshotContentSpec := snapshotContent.Object["spec"].(map[string]interface{})
	volumeSnapshotRef := snapshotContentSpec["volumeSnapshotRef"].(map[string]interface{})
	persistentVolumeRef := snapshotContentSpec["persistentVolumeRef"].(map[string]interface{})

	// Check SnapshotContent properties
	By("checking the SnapshotContent")
	Expect(snapshotContentSpec["snapshotClassName"]).To(Equal(snapshotClass.GetName()))
	Expect(volumeSnapshotRef["name"]).To(Equal(snapshot.GetName()))
	Expect(volumeSnapshotRef["namespace"]).To(Equal(snapshot.GetNamespace()))
	Expect(persistentVolumeRef["name"]).To(Equal(pv.Name))

	// Run the checker
	if t.SnapshotContentCheck != nil {
		err = t.SnapshotContentCheck(snapshotContent)
		Expect(err).NotTo(HaveOccurred())
	}

	return snapshotContent
}

// WaitForSnapshotReady waits for a VolumeSnapshot to be ready to use or until timeout occurs, whichever comes first.
func WaitForSnapshotReady(c dynamic.Interface, ns string, snapshotName string, Poll, timeout time.Duration) error {
	framework.Logf("Waiting up to %v for VolumeSnapshot %s to become ready", timeout, snapshotName)
	for start := time.Now(); time.Since(start) < timeout; time.Sleep(Poll) {
		snapshot, err := c.Resource(snapshotGVR).Namespace(ns).Get(snapshotName, metav1.GetOptions{})
		if err != nil {
			framework.Logf("Failed to get claim %q, retrying in %v. Error: %v", snapshotName, Poll, err)
			continue
		} else {
			status := snapshot.Object["status"]
			if status == nil {
				framework.Logf("VolumeSnapshot %s found but is not ready.", snapshotName)
				continue
			}
			value := status.(map[string]interface{})
			if value["readyToUse"] == true {
				framework.Logf("VolumeSnapshot %s found and is ready", snapshotName, time.Since(start))
				return nil
			} else if value["ready"] == true {
				framework.Logf("VolumeSnapshot %s found and is ready", snapshotName, time.Since(start))
				return nil
			} else {
				framework.Logf("VolumeSnapshot %s found but is not ready.", snapshotName)
			}
		}
	}
	return fmt.Errorf("VolumeSnapshot %s is not ready within %v", snapshotName, timeout)
}
<commit_msg>e2e: refine snapshot test<commit_after>/*
Copyright 2018 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 testsuites

import (
	"fmt"
	"time"

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

	"k8s.io/api/core/v1"
	storage "k8s.io/api/storage/v1"
	apierrs "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/client-go/dynamic"
	clientset "k8s.io/client-go/kubernetes"
	"k8s.io/kubernetes/test/e2e/framework"
	"k8s.io/kubernetes/test/e2e/storage/testpatterns"
)

// snapshot CRD api group
const snapshotGroup = "snapshot.storage.k8s.io"

// snapshot CRD api version
const snapshotAPIVersion = "snapshot.storage.k8s.io/v1alpha1"

var (
	snapshotGVR        = schema.GroupVersionResource{Group: snapshotGroup, Version: "v1alpha1", Resource: "volumesnapshots"}
	snapshotClassGVR   = schema.GroupVersionResource{Group: snapshotGroup, Version: "v1alpha1", Resource: "volumesnapshotclasses"}
	snapshotContentGVR = schema.GroupVersionResource{Group: snapshotGroup, Version: "v1alpha1", Resource: "volumesnapshotcontents"}
)

type SnapshotClassTest struct {
	Name                 string
	CloudProviders       []string
	Snapshotter          string
	Parameters           map[string]string
	NodeName             string
	NodeSelector         map[string]string // NodeSelector for the pod
	SnapshotContentCheck func(snapshotContent *unstructured.Unstructured) error
}

type snapshottableTestSuite struct {
	tsInfo TestSuiteInfo
}

var _ TestSuite = &snapshottableTestSuite{}

// InitSnapshottableTestSuite returns snapshottableTestSuite that implements TestSuite interface
func InitSnapshottableTestSuite() TestSuite {
	return &snapshottableTestSuite{
		tsInfo: TestSuiteInfo{
			name: "snapshottable",
			testPatterns: []testpatterns.TestPattern{
				testpatterns.DynamicSnapshot,
			},
		},
	}
}

func (s *snapshottableTestSuite) getTestSuiteInfo() TestSuiteInfo {
	return s.tsInfo
}

func (s *snapshottableTestSuite) skipUnsupportedTest(pattern testpatterns.TestPattern, driver TestDriver) {
	dInfo := driver.GetDriverInfo()
	if !dInfo.Capabilities[CapDataSource] {
		framework.Skipf("Driver %q does not support snapshots - skipping", dInfo.Name)
	}
}

func createSnapshottableTestInput(driver TestDriver, pattern testpatterns.TestPattern) (snapshottableTestResource, snapshottableTestInput) {
	// Setup test resource for driver and testpattern
	resource := snapshottableTestResource{}
	resource.setupResource(driver, pattern)

	input := snapshottableTestInput{
		testCase: SnapshotClassTest{},
		cs:       driver.GetDriverInfo().Config.Framework.ClientSet,
		dc:       driver.GetDriverInfo().Config.Framework.DynamicClient,
		pvc:      resource.pvc,
		sc:       resource.sc,
		vsc:      resource.vsc,
		dInfo:    driver.GetDriverInfo(),
	}

	if driver.GetDriverInfo().Config.ClientNodeName != "" {
		input.testCase.NodeName = driver.GetDriverInfo().Config.ClientNodeName
	}

	return resource, input
}

func (s *snapshottableTestSuite) execTest(driver TestDriver, pattern testpatterns.TestPattern) {
	Context(getTestNameStr(s, pattern), func() {
		var (
			resource     snapshottableTestResource
			input        snapshottableTestInput
			needsCleanup bool
		)

		BeforeEach(func() {
			needsCleanup = false
			// Skip unsupported tests to avoid unnecessary resource initialization
			skipUnsupportedTest(s, driver, pattern)
			needsCleanup = true

			// Create test input
			resource, input = createSnapshottableTestInput(driver, pattern)
		})

		AfterEach(func() {
			if needsCleanup {
				resource.cleanupResource(driver, pattern)
			}
		})

		// Ginkgo's "Global Shared Behaviors" require arguments for a shared function
		// to be a single struct and to be passed as a pointer.
		// Please see https://onsi.github.io/ginkgo/#global-shared-behaviors for details.
		testSnapshot(&input)
	})
}

type snapshottableTestResource struct {
	driver    TestDriver
	claimSize string

	sc  *storage.StorageClass
	pvc *v1.PersistentVolumeClaim
	// volume snapshot class
	vsc *unstructured.Unstructured
}

var _ TestResource = &snapshottableTestResource{}

func (s *snapshottableTestResource) setupResource(driver TestDriver, pattern testpatterns.TestPattern) {
	// Setup snapshottableTest resource
	switch pattern.SnapshotType {
	case testpatterns.DynamicCreatedSnapshot:
		if dDriver, ok := driver.(DynamicPVTestDriver); ok {
			s.sc = dDriver.GetDynamicProvisionStorageClass("")
			if s.sc == nil {
				framework.Skipf("Driver %q does not define Dynamic Provision StorageClass - skipping", driver.GetDriverInfo().Name)
			}
			s.driver = driver
			s.claimSize = dDriver.GetClaimSize()
			s.pvc = getClaim(s.claimSize, driver.GetDriverInfo().Config.Framework.Namespace.Name)
			s.pvc.Spec.StorageClassName = &s.sc.Name
			framework.Logf("In creating storage class object and pvc object for driver - sc: %v, pvc: %v", s.sc, s.pvc)

			if sDriver, ok := driver.(SnapshottableTestDriver); ok {
				s.vsc = sDriver.GetSnapshotClass()
			}
		}

	default:
		framework.Failf("Dynamic Snapshot test doesn't support: %s", pattern.SnapshotType)
	}
}

func (s *snapshottableTestResource) cleanupResource(driver TestDriver, pattern testpatterns.TestPattern) {
}

type snapshottableTestInput struct {
	testCase SnapshotClassTest
	cs       clientset.Interface
	dc       dynamic.Interface
	pvc      *v1.PersistentVolumeClaim
	sc       *storage.StorageClass
	// volume snapshot class
	vsc   *unstructured.Unstructured
	dInfo *DriverInfo
}

func testSnapshot(input *snapshottableTestInput) {
	It("should create snapshot with defaults [Feature:VolumeSnapshotDataSource]", func() {
		TestCreateSnapshot(input.testCase, input.cs, input.dc, input.pvc, input.sc, input.vsc)
	})
}

// TestCreateSnapshot tests dynamic creating snapshot with specified SnapshotClassTest and snapshotClass
func TestCreateSnapshot(
	t SnapshotClassTest,
	client clientset.Interface,
	dynamicClient dynamic.Interface,
	claim *v1.PersistentVolumeClaim,
	class *storage.StorageClass,
	snapshotClass *unstructured.Unstructured,
) *unstructured.Unstructured {
	var err error
	if class != nil {
		By("creating a StorageClass " + class.Name)
		class, err = client.StorageV1().StorageClasses().Create(class)
		Expect(err).NotTo(HaveOccurred())
		defer func() {
			framework.Logf("deleting storage class %s", class.Name)
			framework.ExpectNoError(client.StorageV1().StorageClasses().Delete(class.Name, nil))
		}()
	}

	By("creating a claim")
	claim, err = client.CoreV1().PersistentVolumeClaims(claim.Namespace).Create(claim)
	Expect(err).NotTo(HaveOccurred())
	defer func() {
		framework.Logf("deleting claim %q/%q", claim.Namespace, claim.Name)
		// typically this claim has already been deleted
		err = client.CoreV1().PersistentVolumeClaims(claim.Namespace).Delete(claim.Name, nil)
		if err != nil && !apierrs.IsNotFound(err) {
			framework.Failf("Error deleting claim %q. Error: %v", claim.Name, err)
		}
	}()
	err = framework.WaitForPersistentVolumeClaimPhase(v1.ClaimBound, client, claim.Namespace, claim.Name, framework.Poll, framework.ClaimProvisionTimeout)
	Expect(err).NotTo(HaveOccurred())

	By("checking the claim")
	// Get new copy of the claim
	claim, err = client.CoreV1().PersistentVolumeClaims(claim.Namespace).Get(claim.Name, metav1.GetOptions{})
	Expect(err).NotTo(HaveOccurred())

	// Get the bound PV
	pv, err := client.CoreV1().PersistentVolumes().Get(claim.Spec.VolumeName, metav1.GetOptions{})
	Expect(err).NotTo(HaveOccurred())

	By("creating a SnapshotClass")
	snapshotClass, err = dynamicClient.Resource(snapshotClassGVR).Create(snapshotClass, metav1.CreateOptions{})
	Expect(err).NotTo(HaveOccurred())
	defer func() {
		framework.Logf("deleting SnapshotClass %s", snapshotClass.GetName())
		framework.ExpectNoError(dynamicClient.Resource(snapshotClassGVR).Delete(snapshotClass.GetName(), nil))
	}()

	By("creating a snapshot")
	snapshot := getSnapshot(claim.Name, claim.Namespace, snapshotClass.GetName())

	snapshot, err = dynamicClient.Resource(snapshotGVR).Namespace(snapshot.GetNamespace()).Create(snapshot, metav1.CreateOptions{})
	Expect(err).NotTo(HaveOccurred())
	defer func() {
		framework.Logf("deleting snapshot %q/%q", snapshot.GetNamespace(), snapshot.GetName())
		// typically this snapshot has already been deleted
		err = dynamicClient.Resource(snapshotGVR).Namespace(snapshot.GetNamespace()).Delete(snapshot.GetName(), nil)
		if err != nil && !apierrs.IsNotFound(err) {
			framework.Failf("Error deleting snapshot %q. Error: %v", claim.Name, err)
		}
	}()
	err = WaitForSnapshotReady(dynamicClient, snapshot.GetNamespace(), snapshot.GetName(), framework.Poll, framework.SnapshotCreateTimeout)
	Expect(err).NotTo(HaveOccurred())

	By("checking the snapshot")
	// Get new copy of the snapshot
	snapshot, err = dynamicClient.Resource(snapshotGVR).Namespace(snapshot.GetNamespace()).Get(snapshot.GetName(), metav1.GetOptions{})
	Expect(err).NotTo(HaveOccurred())

	// Get the bound snapshotContent
	snapshotSpec := snapshot.Object["spec"].(map[string]interface{})
	snapshotContentName := snapshotSpec["snapshotContentName"].(string)
	snapshotContent, err := dynamicClient.Resource(snapshotContentGVR).Get(snapshotContentName, metav1.GetOptions{})
	Expect(err).NotTo(HaveOccurred())

	snapshotContentSpec := snapshotContent.Object["spec"].(map[string]interface{})
	volumeSnapshotRef := snapshotContentSpec["volumeSnapshotRef"].(map[string]interface{})
	persistentVolumeRef := snapshotContentSpec["persistentVolumeRef"].(map[string]interface{})

	// Check SnapshotContent properties
	By("checking the SnapshotContent")
	Expect(snapshotContentSpec["snapshotClassName"]).To(Equal(snapshotClass.GetName()))
	Expect(volumeSnapshotRef["name"]).To(Equal(snapshot.GetName()))
	Expect(volumeSnapshotRef["namespace"]).To(Equal(snapshot.GetNamespace()))
	Expect(persistentVolumeRef["name"]).To(Equal(pv.Name))

	// Run the checker
	if t.SnapshotContentCheck != nil {
		err = t.SnapshotContentCheck(snapshotContent)
		Expect(err).NotTo(HaveOccurred())
	}

	return snapshotContent
}

// WaitForSnapshotReady waits for a VolumeSnapshot to be ready to use or until timeout occurs, whichever comes first.
func WaitForSnapshotReady(c dynamic.Interface, ns string, snapshotName string, Poll, timeout time.Duration) error {
	framework.Logf("Waiting up to %v for VolumeSnapshot %s to become ready", timeout, snapshotName)
	for start := time.Now(); time.Since(start) < timeout; time.Sleep(Poll) {
		snapshot, err := c.Resource(snapshotGVR).Namespace(ns).Get(snapshotName, metav1.GetOptions{})
		if err != nil {
			framework.Logf("Failed to get claim %q, retrying in %v. Error: %v", snapshotName, Poll, err)
			continue
		} else {
			status := snapshot.Object["status"]
			if status == nil {
				framework.Logf("VolumeSnapshot %s found but is not ready.", snapshotName)
				continue
			}
			value := status.(map[string]interface{})
			if value["readyToUse"] == true {
				framework.Logf("VolumeSnapshot %s found and is ready", snapshotName, time.Since(start))
				return nil
			} else if value["ready"] == true {
				framework.Logf("VolumeSnapshot %s found and is ready", snapshotName, time.Since(start))
				return nil
			} else {
				framework.Logf("VolumeSnapshot %s found but is not ready.", snapshotName)
			}
		}
	}
	return fmt.Errorf("VolumeSnapshot %s is not ready within %v", snapshotName, timeout)
}
<|endoftext|>


<commit_before>package jenkins

import (
	"net/http"
	"io/ioutil"
	"encoding/json"
	"fmt"
)

// Initialize Jenkins API
func Init(connection *Connection) *JenkinsApi {
	jenkinsApi := new(JenkinsApi)
	jenkinsApi.connection = connection
	jenkinsApi.client = &http.Client{}
	return jenkinsApi
}

// Get job of specific project and by job number
func (jenkinsApi *JenkinsApi) GetBuild(project string, num int) (*Build, error) {

	// build endpoint url
	url := fmt.Sprintf("%v/job/%v/%v/api/json", jenkinsApi.connection.BaseUrl, project, num)
	r, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}

	r.SetBasicAuth(jenkinsApi.connection.Username, jenkinsApi.connection.AccessToken)
	resp, err := jenkinsApi.client.Do(r)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode == 401 {
		return nil, JenkinsApiError{ What: fmt.Sprintf("Status code: %v", resp.StatusCode) }
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	build := new(Build)
	err = json.Unmarshal(body, &build)
	if err != nil {
		return nil, err
	}

	return build, nil
}

// Get parameter of string type
func (build *Build) GetParamString(name string) (string, error) {
	for _, action := range build.Actions {
		params := action.Parameters
		if len(params) > 0 {
			for _, param := range params {
				if param.Name == name {
					if val, ok := param.Value.(string); ok {
						return val, nil
					} else {
						return "", JenkinsApiError{ What: fmt.Sprintf("The value of '%v' isn't of string type", name) }
					}
				}
			}
		}
	}
	return "", JenkinsApiError{ What: fmt.Sprintf("Param '%v' wasn't found", name) }
}

// Get parameter of int type
func (build *Build) GetParamInt(name string) (int, error) {
	for _, action := range build.Actions {
		params := action.Parameters
		if len(params) > 0 {
			for _, param := range params {
				if param.Name == name {
					if val, ok := param.Value.(int); ok {
						return val, nil
					} else {
						return 0, JenkinsApiError{ What: fmt.Sprintf("The value of '%v' isn't of int type", name) }
					}
				}
			}
		}
	}
	return 0, JenkinsApiError{ What: fmt.Sprintf("Param '%v' wasn't found", name) }
}

// Get parameter of bool type
func (build *Build) GetParamBool(name string) (bool, error) {
	for _, action := range build.Actions {
		params := action.Parameters
		if len(params) > 0 {
			for _, param := range params {
				if param.Name == name {
					if val, ok := param.Value.(bool); ok {
						return val, nil
					} else {
						return false, JenkinsApiError{ What: fmt.Sprintf("The value of '%v' isn't of bool type", name) }
					}
				}
			}
		}
	}
	return false, JenkinsApiError{ What: fmt.Sprintf("Param '%v' wasn't found", name) }
}

// Get user that triggered this job
func (build *Build) GetUser() (*User, error) {
	for _, action := range build.Actions {
		causes := action.Causes
		if len(causes) > 0 {
			for _, cause := range causes {
				if cause.User.UserId != "" {
					return &cause.User, nil
				}
			}
		}
	}
	return nil, JenkinsApiError{ What: "User wasn't found for this job, maybe upstream job triggered this job" }
}

// Get upstream job that triggered this job
func (build *Build) GetUpstreamJob() (*UpstreamJob, error) {
	for _, action := range build.Actions {
		causes := action.Causes
		if len(causes) > 0 {
			for _, cause := range causes {
				if cause.UpstreamJob.UpstreamProject != "" {
					return &cause.UpstreamJob, nil
				}
			}
		}
	}
	return nil, JenkinsApiError{ What: "Upstream job wasn't found for this job, maybe user triggered this job" }
}

// The job can run tests part of the script. Get the tests count summary.
func (build *Build) GetTestResults() (*TestResult, error) {
	for _, action := range build.Actions {
		if action.TestResult.TotalCount > 0 {
			return &action.TestResult, nil
		}
	}
	return nil, JenkinsApiError{ What: "No tests results for this job" }
}

// Start jenkins build and pass params.
func (jenkinsApi *JenkinsApi) StartBuild(job string, params map[string]interface{}) error {

	parameters := &Parameters{}
	if params != nil && len(params) > 0 {
		for k := range params {
			parameters.Params = append(parameters.Params, Parameter{ Name: k, Value: params[k]})
		}
	}

	var buildStr string
	if len(parameters.Params) > 0 {
		jsonbts, _ := json.Marshal(parameters)
		buildStr = string(jsonbts)
	}

	// build endpoint url
	url := fmt.Sprintf("%v/job/%v/build?json=%v", jenkinsApi.connection.BaseUrl, job, buildStr)
	r, err := http.NewRequest("POST", url, nil)
	if err != nil {
		return err
	}

	r.SetBasicAuth(jenkinsApi.connection.Username, jenkinsApi.connection.AccessToken)
	resp, err := jenkinsApi.client.Do(r)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode == 401 {
		return JenkinsApiError{ What: fmt.Sprintf("Status code: %v", resp.StatusCode) }
	}

	return nil
}

func (jenkinsApi *JenkinsApi) GetJob(jobName string) (*Job, error) {
	// build endpoint url
	url := fmt.Sprintf("%v/job/%v/api/json", jenkinsApi.connection.BaseUrl, jobName)
	r, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}

	r.SetBasicAuth(jenkinsApi.connection.Username, jenkinsApi.connection.AccessToken)
	resp, err := jenkinsApi.client.Do(r)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode == 401 {
		return nil, JenkinsApiError{ What: fmt.Sprintf("Status code: %v", resp.StatusCode) }
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	job := new(Job)
	err = json.Unmarshal(body, &job)
	if err != nil {
		return nil, err
	}

	return job, nil
}

// Custom error
type JenkinsApiError struct {
	What string
}

func (e JenkinsApiError) Error() string {
	return fmt.Sprintf("%v", e.What)
}<commit_msg>Clean<commit_after>package jenkins

import (
	"net/http"
	"io/ioutil"
	"encoding/json"
	"fmt"
)

// Initialize Jenkins API
func Init(connection *Connection) *JenkinsApi {
	jenkinsApi := new(JenkinsApi)
	jenkinsApi.connection = connection
	jenkinsApi.client = &http.Client{}
	return jenkinsApi
}

// Get job of specific project and by job number
func (jenkinsApi *JenkinsApi) GetBuild(project string, num int) (*Build, error) {

	// build endpoint url
	url := fmt.Sprintf("%v/job/%v/%v/api/json", jenkinsApi.connection.BaseUrl, project, num)
	body, err := jenkinsApi.get(url)
	if err != nil {
		return nil, err
	}

	build := new(Build)
	err = json.Unmarshal(body, &build)
	if err != nil {
		return nil, err
	}

	return build, nil
}

// Get parameter of string type
func (build *Build) GetParamString(name string) (string, error) {
	for _, action := range build.Actions {
		params := action.Parameters
		if len(params) > 0 {
			for _, param := range params {
				if param.Name == name {
					if val, ok := param.Value.(string); ok {
						return val, nil
					} else {
						return "", JenkinsApiError{ What: fmt.Sprintf("The value of '%v' isn't of string type", name) }
					}
				}
			}
		}
	}
	return "", JenkinsApiError{ What: fmt.Sprintf("Param '%v' wasn't found", name) }
}

// Get parameter of int type
func (build *Build) GetParamInt(name string) (int, error) {
	for _, action := range build.Actions {
		params := action.Parameters
		if len(params) > 0 {
			for _, param := range params {
				if param.Name == name {
					if val, ok := param.Value.(int); ok {
						return val, nil
					} else {
						return 0, JenkinsApiError{ What: fmt.Sprintf("The value of '%v' isn't of int type", name) }
					}
				}
			}
		}
	}
	return 0, JenkinsApiError{ What: fmt.Sprintf("Param '%v' wasn't found", name) }
}

// Get parameter of bool type
func (build *Build) GetParamBool(name string) (bool, error) {
	for _, action := range build.Actions {
		params := action.Parameters
		if len(params) > 0 {
			for _, param := range params {
				if param.Name == name {
					if val, ok := param.Value.(bool); ok {
						return val, nil
					} else {
						return false, JenkinsApiError{ What: fmt.Sprintf("The value of '%v' isn't of bool type", name) }
					}
				}
			}
		}
	}
	return false, JenkinsApiError{ What: fmt.Sprintf("Param '%v' wasn't found", name) }
}

// Get user that triggered this job
func (build *Build) GetUser() (*User, error) {
	for _, action := range build.Actions {
		causes := action.Causes
		if len(causes) > 0 {
			for _, cause := range causes {
				if cause.User.UserId != "" {
					return &cause.User, nil
				}
			}
		}
	}
	return nil, JenkinsApiError{ What: "User wasn't found for this job, maybe upstream job triggered this job" }
}

// Get upstream job that triggered this job
func (build *Build) GetUpstreamJob() (*UpstreamJob, error) {
	for _, action := range build.Actions {
		causes := action.Causes
		if len(causes) > 0 {
			for _, cause := range causes {
				if cause.UpstreamJob.UpstreamProject != "" {
					return &cause.UpstreamJob, nil
				}
			}
		}
	}
	return nil, JenkinsApiError{ What: "Upstream job wasn't found for this job, maybe user triggered this job" }
}

// The job can run tests part of the script. Get the tests count summary.
func (build *Build) GetTestResults() (*TestResult, error) {
	for _, action := range build.Actions {
		if action.TestResult.TotalCount > 0 {
			return &action.TestResult, nil
		}
	}
	return nil, JenkinsApiError{ What: "No tests results for this job" }
}

// Start jenkins build and pass params.
func (jenkinsApi *JenkinsApi) StartBuild(job string, params map[string]interface{}) error {

	parameters := &Parameters{}
	if params != nil && len(params) > 0 {
		for k := range params {
			parameters.Params = append(parameters.Params, Parameter{ Name: k, Value: params[k]})
		}
	}

	var buildStr string
	if len(parameters.Params) > 0 {
		jsonbts, _ := json.Marshal(parameters)
		buildStr = string(jsonbts)
	}

	// build endpoint url
	url := fmt.Sprintf("%v/job/%v/build?json=%v", jenkinsApi.connection.BaseUrl, job, buildStr)
	err := jenkinsApi.post(url)
	if err != nil {
		return err
	}

	return nil
}

func (jenkinsApi *JenkinsApi) GetJob(jobName string) (*Job, error) {
	// build endpoint url
	url := fmt.Sprintf("%v/job/%v/api/json", jenkinsApi.connection.BaseUrl, jobName)
	body, err := jenkinsApi.get(url)
	if err != nil {
		return nil, err
	}

	job := new(Job)
	err = json.Unmarshal(body, &job)
	if err != nil {
		return nil, err
	}

	return job, nil
}

func (jenkinsApi *JenkinsApi) get(url string) ([]byte, error) {
	r, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}

	r.SetBasicAuth(jenkinsApi.connection.Username, jenkinsApi.connection.AccessToken)
	resp, err := jenkinsApi.client.Do(r)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode == 401 {
		return nil, JenkinsApiError{ What: fmt.Sprintf("Status code: %v", resp.StatusCode) }
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	return body, nil
}

func (jenkinsApi *JenkinsApi) post(url string) error {
	r, err := http.NewRequest("POST", url, nil)
	if err != nil {
		return err
	}

	r.SetBasicAuth(jenkinsApi.connection.Username, jenkinsApi.connection.AccessToken)
	resp, err := jenkinsApi.client.Do(r)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode == 401 {
		return JenkinsApiError{ What: fmt.Sprintf("Status code: %v", resp.StatusCode) }
	}

	return nil
}

// Custom error
type JenkinsApiError struct {
	What string
}

func (e JenkinsApiError) Error() string {
	return fmt.Sprintf("%v", e.What)
}<|endoftext|>


<commit_before>// Copyright 2015 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 graph_test

import (
	"runtime"
	"testing"

	"golang.org/x/net/context"

	"github.com/jacobsa/comeback/graph"
	. "github.com/jacobsa/ogletest"
)

func TestTraverse(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helper
////////////////////////////////////////////////////////////////////////

// A graph.Visitor that invokes a wrapped function.
type funcVisitor struct {
	F func(context.Context, string) ([]string, error)
}

var _ graph.Visitor = &funcVisitor{}

func (fv *funcVisitor) Visit(
	ctx context.Context,
	node string) (adjacent []string, err error) {
	adjacent, err = fv.F(ctx, node)
	return
}

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

type TraverseTest struct {
}

var _ SetUpTestSuiteInterface = &TraverseTest{}

func init() { RegisterTestSuite(&TraverseTest{}) }

func (t *TraverseTest) SetUpTestSuite() {
	// Ensure that we get real parallelism where available.
	runtime.GOMAXPROCS(runtime.NumCPU())
}

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *TraverseTest) EmptyGraph() {
	AssertFalse(true, "TODO")
}

func (t *TraverseTest) SimpleRootedTree() {
	AssertFalse(true, "TODO")
}

func (t *TraverseTest) SimpleDAG() {
	AssertFalse(true, "TODO")
}

func (t *TraverseTest) MultipleConnectedComponents() {
	AssertFalse(true, "TODO")
}

func (t *TraverseTest) LargeRootedTree() {
	AssertFalse(true, "TODO")
}

func (t *TraverseTest) VisitorReturnsError() {
	AssertFalse(true, "TODO")
}
<commit_msg>TraverseTest.EmptyGraph<commit_after>// Copyright 2015 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 graph_test

import (
	"runtime"
	"testing"

	"golang.org/x/net/context"

	"github.com/jacobsa/comeback/graph"
	. "github.com/jacobsa/ogletest"
)

func TestTraverse(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helper
////////////////////////////////////////////////////////////////////////

// A graph.Visitor that invokes a wrapped function.
type funcVisitor struct {
	F func(context.Context, string) ([]string, error)
}

var _ graph.Visitor = &funcVisitor{}

func (fv *funcVisitor) Visit(
	ctx context.Context,
	node string) (adjacent []string, err error) {
	adjacent, err = fv.F(ctx, node)
	return
}

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

const parallelism = 16

type TraverseTest struct {
	ctx context.Context
}

var _ SetUpTestSuiteInterface = &TraverseTest{}
var _ SetUpInterface = &TraverseTest{}

func init() { RegisterTestSuite(&TraverseTest{}) }

func (t *TraverseTest) SetUpTestSuite() {
	// Ensure that we get real parallelism where available.
	runtime.GOMAXPROCS(runtime.NumCPU())
}

func (t *TraverseTest) SetUp(ti *TestInfo) {
	t.ctx = ti.Ctx
}

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *TraverseTest) EmptyGraph() {
	// Visitor -- should never be called.
	f := func(ctx context.Context, node string) (adjacent []string, err error) {
		AddFailure("Visitor unexpectedly called with node %q", node)
		return
	}

	v := &funcVisitor{F: f}

	// Traverse.
	roots := []string{}
	err := graph.Traverse(t.ctx, parallelism, roots, v)

	AssertEq(nil, err)
}

func (t *TraverseTest) SimpleRootedTree() {
	AssertFalse(true, "TODO")
}

func (t *TraverseTest) SimpleDAG() {
	AssertFalse(true, "TODO")
}

func (t *TraverseTest) MultipleConnectedComponents() {
	AssertFalse(true, "TODO")
}

func (t *TraverseTest) LargeRootedTree() {
	AssertFalse(true, "TODO")
}

func (t *TraverseTest) VisitorReturnsError() {
	AssertFalse(true, "TODO")
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"runtime"

	"time"

	io_util "github.com/bborbe/io/util"
	"github.com/bborbe/log"
	monitoring_check "github.com/bborbe/monitoring/check"
	monitoring_configuration_parser "github.com/bborbe/monitoring/configuration_parser"
	monitoring_node "github.com/bborbe/monitoring/node"
	monitoring_runner "github.com/bborbe/monitoring/runner"
	monitoring_runner_all "github.com/bborbe/monitoring/runner/all"
	monitoring_runner_hierarchy "github.com/bborbe/monitoring/runner/hierarchy"
	"github.com/bborbe/webdriver"
)

var logger = log.DefaultLogger

const (
	PARAMETER_LOGLEVEL = "loglevel"
	PARAMETER_CONFIG   = "config"
	PARAMETER_MODE     = "mode"
	PARAMETER_MAX      = "max"
	PARAMETER_DRIVER   = "driver"
)

type Run func(nodes []monitoring_node.Node) <-chan monitoring_check.CheckResult

type ParseConfiguration func(content []byte) ([]monitoring_node.Node, error)

func main() {
	defer logger.Close()
	logLevelPtr := flag.String(PARAMETER_LOGLEVEL, log.LogLevelToString(log.ERROR), log.FLAG_USAGE)
	modePtr := flag.String(PARAMETER_MODE, "", "mode (all|hierachy)")
	configPtr := flag.String(PARAMETER_CONFIG, "", "config")
	maxConcurrencyPtr := flag.Int(PARAMETER_MAX, runtime.NumCPU()*4, "max concurrency")
	driverPtr := flag.String(PARAMETER_DRIVER, "phantomjs", "driver phantomjs|chromedriver")
	flag.Parse()
	logger.SetLevelThreshold(log.LogStringToLevel(*logLevelPtr))
	logger.Debugf("set log level to %s", *logLevelPtr)

	logger.Debugf("max concurrency: %d", *maxConcurrencyPtr)

	var driver webdriver.WebDriver
	if *driverPtr == "chromedriver" {
		driver = webdriver.NewChromeDriver("chromedriver")
	} else {
		driver = webdriver.NewPhantomJsDriver("phantomjs")
	}
	driver.Start()
	defer driver.Stop()

	writer := os.Stdout
	var runner monitoring_runner.Runner
	if "all" == *modePtr {
		logger.Debug("runner = all")
		runner = monitoring_runner_all.New(*maxConcurrencyPtr)
	} else {
		logger.Debug("runner = hierarchy")
		runner = monitoring_runner_hierarchy.New(*maxConcurrencyPtr)
	}
	configurationParser := monitoring_configuration_parser.New(driver)

	err := do(writer, runner.Run, configurationParser.ParseConfiguration, *configPtr)
	if err != nil {
		logger.Fatal(err)
		logger.Close()
		os.Exit(1)
	}
	logger.Debug("done")
}

func do(writer io.Writer, run Run, parseConfiguration ParseConfiguration, configPath string) error {
	var err error
	fmt.Fprintf(writer, "check started\n")
	if len(configPath) == 0 {
		return fmt.Errorf("parameter {} missing", PARAMETER_CONFIG)
	}
	path, err := io_util.NormalizePath(configPath)
	if err != nil {
		return err
	}
	content, err := ioutil.ReadFile(path)
	if err != nil {
		return err
	}
	nodes, err := parseConfiguration(content)
	if err != nil {
		return err
	}
	var result monitoring_check.CheckResult
	for result = range run(nodes) {
		if result.Success() {
			fmt.Fprintf(writer, "[OK]   %s (%dms)\n", result.Message(), result.Duration()/time.Millisecond)
		} else {
			fmt.Fprintf(writer, "[FAIL] %s - %v (%dms)\n", result.Message(), result.Error(), result.Duration()/time.Millisecond)
		}
	}
	fmt.Fprintf(writer, "check finished\n")
	return err
}
<commit_msg>* add failed checks * add total duration<commit_after>package main

import (
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"runtime"

	"time"

	io_util "github.com/bborbe/io/util"
	"github.com/bborbe/log"
	monitoring_check "github.com/bborbe/monitoring/check"
	monitoring_configuration_parser "github.com/bborbe/monitoring/configuration_parser"
	monitoring_node "github.com/bborbe/monitoring/node"
	monitoring_runner "github.com/bborbe/monitoring/runner"
	monitoring_runner_all "github.com/bborbe/monitoring/runner/all"
	monitoring_runner_hierarchy "github.com/bborbe/monitoring/runner/hierarchy"
	"github.com/bborbe/webdriver"
)

var logger = log.DefaultLogger

const (
	PARAMETER_LOGLEVEL = "loglevel"
	PARAMETER_CONFIG   = "config"
	PARAMETER_MODE     = "mode"
	PARAMETER_MAX      = "max"
	PARAMETER_DRIVER   = "driver"
)

type Run func(nodes []monitoring_node.Node) <-chan monitoring_check.CheckResult

type ParseConfiguration func(content []byte) ([]monitoring_node.Node, error)

func main() {
	defer logger.Close()
	logLevelPtr := flag.String(PARAMETER_LOGLEVEL, log.LogLevelToString(log.ERROR), log.FLAG_USAGE)
	modePtr := flag.String(PARAMETER_MODE, "", "mode (all|hierachy)")
	configPtr := flag.String(PARAMETER_CONFIG, "", "config")
	maxConcurrencyPtr := flag.Int(PARAMETER_MAX, runtime.NumCPU()*4, "max concurrency")
	driverPtr := flag.String(PARAMETER_DRIVER, "phantomjs", "driver phantomjs|chromedriver")
	flag.Parse()
	logger.SetLevelThreshold(log.LogStringToLevel(*logLevelPtr))
	logger.Debugf("set log level to %s", *logLevelPtr)

	logger.Debugf("max concurrency: %d", *maxConcurrencyPtr)

	var driver webdriver.WebDriver
	if *driverPtr == "chromedriver" {
		driver = webdriver.NewChromeDriver("chromedriver")
	} else {
		driver = webdriver.NewPhantomJsDriver("phantomjs")
	}
	driver.Start()
	defer driver.Stop()

	writer := os.Stdout
	var runner monitoring_runner.Runner
	if "all" == *modePtr {
		logger.Debug("runner = all")
		runner = monitoring_runner_all.New(*maxConcurrencyPtr)
	} else {
		logger.Debug("runner = hierarchy")
		runner = monitoring_runner_hierarchy.New(*maxConcurrencyPtr)
	}
	configurationParser := monitoring_configuration_parser.New(driver)

	err := do(writer, runner.Run, configurationParser.ParseConfiguration, *configPtr)
	if err != nil {
		logger.Fatal(err)
		logger.Close()
		os.Exit(1)
	}
	logger.Debug("done")
}

func do(writer io.Writer, run Run, parseConfiguration ParseConfiguration, configPath string) error {
	var err error
	start := time.Now()
	fmt.Fprintf(writer, "check started\n")
	if len(configPath) == 0 {
		return fmt.Errorf("parameter {} missing", PARAMETER_CONFIG)
	}
	path, err := io_util.NormalizePath(configPath)
	if err != nil {
		return err
	}
	content, err := ioutil.ReadFile(path)
	if err != nil {
		return err
	}
	nodes, err := parseConfiguration(content)
	if err != nil {
		return err
	}
	var result monitoring_check.CheckResult
	var failures int
	for result = range run(nodes) {
		if result.Success() {
			fmt.Fprintf(writer, "[OK]   %s (%dms)\n", result.Message(), result.Duration()/time.Millisecond)
		} else {
			failures++
			fmt.Fprintf(writer, "[FAIL] %s - %v (%dms)\n", result.Message(), result.Error(), result.Duration()/time.Millisecond)
		}
	}
	duration := time.Now().Sub(start) / time.Millisecond
	if failures > 0 {
		fmt.Fprintf(writer, "check finished with %d failures (%dms)\n", failures, duration)
	} else {
		fmt.Fprintf(writer, "check finished successful (%dms)\n", duration)
	}
	return err
}
<|endoftext|>


<commit_before>package main

import (
  "fmt"
  "io/ioutil"
  utils "github.com/hyperledger/fabric/protos/utils"
)

func main(){
  fmt.Println("Use codes to verify fabric")
  blockFile := "/root/go/src/github.com/hyperledger/fabric/examples/e2e_cli/channel-artifacts/genesis.block"
  data, err := ioutil.ReadFile(blockFile)
  if err != nil {
	fmt.Errorf("Could not read block %s", blockFile)
  }
  block, err := utils.GetBlockFromBlockBytes(data)
  if err != nil {
    fmt.Errorf("Could not read block %s", err)
  }
	fmt.Println(block.String())
}
<commit_msg>Update main.go<commit_after>package main

import (
  "fmt"
  "io/ioutil"
  "github.com/hyperledger/fabric/protos/utils"
)

func main(){
  fmt.Println("Use codes to verify fabric")
  blockFile := "/root/go/src/github.com/hyperledger/fabric/examples/e2e_cli/channel-artifacts/genesis.block"
  data, err := ioutil.ReadFile(blockFile)
  if err != nil {
	fmt.Errorf("Could not read block %s", blockFile)
  }
  block, err := utils.GetBlockFromBlockBytes(data)
  if err != nil {
    fmt.Errorf("Could not read block %s", err)
  }
  fmt.Println(block.String())
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/rusco/qunit"
	"github.com/soroushjp/humble/model"
	"reflect"
	"strconv"
)

type Todo struct {
	Id          int
	Title       string
	IsCompleted bool
}

func (t Todo) GetId() string {
	return strconv.Itoa(t.Id)
}

func (t Todo) RootURL() string {
	return "http://localhost:3000/todos"
}

func main() {
	qunit.Test("ReadAll", func(assert qunit.QUnitAssert) {
		qunit.Expect(2)
		expectedTodos := []*Todo{
			{
				Id:          0,
				Title:       "Write a frontend framework in Go",
				IsCompleted: false,
			},
			{
				Id:          1,
				Title:       "???",
				IsCompleted: false,
			},
			{
				Id:          2,
				Title:       "Profit!",
				IsCompleted: false,
			},
		}
		done := assert.Call("async")
		go func() {
			gotTodos := []*Todo{}
			err := model.ReadAll(&gotTodos)
			assert.Ok(err == nil, fmt.Sprintf("model.ReadAll returned an error: %v", err))
			assert.Ok(reflect.DeepEqual(gotTodos, expectedTodos), fmt.Sprintf("Expected: %v, Got: %v", expectedTodos, gotTodos))
			done.Invoke()
		}()
	})
}
<commit_msg>Implement and test model.Read function<commit_after>package main

import (
	"fmt"
	"github.com/rusco/qunit"
	"github.com/soroushjp/humble/model"
	"reflect"
	"strconv"
)

type Todo struct {
	Id          int
	Title       string
	IsCompleted bool
}

func (t Todo) GetId() string {
	return strconv.Itoa(t.Id)
}

func (t Todo) RootURL() string {
	return "http://localhost:3000/todos"
}

func main() {
	qunit.Test("ReadAll", func(assert qunit.QUnitAssert) {
		qunit.Expect(2)
		expectedTodos := []*Todo{
			{
				Id:          0,
				Title:       "Write a frontend framework in Go",
				IsCompleted: false,
			},
			{
				Id:          1,
				Title:       "???",
				IsCompleted: false,
			},
			{
				Id:          2,
				Title:       "Profit!",
				IsCompleted: false,
			},
		}
		done := assert.Call("async")
		go func() {
			gotTodos := []*Todo{}
			err := model.ReadAll(&gotTodos)
			assert.Ok(err == nil, fmt.Sprintf("model.ReadAll returned an error: %v", err))
			assert.Ok(reflect.DeepEqual(gotTodos, expectedTodos), fmt.Sprintf("Expected: %v, Got: %v", expectedTodos, gotTodos))
			done.Invoke()
		}()
	})

	qunit.Test("Read", func(assert qunit.QUnitAssert) {
		qunit.Expect(2)
		expectedTodo := &Todo{
			Id:          0,
			Title:       "Write a frontend framework in Go",
			IsCompleted: false,
		}
		done := assert.Call("async")
		go func() {
			gotTodo := &Todo{}
			err := model.Read("0", gotTodo)
			assert.Ok(err == nil, fmt.Sprintf("model.Read returned an error: %v", err))
			assert.Ok(reflect.DeepEqual(gotTodo, expectedTodo), fmt.Sprintf("Expected: %v, Got: %v", expectedTodo, gotTodo))
			done.Invoke()
		}()
	})
}
<|endoftext|>


<commit_before>// Copyright 2015 The etcd 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 v3rpc implements etcd v3 RPC system based on gRPC.
package v3rpc

import (
	"sort"

	"github.com/coreos/etcd/etcdserver"
	"github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes"
	pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
	"github.com/coreos/pkg/capnslog"
	"golang.org/x/net/context"
)

var (
	plog = capnslog.NewPackageLogger("github.com/coreos/etcd", "etcdserver/api/v3rpc")

	// Max operations per txn list. For example, Txn.Success can have at most 128 operations,
	// and Txn.Failure can have at most 128 operations.
	MaxOpsPerTxn = 128
)

type kvServer struct {
	hdr header
	kv  etcdserver.RaftKV
}

func NewKVServer(s *etcdserver.EtcdServer) pb.KVServer {
	return &kvServer{hdr: newHeader(s), kv: s}
}

func (s *kvServer) Range(ctx context.Context, r *pb.RangeRequest) (*pb.RangeResponse, error) {
	if err := checkRangeRequest(r); err != nil {
		return nil, err
	}

	resp, err := s.kv.Range(ctx, r)
	if err != nil {
		return nil, togRPCError(err)
	}

	if resp.Header == nil {
		plog.Panic("unexpected nil resp.Header")
	}
	s.hdr.fill(resp.Header)
	return resp, err
}

func (s *kvServer) Put(ctx context.Context, r *pb.PutRequest) (*pb.PutResponse, error) {
	if err := checkPutRequest(r); err != nil {
		return nil, err
	}

	resp, err := s.kv.Put(ctx, r)
	if err != nil {
		return nil, togRPCError(err)
	}

	if resp.Header == nil {
		plog.Panic("unexpected nil resp.Header")
	}
	s.hdr.fill(resp.Header)
	return resp, err
}

func (s *kvServer) DeleteRange(ctx context.Context, r *pb.DeleteRangeRequest) (*pb.DeleteRangeResponse, error) {
	if err := checkDeleteRequest(r); err != nil {
		return nil, err
	}

	resp, err := s.kv.DeleteRange(ctx, r)
	if err != nil {
		return nil, togRPCError(err)
	}

	if resp.Header == nil {
		plog.Panic("unexpected nil resp.Header")
	}
	s.hdr.fill(resp.Header)
	return resp, err
}

func (s *kvServer) Txn(ctx context.Context, r *pb.TxnRequest) (*pb.TxnResponse, error) {
	if err := checkTxnRequest(r); err != nil {
		return nil, err
	}

	resp, err := s.kv.Txn(ctx, r)
	if err != nil {
		return nil, togRPCError(err)
	}

	if resp.Header == nil {
		plog.Panic("unexpected nil resp.Header")
	}
	s.hdr.fill(resp.Header)
	return resp, err
}

func (s *kvServer) Compact(ctx context.Context, r *pb.CompactionRequest) (*pb.CompactionResponse, error) {
	resp, err := s.kv.Compact(ctx, r)
	if err != nil {
		return nil, togRPCError(err)
	}

	if resp.Header == nil {
		plog.Panic("unexpected nil resp.Header")
	}
	s.hdr.fill(resp.Header)
	return resp, nil
}

func checkRangeRequest(r *pb.RangeRequest) error {
	if len(r.Key) == 0 {
		return rpctypes.ErrGRPCEmptyKey
	}
	return nil
}

func checkPutRequest(r *pb.PutRequest) error {
	if len(r.Key) == 0 {
		return rpctypes.ErrGRPCEmptyKey
	}
	return nil
}

func checkDeleteRequest(r *pb.DeleteRangeRequest) error {
	if len(r.Key) == 0 {
		return rpctypes.ErrGRPCEmptyKey
	}
	return nil
}

func checkTxnRequest(r *pb.TxnRequest) error {
	if len(r.Compare) > MaxOpsPerTxn || len(r.Success) > MaxOpsPerTxn || len(r.Failure) > MaxOpsPerTxn {
		return rpctypes.ErrGRPCTooManyOps
	}

	for _, c := range r.Compare {
		if len(c.Key) == 0 {
			return rpctypes.ErrGRPCEmptyKey
		}
	}

	for _, u := range r.Success {
		if err := checkRequestOp(u); err != nil {
			return err
		}
	}
	if err := checkRequestDupKeys(r.Success); err != nil {
		return err
	}

	for _, u := range r.Failure {
		if err := checkRequestOp(u); err != nil {
			return err
		}
	}
	return checkRequestDupKeys(r.Failure)
}

// checkRequestDupKeys gives rpctypes.ErrGRPCDuplicateKey if the same key is modified twice
func checkRequestDupKeys(reqs []*pb.RequestOp) error {
	// check put overlap
	keys := make(map[string]struct{})
	for _, requ := range reqs {
		tv, ok := requ.Request.(*pb.RequestOp_RequestPut)
		if !ok {
			continue
		}
		preq := tv.RequestPut
		if preq == nil {
			continue
		}
		if _, ok := keys[string(preq.Key)]; ok {
			return rpctypes.ErrGRPCDuplicateKey
		}
		keys[string(preq.Key)] = struct{}{}
	}

	// no need to check deletes if no puts; delete overlaps are permitted
	if len(keys) == 0 {
		return nil
	}

	// sort keys for range checking
	sortedKeys := []string{}
	for k := range keys {
		sortedKeys = append(sortedKeys, k)
	}
	sort.Strings(sortedKeys)

	// check put overlap with deletes
	for _, requ := range reqs {
		tv, ok := requ.Request.(*pb.RequestOp_RequestDeleteRange)
		if !ok {
			continue
		}
		dreq := tv.RequestDeleteRange
		if dreq == nil {
			continue
		}
		if dreq.RangeEnd == nil {
			if _, found := keys[string(dreq.Key)]; found {
				return rpctypes.ErrGRPCDuplicateKey
			}
		} else {
			lo := sort.SearchStrings(sortedKeys, string(dreq.Key))
			hi := sort.SearchStrings(sortedKeys, string(dreq.RangeEnd))
			if lo != hi {
				// element between lo and hi => overlap
				return rpctypes.ErrGRPCDuplicateKey
			}
		}
	}

	return nil
}

func checkRequestOp(u *pb.RequestOp) error {
	// TODO: ensure only one of the field is set.
	switch uv := u.Request.(type) {
	case *pb.RequestOp_RequestRange:
		if uv.RequestRange != nil {
			return checkRangeRequest(uv.RequestRange)
		}
	case *pb.RequestOp_RequestPut:
		if uv.RequestPut != nil {
			return checkPutRequest(uv.RequestPut)
		}
	case *pb.RequestOp_RequestDeleteRange:
		if uv.RequestDeleteRange != nil {
			return checkDeleteRequest(uv.RequestDeleteRange)
		}
	default:
		// empty op
		return nil
	}
	return nil
}
<commit_msg>v3rpc: return nil as error explicitly<commit_after>// Copyright 2015 The etcd 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 v3rpc implements etcd v3 RPC system based on gRPC.
package v3rpc

import (
	"sort"

	"github.com/coreos/etcd/etcdserver"
	"github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes"
	pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
	"github.com/coreos/pkg/capnslog"
	"golang.org/x/net/context"
)

var (
	plog = capnslog.NewPackageLogger("github.com/coreos/etcd", "etcdserver/api/v3rpc")

	// Max operations per txn list. For example, Txn.Success can have at most 128 operations,
	// and Txn.Failure can have at most 128 operations.
	MaxOpsPerTxn = 128
)

type kvServer struct {
	hdr header
	kv  etcdserver.RaftKV
}

func NewKVServer(s *etcdserver.EtcdServer) pb.KVServer {
	return &kvServer{hdr: newHeader(s), kv: s}
}

func (s *kvServer) Range(ctx context.Context, r *pb.RangeRequest) (*pb.RangeResponse, error) {
	if err := checkRangeRequest(r); err != nil {
		return nil, err
	}

	resp, err := s.kv.Range(ctx, r)
	if err != nil {
		return nil, togRPCError(err)
	}

	if resp.Header == nil {
		plog.Panic("unexpected nil resp.Header")
	}
	s.hdr.fill(resp.Header)
	return resp, nil
}

func (s *kvServer) Put(ctx context.Context, r *pb.PutRequest) (*pb.PutResponse, error) {
	if err := checkPutRequest(r); err != nil {
		return nil, err
	}

	resp, err := s.kv.Put(ctx, r)
	if err != nil {
		return nil, togRPCError(err)
	}

	if resp.Header == nil {
		plog.Panic("unexpected nil resp.Header")
	}
	s.hdr.fill(resp.Header)
	return resp, nil
}

func (s *kvServer) DeleteRange(ctx context.Context, r *pb.DeleteRangeRequest) (*pb.DeleteRangeResponse, error) {
	if err := checkDeleteRequest(r); err != nil {
		return nil, err
	}

	resp, err := s.kv.DeleteRange(ctx, r)
	if err != nil {
		return nil, togRPCError(err)
	}

	if resp.Header == nil {
		plog.Panic("unexpected nil resp.Header")
	}
	s.hdr.fill(resp.Header)
	return resp, nil
}

func (s *kvServer) Txn(ctx context.Context, r *pb.TxnRequest) (*pb.TxnResponse, error) {
	if err := checkTxnRequest(r); err != nil {
		return nil, err
	}

	resp, err := s.kv.Txn(ctx, r)
	if err != nil {
		return nil, togRPCError(err)
	}

	if resp.Header == nil {
		plog.Panic("unexpected nil resp.Header")
	}
	s.hdr.fill(resp.Header)
	return resp, nil
}

func (s *kvServer) Compact(ctx context.Context, r *pb.CompactionRequest) (*pb.CompactionResponse, error) {
	resp, err := s.kv.Compact(ctx, r)
	if err != nil {
		return nil, togRPCError(err)
	}

	if resp.Header == nil {
		plog.Panic("unexpected nil resp.Header")
	}
	s.hdr.fill(resp.Header)
	return resp, nil
}

func checkRangeRequest(r *pb.RangeRequest) error {
	if len(r.Key) == 0 {
		return rpctypes.ErrGRPCEmptyKey
	}
	return nil
}

func checkPutRequest(r *pb.PutRequest) error {
	if len(r.Key) == 0 {
		return rpctypes.ErrGRPCEmptyKey
	}
	return nil
}

func checkDeleteRequest(r *pb.DeleteRangeRequest) error {
	if len(r.Key) == 0 {
		return rpctypes.ErrGRPCEmptyKey
	}
	return nil
}

func checkTxnRequest(r *pb.TxnRequest) error {
	if len(r.Compare) > MaxOpsPerTxn || len(r.Success) > MaxOpsPerTxn || len(r.Failure) > MaxOpsPerTxn {
		return rpctypes.ErrGRPCTooManyOps
	}

	for _, c := range r.Compare {
		if len(c.Key) == 0 {
			return rpctypes.ErrGRPCEmptyKey
		}
	}

	for _, u := range r.Success {
		if err := checkRequestOp(u); err != nil {
			return err
		}
	}
	if err := checkRequestDupKeys(r.Success); err != nil {
		return err
	}

	for _, u := range r.Failure {
		if err := checkRequestOp(u); err != nil {
			return err
		}
	}
	return checkRequestDupKeys(r.Failure)
}

// checkRequestDupKeys gives rpctypes.ErrGRPCDuplicateKey if the same key is modified twice
func checkRequestDupKeys(reqs []*pb.RequestOp) error {
	// check put overlap
	keys := make(map[string]struct{})
	for _, requ := range reqs {
		tv, ok := requ.Request.(*pb.RequestOp_RequestPut)
		if !ok {
			continue
		}
		preq := tv.RequestPut
		if preq == nil {
			continue
		}
		if _, ok := keys[string(preq.Key)]; ok {
			return rpctypes.ErrGRPCDuplicateKey
		}
		keys[string(preq.Key)] = struct{}{}
	}

	// no need to check deletes if no puts; delete overlaps are permitted
	if len(keys) == 0 {
		return nil
	}

	// sort keys for range checking
	sortedKeys := []string{}
	for k := range keys {
		sortedKeys = append(sortedKeys, k)
	}
	sort.Strings(sortedKeys)

	// check put overlap with deletes
	for _, requ := range reqs {
		tv, ok := requ.Request.(*pb.RequestOp_RequestDeleteRange)
		if !ok {
			continue
		}
		dreq := tv.RequestDeleteRange
		if dreq == nil {
			continue
		}
		if dreq.RangeEnd == nil {
			if _, found := keys[string(dreq.Key)]; found {
				return rpctypes.ErrGRPCDuplicateKey
			}
		} else {
			lo := sort.SearchStrings(sortedKeys, string(dreq.Key))
			hi := sort.SearchStrings(sortedKeys, string(dreq.RangeEnd))
			if lo != hi {
				// element between lo and hi => overlap
				return rpctypes.ErrGRPCDuplicateKey
			}
		}
	}

	return nil
}

func checkRequestOp(u *pb.RequestOp) error {
	// TODO: ensure only one of the field is set.
	switch uv := u.Request.(type) {
	case *pb.RequestOp_RequestRange:
		if uv.RequestRange != nil {
			return checkRangeRequest(uv.RequestRange)
		}
	case *pb.RequestOp_RequestPut:
		if uv.RequestPut != nil {
			return checkPutRequest(uv.RequestPut)
		}
	case *pb.RequestOp_RequestDeleteRange:
		if uv.RequestDeleteRange != nil {
			return checkDeleteRequest(uv.RequestDeleteRange)
		}
	default:
		// empty op
		return nil
	}
	return nil
}
<|endoftext|>


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

// Package usercache provides a KeyServer implementation that wraps
// another and caches Lookups.
// If a Lookup is made for the user that last Dialed the service,
// data from that user's config will be provided instead of making
// a request to the underlying server.
// The caching KeyServer will defer Dialing the underlying service
// until a Lookup or Put request needs to access that service.
package usercache // import "upspin.io/key/usercache"

import (
	"sync"
	"time"

	"upspin.io/cache"
	"upspin.io/errors"
	"upspin.io/upspin"
)

type entry struct {
	expires time.Time // when the information expires.
	user    *upspin.User
}

type userCacheServer struct {
	cache *userCache

	// The underlying key server.
	base upspin.KeyServer

	// The following fields are used to defer dialing the underlying
	// service until a Lookup or Put call requires it.
	// If dialConfig is non-nil, then the Dial method has been called.
	// If dialed is non-nil, then the underlying service has been dialed.
	mu           sync.Mutex
	dialConfig   upspin.Config
	dialEndpoint upspin.Endpoint
	dialed       upspin.KeyServer
}

var _ upspin.KeyServer = (*userCacheServer)(nil)

type userCache struct {
	entries  *cache.LRU
	duration time.Duration
}

const (
	// defaultDuration is the default entry expiration time.
	defaultDuration = 15 * time.Minute

	// configUserDuration is the expiration time of the dialing user's
	// pre-populated record. This is set to a decade to ensure that we
	// always use the config's values, unless overridden by a Put.
	configUserDuration = 3650 * 24 * time.Hour
)

var globalCache = userCache{entries: cache.NewLRU(256), duration: defaultDuration}

// Global returns the provided key server wrapped in a global user cache.
func Global(s upspin.KeyServer) upspin.KeyServer {
	return &userCacheServer{
		base:  s,
		cache: &globalCache,
	}
}

// ResetGlobal resets the global cache.
func ResetGlobal() {
	globalCache.entries = cache.NewLRU(256)
}

// Lookup implements upspin.KeyServer.
func (c *userCacheServer) Lookup(name upspin.UserName) (*upspin.User, error) {
	const op = "key/usercache.Lookup"

	// If we have an unexpired cache entry, use it.
	if v, ok := c.cache.entries.Get(name); ok {
		if !time.Now().After(v.(*entry).expires) {
			e := v.(*entry)
			return e.user, nil
		}
		c.cache.entries.Remove(name)
	}

	// Not found, look it up.
	if err := c.dial(); err != nil {
		return nil, errors.E(op, err)
	}
	u, err := c.dialed.Lookup(name)
	if err != nil {
		return nil, errors.E(op, err)
	}
	e := &entry{
		expires: time.Now().Add(c.cache.duration),
		user:    u,
	}
	c.cache.entries.Add(name, e)
	return u, nil
}

// Put implements upspin.KeyServer.
func (c *userCacheServer) Put(user *upspin.User) error {
	const op = "key/usercache.Put"
	if err := c.dial(); err != nil {
		return errors.E(op, err)
	}
	if err := c.dialed.Put(user); err != nil {
		return errors.E(op, err)
	}
	c.cache.entries.Remove(user.Name)
	return nil
}

// Endpoint implements upspin.Service.
func (c *userCacheServer) Endpoint() upspin.Endpoint {
	// We don't want Endpoint to trigger a Dial.
	// Just return the Endpoint for either the dialed or base service.
	c.mu.Lock()
	svc := c.dialed
	c.mu.Unlock()
	if svc == nil {
		return svc.Endpoint()
	}
	return c.base.Endpoint()
}

// Ping implements upspin.Service.
func (c *userCacheServer) Ping() bool {
	// We don't want Ping to trigger a Dial.
	// If we're not yet dialed, just return true.
	c.mu.Lock()
	svc := c.dialed
	c.mu.Unlock()
	if svc == nil {
		return true
	}
	return svc.Ping()
}

// Authenticate implements upspin.Service.
func (c *userCacheServer) Authenticate(upspin.Config) error {
	return errors.Str("key/usercache.Authenticate: not implemented")
}

// Close implements upspin.Service.
func (c *userCacheServer) Close() {
	// If we're dialed, closed the dialed service.
	c.mu.Lock()
	svc := c.dialed
	c.mu.Unlock()
	if svc != nil {
		svc.Close()
		return
	}

	// Otherwise, close the underlying service.
	c.base.Close()
}

// Dial implements upspin.Dialer.
func (c *userCacheServer) Dial(cfg upspin.Config, e upspin.Endpoint) (upspin.Service, error) {
	c.cacheConfigUser(cfg)

	cc := *c
	cc.mu = sync.Mutex{}
	cc.dialed = nil
	cc.dialConfig = cfg
	cc.dialEndpoint = e
	return &cc, nil
}

// cacheConfigUser puts the dialed user in the cache with an extra-long expiry
// time, so that we don't hit the underlying cache for the current user and
// instead use the values from their config.
func (c *userCacheServer) cacheConfigUser(cfg upspin.Config) {
	if cfg == nil {
		return
	}
	f := cfg.Factotum()
	if f == nil {
		return
	}
	name := cfg.UserName()
	c.cache.entries.Add(name, &entry{
		expires: time.Now().Add(configUserDuration),
		user: &upspin.User{
			Name: name,
			Dirs: []upspin.Endpoint{
				cfg.DirEndpoint(),
			},
			Stores: []upspin.Endpoint{
				cfg.StoreEndpoint(),
			},
			PublicKey: f.PublicKey(),
		},
	})
}

// dial dials the underlying key service using the arguments
// provided to the previous invocation of Dial.
// If Dial was not called, it returns an error.
// If there is already a dialed service, it does nothing.
func (c *userCacheServer) dial() error {
	c.mu.Lock()
	defer c.mu.Unlock()

	if c.dialed != nil {
		return nil
	}
	if c.dialConfig == nil {
		return errors.Str("server not dialed")
	}

	svc, err := c.base.Dial(c.dialConfig, c.dialEndpoint)
	if err != nil {
		return err
	}
	c.dialed = svc.(upspin.KeyServer)
	return nil
}
<commit_msg>key/usercache: move deferred dialing fields into their own struct<commit_after>// Copyright 2016 The Upspin Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package usercache provides a KeyServer implementation that wraps
// another and caches Lookups.
// If a Lookup is made for the user that last Dialed the service,
// data from that user's config will be provided instead of making
// a request to the underlying server.
// The caching KeyServer will defer Dialing the underlying service
// until a Lookup or Put request needs to access that service.
package usercache // import "upspin.io/key/usercache"

import (
	"sync"
	"time"

	"upspin.io/cache"
	"upspin.io/errors"
	"upspin.io/upspin"
)

type entry struct {
	expires time.Time // when the information expires.
	user    *upspin.User
}

type userCacheServer struct {
	cache *userCache

	// The underlying key server.
	base upspin.KeyServer

	dd *deferredDial
}

// deferredDial is used to defer dialing the underlying
// service until a Lookup or Put call requires it.
// If config is non-nil, then the Dial method has been called.
// If dialed is non-nil, then the underlying service has been dialed.
type deferredDial struct {
	mu       sync.Mutex
	config   upspin.Config
	endpoint upspin.Endpoint
	dialed   upspin.KeyServer
}

var _ upspin.KeyServer = (*userCacheServer)(nil)

type userCache struct {
	entries  *cache.LRU
	duration time.Duration
}

const (
	// defaultDuration is the default entry expiration time.
	defaultDuration = 15 * time.Minute

	// configUserDuration is the expiration time of the dialing user's
	// pre-populated record. This is set to a decade to ensure that we
	// always use the config's values, unless overridden by a Put.
	configUserDuration = 3650 * 24 * time.Hour
)

var globalCache = userCache{entries: cache.NewLRU(256), duration: defaultDuration}

// Global returns the provided key server wrapped in a global user cache.
func Global(s upspin.KeyServer) upspin.KeyServer {
	return &userCacheServer{
		base:  s,
		cache: &globalCache,
	}
}

// ResetGlobal resets the global cache.
func ResetGlobal() {
	globalCache.entries = cache.NewLRU(256)
}

// Lookup implements upspin.KeyServer.
func (c *userCacheServer) Lookup(name upspin.UserName) (*upspin.User, error) {
	const op = "key/usercache.Lookup"

	// If we have an unexpired cache entry, use it.
	if v, ok := c.cache.entries.Get(name); ok {
		if !time.Now().After(v.(*entry).expires) {
			e := v.(*entry)
			return e.user, nil
		}
		c.cache.entries.Remove(name)
	}

	// Not found, look it up.
	if err := c.dial(); err != nil {
		return nil, errors.E(op, err)
	}
	u, err := c.dd.dialed.Lookup(name)
	if err != nil {
		return nil, errors.E(op, err)
	}
	e := &entry{
		expires: time.Now().Add(c.cache.duration),
		user:    u,
	}
	c.cache.entries.Add(name, e)
	return u, nil
}

// Put implements upspin.KeyServer.
func (c *userCacheServer) Put(user *upspin.User) error {
	const op = "key/usercache.Put"
	if err := c.dial(); err != nil {
		return errors.E(op, err)
	}
	if err := c.dd.dialed.Put(user); err != nil {
		return errors.E(op, err)
	}
	c.cache.entries.Remove(user.Name)
	return nil
}

// Endpoint implements upspin.Service.
func (c *userCacheServer) Endpoint() upspin.Endpoint {
	// We don't want Endpoint to trigger a Dial.
	// Just return the Endpoint for either the dialed or base service.
	c.dd.mu.Lock()
	svc := c.dd.dialed
	c.dd.mu.Unlock()
	if svc == nil {
		return svc.Endpoint()
	}
	return c.base.Endpoint()
}

// Ping implements upspin.Service.
func (c *userCacheServer) Ping() bool {
	// We don't want Ping to trigger a Dial.
	// If we're not yet dialed, just return true.
	c.dd.mu.Lock()
	svc := c.dd.dialed
	c.dd.mu.Unlock()
	if svc == nil {
		return true
	}
	return svc.Ping()
}

// Authenticate implements upspin.Service.
func (c *userCacheServer) Authenticate(upspin.Config) error {
	return errors.Str("key/usercache.Authenticate: not implemented")
}

// Close implements upspin.Service.
func (c *userCacheServer) Close() {
	// If we're dialed, closed the dialed service.
	c.dd.mu.Lock()
	svc := c.dd.dialed
	c.dd.mu.Unlock()
	if svc != nil {
		svc.Close()
		return
	}

	// Otherwise, close the underlying service.
	c.base.Close()
}

// Dial implements upspin.Dialer.
func (c *userCacheServer) Dial(cfg upspin.Config, e upspin.Endpoint) (upspin.Service, error) {
	c.cacheConfigUser(cfg)

	cc := *c
	cc.dd = &deferredDial{
		config:   cfg,
		endpoint: e,
	}
	return &cc, nil
}

// cacheConfigUser puts the dialed user in the cache with an extra-long expiry
// time, so that we don't hit the underlying cache for the current user and
// instead use the values from their config.
func (c *userCacheServer) cacheConfigUser(cfg upspin.Config) {
	if cfg == nil {
		return
	}
	f := cfg.Factotum()
	if f == nil {
		return
	}
	name := cfg.UserName()
	c.cache.entries.Add(name, &entry{
		expires: time.Now().Add(configUserDuration),
		user: &upspin.User{
			Name: name,
			Dirs: []upspin.Endpoint{
				cfg.DirEndpoint(),
			},
			Stores: []upspin.Endpoint{
				cfg.StoreEndpoint(),
			},
			PublicKey: f.PublicKey(),
		},
	})
}

// dial dials the underlying key service using the arguments
// provided to the previous invocation of Dial.
// If Dial was not called, it returns an error.
// If there is already a dialed service, it does nothing.
func (c *userCacheServer) dial() error {
	c.dd.mu.Lock()
	defer c.dd.mu.Unlock()

	if c.dd.dialed != nil {
		return nil
	}
	if c.dd.config == nil {
		return errors.Str("server not dialed")
	}

	svc, err := c.base.Dial(c.dd.config, c.dd.endpoint)
	if err != nil {
		return err
	}
	c.dd.dialed = svc.(upspin.KeyServer)
	return nil
}
<|endoftext|>


<commit_before>package common

import (
	"reflect"
	"testing"
)

func testAMIConfig() *AMIConfig {
	return &AMIConfig{
		AMIName: "foo",
	}
}

func TestAMIConfigPrepare_name(t *testing.T) {
	c := testAMIConfig()
	if err := c.Prepare(nil); err != nil {
		t.Fatalf("shouldn't have err: %s", err)
	}

	c.AMIName = ""
	if err := c.Prepare(nil); err == nil {
		t.Fatal("should have error")
	}
}

func TestAMIConfigPrepare_regions(t *testing.T) {
	c := testAMIConfig()
	c.AMIRegions = nil
	if err := c.Prepare(nil); err != nil {
		t.Fatalf("shouldn't have err: %s", err)
	}

	c.AMIRegions = []string{"foo"}
	if err := c.Prepare(nil); err == nil {
		t.Fatal("should have error")
	}

	c.AMIRegions = []string{"us-east-1", "us-west-1", "us-east-1"}
	if err := c.Prepare(nil); err != nil {
		t.Fatalf("bad: %s", err)
	}

	expected := []string{"us-east-1", "us-west-1"}
	if !reflect.DeepEqual(c.AMIRegions, expected) {
		t.Fatalf("bad: %#v", c.AMIRegions)
	}
}
<commit_msg>add tests for all ami regions<commit_after>package common

import (
	"reflect"
	"testing"
)

func testAMIConfig() *AMIConfig {
	return &AMIConfig{
		AMIName: "foo",
	}
}

func TestAMIConfigPrepare_name(t *testing.T) {
	c := testAMIConfig()
	if err := c.Prepare(nil); err != nil {
		t.Fatalf("shouldn't have err: %s", err)
	}

	c.AMIName = ""
	if err := c.Prepare(nil); err == nil {
		t.Fatal("should have error")
	}
}

func TestAMIConfigPrepare_regions(t *testing.T) {
	c := testAMIConfig()
	c.AMIRegions = nil
	if err := c.Prepare(nil); err != nil {
		t.Fatalf("shouldn't have err: %s", err)
	}

	c.AMIRegions = []string{"ap-northeast-1", "ap-southeast-1", "ap-southeast-2",
		"cn-north-1", "eu-central-1", "eu-west-1", "sa-east-1",
		"us-east-1", "us-gov-west-1", "us-west-1", "us-west-2"}
	if err := c.Prepare(nil); err != nil {
		t.Fatalf("shouldn't have err: %s", err)
	}

	c.AMIRegions = []string{"foo"}
	if err := c.Prepare(nil); err == nil {
		t.Fatal("should have error")
	}

	c.AMIRegions = []string{"us-east-1", "us-west-1", "us-east-1"}
	if err := c.Prepare(nil); err != nil {
		t.Fatalf("bad: %s", err)
	}

	expected := []string{"us-east-1", "us-west-1"}
	if !reflect.DeepEqual(c.AMIRegions, expected) {
		t.Fatalf("bad: %#v", c.AMIRegions)
	}
}
<|endoftext|>