<commit_before>package pg_test

import (
	"database/sql"
	"database/sql/driver"
	"encoding/json"
	"fmt"
	"math"
	"reflect"
	"testing"
	"time"

	"gopkg.in/pg.v3"
)

type JSONMap map[string]interface{}

func (m *JSONMap) Scan(value interface{}) error {
	return json.Unmarshal(value.([]byte), m)
}

func (m JSONMap) Value() (driver.Value, error) {
	b, err := json.Marshal(m)
	if err != nil {
		return nil, err
	}
	return string(b), nil
}

type JSONField struct {
	Foo string
}

type JSONRecord1 struct {
	Field JSONField
}

type JSONRecord2 struct {
	Field *JSONField
}

type conversionTest struct {
	src, dst, wanted interface{}
	pgtype           string

	wanterr  string
	wantnil  bool
	wantzero bool
}

func deref(viface interface{}) interface{} {
	v := reflect.ValueOf(viface)
	for v.Kind() == reflect.Ptr {
		v = v.Elem()
	}
	if v.IsValid() {
		return v.Interface()
	}
	return nil
}

func zero(v interface{}) interface{} {
	return reflect.Zero(reflect.ValueOf(v).Elem().Type()).Interface()
}

func (test *conversionTest) String() string {
	return fmt.Sprintf("src=%#v dst=%#v", test.src, test.dst)
}

func (test *conversionTest) Fatalf(t *testing.T, s interface{}, args ...interface{}) {
	args = append(args, test.String())
	t.Fatalf(fmt.Sprint(s)+" (%s)", args...)
}

func (test *conversionTest) Assert(t *testing.T, err error) {
	if test.wanterr != "" {
		if err == nil || err.Error() != test.wanterr {
			test.Fatalf(t, "error is %q, wanted %q", err, test.wanterr)
		}
		return
	}

	if err != nil {
		test.Fatalf(t, "error is %s, wanted nil", err)
	}

	src := deref(test.src)
	dst := deref(test.dst)

	if test.wantzero {
		dstValue := reflect.ValueOf(dst)
		if dstValue.Kind() == reflect.Slice {
			if dstValue.IsNil() {
				test.Fatalf(t, "got nil, wanted zero value")
			}
			if dstValue.Len() != 0 {
				test.Fatalf(t, "got %d items, wanted 0", dstValue.Len())
			}
		} else {
			zero := zero(test.dst)
			if dst != zero {
				test.Fatalf(t, "%#v != %#v", dst, zero)
			}
		}
		return
	}

	if test.wantnil {
		if dst == nil {
			return
		}
		if reflect.ValueOf(dst).IsNil() {
			return
		}
		test.Fatalf(t, "got %#v, wanted nil", dst)
		return
	}

	if dstTime, ok := dst.(time.Time); ok {
		srcTime := src.(time.Time)
		if dstTime.Unix() != srcTime.Unix() {
			test.Fatalf(t, "%#v != %#v", dstTime, srcTime)
		}
		return
	}

	wanted := test.wanted
	if wanted == nil {
		wanted = src
	}
	if !reflect.DeepEqual(dst, wanted) {
		test.Fatalf(t, "%#v != %#v", dst, wanted)
	}
}

func TestConversion(t *testing.T) {
	conversionTests := []conversionTest{
		{src: true, dst: nil, wanterr: "pg: Decode(nil)"},
		{src: true, dst: new(uintptr), wanterr: "pg: Decode(unsupported uintptr)"},
		{src: true, dst: true, wanterr: "pg: Decode(nonsettable bool)"},
		{src: true, dst: (*bool)(nil), wanterr: "pg: Decode(nonsettable *bool)"},

		{src: false, dst: new(bool), pgtype: "bool"},
		{src: true, dst: new(bool), pgtype: "bool"},
		{src: nil, dst: new(bool), pgtype: "bool", wantzero: true},
		{src: true, dst: new(*bool), pgtype: "bool"},
		{src: nil, dst: new(*bool), pgtype: "bool", wantnil: true},

		{src: "hello world", dst: new(string), pgtype: "text"},
		{src: nil, dst: new(string), pgtype: "text", wantzero: true},
		{src: "hello world", dst: new(*string), pgtype: "text"},
		{src: nil, dst: new(*string), pgtype: "text", wantnil: true},

		{src: []byte("hello world\000"), dst: new([]byte), pgtype: "bytea"},
		{src: []byte{}, dst: new([]byte), pgtype: "bytea", wantzero: true},
		{src: nil, dst: new([]byte), pgtype: "bytea", wantnil: true},

		{src: int(math.MaxInt32), dst: new(int), pgtype: "int"},
		{src: int(math.MinInt32), dst: new(int), pgtype: "int"},
		{src: nil, dst: new(int), pgtype: "int", wantzero: true},
		{src: int(math.MaxInt32), dst: new(*int), pgtype: "int"},
		{src: nil, dst: new(*int), pgtype: "int", wantnil: true},
		{src: int8(math.MaxInt8), dst: new(int8), pgtype: "smallint"},
		{src: int8(math.MinInt8), dst: new(int8), pgtype: "smallint"},
		{src: int16(math.MaxInt16), dst: new(int16), pgtype: "smallint"},
		{src: int16(math.MinInt16), dst: new(int16), pgtype: "smallint"},
		{src: int32(math.MaxInt32), dst: new(int32), pgtype: "int"},
		{src: int32(math.MinInt32), dst: new(int32), pgtype: "int"},
		{src: int64(math.MaxInt64), dst: new(int64), pgtype: "bigint"},
		{src: int64(math.MinInt64), dst: new(int64), pgtype: "bigint"},
		{src: uint(math.MaxUint32), dst: new(uint), pgtype: "bigint"},
		{src: uint8(math.MaxUint8), dst: new(uint8), pgtype: "smallint"},
		{src: uint16(math.MaxUint16), dst: new(uint16), pgtype: "int"},
		{src: uint32(math.MaxUint32), dst: new(uint32), pgtype: "bigint"},
		{src: uint64(math.MaxUint64), dst: new(uint64)},

		{src: float32(math.MaxFloat32), dst: new(float32), pgtype: "decimal"},
		{src: float32(math.SmallestNonzeroFloat32), dst: new(float32), pgtype: "decimal"},
		{src: float64(math.MaxFloat64), dst: new(float64), pgtype: "decimal"},
		{src: float64(math.SmallestNonzeroFloat64), dst: new(float64), pgtype: "decimal"},

		{src: []int{}, dst: new([]int), pgtype: "int[]"},
		{src: []int{1, 2, 3}, dst: new([]int), pgtype: "int[]"},
		{src: []int64{1, 2, 3}, dst: new([]int64), pgtype: "bigint[]"},
		{src: []float64{1.1, 2.22, 3.333}, dst: new([]float64), pgtype: "double precision[]"},

		{src: []string{"foo\n", "bar {}", "'\\\""}, dst: new([]string), pgtype: "text[]"},
		{src: []string{}, dst: new([]string), pgtype: "text[]", wantzero: true},
		{src: nil, dst: new([]string), pgtype: "text[]", wantnil: true},

		{
			src:    map[string]string{"foo\n =>": "bar\n =>", "'\\\"": "'\\\""},
			dst:    new(map[string]string),
			pgtype: "hstore",
		},

		{src: &sql.NullBool{}, dst: &sql.NullBool{}, pgtype: "bool"},
		{src: &sql.NullBool{Valid: true}, dst: &sql.NullBool{}, pgtype: "bool"},
		{src: &sql.NullBool{Valid: true, Bool: true}, dst: &sql.NullBool{}, pgtype: "bool"},

		{src: &sql.NullString{}, dst: &sql.NullString{}, pgtype: "text"},
		{src: &sql.NullString{Valid: true}, dst: &sql.NullString{}, pgtype: "text"},
		{src: &sql.NullString{Valid: true, String: "foo"}, dst: &sql.NullString{}, pgtype: "text"},

		{src: &sql.NullInt64{}, dst: &sql.NullInt64{}, pgtype: "bigint"},
		{src: &sql.NullInt64{Valid: true}, dst: &sql.NullInt64{}, pgtype: "bigint"},
		{src: &sql.NullInt64{Valid: true, Int64: math.MaxInt64}, dst: &sql.NullInt64{}, pgtype: "bigint"},

		{src: &sql.NullFloat64{}, dst: &sql.NullFloat64{}, pgtype: "decimal"},
		{src: &sql.NullFloat64{Valid: true}, dst: &sql.NullFloat64{}, pgtype: "decimal"},
		{src: &sql.NullFloat64{Valid: true, Float64: math.MaxFloat64}, dst: &sql.NullFloat64{}, pgtype: "decimal"},

		{src: customStrSlice{}, dst: &customStrSlice{}, wantzero: true},
		{src: nil, dst: &customStrSlice{}, wantnil: true},
		{src: customStrSlice{"one", "two"}, dst: &customStrSlice{}},

		{src: time.Time{}, dst: &time.Time{}, pgtype: "timestamp"},
		{src: time.Now(), dst: &time.Time{}, pgtype: "timestamp"},
		{src: time.Now().UTC(), dst: &time.Time{}, pgtype: "timestamp"},
		{src: nil, dst: &time.Time{}, pgtype: "timestamp", wantzero: true},
		{src: time.Now(), dst: new(*time.Time), pgtype: "timestamp"},
		{src: nil, dst: new(*time.Time), pgtype: "timestamp", wantnil: true},

		{src: time.Time{}, dst: &time.Time{}, pgtype: "timestamptz"},
		{src: time.Now(), dst: &time.Time{}, pgtype: "timestamptz"},
		{src: time.Now().UTC(), dst: &time.Time{}, pgtype: "timestamptz"},
		{src: nil, dst: &time.Time{}, pgtype: "timestamptz", wantzero: true},
		{src: time.Now(), dst: new(*time.Time), pgtype: "timestamptz"},
		{src: nil, dst: new(*time.Time), pgtype: "timestamptz", wantnil: true},

		{src: 1, dst: new(pg.Ints), wanted: pg.Ints{1}},
		{src: "hello", dst: new(pg.Strings), wanted: pg.Strings{"hello"}},
		{src: 1, dst: new(pg.IntSet), wanted: pg.IntSet{1: struct{}{}}},

		{src: JSONMap{"foo": "bar"}, dst: &JSONMap{}, pgtype: "json"},
		{src: JSONMap{"foo": "bar"}, dst: new(*JSONMap), pgtype: "json"},
		{src: nil, dst: new(*JSONMap), wantnil: true, pgtype: "json"},
		{src: `{"foo": "bar"}`, dst: &JSONField{}, wanted: JSONField{Foo: "bar"}},
		{src: `{"foo": "bar"}`, dst: new(*JSONField), wanted: JSONField{Foo: "bar"}},
	}

	db := pgdb()
	db.Exec("CREATE EXTENSION hstore")
	defer db.Exec("DROP EXTENSION hstore")

	for _, test := range conversionTests {
		var err error
		if _, ok := test.dst.(pg.ColumnLoader); ok {
			_, err = db.QueryOne(test.dst, "SELECT (?) AS dst", test.src)
		} else {
			dst := struct{ Dst interface{} }{Dst: test.dst}
			_, err = db.QueryOne(&dst, "SELECT (?) AS dst", test.src)
		}
		test.Assert(t, err)
	}

	for _, test := range conversionTests {
		if test.pgtype == "" {
			continue
		}

		stmt, err := db.Prepare(fmt.Sprintf("SELECT ($1::%s) AS dst", test.pgtype))
		if err != nil {
			test.Fatalf(t, err)
		}

		if _, ok := test.dst.(pg.ColumnLoader); ok {
			_, err = stmt.QueryOne(test.dst, test.src)
		} else {
			dst := struct{ Dst interface{} }{Dst: test.dst}
			_, err = stmt.QueryOne(&dst, test.src)
		}
		test.Assert(t, err)

		if err := stmt.Close(); err != nil {
			test.Fatalf(t, err)
		}
	}

	for _, test := range conversionTests {
		if _, ok := test.dst.(pg.ColumnLoader); ok {
			continue
		}

		_, err := db.QueryOne(pg.LoadInto(test.dst), "SELECT (?) AS dst", test.src)
		test.Assert(t, err)
	}

	for _, test := range conversionTests {
		if _, ok := test.dst.(pg.ColumnLoader); ok {
			continue
		}
		if test.pgtype == "" {
			continue
		}

		stmt, err := db.Prepare(fmt.Sprintf("SELECT ($1::%s) AS dst", test.pgtype))
		if err != nil {
			test.Fatalf(t, err)
		}

		_, err = stmt.QueryOne(pg.LoadInto(test.dst), test.src)
		test.Assert(t, err)

		if err := stmt.Close(); err != nil {
			test.Fatalf(t, err)
		}
	}
}
<commit_msg>Cleanup conversion tests.<commit_after>package pg_test

import (
	"database/sql"
	"database/sql/driver"
	"encoding/json"
	"fmt"
	"math"
	"reflect"
	"testing"
	"time"

	"gopkg.in/pg.v3"
)

type JSONMap map[string]interface{}

func (m *JSONMap) Scan(value interface{}) error {
	return json.Unmarshal(value.([]byte), m)
}

func (m JSONMap) Value() (driver.Value, error) {
	b, err := json.Marshal(m)
	if err != nil {
		return nil, err
	}
	return string(b), nil
}

type JSONField struct {
	Foo string
}

type JSONRecord1 struct {
	Field JSONField
}

type JSONRecord2 struct {
	Field *JSONField
}

type conversionTest struct {
	src, dst, wanted interface{}
	pgtype           string

	wanterr  string
	wantnil  bool
	wantzero bool
}

