<commit_before>package grpc

import (
	"context"
	"net"

	user_proto "github.com/vardius/go-api-boilerplate/cmd/user/proto"
	grpc_main "google.golang.org/grpc"
	grpc_health "google.golang.org/grpc/health"
	grpc_health_proto "google.golang.org/grpc/health/grpc_health_v1"
)

// Adapter is grpc server app adapter
type Adapter struct {
	address      string
	server       *grpc_main.Server
	healthServer *grpc_health.Server
	userServer   user_proto.UserServiceServer
}

// NewAdapter provides new primary adapter
func NewAdapter(address string, server *grpc_main.Server, healthServer *grpc_health.Server, userServer user_proto.UserServiceServer) *Adapter {
	return &Adapter{
		address:      address,
		server:       server,
		healthServer: healthServer,
		userServer:   userServer,
	}
}

// Start start grpc application adapter
func (adapter *Adapter) Start(ctx context.Context) error {
	user_proto.RegisterUserServiceServer(adapter.server, adapter.userServer)
	grpc_health_proto.RegisterHealthServer(adapter.server, adapter.healthServer)

	lis, err := net.Listen("tcp", adapter.address)
	if err != nil {
		return err
	}

	adapter.healthServer.SetServingStatus("auth", grpc_health_proto.HealthCheckResponse_SERVING)

	return adapter.server.Serve(lis)
}

// Stop stops grpc application adapter
func (adapter *Adapter) Stop(ctx context.Context) error {
	adapter.healthServer.SetServingStatus("auth", grpc_health_proto.HealthCheckResponse_NOT_SERVING)

	adapter.server.GracefulStop()

	return nil
}
<commit_msg>Fix user service adapter<commit_after>package grpc

import (
	"context"
	"net"

	user_proto "github.com/vardius/go-api-boilerplate/cmd/user/proto"
	grpc_main "google.golang.org/grpc"
	grpc_health "google.golang.org/grpc/health"
	grpc_health_proto "google.golang.org/grpc/health/grpc_health_v1"
)

// Adapter is grpc server app adapter
type Adapter struct {
	address      string
	server       *grpc_main.Server
	healthServer *grpc_health.Server
	userServer   user_proto.UserServiceServer
}

// NewAdapter provides new primary adapter
func NewAdapter(address string, server *grpc_main.Server, healthServer *grpc_health.Server, userServer user_proto.UserServiceServer) *Adapter {
	return &Adapter{
		address:      address,
		server:       server,
		healthServer: healthServer,
		userServer:   userServer,
	}
}

// Start start grpc application adapter
func (adapter *Adapter) Start(ctx context.Context) error {
	user_proto.RegisterUserServiceServer(adapter.server, adapter.userServer)
	grpc_health_proto.RegisterHealthServer(adapter.server, adapter.healthServer)

	lis, err := net.Listen("tcp", adapter.address)
	if err != nil {
		return err
	}

	adapter.healthServer.SetServingStatus("user", grpc_health_proto.HealthCheckResponse_SERVING)

	return adapter.server.Serve(lis)
}

// Stop stops grpc application adapter
func (adapter *Adapter) Stop(ctx context.Context) error {
	adapter.healthServer.SetServingStatus("user", grpc_health_proto.HealthCheckResponse_NOT_SERVING)

	adapter.server.GracefulStop()

	return nil
}
<|endoftext|>


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

// Package sort provides primitives for sorting slices and user-defined
// collections.
package sort

import "math"