func deref(viface interface{}) interface{} {
	v := reflect.ValueOf(viface)
	for v.Kind() == reflect.Ptr {
		v = v.Elem()
	}
	if v.IsValid() {
		return v.Interface()
	}
	return nil
}

func zero(v interface{}) interface{} {
	return reflect.Zero(reflect.ValueOf(v).Elem().Type()).Interface()
}

func (test *conversionTest) String() string {
	return fmt.Sprintf("src=%#v dst=%#v", test.src, test.dst)
}

func (test *conversionTest) Fatalf(t *testing.T, s interface{}, args ...interface{}) {
	args = append(args, test.String())
	t.Fatalf(fmt.Sprint(s)+" (%s)", args...)
}

func (test *conversionTest) Assert(t *testing.T, err error) {
	if test.wanterr != "" {
		if err == nil || err.Error() != test.wanterr {
			test.Fatalf(t, "error is %q, wanted %q", err, test.wanterr)
		}
		return
	}

	if err != nil {
		test.Fatalf(t, "error is %s, wanted nil", err)
	}

	// test.dst is a pointer to the value.
	dst := reflect.ValueOf(test.dst).Elem().Interface()

	if test.wantnil {
		dstValue := reflect.ValueOf(dst)
		if dstValue.IsNil() {
			return
		}
		test.Fatalf(t, "got %#v, wanted nil", dst)
		return
	}

	// Remove any intermediate pointers to compare values, not pointers.
	dst = deref(dst)
	src := deref(test.src)

	if test.wantzero {
		dstValue := reflect.ValueOf(dst)
		if dstValue.Kind() == reflect.Slice {
			if dstValue.IsNil() {
				test.Fatalf(t, "got nil, wanted zero value")
			}
			if dstValue.Len() != 0 {
				test.Fatalf(t, "got %d items, wanted 0", dstValue.Len())
			}
		} else {
			zero := zero(test.dst)
			if dst != zero {
				test.Fatalf(t, "%#v != %#v", dst, zero)
			}
		}
		return
	}

	if dstTime, ok := dst.(time.Time); ok {
		srcTime := src.(time.Time)
		if dstTime.Unix() != srcTime.Unix() {
			test.Fatalf(t, "%#v != %#v", dstTime, srcTime)
		}
		return
	}

	wanted := test.wanted
	if wanted == nil {
		wanted = src
	}
	if !reflect.DeepEqual(dst, wanted) {
		test.Fatalf(t, "%#v != %#v", dst, wanted)
	}
}

func TestConversion(t *testing.T) {
	conversionTests := []conversionTest{
		{src: true, dst: nil, wanterr: "pg: Decode(nil)"},
		{src: true, dst: new(uintptr), wanterr: "pg: Decode(unsupported uintptr)"},
		{src: true, dst: true, wanterr: "pg: Decode(nonsettable bool)"},
		{src: true, dst: (*bool)(nil), wanterr: "pg: Decode(nonsettable *bool)"},

		{src: false, dst: new(bool), pgtype: "bool"},
		{src: true, dst: new(bool), pgtype: "bool"},
		{src: nil, dst: new(bool), pgtype: "bool", wantzero: true},
		{src: true, dst: new(*bool), pgtype: "bool"},
		{src: nil, dst: new(*bool), pgtype: "bool", wantnil: true},

		{src: "hello world", dst: new(string), pgtype: "text"},
		{src: nil, dst: new(string), pgtype: "text", wantzero: true},
		{src: "hello world", dst: new(*string), pgtype: "text"},
		{src: nil, dst: new(*string), pgtype: "text", wantnil: true},

		{src: []byte("hello world\000"), dst: new([]byte), pgtype: "bytea"},
		{src: []byte{}, dst: new([]byte), pgtype: "bytea", wantzero: true},
		{src: nil, dst: new([]byte), pgtype: "bytea", wantnil: true},

		{src: int(math.MaxInt32), dst: new(int), pgtype: "int"},
		{src: int(math.MinInt32), dst: new(int), pgtype: "int"},
		{src: nil, dst: new(int), pgtype: "int", wantzero: true},
		{src: int(math.MaxInt32), dst: new(*int), pgtype: "int"},
		{src: nil, dst: new(*int), pgtype: "int", wantnil: true},
		{src: int8(math.MaxInt8), dst: new(int8), pgtype: "smallint"},
		{src: int8(math.MinInt8), dst: new(int8), pgtype: "smallint"},
		{src: int16(math.MaxInt16), dst: new(int16), pgtype: "smallint"},
		{src: int16(math.MinInt16), dst: new(int16), pgtype: "smallint"},
		{src: int32(math.MaxInt32), dst: new(int32), pgtype: "int"},
		{src: int32(math.MinInt32), dst: new(int32), pgtype: "int"},
		{src: int64(math.MaxInt64), dst: new(int64), pgtype: "bigint"},
		{src: int64(math.MinInt64), dst: new(int64), pgtype: "bigint"},
		{src: uint(math.MaxUint32), dst: new(uint), pgtype: "bigint"},
		{src: uint8(math.MaxUint8), dst: new(uint8), pgtype: "smallint"},
		{src: uint16(math.MaxUint16), dst: new(uint16), pgtype: "int"},
		{src: uint32(math.MaxUint32), dst: new(uint32), pgtype: "bigint"},
		{src: uint64(math.MaxUint64), dst: new(uint64)},

		{src: float32(math.MaxFloat32), dst: new(float32), pgtype: "decimal"},
		{src: float32(math.SmallestNonzeroFloat32), dst: new(float32), pgtype: "decimal"},
		{src: float64(math.MaxFloat64), dst: new(float64), pgtype: "decimal"},
		{src: float64(math.SmallestNonzeroFloat64), dst: new(float64), pgtype: "decimal"},

		{src: nil, dst: new([]int), pgtype: "int[]", wantnil: true},
		{src: []int{}, dst: new([]int), pgtype: "int[]", wantzero: true},
		{src: []int{1, 2, 3}, dst: new([]int), pgtype: "int[]"},
		{src: []int64{1, 2, 3}, dst: new([]int64), pgtype: "bigint[]"},
		{src: []float64{1.1, 2.22, 3.333}, dst: new([]float64), pgtype: "double precision[]"},

		{src: nil, dst: new([]string), pgtype: "text[]", wantnil: true},
		{src: []string{}, dst: new([]string), pgtype: "text[]", wantzero: true},
		{src: []string{"foo\n", "bar {}", "'\\\""}, dst: new([]string), pgtype: "text[]"},

		{
			src:    map[string]string{"foo\n =>": "bar\n =>", "'\\\"": "'\\\""},
			dst:    new(map[string]string),
			pgtype: "hstore",
		},

		{src: &sql.NullBool{}, dst: &sql.NullBool{}, pgtype: "bool"},
		{src: &sql.NullBool{Valid: true}, dst: &sql.NullBool{}, pgtype: "bool"},
		{src: &sql.NullBool{Valid: true, Bool: true}, dst: &sql.NullBool{}, pgtype: "bool"},

		{src: &sql.NullString{}, dst: &sql.NullString{}, pgtype: "text"},
		{src: &sql.NullString{Valid: true}, dst: &sql.NullString{}, pgtype: "text"},
		{src: &sql.NullString{Valid: true, String: "foo"}, dst: &sql.NullString{}, pgtype: "text"},

		{src: &sql.NullInt64{}, dst: &sql.NullInt64{}, pgtype: "bigint"},
		{src: &sql.NullInt64{Valid: true}, dst: &sql.NullInt64{}, pgtype: "bigint"},
		{src: &sql.NullInt64{Valid: true, Int64: math.MaxInt64}, dst: &sql.NullInt64{}, pgtype: "bigint"},

		{src: &sql.NullFloat64{}, dst: &sql.NullFloat64{}, pgtype: "decimal"},
		{src: &sql.NullFloat64{Valid: true}, dst: &sql.NullFloat64{}, pgtype: "decimal"},
		{src: &sql.NullFloat64{Valid: true, Float64: math.MaxFloat64}, dst: &sql.NullFloat64{}, pgtype: "decimal"},

		{src: nil, dst: &customStrSlice{}, wantnil: true},
		{src: customStrSlice{}, dst: &customStrSlice{}, wantzero: true},
		{src: customStrSlice{"one", "two"}, dst: &customStrSlice{}},

		{src: time.Time{}, dst: &time.Time{}, pgtype: "timestamp"},
		{src: time.Now(), dst: &time.Time{}, pgtype: "timestamp"},
		{src: time.Now().UTC(), dst: &time.Time{}, pgtype: "timestamp"},
		{src: nil, dst: &time.Time{}, pgtype: "timestamp", wantzero: true},
		{src: time.Now(), dst: new(*time.Time), pgtype: "timestamp"},
		{src: nil, dst: new(*time.Time), pgtype: "timestamp", wantnil: true},

		{src: time.Time{}, dst: &time.Time{}, pgtype: "timestamptz"},
		{src: time.Now(), dst: &time.Time{}, pgtype: "timestamptz"},
		{src: time.Now().UTC(), dst: &time.Time{}, pgtype: "timestamptz"},
		{src: nil, dst: &time.Time{}, pgtype: "timestamptz", wantzero: true},
		{src: time.Now(), dst: new(*time.Time), pgtype: "timestamptz"},
		{src: nil, dst: new(*time.Time), pgtype: "timestamptz", wantnil: true},

		{src: 1, dst: new(pg.Ints), wanted: pg.Ints{1}},
		{src: "hello", dst: new(pg.Strings), wanted: pg.Strings{"hello"}},
		{src: 1, dst: new(pg.IntSet), wanted: pg.IntSet{1: struct{}{}}},

		{src: JSONMap{"foo": "bar"}, dst: &JSONMap{}, pgtype: "json"},
		{src: JSONMap{"foo": "bar"}, dst: new(*JSONMap), pgtype: "json"},
		{src: nil, dst: new(*JSONMap), wantnil: true, pgtype: "json"},
		{src: `{"foo": "bar"}`, dst: &JSONField{}, wanted: JSONField{Foo: "bar"}},
		{src: `{"foo": "bar"}`, dst: new(*JSONField), wanted: JSONField{Foo: "bar"}},
	}

	db := pgdb()
	db.Exec("CREATE EXTENSION hstore")
	defer db.Exec("DROP EXTENSION hstore")

	for _, test := range conversionTests {
		var err error
		if _, ok := test.dst.(pg.ColumnLoader); ok {
			_, err = db.QueryOne(test.dst, "SELECT (?) AS dst", test.src)
		} else {
			dst := struct{ Dst interface{} }{Dst: test.dst}
			_, err = db.QueryOne(&dst, "SELECT (?) AS dst", test.src)
		}
		test.Assert(t, err)
	}

	for _, test := range conversionTests {
		if test.pgtype == "" {
			continue
		}

		stmt, err := db.Prepare(fmt.Sprintf("SELECT ($1::%s) AS dst", test.pgtype))
		if err != nil {
			test.Fatalf(t, err)
		}

		if _, ok := test.dst.(pg.ColumnLoader); ok {
			_, err = stmt.QueryOne(test.dst, test.src)
		} else {
			dst := struct{ Dst interface{} }{Dst: test.dst}
			_, err = stmt.QueryOne(&dst, test.src)
		}
		test.Assert(t, err)

		if err := stmt.Close(); err != nil {
			test.Fatalf(t, err)
		}
	}

	for _, test := range conversionTests {
		if _, ok := test.dst.(pg.ColumnLoader); ok {
			continue
		}

		_, err := db.QueryOne(pg.LoadInto(test.dst), "SELECT (?) AS dst", test.src)
		test.Assert(t, err)
	}

	for _, test := range conversionTests {
		if _, ok := test.dst.(pg.ColumnLoader); ok {
			continue
		}
		if test.pgtype == "" {
			continue
		}

		stmt, err := db.Prepare(fmt.Sprintf("SELECT ($1::%s) AS dst", test.pgtype))
		if err != nil {
			test.Fatalf(t, err)
		}

		_, err = stmt.QueryOne(pg.LoadInto(test.dst), test.src)
		test.Assert(t, err)

		if err := stmt.Close(); err != nil {
			test.Fatalf(t, err)
		}
	}
}
<|endoftext|>


<commit_before>//
// DISCLAIMER
//
// Copyright 2017 ArangoDB GmbH, Cologne, Germany
//
// 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.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
// Author Ewout Prangsma
//

package test

import (
	"context"
	"testing"

	driver "github.com/arangodb/go-driver"
)

// ensureEdgeCollection returns the edge collection with given name, creating it if needed.
func ensureEdgeCollection(ctx context.Context, g driver.Graph, collection string, from, to []string, t *testing.T) driver.Collection {
	ec, err := g.EdgeCollection(ctx, collection)
	if driver.IsNotFound(err) {
		ec, err := g.CreateEdgeCollection(ctx, collection, from, to)
		if err != nil {
			t.Fatalf("Failed to create edge collection: %s", describe(err))
		}
		return ec
	} else if err != nil {
		t.Fatalf("Failed to open edge collection: %s", describe(err))
	}
	return ec
}

// TestCreateEdgeCollection creates a graph and then adds an edge collection in it
func TestCreateEdgeCollection(t *testing.T) {
	c := createClientFromEnv(t, true)
	db := ensureDatabase(nil, c, "edge_collection_test", nil, t)
	name := "test_create_edge_collection"
	g, err := db.CreateGraph(nil, name, nil)
	if err != nil {
		t.Fatalf("Failed to create graph '%s': %s", name, describe(err))
	}

	// List edge collections, must be empty
	if list, err := g.EdgeCollections(nil); err != nil {
		t.Errorf("EdgeCollections failed: %s", describe(err))
	} else if len(list) > 0 {
		t.Errorf("EdgeCollections return %d edge collections, expected 0", len(list))
	}

	// Now create an edge collection
	if ec, err := g.CreateEdgeCollection(nil, "friends", []string{"person"}, []string{"person"}); err != nil {
		t.Errorf("CreateEdgeCollection failed: %s", describe(err))
	} else if ec.Name() != "friends" {
		t.Errorf("Invalid name, expected 'friends', got '%s'", ec.Name())
	}

	assertCollection(nil, db, "friends", t)
	assertCollection(nil, db, "person", t)

	// List edge collections, must be contain 'friends'
	if list, err := g.EdgeCollections(nil); err != nil {
		t.Errorf("EdgeCollections failed: %s", describe(err))
	} else if len(list) != 1 {
		t.Errorf("EdgeCollections return %d edge collections, expected 1", len(list))
	} else if list[0].Name() != "friends" {
		t.Errorf("Invalid list[0].name, expected 'friends', got '%s'", list[0].Name())
	}

	// Friends edge collection must exits
	if found, err := g.EdgeCollectionExists(nil, "friends"); err != nil {
		t.Errorf("EdgeCollectionExists failed: %s", describe(err))
	} else if !found {
		t.Errorf("EdgeCollectionExists return false, expected true")
	}

	// Open friends edge collection must exits
	if ec, err := g.EdgeCollection(nil, "friends"); err != nil {
		t.Errorf("EdgeCollection failed: %s", describe(err))
	} else if ec.Name() != "friends" {
		t.Errorf("EdgeCollection return invalid collection, expected 'friends', got '%s'", ec.Name())
	}
}

// TestRemoveEdgeCollection creates a graph and then adds an edge collection in it and then removes the edge collection.
func TestRemoveEdgeCollection(t *testing.T) {
	c := createClientFromEnv(t, true)
	db := ensureDatabase(nil, c, "edge_collection_test", nil, t)
	name := "test_remove_edge_collection"
	g, err := db.CreateGraph(nil, name, nil)
	if err != nil {
		t.Fatalf("Failed to create graph '%s': %s", name, describe(err))
	}

	// Now create an edge collection
	ec, err := g.CreateEdgeCollection(nil, "friends", []string{"person"}, []string{"person"})
	if err != nil {
		t.Errorf("CreateEdgeCollection failed: %s", describe(err))
	} else if ec.Name() != "friends" {
		t.Errorf("Invalid name, expected 'friends', got '%s'", ec.Name())
	}

	// Friends edge collection must exits
	if found, err := g.EdgeCollectionExists(nil, "friends"); err != nil {
		t.Errorf("EdgeCollectionExists failed: %s", describe(err))
	} else if !found {
		t.Errorf("EdgeCollectionExists return false, expected true")
	}

	// Remove edge collection
	if err := ec.Remove(nil); err != nil {
		t.Errorf("Remove failed: %s", describe(err))
	}

	// Friends edge collection must NOT exits
	if found, err := g.EdgeCollectionExists(nil, "friends"); err != nil {
		t.Errorf("EdgeCollectionExists failed: %s", describe(err))
	} else if found {
		t.Errorf("EdgeCollectionExists return true, expected false")
	}
}

// TestReplaceEdgeCollection creates a graph and then adds an edge collection in it and then replaces the edge collection.
/*func TestReplaceEdgeCollection(t *testing.T) {
	c := createClientFromEnv(t, true)
	db := ensureDatabase(nil, c, "edge_collection_test", nil, t)
	name := "test_replace_edge_collection"
	g, err := db.CreateGraph(nil, name, nil)
	if err != nil {
		t.Fatalf("Failed to create graph '%s': %s", name, describe(err))
	}

	// Now create an edge collection
	ec, err := g.CreateEdgeCollection(nil, "friends", []string{"person"}, []string{"person"})
	if err != nil {
		t.Errorf("CreateEdgeCollection failed: %s", describe(err))
	} else if ec.Name() != "friends" {
		t.Errorf("Invalid name, expected 'friends', got '%s'", ec.Name())
	}

	// Friends edge collection must exits
	if found, err := g.EdgeCollectionExists(nil, "friends"); err != nil {
		t.Errorf("EdgeCollectionExists failed: %s", describe(err))
	} else if !found {
		t.Errorf("EdgeCollectionExists return false, expected true")
	}

	// Replace edge collection
	if err := ec.Replace(nil, []string{"city"}, []string{"state"}); err != nil {
		t.Errorf("Replace failed: %s", describe(err))
	}

	assertCollection(nil, db, "city", t)
	assertCollection(nil, db, "state", t)
}
*/
<commit_msg>Prevent panic incase an earlier test fails<commit_after>//
// DISCLAIMER
//
// Copyright 2017 ArangoDB GmbH, Cologne, Germany
//
// 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.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
// Author Ewout Prangsma
//

package test

import (
	"context"
	"testing"

	driver "github.com/arangodb/go-driver"
)

// ensureEdgeCollection returns the edge collection with given name, creating it if needed.
func ensureEdgeCollection(ctx context.Context, g driver.Graph, collection string, from, to []string, t *testing.T) driver.Collection {
	ec, err := g.EdgeCollection(ctx, collection)
	if driver.IsNotFound(err) {
		ec, err := g.CreateEdgeCollection(ctx, collection, from, to)
		if err != nil {
			t.Fatalf("Failed to create edge collection: %s", describe(err))
		}
		return ec
	} else if err != nil {
		t.Fatalf("Failed to open edge collection: %s", describe(err))
	}
	return ec
}

// TestCreateEdgeCollection creates a graph and then adds an edge collection in it
func TestCreateEdgeCollection(t *testing.T) {
	c := createClientFromEnv(t, true)
	db := ensureDatabase(nil, c, "edge_collection_test", nil, t)
	name := "test_create_edge_collection"
	g, err := db.CreateGraph(nil, name, nil)
	if err != nil {
		t.Fatalf("Failed to create graph '%s': %s", name, describe(err))
	}

	// List edge collections, must be empty
	if list, err := g.EdgeCollections(nil); err != nil {
		t.Errorf("EdgeCollections failed: %s", describe(err))
	} else if len(list) > 0 {
		t.Errorf("EdgeCollections return %d edge collections, expected 0", len(list))
	}

	// Now create an edge collection
	if ec, err := g.CreateEdgeCollection(nil, "friends", []string{"person"}, []string{"person"}); err != nil {
		t.Errorf("CreateEdgeCollection failed: %s", describe(err))
	} else if ec.Name() != "friends" {
		t.Errorf("Invalid name, expected 'friends', got '%s'", ec.Name())
	}

	assertCollection(nil, db, "friends", t)
	assertCollection(nil, db, "person", t)

	// List edge collections, must be contain 'friends'
	if list, err := g.EdgeCollections(nil); err != nil {
		t.Errorf("EdgeCollections failed: %s", describe(err))
	} else if len(list) != 1 {
		t.Errorf("EdgeCollections return %d edge collections, expected 1", len(list))
	} else if list[0].Name() != "friends" {
		t.Errorf("Invalid list[0].name, expected 'friends', got '%s'", list[0].Name())
	}

	// Friends edge collection must exits
	if found, err := g.EdgeCollectionExists(nil, "friends"); err != nil {
		t.Errorf("EdgeCollectionExists failed: %s", describe(err))
	} else if !found {
		t.Errorf("EdgeCollectionExists return false, expected true")
	}

	// Open friends edge collection must exits
	if ec, err := g.EdgeCollection(nil, "friends"); err != nil {
		t.Errorf("EdgeCollection failed: %s", describe(err))
	} else if ec.Name() != "friends" {
		t.Errorf("EdgeCollection return invalid collection, expected 'friends', got '%s'", ec.Name())
	}
}

// TestRemoveEdgeCollection creates a graph and then adds an edge collection in it and then removes the edge collection.
func TestRemoveEdgeCollection(t *testing.T) {
	c := createClientFromEnv(t, true)
	db := ensureDatabase(nil, c, "edge_collection_test", nil, t)
	name := "test_remove_edge_collection"
	g, err := db.CreateGraph(nil, name, nil)
	if err != nil {
		t.Fatalf("Failed to create graph '%s': %s", name, describe(err))
	}

	// Now create an edge collection
	ec, err := g.CreateEdgeCollection(nil, "friends", []string{"person"}, []string{"person"})
	if err != nil {
		t.Fatalf("CreateEdgeCollection failed: %s", describe(err))
	} else if ec.Name() != "friends" {
		t.Errorf("Invalid name, expected 'friends', got '%s'", ec.Name())
	}

	// Friends edge collection must exits
	if found, err := g.EdgeCollectionExists(nil, "friends"); err != nil {
		t.Errorf("EdgeCollectionExists failed: %s", describe(err))
	} else if !found {
		t.Errorf("EdgeCollectionExists return false, expected true")
	}

	// Remove edge collection
	if err := ec.Remove(nil); err != nil {
		t.Errorf("Remove failed: %s", describe(err))
	}

	// Friends edge collection must NOT exits
	if found, err := g.EdgeCollectionExists(nil, "friends"); err != nil {
		t.Errorf("EdgeCollectionExists failed: %s", describe(err))
	} else if found {
		t.Errorf("EdgeCollectionExists return true, expected false")
	}
}

// TestReplaceEdgeCollection creates a graph and then adds an edge collection in it and then replaces the edge collection.
/*func TestReplaceEdgeCollection(t *testing.T) {
	c := createClientFromEnv(t, true)
	db := ensureDatabase(nil, c, "edge_collection_test", nil, t)
	name := "test_replace_edge_collection"
	g, err := db.CreateGraph(nil, name, nil)
	if err != nil {
		t.Fatalf("Failed to create graph '%s': %s", name, describe(err))
	}

	// Now create an edge collection
	ec, err := g.CreateEdgeCollection(nil, "friends", []string{"person"}, []string{"person"})
	if err != nil {
		t.Errorf("CreateEdgeCollection failed: %s", describe(err))
	} else if ec.Name() != "friends" {
		t.Errorf("Invalid name, expected 'friends', got '%s'", ec.Name())
	}

	// Friends edge collection must exits
	if found, err := g.EdgeCollectionExists(nil, "friends"); err != nil {
		t.Errorf("EdgeCollectionExists failed: %s", describe(err))
	} else if !found {
		t.Errorf("EdgeCollectionExists return false, expected true")
	}

	// Replace edge collection
	if err := ec.Replace(nil, []string{"city"}, []string{"state"}); err != nil {
		t.Errorf("Replace failed: %s", describe(err))
	}

	assertCollection(nil, db, "city", t)
	assertCollection(nil, db, "state", t)
}
*/
<|endoftext|>


<commit_before>// +build integration

/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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

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

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

package integration

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

	"k8s.io/minikube/pkg/kapi"
	"k8s.io/minikube/pkg/util/retry"
)