// A type, typically a collection, that satisfies sort.Interface can be
// sorted by the routines in this package.  The methods require that the
// elements of the collection be enumerated by an integer index.
type Interface interface {
	// Len is the number of elements in the collection.
	Len() int
	// Less returns whether the element with index i should sort
	// before the element with index j.
	Less(i, j int) bool
	// Swap swaps the elements with indexes i and j.
	Swap(i, j int)
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

// Insertion sort
func insertionSort(data Interface, a, b int) {
	for i := a + 1; i < b; i++ {
		for j := i; j > a && data.Less(j, j-1); j-- {
			data.Swap(j, j-1)
		}
	}
}

// siftDown implements the heap property on data[lo, hi).
// first is an offset into the array where the root of the heap lies.
func siftDown(data Interface, lo, hi, first int) {
	root := lo
	for {
		child := 2*root + 1
		if child >= hi {
			break
		}
		if child+1 < hi && data.Less(first+child, first+child+1) {
			child++
		}
		if !data.Less(first+root, first+child) {
			return
		}
		data.Swap(first+root, first+child)
		root = child
	}
}

func heapSort(data Interface, a, b int) {
	first := a
	lo := 0
	hi := b - a

	// Build heap with greatest element at top.
	for i := (hi - 1) / 2; i >= 0; i-- {
		siftDown(data, i, hi, first)
	}

	// Pop elements, largest first, into end of data.
	for i := hi - 1; i >= 0; i-- {
		data.Swap(first, first+i)
		siftDown(data, lo, i, first)
	}
}

// Quicksort, following Bentley and McIlroy,
// ``Engineering a Sort Function,'' SP&E November 1993.

// medianOfThree moves the median of the three values data[a], data[b], data[c] into data[a].
func medianOfThree(data Interface, a, b, c int) {
	m0 := b
	m1 := a
	m2 := c
	// bubble sort on 3 elements
	if data.Less(m1, m0) {
		data.Swap(m1, m0)
	}
	if data.Less(m2, m1) {
		data.Swap(m2, m1)
	}
	if data.Less(m1, m0) {
		data.Swap(m1, m0)
	}
	// now data[m0] <= data[m1] <= data[m2]
}

func swapRange(data Interface, a, b, n int) {
	for i := 0; i < n; i++ {
		data.Swap(a+i, b+i)
	}
}

func doPivot(data Interface, lo, hi int) (midlo, midhi int) {
	m := lo + (hi-lo)/2 // Written like this to avoid integer overflow.
	if hi-lo > 40 {
		// Tukey's ``Ninther,'' median of three medians of three.
		s := (hi - lo) / 8
		medianOfThree(data, lo, lo+s, lo+2*s)
		medianOfThree(data, m, m-s, m+s)
		medianOfThree(data, hi-1, hi-1-s, hi-1-2*s)
	}
	medianOfThree(data, lo, m, hi-1)

	// Invariants are:
	//	data[lo] = pivot (set up by ChoosePivot)
	//	data[lo <= i < a] = pivot
	//	data[a <= i < b] < pivot
	//	data[b <= i < c] is unexamined
	//	data[c <= i < d] > pivot
	//	data[d <= i < hi] = pivot
	//
	// Once b meets c, can swap the "= pivot" sections
	// into the middle of the slice.
	pivot := lo
	a, b, c, d := lo+1, lo+1, hi, hi
	for b < c {
		if data.Less(b, pivot) { // data[b] < pivot
			b++
			continue
		}
		if !data.Less(pivot, b) { // data[b] = pivot
			data.Swap(a, b)
			a++
			b++
			continue
		}
		if data.Less(pivot, c-1) { // data[c-1] > pivot
			c--
			continue
		}
		if !data.Less(c-1, pivot) { // data[c-1] = pivot
			data.Swap(c-1, d-1)
			c--
			d--
			continue
		}
		// data[b] > pivot; data[c-1] < pivot
		data.Swap(b, c-1)
		b++
		c--
	}

	n := min(b-a, a-lo)
	swapRange(data, lo, b-n, n)

	n = min(hi-d, d-c)
	swapRange(data, c, hi-n, n)

	return lo + b - a, hi - (d - c)
}

func quickSort(data Interface, a, b, maxDepth int) {
	for b-a > 7 {
		if maxDepth == 0 {
			heapSort(data, a, b)
			return
		}
		maxDepth--
		mlo, mhi := doPivot(data, a, b)
		// Avoiding recursion on the larger subproblem guarantees
		// a stack depth of at most lg(b-a).
		if mlo-a < b-mhi {
			quickSort(data, a, mlo, maxDepth)
			a = mhi // i.e., quickSort(data, mhi, b)
		} else {
			quickSort(data, mhi, b, maxDepth)
			b = mlo // i.e., quickSort(data, a, mlo)
		}
	}
	if b-a > 1 {
		insertionSort(data, a, b)
	}
}

// Sort sorts data.
// The algorithm used is not guaranteed to be a stable sort.
func Sort(data Interface) {
	// Switch to heapsort if depth of 2*ceil(lg(n+1)) is reached.
	n := data.Len()
	maxDepth := 0
	for i := n; i > 0; i >>= 1 {
		maxDepth++
	}
	maxDepth *= 2
	quickSort(data, 0, n, maxDepth)
}

// IsSorted reports whether data is sorted.
func IsSorted(data Interface) bool {
	n := data.Len()
	for i := n - 1; i > 0; i-- {
		if data.Less(i, i-1) {
			return false
		}
	}
	return true
}

// Convenience types for common cases

// IntSlice attaches the methods of Interface to []int, sorting in increasing order.
type IntSlice []int

func (p IntSlice) Len() int           { return len(p) }
func (p IntSlice) Less(i, j int) bool { return p[i] < p[j] }
func (p IntSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }

// Sort is a convenience method.
func (p IntSlice) Sort() { Sort(p) }

// Float64Slice attaches the methods of Interface to []float64, sorting in increasing order.
type Float64Slice []float64

func (p Float64Slice) Len() int           { return len(p) }
func (p Float64Slice) Less(i, j int) bool { return p[i] < p[j] || math.IsNaN(p[i]) && !math.IsNaN(p[j]) }
func (p Float64Slice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }

// Sort is a convenience method.
func (p Float64Slice) Sort() { Sort(p) }

// StringSlice attaches the methods of Interface to []string, sorting in increasing order.
type StringSlice []string

func (p StringSlice) Len() int           { return len(p) }
func (p StringSlice) Less(i, j int) bool { return p[i] < p[j] }
func (p StringSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }

// Sort is a convenience method.
func (p StringSlice) Sort() { Sort(p) }

// Convenience wrappers for common cases

// Ints sorts a slice of ints in increasing order.
func Ints(a []int) { Sort(IntSlice(a)) }

// Float64s sorts a slice of float64s in increasing order.
func Float64s(a []float64) { Sort(Float64Slice(a)) }

// Strings sorts a slice of strings in increasing order.
func Strings(a []string) { Sort(StringSlice(a)) }

// IntsAreSorted tests whether a slice of ints is sorted in increasing order.
func IntsAreSorted(a []int) bool { return IsSorted(IntSlice(a)) }

// Float64sAreSorted tests whether a slice of float64s is sorted in increasing order.
func Float64sAreSorted(a []float64) bool { return IsSorted(Float64Slice(a)) }

// StringsAreSorted tests whether a slice of strings is sorted in increasing order.
func StringsAreSorted(a []string) bool { return IsSorted(StringSlice(a)) }
<commit_msg>sort: add time complexity to doc<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package sort provides primitives for sorting slices and user-defined
// collections.
package sort

import "math"

// A type, typically a collection, that satisfies sort.Interface can be
// sorted by the routines in this package.  The methods require that the
// elements of the collection be enumerated by an integer index.
type Interface interface {
	// Len is the number of elements in the collection.
	Len() int
	// Less returns whether the element with index i should sort
	// before the element with index j.
	Less(i, j int) bool
	// Swap swaps the elements with indexes i and j.
	Swap(i, j int)
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

// Insertion sort
func insertionSort(data Interface, a, b int) {
	for i := a + 1; i < b; i++ {
		for j := i; j > a && data.Less(j, j-1); j-- {
			data.Swap(j, j-1)
		}
	}
}

// siftDown implements the heap property on data[lo, hi).
// first is an offset into the array where the root of the heap lies.
func siftDown(data Interface, lo, hi, first int) {
	root := lo
	for {
		child := 2*root + 1
		if child >= hi {
			break
		}
		if child+1 < hi && data.Less(first+child, first+child+1) {
			child++
		}
		if !data.Less(first+root, first+child) {
			return
		}
		data.Swap(first+root, first+child)
		root = child
	}
}

func heapSort(data Interface, a, b int) {
	first := a
	lo := 0
	hi := b - a

	// Build heap with greatest element at top.
	for i := (hi - 1) / 2; i >= 0; i-- {
		siftDown(data, i, hi, first)
	}

	// Pop elements, largest first, into end of data.
	for i := hi - 1; i >= 0; i-- {
		data.Swap(first, first+i)
		siftDown(data, lo, i, first)
	}
}

// Quicksort, following Bentley and McIlroy,
// ``Engineering a Sort Function,'' SP&E November 1993.

// medianOfThree moves the median of the three values data[a], data[b], data[c] into data[a].
func medianOfThree(data Interface, a, b, c int) {
	m0 := b
	m1 := a
	m2 := c
	// bubble sort on 3 elements
	if data.Less(m1, m0) {
		data.Swap(m1, m0)
	}
	if data.Less(m2, m1) {
		data.Swap(m2, m1)
	}
	if data.Less(m1, m0) {
		data.Swap(m1, m0)
	}
	// now data[m0] <= data[m1] <= data[m2]
}

func swapRange(data Interface, a, b, n int) {
	for i := 0; i < n; i++ {
		data.Swap(a+i, b+i)
	}
}

func doPivot(data Interface, lo, hi int) (midlo, midhi int) {
	m := lo + (hi-lo)/2 // Written like this to avoid integer overflow.
	if hi-lo > 40 {
		// Tukey's ``Ninther,'' median of three medians of three.
		s := (hi - lo) / 8
		medianOfThree(data, lo, lo+s, lo+2*s)
		medianOfThree(data, m, m-s, m+s)
		medianOfThree(data, hi-1, hi-1-s, hi-1-2*s)
	}
	medianOfThree(data, lo, m, hi-1)

	// Invariants are:
	//	data[lo] = pivot (set up by ChoosePivot)
	//	data[lo <= i < a] = pivot
	//	data[a <= i < b] < pivot
	//	data[b <= i < c] is unexamined
	//	data[c <= i < d] > pivot
	//	data[d <= i < hi] = pivot
	//
	// Once b meets c, can swap the "= pivot" sections
	// into the middle of the slice.
	pivot := lo
	a, b, c, d := lo+1, lo+1, hi, hi
	for b < c {
		if data.Less(b, pivot) { // data[b] < pivot
			b++
			continue
		}
		if !data.Less(pivot, b) { // data[b] = pivot
			data.Swap(a, b)
			a++
			b++
			continue
		}
		if data.Less(pivot, c-1) { // data[c-1] > pivot
			c--
			continue
		}
		if !data.Less(c-1, pivot) { // data[c-1] = pivot
			data.Swap(c-1, d-1)
			c--
			d--
			continue
		}
		// data[b] > pivot; data[c-1] < pivot
		data.Swap(b, c-1)
		b++
		c--
	}

	n := min(b-a, a-lo)
	swapRange(data, lo, b-n, n)

	n = min(hi-d, d-c)
	swapRange(data, c, hi-n, n)

	return lo + b - a, hi - (d - c)
}

func quickSort(data Interface, a, b, maxDepth int) {
	for b-a > 7 {
		if maxDepth == 0 {
			heapSort(data, a, b)
			return
		}
		maxDepth--
		mlo, mhi := doPivot(data, a, b)
		// Avoiding recursion on the larger subproblem guarantees
		// a stack depth of at most lg(b-a).
		if mlo-a < b-mhi {
			quickSort(data, a, mlo, maxDepth)
			a = mhi // i.e., quickSort(data, mhi, b)
		} else {
			quickSort(data, mhi, b, maxDepth)
			b = mlo // i.e., quickSort(data, a, mlo)
		}
	}
	if b-a > 1 {
		insertionSort(data, a, b)
	}
}

// Sort sorts data.
// It makes one call to data.Len to determine n, and O(n*log(n)) calls to
// data.Less and data.Swap. The sort is not guaranteed to be stable.
func Sort(data Interface) {
	// Switch to heapsort if depth of 2*ceil(lg(n+1)) is reached.
	n := data.Len()
	maxDepth := 0
	for i := n; i > 0; i >>= 1 {
		maxDepth++
	}
	maxDepth *= 2
	quickSort(data, 0, n, maxDepth)
}

// IsSorted reports whether data is sorted.
func IsSorted(data Interface) bool {
	n := data.Len()
	for i := n - 1; i > 0; i-- {
		if data.Less(i, i-1) {
			return false
		}
	}
	return true
}

// Convenience types for common cases

// IntSlice attaches the methods of Interface to []int, sorting in increasing order.
type IntSlice []int

func (p IntSlice) Len() int           { return len(p) }
func (p IntSlice) Less(i, j int) bool { return p[i] < p[j] }
func (p IntSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }

// Sort is a convenience method.
func (p IntSlice) Sort() { Sort(p) }

// Float64Slice attaches the methods of Interface to []float64, sorting in increasing order.
type Float64Slice []float64

func (p Float64Slice) Len() int           { return len(p) }
func (p Float64Slice) Less(i, j int) bool { return p[i] < p[j] || math.IsNaN(p[i]) && !math.IsNaN(p[j]) }
func (p Float64Slice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }

// Sort is a convenience method.
func (p Float64Slice) Sort() { Sort(p) }

// StringSlice attaches the methods of Interface to []string, sorting in increasing order.
type StringSlice []string

func (p StringSlice) Len() int           { return len(p) }
func (p StringSlice) Less(i, j int) bool { return p[i] < p[j] }
func (p StringSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }

// Sort is a convenience method.
func (p StringSlice) Sort() { Sort(p) }

// Convenience wrappers for common cases

// Ints sorts a slice of ints in increasing order.
func Ints(a []int) { Sort(IntSlice(a)) }

// Float64s sorts a slice of float64s in increasing order.
func Float64s(a []float64) { Sort(Float64Slice(a)) }

// Strings sorts a slice of strings in increasing order.
func Strings(a []string) { Sort(StringSlice(a)) }

// IntsAreSorted tests whether a slice of ints is sorted in increasing order.
func IntsAreSorted(a []int) bool { return IsSorted(IntSlice(a)) }

// Float64sAreSorted tests whether a slice of float64s is sorted in increasing order.
func Float64sAreSorted(a []float64) bool { return IsSorted(Float64Slice(a)) }

// StringsAreSorted tests whether a slice of strings is sorted in increasing order.
func StringsAreSorted(a []string) bool { return IsSorted(StringSlice(a)) }
<|endoftext|>


<commit_before>package util

import (
	"fmt"
	"io"
	"log"
	"os"
	"strings"
)

// Sufficient for 10**6 simultaneous IDs with probability of collision less
// than 10**-7.
const IdBits = 64

type NullWriter struct{}

func (nw NullWriter) Write(p []byte) (int, os.Error) {
	return len(p), nil
}

// Misc
var (
	urandom = MustOpen("/dev/urandom", os.O_RDONLY, 0)
)

// Logging
var (
	LogWriter io.Writer = NullWriter{}
)

// MustOpen is like os.Open but panics if the file cannot be opened. It
// simplifies safe initialization of global variables holding file descriptors.
func MustOpen(name string, flag int, perm uint32) *os.File {
	file, err := os.Open(name, flag, perm)
	if err != nil {
		panic(err)
	}
	return file
}

func RandBytes(b []byte) {
	n, err := io.ReadFull(urandom, b)
	if err != nil {
		panic(err)
	}
	if n != len(b) {
		panic(fmt.Sprintf("RandBytes: %d != %d", n, len(b)))
	}
}

func Packui64(b []byte, n uint64) {
	l := len(b)
	for i := range b {
		b[l-i-1] = uint8(n & 0xff)
		n >>= 8
	}
}

func Unpackui64(b []byte) (n uint64) {
	for _, k := range b {
		n <<= 8
		n |= uint64(k)
	}
	return
}

func NewLogger(format string, a ...interface{}) *log.Logger {
	prefix := fmt.Sprintf(format, a...)

	if prefix == "" {
		panic("always give a prefix!")
	}

	if strings.HasPrefix(prefix, "udp") {
		return log.New(NullWriter{}, "", log.Lshortfile)
	}

	return log.New(LogWriter, "doozerd: "+prefix+" ", log.Lshortfile)
}

func RandHexString(bits int) string {
	buf := make([]byte, bits/8)
	RandBytes(buf)
	return fmt.Sprintf("%x", buf)
}

// Generates a random string with IdBits bits of entropy. The string will
// contain only the characters [0-9a-f] and dot, formatted for easier reading.
func RandId() string {
	return RandHexString(IdBits/2) + "." +
		RandHexString(IdBits/2)
}
<commit_msg>add datestamp (to microseconds) to logger<commit_after>package util

import (
	"fmt"
	"io"
	"log"
	"os"
	"strings"
)

// Sufficient for 10**6 simultaneous IDs with probability of collision less
// than 10**-7.
const IdBits = 64

type NullWriter struct{}

func (nw NullWriter) Write(p []byte) (int, os.Error) {
	return len(p), nil
}

// Misc
var (
	urandom = MustOpen("/dev/urandom", os.O_RDONLY, 0)
)

// Logging
var (
	LogWriter io.Writer = NullWriter{}
)

// MustOpen is like os.Open but panics if the file cannot be opened. It
// simplifies safe initialization of global variables holding file descriptors.
func MustOpen(name string, flag int, perm uint32) *os.File {
	file, err := os.Open(name, flag, perm)
	if err != nil {
		panic(err)
	}
	return file
}

func RandBytes(b []byte) {
	n, err := io.ReadFull(urandom, b)
	if err != nil {
		panic(err)
	}
	if n != len(b) {
		panic(fmt.Sprintf("RandBytes: %d != %d", n, len(b)))
	}
}

func Packui64(b []byte, n uint64) {
	l := len(b)
	for i := range b {
		b[l-i-1] = uint8(n & 0xff)
		n >>= 8
	}
}

func Unpackui64(b []byte) (n uint64) {
	for _, k := range b {
		n <<= 8
		n |= uint64(k)
	}
	return
}

func NewLogger(format string, a ...interface{}) *log.Logger {
	prefix := fmt.Sprintf(format, a...)

	if prefix == "" {
		panic("always give a prefix!")
	}

	if strings.HasPrefix(prefix, "udp") {
		return log.New(NullWriter{}, "", log.Lshortfile)
	}

	return log.New(LogWriter, "doozerd: "+prefix+" ", log.Lshortfile | log.Lmicroseconds)
}

func RandHexString(bits int) string {
	buf := make([]byte, bits/8)
	RandBytes(buf)
	return fmt.Sprintf("%x", buf)
}

// Generates a random string with IdBits bits of entropy. The string will
// contain only the characters [0-9a-f] and dot, formatted for easier reading.
func RandId() string {
	return RandHexString(IdBits/2) + "." +
		RandHexString(IdBits/2)
}
<|endoftext|>


<commit_before>//go:build gofuzz
// +build gofuzz

/*
Copyright 2021 The Vitess 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 abstract

import (
	"fmt"

	"vitess.io/vitess/go/vt/key"
	topodatapb "vitess.io/vitess/go/vt/proto/topodata"
	"vitess.io/vitess/go/vt/sqlparser"
	"vitess.io/vitess/go/vt/vtgate/semantics"
	"vitess.io/vitess/go/vt/vtgate/vindexes"

	fuzz "github.com/AdaLogics/go-fuzz-headers"
)

var _ semantics.SchemaInformation = (*fakeFuzzSI)(nil)

type fakeFuzzSI struct {
	tables map[string]*vindexes.Table
}

// FindTableOrVindex is a helper func
func (s *fakeFuzzSI) FindTableOrVindex(tablename sqlparser.TableName) (*vindexes.Table, vindexes.Vindex, string, topodatapb.TabletType, key.Destination, error) {
	table, found := s.tables[sqlparser.String(tablename)]
	if !found {
		return nil, nil, "", 0, nil, fmt.Errorf("fuzzer error - table not found")
	}
	return table, nil, "", 0, nil, nil
}

// FuzzAnalyse implements the fuzzer
func FuzzAnalyse(data []byte) int {
	f := fuzz.NewConsumer(data)
	query, err := f.GetSQLString()
	if err != nil {
		return 0
	}
	tree, err := sqlparser.Parse(query)
	if err != nil {
		return -1
	}
	switch stmt := tree.(type) {
	case *sqlparser.Select:
		semTable, err := semantics.Analyze(stmt, "", &fakeFuzzSI{})
		if err != nil {
			return 0
		}
		_, _ = createOperatorFromSelect(stmt, semTable)

	default:
		return 0
	}
	return 1
}
<commit_msg>Fuzzing: Refactor abstract_fuzzer<commit_after>//go:build gofuzz
// +build gofuzz

/*
Copyright 2021 The Vitess 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 abstract

import (
	"vitess.io/vitess/go/vt/sqlparser"
	"vitess.io/vitess/go/vt/vtgate/semantics"

	fuzz "github.com/AdaLogics/go-fuzz-headers"
)

// FuzzAnalyse implements the fuzzer
func FuzzAnalyse(data []byte) int {
	f := fuzz.NewConsumer(data)
	query, err := f.GetSQLString()
	if err != nil {
		return 0
	}
	tree, err := sqlparser.Parse(query)
	if err != nil {
		return -1
	}
	switch stmt := tree.(type) {
	case *sqlparser.Select:
		semTable, err := semantics.Analyze(stmt, "", &semantics.FakeSI{})
		if err != nil {
			return 0
		}
		_, _ = createOperatorFromSelect(stmt, semTable)

	default:
		return 0
	}
	return 1
}
<|endoftext|>


<commit_before>package validation

import (
	"regexp"

	kubeapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	. "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
	. "github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation"

	. "github.com/openshift/origin/pkg/template/api"
	routeapi "github.com/openshift/origin/pkg/route/api"
	. "github.com/openshift/origin/pkg/route/api/validation"
)

var parameterNameExp = regexp.MustCompile(`^[a-zA-Z0-9\_]+$`)

// ValidateParameter tests if required fields in the Parameter are set.
func ValidateParameter(param *Parameter) (errs ErrorList) {
	if len(param.Name) == 0 {
		errs = append(errs, NewFieldRequired("name", ""))
		return
	}
	if !parameterNameExp.MatchString(param.Name) {
		errs = append(errs, NewFieldInvalid("name", param.Name))
	}
	return
}

// ValidateTemplate tests if required fields in the Template are set.
func ValidateTemplate(template *Template) (errs ErrorList) {
	if len(template.ID) == 0 {
		errs = append(errs, NewFieldRequired("id", template.ID))
	}
	for i, item := range template.Items {
		err := ErrorList{}
		switch obj := item.Object.(type) {
		case *kubeapi.ReplicationController:
			err = ValidateReplicationController(obj)
		case *kubeapi.Pod:
			err = ValidatePod(obj)
		case *kubeapi.Service:
			err = ValidateService(obj)
                case *routeapi.Route:
                        err = ValidateRoute(obj)
		default:
			// Pass-through unknown types.
		}
		errs = append(errs, err.PrefixIndex(i).Prefix("items")...)
	}
	for i := range template.Parameters {
		paramErr := ValidateParameter(&template.Parameters[i])
		errs = append(errs, paramErr.PrefixIndex(i).Prefix("parameters")...)
	}
	return
}
<commit_msg>Work around Namespace validation being added but not used<commit_after>package validation

import (
	"regexp"
	"strings"

	kubeapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation"

	routeapi "github.com/openshift/origin/pkg/route/api"
	routevalidation "github.com/openshift/origin/pkg/route/api/validation"
	"github.com/openshift/origin/pkg/template/api"
)

var parameterNameExp = regexp.MustCompile(`^[a-zA-Z0-9\_]+$`)

// ValidateParameter tests if required fields in the Parameter are set.
func ValidateParameter(param *api.Parameter) (errs errors.ErrorList) {
	if len(param.Name) == 0 {
		errs = append(errs, errors.NewFieldRequired("name", ""))
		return
	}
	if !parameterNameExp.MatchString(param.Name) {
		errs = append(errs, errors.NewFieldInvalid("name", param.Name))
	}
	return
}

// ValidateTemplate tests if required fields in the Template are set.
func ValidateTemplate(template *api.Template) (errs errors.ErrorList) {
	if len(template.ID) == 0 {
		errs = append(errs, errors.NewFieldRequired("id", template.ID))
	}
	for i, item := range template.Items {
		err := errors.ErrorList{}
		switch obj := item.Object.(type) {
		case *kubeapi.ReplicationController:
			err = validation.ValidateReplicationController(obj)
		case *kubeapi.Pod:
			err = validation.ValidatePod(obj)
		case *kubeapi.Service:
			err = validation.ValidateService(obj)
		case *routeapi.Route:
			err = routevalidation.ValidateRoute(obj)
		default:
			// Pass-through unknown types.
		}
		// ignore namespace validation errors in templates
		err = filter(err, "namespace")
		errs = append(errs, err.PrefixIndex(i).Prefix("items")...)
	}
	for i := range template.Parameters {
		paramErr := ValidateParameter(&template.Parameters[i])
		errs = append(errs, paramErr.PrefixIndex(i).Prefix("parameters")...)
	}
	return
}

func filter(errs errors.ErrorList, prefix string) errors.ErrorList {
	if errs == nil {
		return errs
	}
	next := errors.ErrorList{}
	for _, err := range errs {
		ve, ok := err.(errors.ValidationError)
		if ok && strings.HasPrefix(ve.Field, prefix) {
			continue
		}
		next = append(next, err)
	}
	return next
}
<|endoftext|>


<commit_before>package weed_server

import (
	"bytes"
	"io"
	"mime"
	"mime/multipart"
	"net/http"
	"net/url"
	"path"
	"strconv"
	"strings"
	"time"

	"encoding/json"

	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/images"
	"github.com/chrislusf/seaweedfs/weed/operation"
	"github.com/chrislusf/seaweedfs/weed/storage"
	"github.com/chrislusf/seaweedfs/weed/util"
)

var fileNameEscaper = strings.NewReplacer("\\", "\\\\", "\"", "\\\"")

func (vs *VolumeServer) GetOrHeadHandler(w http.ResponseWriter, r *http.Request) {
	n := new(storage.Needle)
	vid, fid, filename, ext, _ := parseURLPath(r.URL.Path)
	volumeId, err := storage.NewVolumeId(vid)
	if err != nil {
		glog.V(2).Infoln("parsing error:", err, r.URL.Path)
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	err = n.ParsePath(fid)
	if err != nil {
		glog.V(2).Infoln("parsing fid error:", err, r.URL.Path)
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	glog.V(4).Infoln("volume", volumeId, "reading", n)
	if !vs.store.HasVolume(volumeId) {
		if !vs.ReadRedirect {
			glog.V(2).Infoln("volume is not local:", err, r.URL.Path)
			w.WriteHeader(http.StatusNotFound)
			return
		}
		lookupResult, err := operation.Lookup(vs.GetMasterNode(), volumeId.String())
		glog.V(2).Infoln("volume", volumeId, "found on", lookupResult, "error", err)
		if err == nil && len(lookupResult.Locations) > 0 {
			u, _ := url.Parse(util.NormalizeUrl(lookupResult.Locations[0].PublicUrl))
			u.Path = r.URL.Path
			arg := url.Values{}
			if c := r.FormValue("collection"); c != "" {
				arg.Set("collection", c)
			}
			u.RawQuery = arg.Encode()
			http.Redirect(w, r, u.String(), http.StatusMovedPermanently)

		} else {
			glog.V(2).Infoln("lookup error:", err, r.URL.Path)
			w.WriteHeader(http.StatusNotFound)
		}
		return
	}
	cookie := n.Cookie
	count, e := vs.store.ReadVolumeNeedle(volumeId, n)
	glog.V(4).Infoln("read bytes", count, "error", e)
	if e != nil || count <= 0 {
		glog.V(0).Infoln("read error:", e, r.URL.Path)
		w.WriteHeader(http.StatusNotFound)
		return
	}
	defer n.ReleaseMemory()
	if n.Cookie != cookie {
		glog.V(0).Infoln("request", r.URL.Path, "with unmaching cookie seen:", cookie, "expected:", n.Cookie, "from", r.RemoteAddr, "agent", r.UserAgent())
		w.WriteHeader(http.StatusNotFound)
		return
	}
	if n.LastModified != 0 {
		w.Header().Set("Last-Modified", time.Unix(int64(n.LastModified), 0).UTC().Format(http.TimeFormat))
		if r.Header.Get("If-Modified-Since") != "" {
			if t, parseError := time.Parse(http.TimeFormat, r.Header.Get("If-Modified-Since")); parseError == nil {
				if t.Unix() >= int64(n.LastModified) {
					w.WriteHeader(http.StatusNotModified)
					return
				}
			}
		}
	}
	etag := n.Etag()
	if inm := r.Header.Get("If-None-Match"); inm == etag {
		w.WriteHeader(http.StatusNotModified)
		return
	}
	w.Header().Set("Etag", etag)

	if n.HasPairs() {
		pairMap := make(map[string]string)
		err = json.Unmarshal(n.Pairs, &pairMap)
		if err != nil {
			glog.V(0).Infoln("Unmarshal pairs error:", err)
		}
		for k, v := range pairMap {
			w.Header().Set(k, v)
		}
	}

	if vs.tryHandleChunkedFile(n, filename, w, r) {
		return
	}

	if n.NameSize > 0 && filename == "" {
		filename = string(n.Name)
		if ext == "" {
			ext = path.Ext(filename)
		}
	}
	mtype := ""
	if n.MimeSize > 0 {
		mt := string(n.Mime)
		if !strings.HasPrefix(mt, "application/octet-stream") {
			mtype = mt
		}
	}

	if ext != ".gz" {
		if n.IsGzipped() {
			if strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
				w.Header().Set("Content-Encoding", "gzip")
			} else {
				if n.Data, err = operation.UnGzipData(n.Data); err != nil {
					glog.V(0).Infoln("ungzip error:", err, r.URL.Path)
				}
			}
		}
	}
	if ext == ".png" || ext == ".jpg" || ext == ".gif" {
		width, height := 0, 0
		if r.FormValue("width") != "" {
			width, _ = strconv.Atoi(r.FormValue("width"))
		}
		if r.FormValue("height") != "" {
			height, _ = strconv.Atoi(r.FormValue("height"))
		}
		n.Data, _, _ = images.Resized(ext, n.Data, width, height)
	}

	if e := writeResponseContent(filename, mtype, bytes.NewReader(n.Data), w, r); e != nil {
		glog.V(2).Infoln("response write error:", e)
	}
}

func (vs *VolumeServer) FaviconHandler(w http.ResponseWriter, r *http.Request) {
	data, err := images.Asset("favicon/favicon.ico")
	if err != nil {
		glog.V(2).Infoln("favicon read error:", err)
		return
	}

	if e := writeResponseContent("favicon.ico", "image/x-icon", bytes.NewReader(data), w, r); e != nil {
		glog.V(2).Infoln("response write error:", e)
	}
}

func (vs *VolumeServer) tryHandleChunkedFile(n *storage.Needle, fileName string, w http.ResponseWriter, r *http.Request) (processed bool) {
	if !n.IsChunkedManifest() {
		return false
	}

	chunkManifest, e := operation.LoadChunkManifest(n.Data, n.IsGzipped())
	if e != nil {
		glog.V(0).Infof("load chunked manifest (%s) error: %v", r.URL.Path, e)
		return false
	}
	if fileName == "" && chunkManifest.Name != "" {
		fileName = chunkManifest.Name
	}
	mType := ""
	if chunkManifest.Mime != "" {
		mt := chunkManifest.Mime
		if !strings.HasPrefix(mt, "application/octet-stream") {
			mType = mt
		}
	}

	w.Header().Set("X-File-Store", "chunked")

	chunkedFileReader := &operation.ChunkedFileReader{
		Manifest: chunkManifest,
		Master:   vs.GetMasterNode(),
	}
	defer chunkedFileReader.Close()
	if e := writeResponseContent(fileName, mType, chunkedFileReader, w, r); e != nil {
		glog.V(2).Infoln("response write error:", e)
	}
	return true
}

func writeResponseContent(filename, mimeType string, rs io.ReadSeeker, w http.ResponseWriter, r *http.Request) error {
	totalSize, e := rs.Seek(0, 2)
	if mimeType == "" {
		if ext := path.Ext(filename); ext != "" {
			mimeType = mime.TypeByExtension(ext)
		}
	}
	if mimeType != "" {
		w.Header().Set("Content-Type", mimeType)
	}
	if filename != "" {
		contentDisposition := "inline"
		if r.FormValue("dl") != "" {
			if dl, _ := strconv.ParseBool(r.FormValue("dl")); dl {
				contentDisposition = "attachment"
			}
		}
		w.Header().Set("Content-Disposition", contentDisposition+`; filename="`+fileNameEscaper.Replace(filename)+`"`)
	}
	w.Header().Set("Accept-Ranges", "bytes")
	if r.Method == "HEAD" {
		w.Header().Set("Content-Length", strconv.FormatInt(totalSize, 10))
		return nil
	}
	rangeReq := r.Header.Get("Range")
	if rangeReq == "" {
		w.Header().Set("Content-Length", strconv.FormatInt(totalSize, 10))
		if _, e = rs.Seek(0, 0); e != nil {
			return e
		}
		_, e = io.Copy(w, rs)
		return e
	}

	//the rest is dealing with partial content request
	//mostly copy from src/pkg/net/http/fs.go
	ranges, err := parseRange(rangeReq, totalSize)
	if err != nil {
		http.Error(w, err.Error(), http.StatusRequestedRangeNotSatisfiable)
		return nil
	}
	if sumRangesSize(ranges) > totalSize {
		// The total number of bytes in all the ranges
		// is larger than the size of the file by
		// itself, so this is probably an attack, or a
		// dumb client.  Ignore the range request.
		return nil
	}
	if len(ranges) == 0 {
		return nil
	}
	if len(ranges) == 1 {
		// RFC 2616, Section 14.16:
		// "When an HTTP message includes the content of a single
		// range (for example, a response to a request for a
		// single range, or to a request for a set of ranges
		// that overlap without any holes), this content is
		// transmitted with a Content-Range header, and a
		// Content-Length header showing the number of bytes
		// actually transferred.
		// ...
		// A response to a request for a single range MUST NOT
		// be sent using the multipart/byteranges media type."
		ra := ranges[0]
		w.Header().Set("Content-Length", strconv.FormatInt(ra.length, 10))
		w.Header().Set("Content-Range", ra.contentRange(totalSize))
		w.WriteHeader(http.StatusPartialContent)
		if _, e = rs.Seek(ra.start, 0); e != nil {
			return e
		}

		_, e = io.CopyN(w, rs, ra.length)
		return e
	}
	// process multiple ranges
	for _, ra := range ranges {
		if ra.start > totalSize {
			http.Error(w, "Out of Range", http.StatusRequestedRangeNotSatisfiable)
			return nil
		}
	}
	sendSize := rangesMIMESize(ranges, mimeType, totalSize)
	pr, pw := io.Pipe()
	mw := multipart.NewWriter(pw)
	w.Header().Set("Content-Type", "multipart/byteranges; boundary="+mw.Boundary())
	sendContent := pr
	defer pr.Close() // cause writing goroutine to fail and exit if CopyN doesn't finish.
	go func() {
		for _, ra := range ranges {
			part, e := mw.CreatePart(ra.mimeHeader(mimeType, totalSize))
			if e != nil {
				pw.CloseWithError(e)
				return
			}
			if _, e = rs.Seek(ra.start, 0); e != nil {
				pw.CloseWithError(e)
				return
			}
			if _, e = io.CopyN(part, rs, ra.length); e != nil {
				pw.CloseWithError(e)
				return
			}
		}
		mw.Close()
		pw.Close()
	}()
	if w.Header().Get("Content-Encoding") == "" {
		w.Header().Set("Content-Length", strconv.FormatInt(sendSize, 10))
	}
	w.WriteHeader(http.StatusPartialContent)
	_, e = io.CopyN(w, sendContent, sendSize)
	return e
}
<commit_msg>supporting reading file of size zero<commit_after>package weed_server

import (
	"bytes"
	"io"
	"mime"
	"mime/multipart"
	"net/http"
	"net/url"
	"path"
	"strconv"
	"strings"
	"time"

	"encoding/json"

	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/images"
	"github.com/chrislusf/seaweedfs/weed/operation"
	"github.com/chrislusf/seaweedfs/weed/storage"
	"github.com/chrislusf/seaweedfs/weed/util"
)

var fileNameEscaper = strings.NewReplacer("\\", "\\\\", "\"", "\\\"")

func (vs *VolumeServer) GetOrHeadHandler(w http.ResponseWriter, r *http.Request) {
	n := new(storage.Needle)
	vid, fid, filename, ext, _ := parseURLPath(r.URL.Path)
	volumeId, err := storage.NewVolumeId(vid)
	if err != nil {
		glog.V(2).Infoln("parsing error:", err, r.URL.Path)
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	err = n.ParsePath(fid)
	if err != nil {
		glog.V(2).Infoln("parsing fid error:", err, r.URL.Path)
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	glog.V(4).Infoln("volume", volumeId, "reading", n)
	if !vs.store.HasVolume(volumeId) {
		if !vs.ReadRedirect {
			glog.V(2).Infoln("volume is not local:", err, r.URL.Path)
			w.WriteHeader(http.StatusNotFound)
			return
		}
		lookupResult, err := operation.Lookup(vs.GetMasterNode(), volumeId.String())
		glog.V(2).Infoln("volume", volumeId, "found on", lookupResult, "error", err)
		if err == nil && len(lookupResult.Locations) > 0 {
			u, _ := url.Parse(util.NormalizeUrl(lookupResult.Locations[0].PublicUrl))
			u.Path = r.URL.Path
			arg := url.Values{}
			if c := r.FormValue("collection"); c != "" {
				arg.Set("collection", c)
			}
			u.RawQuery = arg.Encode()
			http.Redirect(w, r, u.String(), http.StatusMovedPermanently)

		} else {
			glog.V(2).Infoln("lookup error:", err, r.URL.Path)
			w.WriteHeader(http.StatusNotFound)
		}
		return
	}
	cookie := n.Cookie
	count, e := vs.store.ReadVolumeNeedle(volumeId, n)
	glog.V(4).Infoln("read bytes", count, "error", e)
	if e != nil || count < 0 {
		glog.V(0).Infoln("read error:", e, r.URL.Path)
		w.WriteHeader(http.StatusNotFound)
		return
	}
	defer n.ReleaseMemory()
	if n.Cookie != cookie {
		glog.V(0).Infoln("request", r.URL.Path, "with unmaching cookie seen:", cookie, "expected:", n.Cookie, "from", r.RemoteAddr, "agent", r.UserAgent())
		w.WriteHeader(http.StatusNotFound)
		return
	}
	if n.LastModified != 0 {
		w.Header().Set("Last-Modified", time.Unix(int64(n.LastModified), 0).UTC().Format(http.TimeFormat))
		if r.Header.Get("If-Modified-Since") != "" {
			if t, parseError := time.Parse(http.TimeFormat, r.Header.Get("If-Modified-Since")); parseError == nil {
				if t.Unix() >= int64(n.LastModified) {
					w.WriteHeader(http.StatusNotModified)
					return
				}
			}
		}
	}
	etag := n.Etag()
	if inm := r.Header.Get("If-None-Match"); inm == etag {
		w.WriteHeader(http.StatusNotModified)
		return
	}
	w.Header().Set("Etag", etag)

	if n.HasPairs() {
		pairMap := make(map[string]string)
		err = json.Unmarshal(n.Pairs, &pairMap)
		if err != nil {
			glog.V(0).Infoln("Unmarshal pairs error:", err)
		}
		for k, v := range pairMap {
			w.Header().Set(k, v)
		}
	}

	if vs.tryHandleChunkedFile(n, filename, w, r) {
		return
	}

	if n.NameSize > 0 && filename == "" {
		filename = string(n.Name)
		if ext == "" {
			ext = path.Ext(filename)
		}
	}
	mtype := ""
	if n.MimeSize > 0 {
		mt := string(n.Mime)
		if !strings.HasPrefix(mt, "application/octet-stream") {
			mtype = mt
		}
	}

	if ext != ".gz" {
		if n.IsGzipped() {
			if strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
				w.Header().Set("Content-Encoding", "gzip")
			} else {
				if n.Data, err = operation.UnGzipData(n.Data); err != nil {
					glog.V(0).Infoln("ungzip error:", err, r.URL.Path)
				}
			}
		}
	}
	if ext == ".png" || ext == ".jpg" || ext == ".gif" {
		width, height := 0, 0
		if r.FormValue("width") != "" {
			width, _ = strconv.Atoi(r.FormValue("width"))
		}
		if r.FormValue("height") != "" {
			height, _ = strconv.Atoi(r.FormValue("height"))
		}
		n.Data, _, _ = images.Resized(ext, n.Data, width, height)
	}

	if e := writeResponseContent(filename, mtype, bytes.NewReader(n.Data), w, r); e != nil {
		glog.V(2).Infoln("response write error:", e)
	}
}

func (vs *VolumeServer) FaviconHandler(w http.ResponseWriter, r *http.Request) {
	data, err := images.Asset("favicon/favicon.ico")
	if err != nil {
		glog.V(2).Infoln("favicon read error:", err)
		return
	}

	if e := writeResponseContent("favicon.ico", "image/x-icon", bytes.NewReader(data), w, r); e != nil {
		glog.V(2).Infoln("response write error:", e)
	}
}

func (vs *VolumeServer) tryHandleChunkedFile(n *storage.Needle, fileName string, w http.ResponseWriter, r *http.Request) (processed bool) {
	if !n.IsChunkedManifest() {
		return false
	}

	chunkManifest, e := operation.LoadChunkManifest(n.Data, n.IsGzipped())
	if e != nil {
		glog.V(0).Infof("load chunked manifest (%s) error: %v", r.URL.Path, e)
		return false
	}
	if fileName == "" && chunkManifest.Name != "" {
		fileName = chunkManifest.Name
	}
	mType := ""
	if chunkManifest.Mime != "" {
		mt := chunkManifest.Mime
		if !strings.HasPrefix(mt, "application/octet-stream") {
			mType = mt
		}
	}

	w.Header().Set("X-File-Store", "chunked")

	chunkedFileReader := &operation.ChunkedFileReader{
		Manifest: chunkManifest,
		Master:   vs.GetMasterNode(),
	}
	defer chunkedFileReader.Close()
	if e := writeResponseContent(fileName, mType, chunkedFileReader, w, r); e != nil {
		glog.V(2).Infoln("response write error:", e)
	}
	return true
}

func writeResponseContent(filename, mimeType string, rs io.ReadSeeker, w http.ResponseWriter, r *http.Request) error {
	totalSize, e := rs.Seek(0, 2)
	if mimeType == "" {
		if ext := path.Ext(filename); ext != "" {
			mimeType = mime.TypeByExtension(ext)
		}
	}
	if mimeType != "" {
		w.Header().Set("Content-Type", mimeType)
	}
	if filename != "" {
		contentDisposition := "inline"
		if r.FormValue("dl") != "" {
			if dl, _ := strconv.ParseBool(r.FormValue("dl")); dl {
				contentDisposition = "attachment"
			}
		}
		w.Header().Set("Content-Disposition", contentDisposition+`; filename="`+fileNameEscaper.Replace(filename)+`"`)
	}
	w.Header().Set("Accept-Ranges", "bytes")
	if r.Method == "HEAD" {
		w.Header().Set("Content-Length", strconv.FormatInt(totalSize, 10))
		return nil
	}
	rangeReq := r.Header.Get("Range")
	if rangeReq == "" {
		w.Header().Set("Content-Length", strconv.FormatInt(totalSize, 10))
		if _, e = rs.Seek(0, 0); e != nil {
			return e
		}
		_, e = io.Copy(w, rs)
		return e
	}

	//the rest is dealing with partial content request
	//mostly copy from src/pkg/net/http/fs.go
	ranges, err := parseRange(rangeReq, totalSize)
	if err != nil {
		http.Error(w, err.Error(), http.StatusRequestedRangeNotSatisfiable)
		return nil
	}
	if sumRangesSize(ranges) > totalSize {
		// The total number of bytes in all the ranges
		// is larger than the size of the file by
		// itself, so this is probably an attack, or a
		// dumb client.  Ignore the range request.
		return nil
	}
	if len(ranges) == 0 {
		return nil
	}
	if len(ranges) == 1 {
		// RFC 2616, Section 14.16:
		// "When an HTTP message includes the content of a single
		// range (for example, a response to a request for a
		// single range, or to a request for a set of ranges
		// that overlap without any holes), this content is
		// transmitted with a Content-Range header, and a
		// Content-Length header showing the number of bytes
		// actually transferred.
		// ...
		// A response to a request for a single range MUST NOT
		// be sent using the multipart/byteranges media type."
		ra := ranges[0]
		w.Header().Set("Content-Length", strconv.FormatInt(ra.length, 10))
		w.Header().Set("Content-Range", ra.contentRange(totalSize))
		w.WriteHeader(http.StatusPartialContent)
		if _, e = rs.Seek(ra.start, 0); e != nil {
			return e
		}

		_, e = io.CopyN(w, rs, ra.length)
		return e
	}
	// process multiple ranges
	for _, ra := range ranges {
		if ra.start > totalSize {
			http.Error(w, "Out of Range", http.StatusRequestedRangeNotSatisfiable)
			return nil
		}
	}
	sendSize := rangesMIMESize(ranges, mimeType, totalSize)
	pr, pw := io.Pipe()
	mw := multipart.NewWriter(pw)
	w.Header().Set("Content-Type", "multipart/byteranges; boundary="+mw.Boundary())
	sendContent := pr
	defer pr.Close() // cause writing goroutine to fail and exit if CopyN doesn't finish.
	go func() {
		for _, ra := range ranges {
			part, e := mw.CreatePart(ra.mimeHeader(mimeType, totalSize))
			if e != nil {
				pw.CloseWithError(e)
				return
			}
			if _, e = rs.Seek(ra.start, 0); e != nil {
				pw.CloseWithError(e)
				return
			}
			if _, e = io.CopyN(part, rs, ra.length); e != nil {
				pw.CloseWithError(e)
				return
			}
		}
		mw.Close()
		pw.Close()
	}()
	if w.Header().Get("Content-Encoding") == "" {
		w.Header().Set("Content-Length", strconv.FormatInt(sendSize, 10))
	}
	w.WriteHeader(http.StatusPartialContent)
	_, e = io.CopyN(w, sendContent, sendSize)
	return e
}
<|endoftext|>


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

package filesystem

import (
	"os"
	"reflect"
	"syscall"

	storage "github.com/vmware/harbor/src/adminserver/systeminfo/imagestorage"
	"github.com/vmware/harbor/src/common/utils/log"
)

const (
	driverName = "filesystem"
)

type driver struct {
	path string
}

// NewDriver returns an instance of filesystem driver
func NewDriver(path string) storage.Driver {
	return &driver{
		path: path,
	}
}

// Name returns a human-readable name of the fielsystem driver
func (d *driver) Name() string {
	return driverName
}

// Cap returns the capacity of the filesystem storage
func (d *driver) Cap() (*storage.Capacity, error) {
	var stat syscall.Statfs_t
	if _, err := os.Stat(d.path); os.IsNotExist(err) {
		// Return zero value if the path does not exist.
		log.Warningf("The path %s is not found, will return zero value of capacity", d.path)
		return &storage.Capacity{Total: 0, Free: 0}, nil
	}

	err := syscall.Statfs(d.path, &stat)
	if err != nil {
		return nil, err
	}

	bSize := uint64(stat.Bsize)
	field := reflect.ValueOf(&stat).Elem().FieldByName("Frsize")
	if field.IsValid() {
		if field.Kind() == reflect.Uint64 {
			bSize = field.Uint()
		} else {
			bSize = uint64(field.Int())
		}
	}

	return &storage.Capacity{
		Total: stat.Blocks * bSize,
		Free:  stat.Bavail * bSize,
	}, nil
}
<commit_msg>Add comment to source code<commit_after>// Copyright (c) 2017 VMware, Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package filesystem

import (
	"os"
	"reflect"
	"syscall"

	storage "github.com/vmware/harbor/src/adminserver/systeminfo/imagestorage"
	"github.com/vmware/harbor/src/common/utils/log"
)

const (
	driverName = "filesystem"
)

type driver struct {
	path string
}

// NewDriver returns an instance of filesystem driver
func NewDriver(path string) storage.Driver {
	return &driver{
		path: path,
	}
}

// Name returns a human-readable name of the fielsystem driver
func (d *driver) Name() string {
	return driverName
}

// Cap returns the capacity of the filesystem storage
func (d *driver) Cap() (*storage.Capacity, error) {
	var stat syscall.Statfs_t
	if _, err := os.Stat(d.path); os.IsNotExist(err) {
		// Return zero value if the path does not exist.
		log.Warningf("The path %s is not found, will return zero value of capacity", d.path)
		return &storage.Capacity{Total: 0, Free: 0}, nil
	}

	err := syscall.Statfs(d.path, &stat)
	if err != nil {
		return nil, err
	}

	// When container is run in MacOS, `bsize` obtained by `statfs` syscall is not the fundamental block size,
	// but the `iosize` (optimal transfer block size) instead, it's usually 1024 times larger than the `bsize`.
	// for example `4096 * 1024`. To get the correct block size, we should use `frsize`. But `frsize` isn't
	// guaranteed to be supported everywhere, so we need to check whether it's supported before use it.
	// For more details, please refer to: https://github.com/docker/for-mac/issues/2136
	bSize := uint64(stat.Bsize)
	field := reflect.ValueOf(&stat).Elem().FieldByName("Frsize")
	if field.IsValid() {
		if field.Kind() == reflect.Uint64 {
			bSize = field.Uint()
		} else {
			bSize = uint64(field.Int())
		}
	}

	return &storage.Capacity{
		Total: stat.Blocks * bSize,
		Free:  stat.Bavail * bSize,
	}, nil
}
<|endoftext|>


<commit_before>package container

import (
	"archive/tar"
	"bytes"
	"encoding/hex"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
	"time"

	"github.com/openblockchain/obc-peer/openchain/util"
	pb "github.com/openblockchain/obc-peer/protos"
)

func addFile(tw *tar.Writer, path string, info os.FileInfo, fbytes []byte) error {
	h, err := tar.FileInfoHeader(info, path)
	if err != nil {
		return fmt.Errorf("Error getting FileInfoHeader: %s", err)
	}
	//Let's take the variance out of the tar, make headers identical by using zero time
	var zeroTime time.Time
	h.AccessTime = zeroTime
	h.ModTime = zeroTime
	h.ChangeTime = zeroTime
	h.Name = path
	if err = tw.WriteHeader(h); err != nil {
		return fmt.Errorf("Error writing header: %s", err)
	}
	rdr := bytes.NewReader(fbytes)
	if _, err := io.Copy(tw, rdr); err != nil {
		return fmt.Errorf("Error copying file : %s", err)
	}
	return nil
}

//hashFilesInDir computes h=hash(h,file bytes) for each file in a directory
//Directory entries are traversed recursively. In the end a single
//hash value is returned for the entire directory structure
func hashFilesInDir(rootDir string, dir string, hash []byte, tw *tar.Writer) ([]byte, error) {
	//ReadDir returns sorted list of files in dir
	fis, err := ioutil.ReadDir(rootDir + "/" + dir)
	if err != nil {
		return hash, fmt.Errorf("ReadDir failed %s\n", err)
	}
	for _, fi := range fis {
		name := fmt.Sprintf("%s/%s", dir, fi.Name())
		if fi.IsDir() {
			var err error
			hash, err = hashFilesInDir(rootDir, name, hash, tw)
			if err != nil {
				return hash, err
			}
			continue
		}
		buf, err := ioutil.ReadFile(rootDir + "/" + name)
		if err != nil {
			fmt.Printf("Error reading %s\n", err)
			return hash, err
		}

		newSlice := make([]byte, len(hash)+len(buf))
		copy(newSlice[len(buf):], hash[:])
		//hash = md5.Sum(newSlice)
		hash = util.ComputeCryptoHash(newSlice)

		if tw != nil {
			if err = addFile(tw, "src/"+name, fi, buf); err != nil {
				return hash, fmt.Errorf("Error adding file to tar %s", err)
			}
		}
	}
	return hash, nil
}

func isCodeExist(tmppath string) error {
	file, err := os.Open(tmppath)
	if err != nil {
		return fmt.Errorf("Download failer %s", err)
	}

	fi, err := file.Stat()
	if err != nil {
		return fmt.Errorf("could not stat file %s", err)
	}

	if !fi.IsDir() {
		return fmt.Errorf("file %s is not dir\n", file.Name())
	}

	return nil
}

func getCodeFromHTTP(path string) (codegopath string, err error) {
	codegopath = ""
	err = nil

	env := os.Environ()
	var newgopath string
	var origgopath string
	var gopathenvIndex int
	for i, v := range env {
		if strings.Index(v, "GOPATH=") == 0 {
			p := strings.SplitAfter(v, "GOPATH=")
			origgopath = p[1]
			newgopath = origgopath + "/_usercode_"
			gopathenvIndex = i
			break
		}
	}

	if newgopath == "" {
		err = fmt.Errorf("GOPATH not defined")
		return
	}

	//ignore errors.. _usercode_ might exist. TempDir will catch any other errors
	os.Mkdir(newgopath, 0755)

	if codegopath, err = ioutil.TempDir(newgopath, ""); err != nil {
		err = fmt.Errorf("could not create tmp dir under %s(%s)", newgopath, err)
		return
	}

	// If we don't copy the obc-peer code into the temp dir with the chaincode,
	// go get will have to redownload obc-peer, which requires credentials.
	cmd := exec.Command("cp", "-r", origgopath + "/src", codegopath + "/src")
	cmd.Env = env
	var out bytes.Buffer
	cmd.Stdout = &out
	err = cmd.Run()
	if err != nil {
		return
	}

	env[gopathenvIndex] = "GOPATH=" + codegopath

	cmd = exec.Command("go", "get", path)
	cmd.Env = env
	cmd.Stdout = &out
	err = cmd.Run()
	if err != nil {
		return
	}

	return
}

func getCodeFromFS(path string) (codegopath string, err error) {
	env := os.Environ()
	var gopath string
	for _, v := range env {
		if strings.Index(v, "GOPATH=") == 0 {
			p := strings.SplitAfter(v, "GOPATH=")
			gopath = p[1]
			break
		}
	}

	if gopath == "" {
		return
	}

	codegopath = gopath

	return
}

//name could be ChaincodeID.Name or ChaincodeID.Path
func generateHashFromSignature(path string, ctor string, args []string) []byte {
	fargs := ctor
	if args != nil {
		for _, str := range args {
			fargs = fargs + str
		}
	}
	cbytes := []byte(path + fargs)

	b := make([]byte, len(cbytes))
	copy(b, cbytes)
	hash := util.ComputeCryptoHash(b)
	return hash
}

//generateHashcode gets hashcode of the code under path. If path is a HTTP(s) url
//it downloads the code first to compute the hash.
//NOTE: for dev mode, user builds and runs chaincode manually. The name provided
//by the user is equivalent to the path. This method will treat the name
//as codebytes and compute the hash from it. ie, user cannot run the chaincode
//with the same (name, ctor, args)
func generateHashcode(spec *pb.ChaincodeSpec, tw *tar.Writer) (string, error) {
	if spec == nil {
		return "", fmt.Errorf("Cannot generate hashcode from nil spec")
	}

	chaincodeID := spec.ChaincodeID
	if chaincodeID == nil || chaincodeID.Path == "" {
		return "", fmt.Errorf("Cannot generate hashcode from empty chaincode path")
	}

	ctor := spec.CtorMsg
	if ctor == nil || ctor.Function == "" {
		return "", fmt.Errorf("Cannot generate hashcode from empty ctor")
	}

	//code root will point to the directory where the code exists
	//in the case of http it will be a temporary dir that
	//will have to be deleted
	var codegopath string

	var ishttp bool
	defer func() {
		if ishttp && codegopath != "" {
			os.RemoveAll(codegopath)
		}
	}()

	path := chaincodeID.Path

	var err error
	var actualcodepath string
	if strings.HasPrefix(path, "http://") {
		ishttp = true
		actualcodepath = path[7:]
		codegopath, err = getCodeFromHTTP(actualcodepath)
	} else if strings.HasPrefix(path, "https://") {
		ishttp = true
		actualcodepath = path[8:]
		codegopath, err = getCodeFromHTTP(actualcodepath)
	} else {
		actualcodepath = path
		codegopath, err = getCodeFromFS(path)
	}

	if err != nil {
		return "", fmt.Errorf("Error getting code %s", err)
	}

	tmppath := codegopath + "/src/" + actualcodepath
	if err = isCodeExist(tmppath); err != nil {
		return "", fmt.Errorf("code does not exist %s", err)
	}

	hash := generateHashFromSignature(actualcodepath, ctor.Function, ctor.Args)

	hash, err = hashFilesInDir(codegopath+"/src/", actualcodepath, hash, tw)
	if err != nil {
		return "", fmt.Errorf("Could not get hashcode for %s - %s\n", path, err)
	}

	return hex.EncodeToString(hash[:]), nil
}
<commit_msg>Updated chaincode download process to have a timeout<commit_after>package container

import (
	"archive/tar"
	"bytes"
	"encoding/hex"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
	"time"
	"errors"

	"github.com/openblockchain/obc-peer/openchain/util"
	pb "github.com/openblockchain/obc-peer/protos"
)

func addFile(tw *tar.Writer, path string, info os.FileInfo, fbytes []byte) error {
	h, err := tar.FileInfoHeader(info, path)
	if err != nil {
		return fmt.Errorf("Error getting FileInfoHeader: %s", err)
	}
	//Let's take the variance out of the tar, make headers identical by using zero time
	var zeroTime time.Time
	h.AccessTime = zeroTime
	h.ModTime = zeroTime
	h.ChangeTime = zeroTime
	h.Name = path
	if err = tw.WriteHeader(h); err != nil {
		return fmt.Errorf("Error writing header: %s", err)
	}
	rdr := bytes.NewReader(fbytes)
	if _, err := io.Copy(tw, rdr); err != nil {
		return fmt.Errorf("Error copying file : %s", err)
	}
	return nil
}

//hashFilesInDir computes h=hash(h,file bytes) for each file in a directory
//Directory entries are traversed recursively. In the end a single
//hash value is returned for the entire directory structure
func hashFilesInDir(rootDir string, dir string, hash []byte, tw *tar.Writer) ([]byte, error) {
	//ReadDir returns sorted list of files in dir
	fis, err := ioutil.ReadDir(rootDir + "/" + dir)
	if err != nil {
		return hash, fmt.Errorf("ReadDir failed %s\n", err)
	}
	for _, fi := range fis {
		name := fmt.Sprintf("%s/%s", dir, fi.Name())
		if fi.IsDir() {
			var err error
			hash, err = hashFilesInDir(rootDir, name, hash, tw)
			if err != nil {
				return hash, err
			}
			continue
		}
		buf, err := ioutil.ReadFile(rootDir + "/" + name)
		if err != nil {
			fmt.Printf("Error reading %s\n", err)
			return hash, err
		}

		newSlice := make([]byte, len(hash)+len(buf))
		copy(newSlice[len(buf):], hash[:])
		//hash = md5.Sum(newSlice)
		hash = util.ComputeCryptoHash(newSlice)

		if tw != nil {
			if err = addFile(tw, "src/"+name, fi, buf); err != nil {
				return hash, fmt.Errorf("Error adding file to tar %s", err)
			}
		}
	}
	return hash, nil
}

func isCodeExist(tmppath string) error {
	file, err := os.Open(tmppath)
	if err != nil {
		return fmt.Errorf("Download failer %s", err)
	}

	fi, err := file.Stat()
	if err != nil {
		return fmt.Errorf("could not stat file %s", err)
	}

	if !fi.IsDir() {
		return fmt.Errorf("file %s is not dir\n", file.Name())
	}

	return nil
}

func getCodeFromHTTP(path string) (codegopath string, err error) {
	codegopath = ""
	err = nil

	env := os.Environ()
	var newgopath string
	var origgopath string
	var gopathenvIndex int
	for i, v := range env {
		if strings.Index(v, "GOPATH=") == 0 {
			p := strings.SplitAfter(v, "GOPATH=")
			origgopath = p[1]
			newgopath = origgopath + "/_usercode_"
			gopathenvIndex = i
			break
		}
	}

	if newgopath == "" {
		err = fmt.Errorf("GOPATH not defined")
		return
	}

	//ignore errors.. _usercode_ might exist. TempDir will catch any other errors
	os.Mkdir(newgopath, 0755)

	if codegopath, err = ioutil.TempDir(newgopath, ""); err != nil {
		err = fmt.Errorf("could not create tmp dir under %s(%s)", newgopath, err)
		return
	}

	// We're about to run some commands.  Let's give them somewhere to talk.
	var out bytes.Buffer

	/*
	// If we don't copy the obc-peer code into the temp dir with the chaincode,
	// go get will have to redownload obc-peer, which requires credentials.
	cmd := exec.Command("cp", "-r", origgopath + "/src", codegopath + "/src")
	cmd.Env = env
	cmd.Stdout = &out
	err = cmd.Run()
	if err != nil {
		return
	}
	*/

	env[gopathenvIndex] = "GOPATH=" + codegopath

	/* The old way of getting the chaincode
	cmd = exec.Command("go", "get", path)
	cmd.Env = env
	cmd.Stdout = &out
	err = cmd.Run()
	if err != nil {
		return
	}*/

	// Use a 'go get' command to pull the chaincode from the given repo
	cmd := exec.Command("go", "get", path)
	cmd.Env = env
	cmd.Stdout = &out
	err = cmd.Start()

	// Create a go routine that will wait for the command to finish
	done := make(chan error, 1)
	go func() {
    	done <- cmd.Wait()
	}()

	select {
	case <-time.After(30 * time.Second):
		// If pulling repos takes too long, we should give up
		// (This can happen if a repo is private and the git clone asks for credentials)
		if err := cmd.Process.Kill(); err != nil {
			err = errors.New(fmt.Sprintf("failed to kill: %s", err))
		}
		err = errors.New("Getting chaincode took too long")
	case err := <-done:
		// If we're here, the 'go get' command must have finished
		if err != nil {
			err = errors.New(fmt.Sprintf("process done with error = %v", err))
		}
	}
	return
}

func getCodeFromFS(path string) (codegopath string, err error) {
	env := os.Environ()
	var gopath string
	for _, v := range env {
		if strings.Index(v, "GOPATH=") == 0 {
			p := strings.SplitAfter(v, "GOPATH=")
			gopath = p[1]
			break
		}
	}

	if gopath == "" {
		return
	}

	codegopath = gopath

	return
}

//name could be ChaincodeID.Name or ChaincodeID.Path
func generateHashFromSignature(path string, ctor string, args []string) []byte {
	fargs := ctor
	if args != nil {
		for _, str := range args {
			fargs = fargs + str
		}
	}
	cbytes := []byte(path + fargs)

	b := make([]byte, len(cbytes))
	copy(b, cbytes)
	hash := util.ComputeCryptoHash(b)
	return hash
}

//generateHashcode gets hashcode of the code under path. If path is a HTTP(s) url
//it downloads the code first to compute the hash.
//NOTE: for dev mode, user builds and runs chaincode manually. The name provided
//by the user is equivalent to the path. This method will treat the name
//as codebytes and compute the hash from it. ie, user cannot run the chaincode
//with the same (name, ctor, args)
func generateHashcode(spec *pb.ChaincodeSpec, tw *tar.Writer) (string, error) {
	if spec == nil {
		return "", fmt.Errorf("Cannot generate hashcode from nil spec")
	}

	chaincodeID := spec.ChaincodeID
	if chaincodeID == nil || chaincodeID.Path == "" {
		return "", fmt.Errorf("Cannot generate hashcode from empty chaincode path")
	}

	ctor := spec.CtorMsg
	if ctor == nil || ctor.Function == "" {
		return "", fmt.Errorf("Cannot generate hashcode from empty ctor")
	}

	//code root will point to the directory where the code exists
	//in the case of http it will be a temporary dir that
	//will have to be deleted
	var codegopath string

	var ishttp bool
	defer func() {
		if ishttp && codegopath != "" {
			os.RemoveAll(codegopath)
		}
	}()

	path := chaincodeID.Path

	var err error
	var actualcodepath string
	if strings.HasPrefix(path, "http://") {
		ishttp = true
		actualcodepath = path[7:]
		codegopath, err = getCodeFromHTTP(actualcodepath)
	} else if strings.HasPrefix(path, "https://") {
		ishttp = true
		actualcodepath = path[8:]
		codegopath, err = getCodeFromHTTP(actualcodepath)
	} else {
		actualcodepath = path
		codegopath, err = getCodeFromFS(path)
	}

	if err != nil {
		return "", fmt.Errorf("Error getting code %s", err)
	}

	tmppath := codegopath + "/src/" + actualcodepath
	if err = isCodeExist(tmppath); err != nil {
		return "", fmt.Errorf("code does not exist %s", err)
	}

	hash := generateHashFromSignature(actualcodepath, ctor.Function, ctor.Args)

	hash, err = hashFilesInDir(codegopath+"/src/", actualcodepath, hash, tw)
	if err != nil {
		return "", fmt.Errorf("Could not get hashcode for %s - %s\n", path, err)
	}

	return hex.EncodeToString(hash[:]), nil
}
<|endoftext|>


<commit_before>/*
Copyright IBM Corp. 2016 All Rights Reserved.

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

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

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

package couchdb

import (
	"fmt"
	"testing"

	"github.com/hyperledger/fabric/common/ledger/testutil"
	"github.com/hyperledger/fabric/core/ledger/ledgerconfig"
)

//Unit test of couch db util functionality
func TestCreateCouchDBConnectionAndDB(t *testing.T) {
	if ledgerconfig.IsCouchDBEnabled() {

		database := "testcreatecouchdbconnectionanddb"
		cleanup(database)
		defer cleanup(database)
		//create a new connection
		couchInstance, err := CreateCouchInstance(couchDBDef.URL, couchDBDef.Username, couchDBDef.Password,
			couchDBDef.MaxRetries, couchDBDef.MaxRetriesOnStartup, couchDBDef.RequestTimeout)
		testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to CreateCouchInstance"))

		_, err = CreateCouchDatabase(*couchInstance, database)
		testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to CreateCouchDatabase"))
	}

}

//Unit test of couch db util functionality
func TestCreateCouchDBSystemDBs(t *testing.T) {
	if ledgerconfig.IsCouchDBEnabled() {

		database := "testcreatecouchdbsystemdb"
		cleanup(database)
		defer cleanup(database)

		//create a new connection
		couchInstance, err := CreateCouchInstance(connectURL, "", "", maxRetries,
			maxRetriesOnStartup, requestTimeout)
		testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to CreateCouchInstance"))

		err = CreateSystemDatabasesIfNotExist(*couchInstance)
		testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create system databases"))

		db := CouchDatabase{CouchInstance: *couchInstance, DBName: "_users"}

		//Retrieve the info for the new database and make sure the name matches
		dbResp, _, errdb := db.GetDatabaseInfo()
		testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to retrieve _users database information"))
		testutil.AssertEquals(t, dbResp.DbName, "_users")

		db = CouchDatabase{CouchInstance: *couchInstance, DBName: "_replicator"}

		//Retrieve the info for the new database and make sure the name matches
		dbResp, _, errdb = db.GetDatabaseInfo()
		testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to retrieve _replicator database information"))
		testutil.AssertEquals(t, dbResp.DbName, "_replicator")

		db = CouchDatabase{CouchInstance: *couchInstance, DBName: "_global_changes"}

		//Retrieve the info for the new database and make sure the name matches
		dbResp, _, errdb = db.GetDatabaseInfo()
		testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to retrieve _global_changes database information"))
		testutil.AssertEquals(t, dbResp.DbName, "_global_changes")

	}

}
func TestDatabaseMapping(t *testing.T) {

	//create a new instance and database object using a database name mixed case
	databaseName, err := mapAndValidateDatabaseName("testDB")
	testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to map database name"))
	testutil.AssertEquals(t, databaseName, "testdb")

	//create a new instance and database object using a database name with numerics
	databaseName, err = mapAndValidateDatabaseName("test1234DB")
	testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to map database name"))
	testutil.AssertEquals(t, databaseName, "test1234db")

	//create a new instance and database object using a database name with special characters
	databaseName, err = mapAndValidateDatabaseName("test1234_$(),+-/~!@#%^&*[]{}.")
	testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to map database name"))
	testutil.AssertEquals(t, databaseName, "test1234_$(),+-/_____________")

	//create a new instance and database object using a database name with special characters
	databaseName, err = mapAndValidateDatabaseName("5test1234")
	testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to map database name"))
	testutil.AssertEquals(t, databaseName, "db_5test1234")

	//create a new instance and database object using an empty string
	_, err = mapAndValidateDatabaseName("")
	testutil.AssertError(t, err, fmt.Sprintf("Error should have been thrown for an invalid name"))

	_, err = mapAndValidateDatabaseName("A12345678901234567890123456789012345678901234" +
		"56789012345678901234567890123456789012345678901234567890123456789012345678901234567890" +
		"12345678901234567890123456789012345678901234567890123456789012345678901234567890123456" +
		"78901234567890123456789012345678901234567890")
	testutil.AssertError(t, err, fmt.Sprintf("Error should have been thrown for an invalid name"))

}
<commit_msg>[FAB-3328] fix couchdb unit test failures<commit_after>/*
Copyright IBM Corp. 2016 All Rights Reserved.

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

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

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

package couchdb

import (
	"fmt"
	"testing"

	"github.com/hyperledger/fabric/common/ledger/testutil"
	"github.com/hyperledger/fabric/core/ledger/ledgerconfig"
)

//Unit test of couch db util functionality
func TestCreateCouchDBConnectionAndDB(t *testing.T) {
	if ledgerconfig.IsCouchDBEnabled() {

		database := "testcreatecouchdbconnectionanddb"
		cleanup(database)
		defer cleanup(database)
		//create a new connection
		couchInstance, err := CreateCouchInstance(couchDBDef.URL, couchDBDef.Username, couchDBDef.Password,
			couchDBDef.MaxRetries, couchDBDef.MaxRetriesOnStartup, couchDBDef.RequestTimeout)
		testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to CreateCouchInstance"))

		_, err = CreateCouchDatabase(*couchInstance, database)
		testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to CreateCouchDatabase"))
	}

}

//Unit test of couch db util functionality
func TestCreateCouchDBSystemDBs(t *testing.T) {
	if ledgerconfig.IsCouchDBEnabled() {

		database := "testcreatecouchdbsystemdb"
		cleanup(database)
		defer cleanup(database)

		//create a new connection
		couchInstance, err := CreateCouchInstance(couchDBDef.URL, couchDBDef.Username, couchDBDef.Password,
			couchDBDef.MaxRetries, couchDBDef.MaxRetriesOnStartup, couchDBDef.RequestTimeout)

		testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to CreateCouchInstance"))

		err = CreateSystemDatabasesIfNotExist(*couchInstance)
		testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create system databases"))

		db := CouchDatabase{CouchInstance: *couchInstance, DBName: "_users"}

		//Retrieve the info for the new database and make sure the name matches
		dbResp, _, errdb := db.GetDatabaseInfo()
		testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to retrieve _users database information"))
		testutil.AssertEquals(t, dbResp.DbName, "_users")

		db = CouchDatabase{CouchInstance: *couchInstance, DBName: "_replicator"}

		//Retrieve the info for the new database and make sure the name matches
		dbResp, _, errdb = db.GetDatabaseInfo()
		testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to retrieve _replicator database information"))
		testutil.AssertEquals(t, dbResp.DbName, "_replicator")

		db = CouchDatabase{CouchInstance: *couchInstance, DBName: "_global_changes"}

		//Retrieve the info for the new database and make sure the name matches
		dbResp, _, errdb = db.GetDatabaseInfo()
		testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to retrieve _global_changes database information"))
		testutil.AssertEquals(t, dbResp.DbName, "_global_changes")

	}

}
func TestDatabaseMapping(t *testing.T) {

	//create a new instance and database object using a database name mixed case
	databaseName, err := mapAndValidateDatabaseName("testDB")
	testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to map database name"))
	testutil.AssertEquals(t, databaseName, "testdb")

	//create a new instance and database object using a database name with numerics
	databaseName, err = mapAndValidateDatabaseName("test1234DB")
	testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to map database name"))
	testutil.AssertEquals(t, databaseName, "test1234db")

	//create a new instance and database object using a database name with special characters
	databaseName, err = mapAndValidateDatabaseName("test1234_$(),+-/~!@#%^&*[]{}.")
	testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to map database name"))
	testutil.AssertEquals(t, databaseName, "test1234_$(),+-/_____________")

	//create a new instance and database object using a database name with special characters
	databaseName, err = mapAndValidateDatabaseName("5test1234")
	testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to map database name"))
	testutil.AssertEquals(t, databaseName, "db_5test1234")

	//create a new instance and database object using an empty string
	_, err = mapAndValidateDatabaseName("")
	testutil.AssertError(t, err, fmt.Sprintf("Error should have been thrown for an invalid name"))

	_, err = mapAndValidateDatabaseName("A12345678901234567890123456789012345678901234" +
		"56789012345678901234567890123456789012345678901234567890123456789012345678901234567890" +
		"12345678901234567890123456789012345678901234567890123456789012345678901234567890123456" +
		"78901234567890123456789012345678901234567890")
	testutil.AssertError(t, err, fmt.Sprintf("Error should have been thrown for an invalid name"))

}
<|endoftext|>


<commit_before>package integrationtest

import (
	"reflect"
	"sort"
	"testing"

	"github.com/zclconf/go-cty/cty"

	"github.com/hashicorp/hcl2/hcldec"

	"github.com/davecgh/go-spew/spew"

	"github.com/hashicorp/hcl2/gohcl"

	"github.com/hashicorp/hcl2/hcl"
	"github.com/hashicorp/hcl2/hcl/hclsyntax"
	"github.com/hashicorp/hcl2/hcl/json"
)

// TestTerraformLike parses both a native syntax and a JSON representation
// of the same HashiCorp Terraform-like configuration structure and then makes
// assertions against the result of each.
//
// Terraform exercises a lot of different HCL codepaths, so this is not
// exhaustive but tries to cover a variety of different relevant scenarios.
func TestTerraformLike(t *testing.T) {
	tests := map[string]func() (*hcl.File, hcl.Diagnostics){
		"native syntax": func() (*hcl.File, hcl.Diagnostics) {
			return hclsyntax.ParseConfig(
				[]byte(terraformLikeNativeSyntax),
				"config.tf", hcl.Pos{Line: 1, Column: 1},
			)
		},
		"JSON": func() (*hcl.File, hcl.Diagnostics) {
			return json.Parse(
				[]byte(terraformLikeJSON),
				"config.tf.json",
			)
		},
	}

	type Variable struct {
		Name string `hcl:"name,label"`
	}
	type Resource struct {
		Type      string         `hcl:"type,label"`
		Name      string         `hcl:"name,label"`
		Config    hcl.Body       `hcl:",remain"`
		DependsOn hcl.Expression `hcl:"depends_on,attr"`
	}
	type Root struct {
		Variables []*Variable `hcl:"variable,block"`
		Resources []*Resource `hcl:"resource,block"`
	}
	instanceDecode := &hcldec.ObjectSpec{
		"image_id": &hcldec.AttrSpec{
			Name:     "image_id",
			Required: true,
			Type:     cty.String,
		},
		"instance_type": &hcldec.AttrSpec{
			Name:     "instance_type",
			Required: true,
			Type:     cty.String,
		},
	}
	securityGroupDecode := &hcldec.ObjectSpec{
		"ingress": &hcldec.BlockListSpec{
			TypeName: "ingress",
			Nested: &hcldec.ObjectSpec{
				"cidr_block": &hcldec.AttrSpec{
					Name:     "cidr_block",
					Required: true,
					Type:     cty.String,
				},
			},
		},
	}

	for name, loadFunc := range tests {
		t.Run(name, func(t *testing.T) {
			file, diags := loadFunc()
			if len(diags) != 0 {
				t.Errorf("unexpected diagnostics during parse")
				for _, diag := range diags {
					t.Logf("- %s", diag)
				}
				return
			}

			body := file.Body

			var root Root
			diags = gohcl.DecodeBody(body, nil, &root)
			if len(diags) != 0 {
				t.Errorf("unexpected diagnostics during root eval")
				for _, diag := range diags {
					t.Logf("- %s", diag)
				}
				return
			}

			wantVars := []*Variable{
				{
					Name: "image_id",
				},
			}
			if gotVars := root.Variables; !reflect.DeepEqual(gotVars, wantVars) {
				t.Errorf("wrong Variables\ngot:  %swant: %s", spew.Sdump(gotVars), spew.Sdump(wantVars))
			}

			if got, want := len(root.Resources), 3; got != want {
				t.Fatalf("wrong number of Resources %d; want %d", got, want)
			}

			sort.Slice(root.Resources, func(i, j int) bool {
				return root.Resources[i].Name < root.Resources[j].Name
			})

			t.Run("resource 0", func(t *testing.T) {
				r := root.Resources[0]
				if got, want := r.Type, "happycloud_security_group"; got != want {
					t.Errorf("wrong type %q; want %q", got, want)
				}
				if got, want := r.Name, "private"; got != want {
					t.Errorf("wrong type %q; want %q", got, want)
				}

				cfg, diags := hcldec.Decode(r.Config, securityGroupDecode, nil)
				if len(diags) != 0 {
					t.Errorf("unexpected diagnostics decoding Config")
					for _, diag := range diags {
						t.Logf("- %s", diag)
					}
					return
				}
				wantCfg := cty.ObjectVal(map[string]cty.Value{
					"ingress": cty.ListVal([]cty.Value{
						cty.ObjectVal(map[string]cty.Value{
							"cidr_block": cty.StringVal("10.0.0.0/8"),
						}),
						cty.ObjectVal(map[string]cty.Value{
							"cidr_block": cty.StringVal("192.168.0.0/16"),
						}),
					}),
				})
				if !cfg.RawEquals(wantCfg) {
					t.Errorf("wrong config\ngot:  %#v\nwant: %#v", cfg, wantCfg)
				}
			})

			t.Run("resource 1", func(t *testing.T) {
				r := root.Resources[1]
				if got, want := r.Type, "happycloud_security_group"; got != want {
					t.Errorf("wrong type %q; want %q", got, want)
				}
				if got, want := r.Name, "public"; got != want {
					t.Errorf("wrong type %q; want %q", got, want)
				}

				cfg, diags := hcldec.Decode(r.Config, securityGroupDecode, nil)
				if len(diags) != 0 {
					t.Errorf("unexpected diagnostics decoding Config")
					for _, diag := range diags {
						t.Logf("- %s", diag)
					}
					return
				}
				wantCfg := cty.ObjectVal(map[string]cty.Value{
					"ingress": cty.ListVal([]cty.Value{
						cty.ObjectVal(map[string]cty.Value{
							"cidr_block": cty.StringVal("0.0.0.0/0"),
						}),
					}),
				})
				if !cfg.RawEquals(wantCfg) {
					t.Errorf("wrong config\ngot:  %#v\nwant: %#v", cfg, wantCfg)
				}
			})

			t.Run("resource 2", func(t *testing.T) {
				r := root.Resources[2]
				if got, want := r.Type, "happycloud_instance"; got != want {
					t.Errorf("wrong type %q; want %q", got, want)
				}
				if got, want := r.Name, "test"; got != want {
					t.Errorf("wrong type %q; want %q", got, want)
				}

				vars := hcldec.Variables(r.Config, &hcldec.AttrSpec{
					Name: "image_id",
					Type: cty.String,
				})
				if got, want := len(vars), 1; got != want {
					t.Errorf("wrong number of variables in image_id %#v; want %#v", got, want)
				}
				if got, want := vars[0].RootName(), "var"; got != want {
					t.Errorf("wrong image_id variable RootName %#v; want %#v", got, want)
				}

				ctx := &hcl.EvalContext{
					Variables: map[string]cty.Value{
						"var": cty.ObjectVal(map[string]cty.Value{
							"image_id": cty.StringVal("image-1234"),
						}),
					},
				}
				cfg, diags := hcldec.Decode(r.Config, instanceDecode, ctx)
				if len(diags) != 0 {
					t.Errorf("unexpected diagnostics decoding Config")
					for _, diag := range diags {
						t.Logf("- %s", diag)
					}
					return
				}
				wantCfg := cty.ObjectVal(map[string]cty.Value{
					"instance_type": cty.StringVal("z3.weedy"),
					"image_id":      cty.StringVal("image-1234"),
				})
				if !cfg.RawEquals(wantCfg) {
					t.Errorf("wrong config\ngot:  %#v\nwant: %#v", cfg, wantCfg)
				}

				exprs, diags := hcl.ExprList(r.DependsOn)
				if len(diags) != 0 {
					t.Errorf("unexpected diagnostics extracting depends_on")
					for _, diag := range diags {
						t.Logf("- %s", diag)
					}
					return
				}
				if got, want := len(exprs), 1; got != want {
					t.Errorf("wrong number of depends_on exprs %#v; want %#v", got, want)
				}

				traversal, diags := hcl.AbsTraversalForExpr(exprs[0])
				if len(diags) != 0 {
					t.Errorf("unexpected diagnostics decoding depends_on[0]")
					for _, diag := range diags {
						t.Logf("- %s", diag)
					}
					return
				}
				if got, want := len(traversal), 2; got != want {
					t.Errorf("wrong number of depends_on traversal steps %#v; want %#v", got, want)
				}
				if got, want := traversal.RootName(), "happycloud_security_group"; got != want {
					t.Errorf("wrong depends_on traversal RootName %#v; want %#v", got, want)
				}
			})
		})
	}
}

const terraformLikeNativeSyntax = `

variable "image_id" {
}

resource "happycloud_instance" "test" {
  instance_type = "z3.weedy"
  image_id      = var.image_id

  depends_on = [
    happycloud_security_group.public,
  ]
}

resource "happycloud_security_group" "public" {
  ingress {
    cidr_block = "0.0.0.0/0"
  }
}

resource "happycloud_security_group" "private" {
  ingress {
    cidr_block = "10.0.0.0/8"
  }
  ingress {
    cidr_block = "192.168.0.0/16"
  }
}

`

const terraformLikeJSON = `
{
  "variable": {
    "image_id": {}
  },
  "resource": {
    "happycloud_instance": {
      "test": {
        "instance_type": "z3.weedy",
        "image_id": "${var.image_id}",
        "depends_on": [
          "happycloud_security_group.public"
        ]
      }
    },
    "happycloud_security_group": {
      "public": {
        "ingress": {
          "cidr_block": "0.0.0.0/0"
        }
      },
      "private": {
        "ingress": [
          {
            "cidr_block": "10.0.0.0/8"
          },
          {
            "cidr_block": "192.168.0.0/16"
          }
        ]
      }
    }
  }
}
`
<commit_msg>integrationtest: include dynblock usage in the "terraformlike" test<commit_after>package integrationtest

import (
	"reflect"
	"sort"
	"testing"

	"github.com/davecgh/go-spew/spew"
	"github.com/hashicorp/hcl2/ext/dynblock"
	"github.com/hashicorp/hcl2/gohcl"
	"github.com/hashicorp/hcl2/hcl"
	"github.com/hashicorp/hcl2/hcl/hclsyntax"
	"github.com/hashicorp/hcl2/hcl/json"
	"github.com/hashicorp/hcl2/hcldec"
	"github.com/zclconf/go-cty/cty"
)

// TestTerraformLike parses both a native syntax and a JSON representation
// of the same HashiCorp Terraform-like configuration structure and then makes
// assertions against the result of each.
//
// Terraform exercises a lot of different HCL codepaths, so this is not
// exhaustive but tries to cover a variety of different relevant scenarios.
func TestTerraformLike(t *testing.T) {
	tests := map[string]func() (*hcl.File, hcl.Diagnostics){
		"native syntax": func() (*hcl.File, hcl.Diagnostics) {
			return hclsyntax.ParseConfig(
				[]byte(terraformLikeNativeSyntax),
				"config.tf", hcl.Pos{Line: 1, Column: 1},
			)
		},
		"JSON": func() (*hcl.File, hcl.Diagnostics) {
			return json.Parse(
				[]byte(terraformLikeJSON),
				"config.tf.json",
			)
		},
	}

	type Variable struct {
		Name string `hcl:"name,label"`
	}
	type Resource struct {
		Type      string         `hcl:"type,label"`
		Name      string         `hcl:"name,label"`
		Config    hcl.Body       `hcl:",remain"`
		DependsOn hcl.Expression `hcl:"depends_on,attr"`
	}
	type Root struct {
		Variables []*Variable `hcl:"variable,block"`
		Resources []*Resource `hcl:"resource,block"`
	}
	instanceDecode := &hcldec.ObjectSpec{
		"image_id": &hcldec.AttrSpec{
			Name:     "image_id",
			Required: true,
			Type:     cty.String,
		},
		"instance_type": &hcldec.AttrSpec{
			Name:     "instance_type",
			Required: true,
			Type:     cty.String,
		},
	}
	securityGroupDecode := &hcldec.ObjectSpec{
		"ingress": &hcldec.BlockListSpec{
			TypeName: "ingress",
			Nested: &hcldec.ObjectSpec{
				"cidr_block": &hcldec.AttrSpec{
					Name:     "cidr_block",
					Required: true,
					Type:     cty.String,
				},
			},
		},
	}

	for name, loadFunc := range tests {
		t.Run(name, func(t *testing.T) {
			file, diags := loadFunc()
			if len(diags) != 0 {
				t.Errorf("unexpected diagnostics during parse")
				for _, diag := range diags {
					t.Logf("- %s", diag)
				}
				return
			}

			body := file.Body

			var root Root
			diags = gohcl.DecodeBody(body, nil, &root)
			if len(diags) != 0 {
				t.Errorf("unexpected diagnostics during root eval")
				for _, diag := range diags {
					t.Logf("- %s", diag)
				}
				return
			}

			wantVars := []*Variable{
				{
					Name: "image_id",
				},
			}
			if gotVars := root.Variables; !reflect.DeepEqual(gotVars, wantVars) {
				t.Errorf("wrong Variables\ngot:  %swant: %s", spew.Sdump(gotVars), spew.Sdump(wantVars))
			}

			if got, want := len(root.Resources), 3; got != want {
				t.Fatalf("wrong number of Resources %d; want %d", got, want)
			}

			sort.Slice(root.Resources, func(i, j int) bool {
				return root.Resources[i].Name < root.Resources[j].Name
			})

			t.Run("resource 0", func(t *testing.T) {
				r := root.Resources[0]
				if got, want := r.Type, "happycloud_security_group"; got != want {
					t.Errorf("wrong type %q; want %q", got, want)
				}
				if got, want := r.Name, "private"; got != want {
					t.Errorf("wrong type %q; want %q", got, want)
				}

				// For this one we're including support for the dynamic block
				// extension, since Terraform uses this to allow dynamic
				// generation of blocks within resource configuration.
				forEachCtx := &hcl.EvalContext{
					Variables: map[string]cty.Value{
						"var": cty.ObjectVal(map[string]cty.Value{
							"extra_private_cidr_blocks": cty.ListVal([]cty.Value{
								cty.StringVal("172.16.0.0/12"),
								cty.StringVal("169.254.0.0/16"),
							}),
						}),
					},
				}
				dynBody := dynblock.Expand(r.Config, forEachCtx)

				cfg, diags := hcldec.Decode(dynBody, securityGroupDecode, nil)
				if len(diags) != 0 {
					t.Errorf("unexpected diagnostics decoding Config")
					for _, diag := range diags {
						t.Logf("- %s", diag)
					}
					return
				}
				wantCfg := cty.ObjectVal(map[string]cty.Value{
					"ingress": cty.ListVal([]cty.Value{
						cty.ObjectVal(map[string]cty.Value{
							"cidr_block": cty.StringVal("10.0.0.0/8"),
						}),
						cty.ObjectVal(map[string]cty.Value{
							"cidr_block": cty.StringVal("192.168.0.0/16"),
						}),
						cty.ObjectVal(map[string]cty.Value{
							"cidr_block": cty.StringVal("172.16.0.0/12"),
						}),
						cty.ObjectVal(map[string]cty.Value{
							"cidr_block": cty.StringVal("169.254.0.0/16"),
						}),
					}),
				})
				if !cfg.RawEquals(wantCfg) {
					t.Errorf("wrong config\ngot:  %#v\nwant: %#v", cfg, wantCfg)
				}
			})

			t.Run("resource 1", func(t *testing.T) {
				r := root.Resources[1]
				if got, want := r.Type, "happycloud_security_group"; got != want {
					t.Errorf("wrong type %q; want %q", got, want)
				}
				if got, want := r.Name, "public"; got != want {
					t.Errorf("wrong type %q; want %q", got, want)
				}

				cfg, diags := hcldec.Decode(r.Config, securityGroupDecode, nil)
				if len(diags) != 0 {
					t.Errorf("unexpected diagnostics decoding Config")
					for _, diag := range diags {
						t.Logf("- %s", diag)
					}
					return
				}
				wantCfg := cty.ObjectVal(map[string]cty.Value{
					"ingress": cty.ListVal([]cty.Value{
						cty.ObjectVal(map[string]cty.Value{
							"cidr_block": cty.StringVal("0.0.0.0/0"),
						}),
					}),
				})
				if !cfg.RawEquals(wantCfg) {
					t.Errorf("wrong config\ngot:  %#v\nwant: %#v", cfg, wantCfg)
				}
			})

			t.Run("resource 2", func(t *testing.T) {
				r := root.Resources[2]
				if got, want := r.Type, "happycloud_instance"; got != want {
					t.Errorf("wrong type %q; want %q", got, want)
				}
				if got, want := r.Name, "test"; got != want {
					t.Errorf("wrong type %q; want %q", got, want)
				}

				vars := hcldec.Variables(r.Config, &hcldec.AttrSpec{
					Name: "image_id",
					Type: cty.String,
				})
				if got, want := len(vars), 1; got != want {
					t.Errorf("wrong number of variables in image_id %#v; want %#v", got, want)
				}
				if got, want := vars[0].RootName(), "var"; got != want {
					t.Errorf("wrong image_id variable RootName %#v; want %#v", got, want)
				}

				ctx := &hcl.EvalContext{
					Variables: map[string]cty.Value{
						"var": cty.ObjectVal(map[string]cty.Value{
							"image_id": cty.StringVal("image-1234"),
						}),
					},
				}
				cfg, diags := hcldec.Decode(r.Config, instanceDecode, ctx)
				if len(diags) != 0 {
					t.Errorf("unexpected diagnostics decoding Config")
					for _, diag := range diags {
						t.Logf("- %s", diag)
					}
					return
				}
				wantCfg := cty.ObjectVal(map[string]cty.Value{
					"instance_type": cty.StringVal("z3.weedy"),
					"image_id":      cty.StringVal("image-1234"),
				})
				if !cfg.RawEquals(wantCfg) {
					t.Errorf("wrong config\ngot:  %#v\nwant: %#v", cfg, wantCfg)
				}

				exprs, diags := hcl.ExprList(r.DependsOn)
				if len(diags) != 0 {
					t.Errorf("unexpected diagnostics extracting depends_on")
					for _, diag := range diags {
						t.Logf("- %s", diag)
					}
					return
				}
				if got, want := len(exprs), 1; got != want {
					t.Errorf("wrong number of depends_on exprs %#v; want %#v", got, want)
				}

				traversal, diags := hcl.AbsTraversalForExpr(exprs[0])
				if len(diags) != 0 {
					t.Errorf("unexpected diagnostics decoding depends_on[0]")
					for _, diag := range diags {
						t.Logf("- %s", diag)
					}
					return
				}
				if got, want := len(traversal), 2; got != want {
					t.Errorf("wrong number of depends_on traversal steps %#v; want %#v", got, want)
				}
				if got, want := traversal.RootName(), "happycloud_security_group"; got != want {
					t.Errorf("wrong depends_on traversal RootName %#v; want %#v", got, want)
				}
			})
		})
	}
}

const terraformLikeNativeSyntax = `

variable "image_id" {
}

resource "happycloud_instance" "test" {
  instance_type = "z3.weedy"
  image_id      = var.image_id

  depends_on = [
    happycloud_security_group.public,
  ]
}

resource "happycloud_security_group" "public" {
  ingress {
    cidr_block = "0.0.0.0/0"
  }
}

resource "happycloud_security_group" "private" {
  ingress {
    cidr_block = "10.0.0.0/8"
  }
  ingress {
    cidr_block = "192.168.0.0/16"
  }
  dynamic "ingress" {
    for_each = var.extra_private_cidr_blocks
    content {
      cidr_block = ingress.value
    }
  }
}

`

const terraformLikeJSON = `
{
  "variable": {
    "image_id": {}
  },
  "resource": {
    "happycloud_instance": {
      "test": {
        "instance_type": "z3.weedy",
        "image_id": "${var.image_id}",
        "depends_on": [
          "happycloud_security_group.public"
        ]
      }
    },
    "happycloud_security_group": {
      "public": {
        "ingress": {
          "cidr_block": "0.0.0.0/0"
        }
      },
      "private": {
        "ingress": [
          {
            "cidr_block": "10.0.0.0/8"
          },
          {
            "cidr_block": "192.168.0.0/16"
          }
        ],
        "dynamic": {
          "ingress": {
            "for_each": "${var.extra_private_cidr_blocks}",
            "iterator": "block",
            "content": {
              "cidr_block": "${block.value}"
            }
          }
        }
      }
    }
  }
}
`
<|endoftext|>