func TestNetworkPlugins(t *testing.T) {
	MaybeParallel(t)
	if NoneDriver() {
		t.Skip("skipping since test for none driver")
	}

	t.Run("group", func(t *testing.T) {
		tests := []struct {
			name          string
			args          []string
			kubeletPlugin string
			podLabel      string
			hairpin       bool
		}{
			{"auto", []string{}, "", "", false},
			{"kubenet", []string{"--network-plugin=kubenet"}, "kubenet", "", true},
			{"bridge", []string{"--cni=bridge"}, "cni", "", true},
			{"enable-default-cni", []string{"--enable-default-cni=true"}, "cni", "", true},
			{"flannel", []string{"--cni=flannel"}, "cni", "app=flannel", true},
			{"kindnet", []string{"--cni=kindnet"}, "cni", "app=kindnet", true},
			{"false", []string{"--cni=false"}, "", "", false},
			{"custom-weave", []string{fmt.Sprintf("--cni=%s", filepath.Join(*testdataDir, "weavenet.yaml"))}, "cni", "", true},
			{"calico", []string{"--cni=calico"}, "cni", "k8s-app=calico-node", true},
			{"cilium", []string{"--cni=cilium"}, "cni", "k8s-app=cilium", true},
		}

		for _, tc := range tests {
			tc := tc

			t.Run(tc.name, func(t *testing.T) {
				if DockerDriver() && strings.Contains(tc.name, "flannel") {
					t.Skipf("flannel is not yet compatible with Docker driver: iptables v1.8.3 (legacy): Couldn't load target `CNI-x': No such file or directory")
				}

				start := time.Now()
				MaybeParallel(t)
				profile := UniqueProfileName(tc.name)

				ctx, cancel := context.WithTimeout(context.Background(), Minutes(30))
				defer CleanupWithLogs(t, profile, cancel)

				startArgs := append([]string{"start", "-p", profile, "--memory=1800", "--alsologtostderr", "--wait=true", "--wait-timeout=3m"}, tc.args...)
				startArgs = append(startArgs, StartArgs()...)

				t.Run("Start", func(t *testing.T) {
					_, err := Run(t, exec.CommandContext(ctx, Target(), startArgs...))
					if err != nil {
						t.Fatalf("failed start: %v", err)
					}
				})

				if !t.Failed() && tc.podLabel != "" {
					t.Run("ControllerPod", func(t *testing.T) {
						if _, err := PodWait(ctx, t, profile, "kube-system", tc.podLabel, Minutes(10)); err != nil {
							t.Fatalf("failed waiting for %s labeled pod: %v", tc.podLabel, err)
						}
					})
				}
				if !t.Failed() {
					t.Run("KubeletFlags", func(t *testing.T) {
						var rr *RunResult
						var err error

						// none does not support 'minikube ssh'
						if NoneDriver() {
							rr, err = Run(t, exec.CommandContext(ctx, "pgrep", "-a", "kubelet"))
						} else {
							rr, err = Run(t, exec.CommandContext(ctx, Target(), "ssh", "-p", profile, "pgrep -a kubelet"))
						}

						if err != nil {
							t.Fatalf("ssh failed: %v", err)
						}
						out := rr.Stdout.String()

						if tc.kubeletPlugin == "" {
							if strings.Contains(out, "--network-plugin") {
								t.Errorf("expected no network plug-in, got %s", out)
							}
						} else {
							if !strings.Contains(out, fmt.Sprintf("--network-plugin=%s", tc.kubeletPlugin)) {
								t.Errorf("expected --network-plugin=%s, got %s", tc.kubeletPlugin, out)
							}
						}

					})
				}

				if !t.Failed() {
					t.Run("NetCatPod", func(t *testing.T) {
						_, err := Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "replace", "--force", "-f", filepath.Join(*testdataDir, "netcat-deployment.yaml")))
						if err != nil {
							t.Errorf("failed to apply netcat manifest: %v", err)
						}

						client, err := kapi.Client(profile)
						if err != nil {
							t.Fatalf("failed to get Kubernetes client for %s: %v", profile, err)
						}

						if err := kapi.WaitForDeploymentToStabilize(client, "default", "netcat", Minutes(15)); err != nil {
							t.Errorf("failed waiting for netcat deployment to stabilize: %v", err)
						}

						if _, err := PodWait(ctx, t, profile, "default", "app=netcat", Minutes(15)); err != nil {
							t.Fatalf("failed waiting for netcat pod: %v", err)
						}

					})
				}

				if strings.Contains(tc.name, "weave") {
					t.Skipf("skipping remaining tests for weave, as results can be unpredictable")
				}

				if !t.Failed() {
					t.Run("DNS", func(t *testing.T) {
						var rr *RunResult
						var err error

						nslookup := func() error {
							rr, err = Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "exec", "deployment/netcat", "--", "nslookup", "kubernetes.default"))
							return err
						}

						// If the coredns process was stable, this retry wouldn't be necessary.
						if err := retry.Expo(nslookup, 1*time.Second, Minutes(6)); err != nil {
							t.Errorf("failed to do nslookup on kubernetes.default: %v", err)
						}

						want := []byte("10.96.0.1")
						if !bytes.Contains(rr.Stdout.Bytes(), want) {
							t.Errorf("failed nslookup: got=%q, want=*%q*", rr.Stdout.Bytes(), want)
						}
					})
				}

				if !t.Failed() {
					t.Run("Localhost", func(t *testing.T) {
						tryLocal := func() error {
							_, err := Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "exec", "deployment/netcat", "--", "/bin/sh", "-c", "nc -w 5 -i 5 -z localhost 8080"))
							return err
						}

						if err := retry.Expo(tryLocal, 1*time.Second, Seconds(60)); err != nil {
							t.Errorf("failed to connect via localhost: %v", err)
						}
					})
				}

				if !t.Failed() {
					t.Run("HairPin", func(t *testing.T) {
						tryHairPin := func() error {
							_, err := Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "exec", "deployment/netcat", "--", "/bin/sh", "-c", "nc -w 5 -i 5 -z netcat 8080"))
							return err
						}

						if tc.hairpin {
							if err := retry.Expo(tryHairPin, 1*time.Second, Seconds(60)); err != nil {
								t.Errorf("failed to connect via pod host: %v", err)
							}
						} else {
							if tryHairPin() == nil {
								t.Fatalf("hairpin connection unexpectedly succeeded - misconfigured test?")
							}
						}
					})
				}

				t.Logf("%q test finished in %s, failed=%v", tc.name, time.Since(start), t.Failed())
			})
		}
	})
}
<commit_msg>reduce retry to 1 minute, when this test passes it takes <1s<commit_after>// +build integration

/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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

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

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

package integration

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

	"k8s.io/minikube/pkg/kapi"
	"k8s.io/minikube/pkg/util/retry"
)

func TestNetworkPlugins(t *testing.T) {
	MaybeParallel(t)
	if NoneDriver() {
		t.Skip("skipping since test for none driver")
	}

	t.Run("group", func(t *testing.T) {
		tests := []struct {
			name          string
			args          []string
			kubeletPlugin string
			podLabel      string
			hairpin       bool
		}{
			{"auto", []string{}, "", "", false},
			{"kubenet", []string{"--network-plugin=kubenet"}, "kubenet", "", true},
			{"bridge", []string{"--cni=bridge"}, "cni", "", true},
			{"enable-default-cni", []string{"--enable-default-cni=true"}, "cni", "", true},
			{"flannel", []string{"--cni=flannel"}, "cni", "app=flannel", true},
			{"kindnet", []string{"--cni=kindnet"}, "cni", "app=kindnet", true},
			{"false", []string{"--cni=false"}, "", "", false},
			{"custom-weave", []string{fmt.Sprintf("--cni=%s", filepath.Join(*testdataDir, "weavenet.yaml"))}, "cni", "", true},
			{"calico", []string{"--cni=calico"}, "cni", "k8s-app=calico-node", true},
			{"cilium", []string{"--cni=cilium"}, "cni", "k8s-app=cilium", true},
		}

		for _, tc := range tests {
			tc := tc

			t.Run(tc.name, func(t *testing.T) {
				if DockerDriver() && strings.Contains(tc.name, "flannel") {
					t.Skipf("flannel is not yet compatible with Docker driver: iptables v1.8.3 (legacy): Couldn't load target `CNI-x': No such file or directory")
				}

				start := time.Now()
				MaybeParallel(t)
				profile := UniqueProfileName(tc.name)

				ctx, cancel := context.WithTimeout(context.Background(), Minutes(30))
				defer CleanupWithLogs(t, profile, cancel)

				startArgs := append([]string{"start", "-p", profile, "--memory=1800", "--alsologtostderr", "--wait=true", "--wait-timeout=3m"}, tc.args...)
				startArgs = append(startArgs, StartArgs()...)

				t.Run("Start", func(t *testing.T) {
					_, err := Run(t, exec.CommandContext(ctx, Target(), startArgs...))
					if err != nil {
						t.Fatalf("failed start: %v", err)
					}
				})

				if !t.Failed() && tc.podLabel != "" {
					t.Run("ControllerPod", func(t *testing.T) {
						if _, err := PodWait(ctx, t, profile, "kube-system", tc.podLabel, Minutes(10)); err != nil {
							t.Fatalf("failed waiting for %s labeled pod: %v", tc.podLabel, err)
						}
					})
				}
				if !t.Failed() {
					t.Run("KubeletFlags", func(t *testing.T) {
						var rr *RunResult
						var err error

						// none does not support 'minikube ssh'
						if NoneDriver() {
							rr, err = Run(t, exec.CommandContext(ctx, "pgrep", "-a", "kubelet"))
						} else {
							rr, err = Run(t, exec.CommandContext(ctx, Target(), "ssh", "-p", profile, "pgrep -a kubelet"))
						}

						if err != nil {
							t.Fatalf("ssh failed: %v", err)
						}
						out := rr.Stdout.String()

						if tc.kubeletPlugin == "" {
							if strings.Contains(out, "--network-plugin") {
								t.Errorf("expected no network plug-in, got %s", out)
							}
						} else {
							if !strings.Contains(out, fmt.Sprintf("--network-plugin=%s", tc.kubeletPlugin)) {
								t.Errorf("expected --network-plugin=%s, got %s", tc.kubeletPlugin, out)
							}
						}

					})
				}

				if !t.Failed() {
					t.Run("NetCatPod", func(t *testing.T) {
						_, err := Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "replace", "--force", "-f", filepath.Join(*testdataDir, "netcat-deployment.yaml")))
						if err != nil {
							t.Errorf("failed to apply netcat manifest: %v", err)
						}

						client, err := kapi.Client(profile)
						if err != nil {
							t.Fatalf("failed to get Kubernetes client for %s: %v", profile, err)
						}

						if err := kapi.WaitForDeploymentToStabilize(client, "default", "netcat", Minutes(15)); err != nil {
							t.Errorf("failed waiting for netcat deployment to stabilize: %v", err)
						}

						if _, err := PodWait(ctx, t, profile, "default", "app=netcat", Minutes(15)); err != nil {
							t.Fatalf("failed waiting for netcat pod: %v", err)
						}

					})
				}

				if strings.Contains(tc.name, "weave") {
					t.Skipf("skipping remaining tests for weave, as results can be unpredictable")
				}

				if !t.Failed() {
					t.Run("DNS", func(t *testing.T) {
						var rr *RunResult
						var err error

						nslookup := func() error {
							rr, err = Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "exec", "deployment/netcat", "--", "nslookup", "kubernetes.default"))
							return err
						}

						// If the coredns process was stable, this retry wouldn't be necessary.
						if err := retry.Expo(nslookup, 1*time.Second, Minutes(1)); err != nil {
							t.Errorf("failed to do nslookup on kubernetes.default: %v", err)
						}

						want := []byte("10.96.0.1")
						if !bytes.Contains(rr.Stdout.Bytes(), want) {
							t.Errorf("failed nslookup: got=%q, want=*%q*", rr.Stdout.Bytes(), want)
						}
					})
				}

				if !t.Failed() {
					t.Run("Localhost", func(t *testing.T) {
						tryLocal := func() error {
							_, err := Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "exec", "deployment/netcat", "--", "/bin/sh", "-c", "nc -w 5 -i 5 -z localhost 8080"))
							return err
						}

						if err := retry.Expo(tryLocal, 1*time.Second, Seconds(60)); err != nil {
							t.Errorf("failed to connect via localhost: %v", err)
						}
					})
				}

				if !t.Failed() {
					t.Run("HairPin", func(t *testing.T) {
						tryHairPin := func() error {
							_, err := Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "exec", "deployment/netcat", "--", "/bin/sh", "-c", "nc -w 5 -i 5 -z netcat 8080"))
							return err
						}

						if tc.hairpin {
							if err := retry.Expo(tryHairPin, 1*time.Second, Seconds(60)); err != nil {
								t.Errorf("failed to connect via pod host: %v", err)
							}
						} else {
							if tryHairPin() == nil {
								t.Fatalf("hairpin connection unexpectedly succeeded - misconfigured test?")
							}
						}
					})
				}

				t.Logf("%q test finished in %s, failed=%v", tc.name, time.Since(start), t.Failed())
			})
		}
	})
}
<|endoftext|>


<commit_before>package main

import (
	. "github.com/conclave/pcduino/core"
)

func init() {
	Init()
	setup()
}

func main() {
	for {
		loop()
	}
}

func setup() {
}

func loop() {
	Delay(100)
}
<commit_msg>update test/linker_rtc_test<commit_after>package main

import (
	"flag"
	"fmt"
	"strconv"

	. "github.com/conclave/pcduino/core"
	. "github.com/conclave/pcduino/lib/wire"
)

func init() {
	Init()
	setup()
}

func main() {
	for {
		loop()
	}
}

const DS1307_I2C_ADDRESS = 0x68 // This is the I2C address
var wire *TwoWire

func setup() {
	flag.Parse()
	wire = NewTwoWire()
	wire.Begin()
	getDateDS1307()
	var second, minute, hour, dayOfWeek, dayOfMonth, month, year int
	if flag.NArg() > 1 {
		year, _ = strconv.Atoi(flag.Arg(0))
	}
	if flag.NArg() > 2 {
		month, _ = strconv.Atoi(flag.Arg(1))
	}
	if flag.NArg() > 3 {
		dayOfMonth, _ = strconv.Atoi(flag.Arg(2))
	}
	if flag.NArg() > 4 {
		hour, _ = strconv.Atoi(flag.Arg(3))
	}
	if flag.NArg() > 5 {
		minute, _ = strconv.Atoi(flag.Arg(4))
	}
	if flag.NArg() > 6 {
		second, _ = strconv.Atoi(flag.Arg(5))
	}
	//force setting
	setDateDS1307(byte(second), byte(minute), byte(hour), byte(dayOfWeek), byte(dayOfMonth), byte(month), byte(year))
}

func loop() {
	Delay(2000)
	getDateDS1307()
}

func decToBcd(val byte) byte {
	return ((val / 10 * 16) + (val % 10))
}

func bcdToDec(val byte) byte {
	return ((val / 16 * 10) + (val % 16))
}

func setDateDS1307(second, minute, hour, dayOfWeek, dayOfMonth, month, year byte) {
	wire.BeginTransmission(DS1307_I2C_ADDRESS)
	wire.Write([]byte{0})
	wire.Write([]byte{decToBcd(second)}) // 0 to bit 7 starts the clock
	wire.Write([]byte{decToBcd(minute)})
	wire.Write([]byte{decToBcd(hour)}) // If you want 12 hour am/pm you need to set
	// bit 6 (also need to change readDateDs1307)
	wire.Write([]byte{decToBcd(dayOfWeek)})
	wire.Write([]byte{decToBcd(dayOfMonth)})
	wire.Write([]byte{decToBcd(month)})
	wire.Write([]byte{decToBcd(year)})
	wire.EndTransmission()
}

func getDateDS1307() {
	wire.BeginTransmission(DS1307_I2C_ADDRESS)
	wire.Write([]byte{0})
	wire.EndTransmission()
	wire.RequestFrom(DS1307_I2C_ADDRESS, 7)
	// A few of these need masks because certain bits are control bits
	second := bcdToDec(byte(wire.Read() & 0x7f))
	minute := bcdToDec(byte(wire.Read()))
	hour := bcdToDec(byte(wire.Read() & 0x3f)) // Need to change this if 12 hour am/pm
	dayOfWeek := bcdToDec(byte(wire.Read()))
	dayOfMonth := bcdToDec(byte(wire.Read()))
	month := bcdToDec(byte(wire.Read()))
	year := bcdToDec(byte(wire.Read()))
	fmt.Printf("%d:%d:%d %d %d/%d/%d.\n", hour, minute, second, dayOfWeek, month, dayOfMonth, year)
}
<|endoftext|>


<commit_before>package parser

import(
	tp "tritium/proto"
	. "exec"
	"log"
	proto "goprotobuf.googlecode.com/hg/proto"
)

func ParseFile(file string) (*tp.ScriptObject) {
	cmd := Command("ts2to", file)
	data, err := cmd.CombinedOutput()
	if err != nil {
		log.Fatal("ts2to failed with message:", err.String(), "\n", string(data))
	}
	obj := &tp.ScriptObject{}
	err = proto.Unmarshal(data, obj)
	if err != nil {
		log.Fatal(err)
	}
	return obj
}

func ParseFileSet(file string) ([]*tp.ScriptObject) {
	objs := make([]*tp.ScriptObject, 0)
	files := make(map[string]int)
	objs = append(objs, ParseFile(file))
	files[file] = 1
	for _, obj := range(objs) {
		for _, importFile := range(obj.Imports()) {
			if(files[importFile] == 0) {
				println("must import ", importFile)
			}
		}
	}

	return objs
}<commit_msg>Use local ts2to <commit_after>package parser

import(
	tp "tritium/proto"
	. "exec"
	"log"
	proto "goprotobuf.googlecode.com/hg/proto"
)

func ParseFile(file string) (*tp.ScriptObject) {
	cmd := Command("./bin/ts2to", file)
	data, err := cmd.CombinedOutput()
	if err != nil {
		log.Fatal("ts2to failed with message:", err.String(), "\n", string(data))
	}
	obj := &tp.ScriptObject{}
	err = proto.Unmarshal(data, obj)
	if err != nil {
		log.Fatal(err)
	}
	return obj
}

func ParseFileSet(file string) ([]*tp.ScriptObject) {
	objs := make([]*tp.ScriptObject, 0)
	files := make(map[string]int)
	objs = append(objs, ParseFile(file))
	files[file] = 1
	for _, obj := range(objs) {
		for _, importFile := range(obj.Imports()) {
			if(files[importFile] == 0) {
				println("must import ", importFile)
			}
		}
	}

	return objs
}<|endoftext|>


<commit_before>package main

import (
	"testing"
)

func TestSplitFile(t *testing.T) {
	err := SplitFile("README.md", 3)
	if err != nil {
		t.Error(err)
	}

}
<commit_msg>removing splited files after test<commit_after>package main

import (
	"os"
	"testing"
)

func TestSplitFile(t *testing.T) {
	err := SplitFile("README.md", 3)
	if err != nil {
		t.Error(err)
	}
	os.Remove("README.md.0")
	os.Remove("README.md.1")
	os.Remove("README.md.2")
}
<|endoftext|>


<commit_before>package main

import (
	"reflect"
	"testing"
)

func stringArr(b [][]byte) []string {
	res := make([]string, len(b))
	for i, bs := range b {
		res[i] = string(bs)
	}
	return res
}

var splitSpacesData = [...]struct {
	orig  string
	split []string
}{
	{"", []string{}},
	{"    ", []string{}},
	{"abc", []string{"abc"}},
	{"abc ", []string{"abc"}},
	{"    abc", []string{"abc"}},
	{"abc 123", []string{"abc", "123"}},
	{"abc 123    ", []string{"abc", "123"}},
	{"abc    123", []string{"abc", "123"}},
	{"   abc    123", []string{"abc", "123"}},
	{"   abc    123 def", []string{"abc", "123", "def"}},
}

func TestSplitSpaces(t *testing.T) {
	for _, pair := range splitSpacesData {
		origB := []byte(pair.orig)
		ss := stringArr(splitSpaces(origB))
		if !reflect.DeepEqual(ss, pair.split) {
			t.Fatalf("expected equal:\n    orig: %#v\n    ref:  %#v\n",
				pair.split, ss)
		}
	}
}
<commit_msg>splitSpaces: add benchmark<commit_after>package main

import (
	"reflect"
	"strings"
	"testing"
)

const benchString = `7fff70e93000-7fff70eb5000 rw-p 00000000 00:00 0                          [stack]
Size:                140 kB
Rss:                  12 kB
Pss:                  12 kB
Shared_Clean:          0 kB
Shared_Dirty:          0 kB
Private_Clean:         0 kB
Private_Dirty:        12 kB
Referenced:           12 kB
Anonymous:            12 kB
AnonHugePages:         0 kB
Swap:                  0 kB
KernelPageSize:        4 kB
MMUPageSize:           4 kB
Locked:                0 kB
VmFlags: rd wr mr mw me gd ac
7fff70fff000-7fff71000000 r-xp 00000000 00:00 0                          [vdso]
Size:                  4 kB
Rss:                   4 kB
Pss:                   0 kB
Shared_Clean:          4 kB
Shared_Dirty:          0 kB
Private_Clean:         0 kB
Private_Dirty:         0 kB
Referenced:            4 kB
Anonymous:             0 kB
AnonHugePages:         0 kB
Swap:                  0 kB
KernelPageSize:        4 kB
MMUPageSize:           4 kB
Locked:                0 kB
VmFlags: rd ex mr mw me de
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
Size:                  4 kB
Rss:                   0 kB
Pss:                   0 kB
Shared_Clean:          0 kB
Shared_Dirty:          0 kB
Private_Clean:         0 kB
Private_Dirty:         0 kB
Referenced:            0 kB
Anonymous:             0 kB
AnonHugePages:         0 kB
Swap:                  0 kB
KernelPageSize:        4 kB
MMUPageSize:           4 kB
Locked:                0 kB
VmFlags: rd ex
`

var (
	benchStrLines = strings.Split(benchString, "\n")
	benchLines    = sliceByteArr(benchStrLines)
	usedResult    [][]byte
)

func sliceByteArr(b []string) [][]byte {
	res := make([][]byte, len(b))
	for i, bs := range b {
		res[i] = []byte(bs)
	}
	return res
}

func stringArr(b [][]byte) []string {
	res := make([]string, len(b))
	for i, bs := range b {
		res[i] = string(bs)
	}
	return res
}

var splitSpacesData = [...]struct {
	orig  string
	split []string
}{
	{"", []string{}},
	{" ", []string{}},
	{"    ", []string{}},
	{"abc", []string{"abc"}},
	{"abc ", []string{"abc"}},
	{"    abc ", []string{"abc"}},
	{"abc 123", []string{"abc", "123"}},
	{"abc 123    ", []string{"abc", "123"}},
	{"abc    123", []string{"abc", "123"}},
	{"   abc    123", []string{"abc", "123"}},
	{"   abc    123 def", []string{"abc", "123", "def"}},
}

func TestSplitSpaces(t *testing.T) {
	for _, pair := range splitSpacesData {
		origB := []byte(pair.orig)
		ss := stringArr(splitSpaces(origB))
		if !reflect.DeepEqual(ss, pair.split) {
			t.Fatalf("expected equal:\n    orig: %#v\n    ref:  %#v\n",
				pair.split, ss)
		}
	}
}

func BenchmarkSplitSpaces(b *testing.B) {
	for i := 0; i < b.N; i++ {
		for _, l := range benchLines {
			usedResult = splitSpaces(l)
		}
	}
}
<|endoftext|>


<commit_before>package gossamer

import (
	"github.com/stretchr/testify/assert"
	"testing"
	"time"
)

func TestUtilFunctions(t *testing.T) {
	assert.Equal(t, "Things(12345)", ResolveEntityLink("12345", ENTITY_THINGS))
	assert.Equal(t, "http://localhost:8000/v1.0/Things(12345)", ResolveSelfLinkUrl("12345", "Things"))
}

func TestValidateMandatoryPropertiesForThing(t *testing.T) {
	var err error

	thingEntity := NewThingEntity()
	err = ValidateMandatoryProperties(thingEntity)
	assert.NotNil(t, err)
	assert.Equal(t, "Missing mandatory property for Thing entity: 'description'", err.Error())

	thingEntity.Description = "XXXXXX"
	err = ValidateMandatoryProperties(thingEntity)
	assert.Nil(t, err)
}

func TestValidateMandatoryPropertiesForLocation(t *testing.T) {
	var err error

	locationEntity := NewLocationEntity()
	err = ValidateMandatoryProperties(locationEntity)
	assert.NotNil(t, err)

	locationEntity.Description = "XXXXXXX"
	err = ValidateMandatoryProperties(locationEntity)
	assert.NotNil(t, err)

	locationEntity.EncodingType = "XXXXXXX"
	err = ValidateMandatoryProperties(locationEntity)
	assert.NotNil(t, err)

	locationEntity.Location = "XXXXXXX"
	err = ValidateMandatoryProperties(locationEntity)
	assert.Nil(t, err)
}

func TestValidateMandatoryPropertiesForHistoricalLocation(t *testing.T) {
	var err error

	historicalLocation := NewHistoricalLocationEntity()
	err = ValidateMandatoryProperties(historicalLocation)
	assert.NotNil(t, err)

	historicalLocation.Time = time.Now()
	err = ValidateMandatoryProperties(historicalLocation)
	assert.Nil(t, err)
}

func TestValidateMandatoryPropertiesForDatastream(t *testing.T) {
	var err error

	datastreamEntity := NewDatastreamEntity()
	err = ValidateMandatoryProperties(datastreamEntity)
	assert.NotNil(t, err)

	datastreamEntity.Description = "XXXXXXX"
	err = ValidateMandatoryProperties(datastreamEntity)
	assert.NotNil(t, err)

	datastreamEntity.UnitOfMeasurement = "XXXXXXX"
	err = ValidateMandatoryProperties(datastreamEntity)
	assert.NotNil(t, err)

	datastreamEntity.ObservationType = "XXXXXXX"
	err = ValidateMandatoryProperties(datastreamEntity)
	assert.Nil(t, err)
}

func TestValidateMandatoryPropertiesForSensor(t *testing.T) {
	var err error

	sensorEntity := NewSensorEntity()
	err = ValidateMandatoryProperties(sensorEntity)
	assert.NotNil(t, err)

	sensorEntity.Description = "XXXXXXX"
	err = ValidateMandatoryProperties(sensorEntity)
	assert.NotNil(t, err)

	sensorEntity.EncodingType = "XXXXXXX"
	err = ValidateMandatoryProperties(sensorEntity)
	assert.NotNil(t, err)

	sensorEntity.Metadata = "XXXXXXX"
	err = ValidateMandatoryProperties(sensorEntity)
	assert.Nil(t, err)
}

func TestValidateMandatoryPropertiesForObservedProperty(t *testing.T) {
	var err error

	observedPropertyEntity := NewObservedPropertyEntity()
	err = ValidateMandatoryProperties(observedPropertyEntity)
	assert.NotNil(t, err)

	observedPropertyEntity.Name = "XXXXXXX"
	err = ValidateMandatoryProperties(observedPropertyEntity)
	assert.NotNil(t, err)

	observedPropertyEntity.Definition = "XXXXXXX"
	err = ValidateMandatoryProperties(observedPropertyEntity)
	assert.NotNil(t, err)

	observedPropertyEntity.Description = "XXXXXXX"
	err = ValidateMandatoryProperties(observedPropertyEntity)
	assert.Nil(t, err)
}

func TestValidateMandatoryPropertiesForObservation(t *testing.T) {
	var err error

	observationEntity := NewObservationEntity()
	err = ValidateMandatoryProperties(observationEntity)
	assert.NotNil(t, err)

	observationEntity.PhenomenonTime = time.Now()
	err = ValidateMandatoryProperties(observationEntity)
	assert.NotNil(t, err)

	observationEntity.ResultTime = time.Now()
	err = ValidateMandatoryProperties(observationEntity)
	assert.NotNil(t, err)

	observationEntity.Result = "XXXXXXX"
	err = ValidateMandatoryProperties(observationEntity)
	assert.Nil(t, err)
}

func TestValidateMandatoryPropertiesForFeatureOfInterest(t *testing.T) {
	var err error

	featureOfInterestEntity := NewFeatureOfInterestEntity()
	err = ValidateMandatoryProperties(featureOfInterestEntity)
	assert.NotNil(t, err)

	featureOfInterestEntity.Description = "XXXXXXX"
	err = ValidateMandatoryProperties(featureOfInterestEntity)
	assert.NotNil(t, err)

	featureOfInterestEntity.EncodingType = "XXXXXXX"
	err = ValidateMandatoryProperties(featureOfInterestEntity)
	assert.NotNil(t, err)

	featureOfInterestEntity.Feature = "XXXXXXX"
	err = ValidateMandatoryProperties(featureOfInterestEntity)
	assert.Nil(t, err)
}

func TestValidateIntegrityConstraints(t *testing.T) {

}
<commit_msg>Test updates for utils<commit_after>package gossamer

import (
	"github.com/stretchr/testify/assert"
	"testing"
	"time"
)

func TestUtilFunctions(t *testing.T) {
	assert.Equal(t, "Things(12345)", ResolveEntityLink("12345", ENTITY_THINGS))
	assert.Equal(t, "http://localhost:8000/v1.0/Things(12345)", ResolveSelfLinkUrl("12345", "Things"))
}

func TestValidateMandatoryPropertiesForThing(t *testing.T) {
	var err error

	thingEntity := NewThingEntity()
	err = ValidateMandatoryProperties(thingEntity)
	assert.NotNil(t, err)
	assert.Equal(t, "Missing mandatory property for Thing entity: 'description'", err.Error())

	thingEntity.Description = "XXXXXX"
	err = ValidateMandatoryProperties(thingEntity)
	assert.Nil(t, err)
}

func TestValidateMandatoryPropertiesForLocation(t *testing.T) {
	var err error

	locationEntity := NewLocationEntity()
	err = ValidateMandatoryProperties(locationEntity)
	assert.NotNil(t, err)
	assert.Equal(t, "Missing mandatory property for Location entity: 'description'", err.Error())

	locationEntity.Description = "XXXXXXX"
	err = ValidateMandatoryProperties(locationEntity)
	assert.NotNil(t, err)
	assert.Equal(t, "Missing mandatory property for Location entity: 'encodingType'", err.Error())

	locationEntity.EncodingType = "XXXXXXX"
	err = ValidateMandatoryProperties(locationEntity)
	assert.NotNil(t, err)
	assert.Equal(t, "Missing mandatory property for Location entity: 'location'", err.Error())

	locationEntity.Location = "XXXXXXX"
	err = ValidateMandatoryProperties(locationEntity)
	assert.Nil(t, err)
}

func TestValidateMandatoryPropertiesForHistoricalLocation(t *testing.T) {
	var err error

	historicalLocation := NewHistoricalLocationEntity()
	err = ValidateMandatoryProperties(historicalLocation)
	assert.NotNil(t, err)
	assert.Equal(t, "Missing mandatory property for HistoricalLocation entity: 'time'", err.Error())

	historicalLocation.Time = time.Now()
	err = ValidateMandatoryProperties(historicalLocation)
	assert.Nil(t, err)
}

func TestValidateMandatoryPropertiesForDatastream(t *testing.T) {
	var err error

	datastreamEntity := NewDatastreamEntity()
	err = ValidateMandatoryProperties(datastreamEntity)
	assert.NotNil(t, err)
	assert.Equal(t, "Missing mandatory property for Datastream entity: 'description'", err.Error())

	datastreamEntity.Description = "XXXXXXX"
	err = ValidateMandatoryProperties(datastreamEntity)
	assert.NotNil(t, err)
	assert.Equal(t, "Missing mandatory property for Datastream entity: 'unitOfMeasurement'", err.Error())

	datastreamEntity.UnitOfMeasurement = "XXXXXXX"
	err = ValidateMandatoryProperties(datastreamEntity)
	assert.NotNil(t, err)
	assert.Equal(t, "Missing mandatory property for Datastream entity: 'observationType'", err.Error())

	datastreamEntity.ObservationType = "XXXXXXX"
	err = ValidateMandatoryProperties(datastreamEntity)
	assert.Nil(t, err)
}

func TestValidateMandatoryPropertiesForSensor(t *testing.T) {
	var err error

	sensorEntity := NewSensorEntity()
	err = ValidateMandatoryProperties(sensorEntity)
	assert.NotNil(t, err)
	assert.Equal(t, "Missing mandatory property for Sensor entity: 'description'", err.Error())

	sensorEntity.Description = "XXXXXXX"
	err = ValidateMandatoryProperties(sensorEntity)
	assert.NotNil(t, err)
	assert.Equal(t, "Missing mandatory property for Sensor entity: 'encodingType'", err.Error())

	sensorEntity.EncodingType = "XXXXXXX"
	err = ValidateMandatoryProperties(sensorEntity)
	assert.NotNil(t, err)
	assert.Equal(t, "Missing mandatory property for Sensor entity: 'metadata'", err.Error())

	sensorEntity.Metadata = "XXXXXXX"
	err = ValidateMandatoryProperties(sensorEntity)
	assert.Nil(t, err)
}

func TestValidateMandatoryPropertiesForObservedProperty(t *testing.T) {
	var err error

	observedPropertyEntity := NewObservedPropertyEntity()
	err = ValidateMandatoryProperties(observedPropertyEntity)
	assert.NotNil(t, err)
	assert.Equal(t, "Missing mandatory property for ObservedProperty entity: 'name'", err.Error())

	observedPropertyEntity.Name = "XXXXXXX"
	err = ValidateMandatoryProperties(observedPropertyEntity)
	assert.NotNil(t, err)
	assert.Equal(t, "Missing mandatory property for ObservedProperty entity: 'definition'", err.Error())

	observedPropertyEntity.Definition = "XXXXXXX"
	err = ValidateMandatoryProperties(observedPropertyEntity)
	assert.NotNil(t, err)
	assert.Equal(t, "Missing mandatory property for ObservedProperty entity: 'description'", err.Error())

	observedPropertyEntity.Description = "XXXXXXX"
	err = ValidateMandatoryProperties(observedPropertyEntity)
	assert.Nil(t, err)
}

func TestValidateMandatoryPropertiesForObservation(t *testing.T) {
	var err error

	observationEntity := NewObservationEntity()
	err = ValidateMandatoryProperties(observationEntity)
	assert.NotNil(t, err)
	assert.Equal(t, "Missing mandatory property for Observation entity: 'phenomenonTime'", err.Error())

	observationEntity.PhenomenonTime = time.Now()
	err = ValidateMandatoryProperties(observationEntity)
	assert.NotNil(t, err)
	assert.Equal(t, "Missing mandatory property for Observation entity: 'resultTime'", err.Error())

	observationEntity.ResultTime = time.Now()
	err = ValidateMandatoryProperties(observationEntity)
	assert.NotNil(t, err)
	assert.Equal(t, "Missing mandatory property for Observation entity: 'result'", err.Error())

	observationEntity.Result = "XXXXXXX"
	err = ValidateMandatoryProperties(observationEntity)
	assert.Nil(t, err)
}

func TestValidateMandatoryPropertiesForFeatureOfInterest(t *testing.T) {
	var err error

	featureOfInterestEntity := NewFeatureOfInterestEntity()
	err = ValidateMandatoryProperties(featureOfInterestEntity)
	assert.NotNil(t, err)
	assert.Equal(t, "Missing mandatory property for FeaturesOfInterest entity: 'description'", err.Error())

	featureOfInterestEntity.Description = "XXXXXXX"
	err = ValidateMandatoryProperties(featureOfInterestEntity)
	assert.NotNil(t, err)
	assert.Equal(t, "Missing mandatory property for FeaturesOfInterest entity: 'encodingType'", err.Error())

	featureOfInterestEntity.EncodingType = "XXXXXXX"
	err = ValidateMandatoryProperties(featureOfInterestEntity)
	assert.NotNil(t, err)
	assert.Equal(t, "Missing mandatory property for FeaturesOfInterest entity: 'feature'", err.Error())

	featureOfInterestEntity.Feature = "XXXXXXX"
	err = ValidateMandatoryProperties(featureOfInterestEntity)
	assert.Nil(t, err)
}

func TestValidateIntegrityConstraints(t *testing.T) {

}
<|endoftext|>


<commit_before>package hmacauth

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"net/http"
	"sort"
	"strings"
	"time"
	"log"
)

const (
	// common parameters
	authorizationHeader = "Authorization"
	apiKeyParam         = "APIKey"
	signatureParam      = "Signature"
	timestampParam      = "Timestamp"

	// timestamp validation
	maxNegativeTimeOffset time.Duration = -10 * time.Second

	// parsing bits
	empty   = ""
	comma   = ","
	space   = " "
	eqSign  = "="
	newline = "\n"
)

type (
	middleware func(http.ResponseWriter, *http.Request)
	KeyLocator func(string) string
)

type Options struct {
	SignedHeaders      []string
	SecretKey          KeyLocator
	SignatureExpiresIn time.Duration
}

type authBits struct {
	APIKey          string
	Signature       string
	TimestampString string
	Timestamp       time.Time
}

func (ab *authBits) IsValid() bool {
	return ab.APIKey != empty &&
		ab.Signature != empty &&
		!ab.Timestamp.IsZero()
}

func (ab *authBits) SetTimestamp(isoTime string) (err error) {
	ab.Timestamp, err = time.Parse(time.RFC3339, isoTime)
	if err == nil {
		ab.TimestampString = isoTime
	}
	return
}

func HMACAuth(options Options) middleware {
	// Validate options
	if options.SecretKey == nil {
		panic(secretKeyRequired)
	}

	return func(res http.ResponseWriter, req *http.Request) {
		var (
			err error
			ab  *authBits
		)

		if ab, err = parseAuthHeader(req.Header.Get(authorizationHeader)); err == nil {
			if err = validateTimestamp(ab.Timestamp, &options); err == nil {
				var sts string
				if sts, err = stringToSign(req, &options, ab.TimestampString); err == nil {
					if sk := options.SecretKey(ab.APIKey); sk != empty {
						if ab.Signature != signString(sts, sk) {
							err = HMACAuthError{invalidSignature}
						}
					} else {
						err = HMACAuthError{invalidAPIKey}
					}
				}
			}
		}

		if err != nil {
			log.Println(err.Error())
			http.Error(res, err.Error(), 401)
		}
	}
}

func signString(str string, secret string) string {
	hash := hmac.New(sha256.New, []byte(secret))
	hash.Write([]byte(str))
	return base64.StdEncoding.EncodeToString(hash.Sum(nil))
}

func stringToSign(req *http.Request, options *Options, timestamp string) (string, error) {
	var buffer bytes.Buffer

	// Standard
	buffer.WriteString(req.Method)
	buffer.WriteString(newline)
	buffer.WriteString(req.Host)
	buffer.WriteString(newline)
	buffer.WriteString(req.URL.RequestURI())
	buffer.WriteString(newline)
	buffer.WriteString(timestamp)
	buffer.WriteString(newline)

	// Headers
	sort.Strings(options.SignedHeaders)
	for _, header := range options.SignedHeaders {
		val := req.Header.Get(header)
		if val == empty {
			return empty, HeaderMissingError{header}
		}
		buffer.WriteString(val)
		buffer.WriteString(newline)
	}

	log.Println(buffer.String())

	return buffer.String(), nil
}

func parseAuthHeader(header string) (*authBits, error) {
	if header == empty {
		return nil, HeaderMissingError{authorizationHeader}
	}

	ab := new(authBits)
	parts := strings.Split(header, comma)
	for _, part := range parts {
		kv := strings.SplitN(strings.Trim(part, space), eqSign, 2)
		if kv[0] == apiKeyParam {
			if ab.APIKey != empty {
				return nil, RepeatedParameterError{kv[0]}
			}
			ab.APIKey = kv[1]
		} else if kv[0] == signatureParam {
			if ab.Signature != empty {
				return nil, RepeatedParameterError{kv[0]}
			}
			ab.Signature = kv[1]
		} else if kv[0] == timestampParam {
			if !ab.Timestamp.IsZero() {
				return nil, RepeatedParameterError{kv[0]}
			}
			if ab.SetTimestamp(kv[1]) != nil {
				return nil, HMACAuthError{invalidTimestamp}
			}
		} else {
			return nil, HMACAuthError{invalidParameter}
		}
	}

	if !ab.IsValid() {
		return nil, HMACAuthError{missingParameter}
	}

	return ab, nil
}

func validateTimestamp(ts time.Time, options *Options) error {
	reqAge := time.Since(ts)

	// Allow for about `maxNegativeTimeOffset` of difference, some servers are
	// ahead and some are behind
	if reqAge < maxNegativeTimeOffset {
		return HMACAuthError{tsOutOfRange}
	}

	if options.SignatureExpiresIn != 0 {
		if reqAge > options.SignatureExpiresIn {
			return HMACAuthError{signatureExpired}
		}
	}

	return nil
}
<commit_msg>removing extra logging<commit_after>package hmacauth

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"net/http"
	"sort"
	"strings"
	"time"
	"log"
)

const (
	// common parameters
	authorizationHeader = "Authorization"
	apiKeyParam         = "APIKey"
	signatureParam      = "Signature"
	timestampParam      = "Timestamp"

	// timestamp validation
	maxNegativeTimeOffset time.Duration = -10 * time.Second

	// parsing bits
	empty   = ""
	comma   = ","
	space   = " "
	eqSign  = "="
	newline = "\n"
)

type (
	middleware func(http.ResponseWriter, *http.Request)
	KeyLocator func(string) string
)

type Options struct {
	SignedHeaders      []string
	SecretKey          KeyLocator
	SignatureExpiresIn time.Duration
}

type authBits struct {
	APIKey          string
	Signature       string
	TimestampString string
	Timestamp       time.Time
}

func (ab *authBits) IsValid() bool {
	return ab.APIKey != empty &&
		ab.Signature != empty &&
		!ab.Timestamp.IsZero()
}

func (ab *authBits) SetTimestamp(isoTime string) (err error) {
	ab.Timestamp, err = time.Parse(time.RFC3339, isoTime)
	if err == nil {
		ab.TimestampString = isoTime
	}
	return
}

func HMACAuth(options Options) middleware {
	// Validate options
	if options.SecretKey == nil {
		panic(secretKeyRequired)
	}

	return func(res http.ResponseWriter, req *http.Request) {
		var (
			err error
			ab  *authBits
		)

		if ab, err = parseAuthHeader(req.Header.Get(authorizationHeader)); err == nil {
			if err = validateTimestamp(ab.Timestamp, &options); err == nil {
				var sts string
				if sts, err = stringToSign(req, &options, ab.TimestampString); err == nil {
					if sk := options.SecretKey(ab.APIKey); sk != empty {
						if ab.Signature != signString(sts, sk) {
							err = HMACAuthError{invalidSignature}
						}
					} else {
						err = HMACAuthError{invalidAPIKey}
					}
				}
			}
		}

		if err != nil {
			log.Println(err.Error())
			http.Error(res, err.Error(), 401)
		}
	}
}

func signString(str string, secret string) string {
	hash := hmac.New(sha256.New, []byte(secret))
	hash.Write([]byte(str))
	return base64.StdEncoding.EncodeToString(hash.Sum(nil))
}

func stringToSign(req *http.Request, options *Options, timestamp string) (string, error) {
	var buffer bytes.Buffer

	// Standard
	buffer.WriteString(req.Method)
	buffer.WriteString(newline)
	buffer.WriteString(req.Host)
	buffer.WriteString(newline)
	buffer.WriteString(req.URL.RequestURI())
	buffer.WriteString(newline)
	buffer.WriteString(timestamp)
	buffer.WriteString(newline)

	// Headers
	sort.Strings(options.SignedHeaders)
	for _, header := range options.SignedHeaders {
		val := req.Header.Get(header)
		if val == empty {
			return empty, HeaderMissingError{header}
		}
		buffer.WriteString(val)
		buffer.WriteString(newline)
	}

	return buffer.String(), nil
}

func parseAuthHeader(header string) (*authBits, error) {
	if header == empty {
		return nil, HeaderMissingError{authorizationHeader}
	}

	ab := new(authBits)
	parts := strings.Split(header, comma)
	for _, part := range parts {
		kv := strings.SplitN(strings.Trim(part, space), eqSign, 2)
		if kv[0] == apiKeyParam {
			if ab.APIKey != empty {
				return nil, RepeatedParameterError{kv[0]}
			}
			ab.APIKey = kv[1]
		} else if kv[0] == signatureParam {
			if ab.Signature != empty {
				return nil, RepeatedParameterError{kv[0]}
			}
			ab.Signature = kv[1]
		} else if kv[0] == timestampParam {
			if !ab.Timestamp.IsZero() {
				return nil, RepeatedParameterError{kv[0]}
			}
			if ab.SetTimestamp(kv[1]) != nil {
				return nil, HMACAuthError{invalidTimestamp}
			}
		} else {
			return nil, HMACAuthError{invalidParameter}
		}
	}

	if !ab.IsValid() {
		return nil, HMACAuthError{missingParameter}
	}

	return ab, nil
}

func validateTimestamp(ts time.Time, options *Options) error {
	reqAge := time.Since(ts)

	// Allow for about `maxNegativeTimeOffset` of difference, some servers are
	// ahead and some are behind
	if reqAge < maxNegativeTimeOffset {
		return HMACAuthError{tsOutOfRange}
	}

	if options.SignatureExpiresIn != 0 {
		if reqAge > options.SignatureExpiresIn {
			return HMACAuthError{signatureExpired}
		}
	}

	return nil
}
<|endoftext|>


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

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

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

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

package store

import (
	"context"

	autoscaling "k8s.io/api/autoscaling/v2beta2"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/watch"
	clientset "k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/cache"

	"k8s.io/kube-state-metrics/v2/pkg/metric"
	generator "k8s.io/kube-state-metrics/v2/pkg/metric_generator"
)

type metricTargetType int

const (
	value metricTargetType = iota
	utilization
	average
)

func (m metricTargetType) String() string {
	return [...]string{"value", "utilization", "average"}[m]
}

var (
	descHorizontalPodAutoscalerAnnotationsName     = "kube_horizontalpodautoscaler_annotations"
	descHorizontalPodAutoscalerAnnotationsHelp     = "Kubernetes annotations converted to Prometheus labels."
	descHorizontalPodAutoscalerLabelsName          = "kube_horizontalpodautoscaler_labels"
	descHorizontalPodAutoscalerLabelsHelp          = "Kubernetes labels converted to Prometheus labels."
	descHorizontalPodAutoscalerLabelsDefaultLabels = []string{"namespace", "horizontalpodautoscaler"}

	targetMetricLabels = []string{"metric_name", "metric_target_type"}
)

func hpaMetricFamilies(allowAnnotationsList, allowLabelsList []string) []generator.FamilyGenerator {
	return []generator.FamilyGenerator{
		*generator.NewFamilyGenerator(
			"kube_horizontalpodautoscaler_info",
			"Information about this autoscaler.",
			metric.Gauge,
			"",
			wrapHPAFunc(func(a *autoscaling.HorizontalPodAutoscaler) *metric.Family {
				labelKeys := []string{"scaletargetref_kind", "scaletargetref_name"}
				labelValues := []string{a.Spec.ScaleTargetRef.Kind, a.Spec.ScaleTargetRef.Name}
				if a.Spec.ScaleTargetRef.APIVersion != "" {
					labelKeys = append([]string{"scaletargetref_api_version"}, labelKeys...)
					labelValues = append([]string{a.Spec.ScaleTargetRef.APIVersion}, labelValues...)
				}
				return &metric.Family{
					Metrics: []*metric.Metric{
						{
							LabelKeys:   labelKeys,
							LabelValues: labelValues,
							Value:       1,
						},
					},
				}
			}),
		),
		*generator.NewFamilyGenerator(
			"kube_horizontalpodautoscaler_metadata_generation",
			"The generation observed by the HorizontalPodAutoscaler controller.",
			metric.Gauge,
			"",
			wrapHPAFunc(func(a *autoscaling.HorizontalPodAutoscaler) *metric.Family {
				return &metric.Family{
					Metrics: []*metric.Metric{
						{
							Value: float64(a.ObjectMeta.Generation),
						},
					},
				}
			}),
		),
		*generator.NewFamilyGenerator(
			"kube_horizontalpodautoscaler_spec_max_replicas",
			"Upper limit for the number of pods that can be set by the autoscaler; cannot be smaller than MinReplicas.",
			metric.Gauge,
			"",
			wrapHPAFunc(func(a *autoscaling.HorizontalPodAutoscaler) *metric.Family {
				return &metric.Family{
					Metrics: []*metric.Metric{
						{
							Value: float64(a.Spec.MaxReplicas),
						},
					},
				}
			}),
		),
		*generator.NewFamilyGenerator(
			"kube_horizontalpodautoscaler_spec_min_replicas",
			"Lower limit for the number of pods that can be set by the autoscaler, default 1.",
			metric.Gauge,
			"",
			wrapHPAFunc(func(a *autoscaling.HorizontalPodAutoscaler) *metric.Family {
				return &metric.Family{
					Metrics: []*metric.Metric{
						{
							Value: float64(*a.Spec.MinReplicas),
						},
					},
				}
			}),
		),
		*generator.NewFamilyGenerator(
			"kube_horizontalpodautoscaler_spec_target_metric",
			"The metric specifications used by this autoscaler when calculating the desired replica count.",
			metric.Gauge,
			"",
			wrapHPAFunc(func(a *autoscaling.HorizontalPodAutoscaler) *metric.Family {
				ms := make([]*metric.Metric, 0, len(a.Spec.Metrics))
				for _, m := range a.Spec.Metrics {
					var metricName string

					// The variable maps the type of metric to the corresponding value
					metricMap := make(map[metricTargetType]float64)

					switch m.Type {
					case autoscaling.ObjectMetricSourceType:
						metricName = m.Object.Metric.Name

						if m.Object.Target.Value != nil {
							metricMap[value] = float64(m.Object.Target.Value.MilliValue()) / 1000
						}
						if m.Object.Target.AverageValue != nil {
							metricMap[average] = float64(m.Object.Target.AverageValue.MilliValue()) / 1000
						}
					case autoscaling.PodsMetricSourceType:
						metricName = m.Pods.Metric.Name

						metricMap[average] = float64(m.Pods.Target.AverageValue.MilliValue()) / 1000
					case autoscaling.ResourceMetricSourceType:
						metricName = string(m.Resource.Name)

						if m.Resource.Target.AverageUtilization != nil {
							metricMap[utilization] = float64(*m.Resource.Target.AverageUtilization)
						}

						if m.Resource.Target.AverageValue != nil {
							metricMap[average] = float64(m.Resource.Target.AverageValue.MilliValue()) / 1000
						}
					case autoscaling.ExternalMetricSourceType:
						metricName = m.External.Metric.Name

						if m.External.Target.Value != nil {
							metricMap[value] = float64(m.External.Target.Value.MilliValue()) / 1000
						}
						if m.External.Target.AverageValue != nil {
							metricMap[average] = float64(m.External.Target.AverageValue.MilliValue()) / 1000
						}
					default:
						// Skip unsupported metric type
						continue
					}

					for metricTypeIndex, metricValue := range metricMap {
						ms = append(ms, &metric.Metric{
							LabelKeys:   targetMetricLabels,
							LabelValues: []string{metricName, metricTypeIndex.String()},
							Value:       metricValue,
						})
					}
				}
				return &metric.Family{Metrics: ms}
			}),
		),
		*generator.NewFamilyGenerator(
			"kube_horizontalpodautoscaler_status_current_metric",
			"The metric current status used by this autoscaler when calculating the desired replica count.",
			metric.Gauge,
			"",
			wrapHPAFunc(func(a *autoscaling.HorizontalPodAutoscaler) *metric.Family {
				ms := make([]*metric.Metric, 0, len(a.Status.CurrentMetrics))
				for _, m := range a.Status.CurrentMetrics {
					var metricName string

					// The variable maps the type of metric to the corresponding value
					metricMap := make(map[metricTargetType]float64)

					switch m.Type {
					case autoscaling.ObjectMetricSourceType:
						metricName = m.Object.Metric.Name

						if m.Object.Current.Value != nil {
							metricMap[value] = float64(m.Object.Current.Value.MilliValue()) / 1000
						}
						if m.Object.Current.AverageValue != nil {
							metricMap[average] = float64(m.Object.Current.AverageValue.MilliValue()) / 1000
						}
					case autoscaling.PodsMetricSourceType:
						metricName = m.Pods.Metric.Name

						metricMap[average] = float64(m.Pods.Current.AverageValue.MilliValue()) / 1000
					case autoscaling.ResourceMetricSourceType:
						metricName = string(m.Resource.Name)

						if m.Resource.Current.AverageUtilization != nil {
							metricMap[utilization] = float64(*m.Resource.Current.AverageUtilization)
						}

						if m.Resource.Current.AverageValue != nil {
							metricMap[average] = float64(m.Resource.Current.AverageValue.MilliValue()) / 1000
						}
					case autoscaling.ExternalMetricSourceType:
						metricName = m.External.Metric.Name

						if m.External.Current.Value != nil {
							metricMap[value] = float64(m.External.Current.Value.MilliValue()) / 1000
						}
						if m.External.Current.AverageValue != nil {
							metricMap[average] = float64(m.External.Current.AverageValue.MilliValue()) / 1000
						}
					default:
						// Skip unsupported metric type
						continue
					}

					for metricTypeIndex, metricValue := range metricMap {
						ms = append(ms, &metric.Metric{
							LabelKeys:   targetMetricLabels,
							LabelValues: []string{metricName, metricTypeIndex.String()},
							Value:       metricValue,
						})
					}
				}
				return &metric.Family{Metrics: ms}
			}),
		),
		*generator.NewFamilyGenerator(
			"kube_horizontalpodautoscaler_status_current_replicas",
			"Current number of replicas of pods managed by this autoscaler.",
			metric.Gauge,
			"",
			wrapHPAFunc(func(a *autoscaling.HorizontalPodAutoscaler) *metric.Family {
				return &metric.Family{
					Metrics: []*metric.Metric{
						{
							Value: float64(a.Status.CurrentReplicas),
						},
					},
				}
			}),
		),
		*generator.NewFamilyGenerator(
			"kube_horizontalpodautoscaler_status_desired_replicas",
			"Desired number of replicas of pods managed by this autoscaler.",
			metric.Gauge,
			"",
			wrapHPAFunc(func(a *autoscaling.HorizontalPodAutoscaler) *metric.Family {
				return &metric.Family{
					Metrics: []*metric.Metric{
						{
							Value: float64(a.Status.DesiredReplicas),
						},
					},
				}
			}),
		),
		*generator.NewFamilyGenerator(
			descHorizontalPodAutoscalerAnnotationsName,
			descHorizontalPodAutoscalerAnnotationsHelp,
			metric.Gauge,
			"",
			wrapHPAFunc(func(a *autoscaling.HorizontalPodAutoscaler) *metric.Family {
				annotationKeys, annotationValues := createPrometheusLabelKeysValues("annotation", a.Annotations, allowAnnotationsList)
				return &metric.Family{
					Metrics: []*metric.Metric{
						{
							LabelKeys:   annotationKeys,
							LabelValues: annotationValues,
							Value:       1,
						},
					},
				}
			}),
		),
		*generator.NewFamilyGenerator(
			descHorizontalPodAutoscalerLabelsName,
			descHorizontalPodAutoscalerLabelsHelp,
			metric.Gauge,
			"",
			wrapHPAFunc(func(a *autoscaling.HorizontalPodAutoscaler) *metric.Family {
				labelKeys, labelValues := createPrometheusLabelKeysValues("label", a.Labels, allowLabelsList)
				return &metric.Family{
					Metrics: []*metric.Metric{
						{
							LabelKeys:   labelKeys,
							LabelValues: labelValues,
							Value:       1,
						},
					},
				}
			}),
		),
		*generator.NewFamilyGenerator(
			"kube_horizontalpodautoscaler_status_condition",
			"The condition of this autoscaler.",
			metric.Gauge,
			"",
			wrapHPAFunc(func(a *autoscaling.HorizontalPodAutoscaler) *metric.Family {
				ms := make([]*metric.Metric, 0, len(a.Status.Conditions)*len(conditionStatuses))

				for _, c := range a.Status.Conditions {
					metrics := addConditionMetrics(c.Status)

					for _, m := range metrics {
						metric := m
						metric.LabelKeys = []string{"condition", "status"}
						metric.LabelValues = append([]string{string(c.Type)}, metric.LabelValues...)
						ms = append(ms, metric)
					}
				}

				return &metric.Family{
					Metrics: ms,
				}
			}),
		),
	}
}

func wrapHPAFunc(f func(*autoscaling.HorizontalPodAutoscaler) *metric.Family) func(interface{}) *metric.Family {
	return func(obj interface{}) *metric.Family {
		hpa := obj.(*autoscaling.HorizontalPodAutoscaler)

		metricFamily := f(hpa)

		for _, m := range metricFamily.Metrics {
			m.LabelKeys, m.LabelValues = mergeKeyValues(descHorizontalPodAutoscalerLabelsDefaultLabels, []string{hpa.Namespace, hpa.Name}, m.LabelKeys, m.LabelValues)
		}

		return metricFamily
	}
}

func createHPAListWatch(kubeClient clientset.Interface, ns string, fieldSelector string) cache.ListerWatcher {
	return &cache.ListWatch{
		ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
			opts.FieldSelector = fieldSelector
			return kubeClient.AutoscalingV2beta2().HorizontalPodAutoscalers(ns).List(context.TODO(), opts)
		},
		WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) {
			opts.FieldSelector = fieldSelector
			return kubeClient.AutoscalingV2beta2().HorizontalPodAutoscalers(ns).Watch(context.TODO(), opts)
		},
	}
}
<commit_msg>chore: apply suggestions from code review<commit_after>/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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

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

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

package store

import (
	"context"

	autoscaling "k8s.io/api/autoscaling/v2beta2"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/watch"
	clientset "k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/cache"

	"k8s.io/kube-state-metrics/v2/pkg/metric"
	generator "k8s.io/kube-state-metrics/v2/pkg/metric_generator"
)

type metricTargetType int

const (
	value metricTargetType = iota
	utilization
	average
)

func (m metricTargetType) String() string {
	return [...]string{"value", "utilization", "average"}[m]
}

var (
	descHorizontalPodAutoscalerAnnotationsName     = "kube_horizontalpodautoscaler_annotations"
	descHorizontalPodAutoscalerAnnotationsHelp     = "Kubernetes annotations converted to Prometheus labels."
	descHorizontalPodAutoscalerLabelsName          = "kube_horizontalpodautoscaler_labels"
	descHorizontalPodAutoscalerLabelsHelp          = "Kubernetes labels converted to Prometheus labels."
	descHorizontalPodAutoscalerLabelsDefaultLabels = []string{"namespace", "horizontalpodautoscaler"}

	targetMetricLabels = []string{"metric_name", "metric_target_type"}
)

func hpaMetricFamilies(allowAnnotationsList, allowLabelsList []string) []generator.FamilyGenerator {
	return []generator.FamilyGenerator{
		*generator.NewFamilyGenerator(
			"kube_horizontalpodautoscaler_info",
			"Information about this autoscaler.",
			metric.Gauge,
			"",
			wrapHPAFunc(func(a *autoscaling.HorizontalPodAutoscaler) *metric.Family {
				labelKeys := []string{"scaletargetref_kind", "scaletargetref_name"}
				labelValues := []string{a.Spec.ScaleTargetRef.Kind, a.Spec.ScaleTargetRef.Name}
				if a.Spec.ScaleTargetRef.APIVersion != "" {
					labelKeys = append([]string{"scaletargetref_api_version"}, labelKeys...)
					labelValues = append([]string{a.Spec.ScaleTargetRef.APIVersion}, labelValues...)
				}
				return &metric.Family{
					Metrics: []*metric.Metric{
						{
							LabelKeys:   labelKeys,
							LabelValues: labelValues,
							Value:       1,
						},
					},
				}
			}),
		),
		*generator.NewFamilyGenerator(
			"kube_horizontalpodautoscaler_metadata_generation",
			"The generation observed by the HorizontalPodAutoscaler controller.",
			metric.Gauge,
			"",
			wrapHPAFunc(func(a *autoscaling.HorizontalPodAutoscaler) *metric.Family {
				return &metric.Family{
					Metrics: []*metric.Metric{
						{
							Value: float64(a.ObjectMeta.Generation),
						},
					},
				}
			}),
		),
		*generator.NewFamilyGenerator(
			"kube_horizontalpodautoscaler_spec_max_replicas",
			"Upper limit for the number of pods that can be set by the autoscaler; cannot be smaller than MinReplicas.",
			metric.Gauge,
			"",
			wrapHPAFunc(func(a *autoscaling.HorizontalPodAutoscaler) *metric.Family {
				return &metric.Family{
					Metrics: []*metric.Metric{
						{
							Value: float64(a.Spec.MaxReplicas),
						},
					},
				}
			}),
		),
		*generator.NewFamilyGenerator(
			"kube_horizontalpodautoscaler_spec_min_replicas",
			"Lower limit for the number of pods that can be set by the autoscaler, default 1.",
			metric.Gauge,
			"",
			wrapHPAFunc(func(a *autoscaling.HorizontalPodAutoscaler) *metric.Family {
				return &metric.Family{
					Metrics: []*metric.Metric{
						{
							Value: float64(*a.Spec.MinReplicas),
						},
					},
				}
			}),
		),
		*generator.NewFamilyGenerator(
			"kube_horizontalpodautoscaler_spec_target_metric",
			"The metric specifications used by this autoscaler when calculating the desired replica count.",
			metric.Gauge,
			"",
			wrapHPAFunc(func(a *autoscaling.HorizontalPodAutoscaler) *metric.Family {
				ms := make([]*metric.Metric, 0, len(a.Spec.Metrics))
				for _, m := range a.Spec.Metrics {
					var metricName string

					// The variable maps the type of metric to the corresponding value
					metricMap := make(map[metricTargetType]float64)

					switch m.Type {
					case autoscaling.ObjectMetricSourceType:
						metricName = m.Object.Metric.Name

						if m.Object.Target.Value != nil {
							metricMap[value] = float64(m.Object.Target.Value.MilliValue()) / 1000
						}
						if m.Object.Target.AverageValue != nil {
							metricMap[average] = float64(m.Object.Target.AverageValue.MilliValue()) / 1000
						}
					case autoscaling.PodsMetricSourceType:
						metricName = m.Pods.Metric.Name

						metricMap[average] = float64(m.Pods.Target.AverageValue.MilliValue()) / 1000
					case autoscaling.ResourceMetricSourceType:
						metricName = string(m.Resource.Name)

						if m.Resource.Target.AverageUtilization != nil {
							metricMap[utilization] = float64(*m.Resource.Target.AverageUtilization)
						}

						if m.Resource.Target.AverageValue != nil {
							metricMap[average] = float64(m.Resource.Target.AverageValue.MilliValue()) / 1000
						}
					case autoscaling.ExternalMetricSourceType:
						metricName = m.External.Metric.Name

						if m.External.Target.Value != nil {
							metricMap[value] = float64(m.External.Target.Value.MilliValue()) / 1000
						}
						if m.External.Target.AverageValue != nil {
							metricMap[average] = float64(m.External.Target.AverageValue.MilliValue()) / 1000
						}
					default:
						// Skip unsupported metric type
						continue
					}

					for metricTypeIndex, metricValue := range metricMap {
						ms = append(ms, &metric.Metric{
							LabelKeys:   targetMetricLabels,
							LabelValues: []string{metricName, metricTypeIndex.String()},
							Value:       metricValue,
						})
					}
				}
				return &metric.Family{Metrics: ms}
			}),
		),
		*generator.NewFamilyGenerator(
			"kube_horizontalpodautoscaler_status_target_metric",
			"The current metric status used by this autoscaler when calculating the desired replica count.",
			metric.Gauge,
			"",
			wrapHPAFunc(func(a *autoscaling.HorizontalPodAutoscaler) *metric.Family {
				ms := make([]*metric.Metric, 0, len(a.Status.CurrentMetrics))
				for _, m := range a.Status.CurrentMetrics {
					var metricName string

					// The variable maps the type of metric to the corresponding value
					metricMap := make(map[metricTargetType]float64)

					switch m.Type {
					case autoscaling.ObjectMetricSourceType:
						metricName = m.Object.Metric.Name

						if m.Object.Current.Value != nil {
							metricMap[value] = float64(m.Object.Current.Value.MilliValue()) / 1000
						}
						if m.Object.Current.AverageValue != nil {
							metricMap[average] = float64(m.Object.Current.AverageValue.MilliValue()) / 1000
						}
					case autoscaling.PodsMetricSourceType:
						metricName = m.Pods.Metric.Name

						metricMap[average] = float64(m.Pods.Current.AverageValue.MilliValue()) / 1000
					case autoscaling.ResourceMetricSourceType:
						metricName = string(m.Resource.Name)

						if m.Resource.Current.AverageUtilization != nil {
							metricMap[utilization] = float64(*m.Resource.Current.AverageUtilization)
						}

						if m.Resource.Current.AverageValue != nil {
							metricMap[average] = float64(m.Resource.Current.AverageValue.MilliValue()) / 1000
						}
					case autoscaling.ExternalMetricSourceType:
						metricName = m.External.Metric.Name

						if m.External.Current.Value != nil {
							metricMap[value] = float64(m.External.Current.Value.MilliValue()) / 1000
						}
						if m.External.Current.AverageValue != nil {
							metricMap[average] = float64(m.External.Current.AverageValue.MilliValue()) / 1000
						}
					default:
						// Skip unsupported metric type
						continue
					}

					for metricTypeIndex, metricValue := range metricMap {
						ms = append(ms, &metric.Metric{
							LabelKeys:   targetMetricLabels,
							LabelValues: []string{metricName, metricTypeIndex.String()},
							Value:       metricValue,
						})
					}
				}
				return &metric.Family{Metrics: ms}
			}),
		),
		*generator.NewFamilyGenerator(
			"kube_horizontalpodautoscaler_status_current_replicas",
			"Current number of replicas of pods managed by this autoscaler.",
			metric.Gauge,
			"",
			wrapHPAFunc(func(a *autoscaling.HorizontalPodAutoscaler) *metric.Family {
				return &metric.Family{
					Metrics: []*metric.Metric{
						{
							Value: float64(a.Status.CurrentReplicas),
						},
					},
				}
			}),
		),
		*generator.NewFamilyGenerator(
			"kube_horizontalpodautoscaler_status_desired_replicas",
			"Desired number of replicas of pods managed by this autoscaler.",
			metric.Gauge,
			"",
			wrapHPAFunc(func(a *autoscaling.HorizontalPodAutoscaler) *metric.Family {
				return &metric.Family{
					Metrics: []*metric.Metric{
						{
							Value: float64(a.Status.DesiredReplicas),
						},
					},
				}
			}),
		),
		*generator.NewFamilyGenerator(
			descHorizontalPodAutoscalerAnnotationsName,
			descHorizontalPodAutoscalerAnnotationsHelp,
			metric.Gauge,
			"",
			wrapHPAFunc(func(a *autoscaling.HorizontalPodAutoscaler) *metric.Family {
				annotationKeys, annotationValues := createPrometheusLabelKeysValues("annotation", a.Annotations, allowAnnotationsList)
				return &metric.Family{
					Metrics: []*metric.Metric{
						{
							LabelKeys:   annotationKeys,
							LabelValues: annotationValues,
							Value:       1,
						},
					},
				}
			}),
		),
		*generator.NewFamilyGenerator(
			descHorizontalPodAutoscalerLabelsName,
			descHorizontalPodAutoscalerLabelsHelp,
			metric.Gauge,
			"",
			wrapHPAFunc(func(a *autoscaling.HorizontalPodAutoscaler) *metric.Family {
				labelKeys, labelValues := createPrometheusLabelKeysValues("label", a.Labels, allowLabelsList)
				return &metric.Family{
					Metrics: []*metric.Metric{
						{
							LabelKeys:   labelKeys,
							LabelValues: labelValues,
							Value:       1,
						},
					},
				}
			}),
		),
		*generator.NewFamilyGenerator(
			"kube_horizontalpodautoscaler_status_condition",
			"The condition of this autoscaler.",
			metric.Gauge,
			"",
			wrapHPAFunc(func(a *autoscaling.HorizontalPodAutoscaler) *metric.Family {
				ms := make([]*metric.Metric, 0, len(a.Status.Conditions)*len(conditionStatuses))

				for _, c := range a.Status.Conditions {
					metrics := addConditionMetrics(c.Status)

					for _, m := range metrics {
						metric := m
						metric.LabelKeys = []string{"condition", "status"}
						metric.LabelValues = append([]string{string(c.Type)}, metric.LabelValues...)
						ms = append(ms, metric)
					}
				}

				return &metric.Family{
					Metrics: ms,
				}
			}),
		),
	}
}

func wrapHPAFunc(f func(*autoscaling.HorizontalPodAutoscaler) *metric.Family) func(interface{}) *metric.Family {
	return func(obj interface{}) *metric.Family {
		hpa := obj.(*autoscaling.HorizontalPodAutoscaler)

		metricFamily := f(hpa)

		for _, m := range metricFamily.Metrics {
			m.LabelKeys, m.LabelValues = mergeKeyValues(descHorizontalPodAutoscalerLabelsDefaultLabels, []string{hpa.Namespace, hpa.Name}, m.LabelKeys, m.LabelValues)
		}

		return metricFamily
	}
}

func createHPAListWatch(kubeClient clientset.Interface, ns string, fieldSelector string) cache.ListerWatcher {
	return &cache.ListWatch{
		ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
			opts.FieldSelector = fieldSelector
			return kubeClient.AutoscalingV2beta2().HorizontalPodAutoscalers(ns).List(context.TODO(), opts)
		},
		WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) {
			opts.FieldSelector = fieldSelector
			return kubeClient.AutoscalingV2beta2().HorizontalPodAutoscalers(ns).Watch(context.TODO(), opts)
		},
	}
}
<|endoftext|>