<commit_before>package server

import (
	"math/rand"
	"strings"
	"testing"
	"time"

	"github.com/pachyderm/pachyderm/src/client"
	"github.com/pachyderm/pachyderm/src/client/pkg/require"
	"github.com/pachyderm/pachyderm/src/server/pkg/workload"
)

func TestPutGet(t *testing.T) {
	c := getPachClient(t)
	object, err := c.PutObject(strings.NewReader("foo"))
	require.NoError(t, err)
	value, err := c.ReadObject(object.Hash)
	require.NoError(t, err)
	require.Equal(t, []byte("foo"), value)
	objectInfo, err := c.InspectObject(object.Hash)
	require.NoError(t, err)
	require.Equal(t, uint64(3), objectInfo.BlockRef.Range.Upper-objectInfo.BlockRef.Range.Lower)
}

func TestTags(t *testing.T) {
	c := getPachClient(t)
	object, err := c.PutObject(strings.NewReader("foo"), "bar", "fizz")
	require.NoError(t, err)
	require.NoError(t, c.TagObject(object.Hash, "buzz"))
	value, err := c.ReadTag("bar")
	require.NoError(t, err)
	require.Equal(t, []byte("foo"), value)
	value, err = c.ReadTag("fizz")
	require.NoError(t, err)
	require.Equal(t, []byte("foo"), value)
	value, err = c.ReadTag("buzz")
	require.NoError(t, err)
	require.Equal(t, []byte("foo"), value)
}

func TestManyObjects(t *testing.T) {
	c := getPachClient(t)
	var objects []string
	for i := 0; i < 25; i++ {
		object, err := c.PutObject(strings.NewReader(string(i)), string(i))
		require.NoError(t, err)
		objects = append(objects, object.Hash)
	}
	require.NoError(t, c.Compact())
	for i, hash := range objects {
		value, err := c.ReadObject(hash)
		require.NoError(t, err)
		require.Equal(t, []byte(string(i)), value)
		value, err = c.ReadTag(string(i))
		require.NoError(t, err)
		require.Equal(t, []byte(string(i)), value)
	}
}

func TestBigObject(t *testing.T) {
	c := getPachClient(t)
	r := workload.NewReader(rand.New(rand.NewSource(time.Now().UnixNano())), 50*1024*1024)
	object, err := c.PutObject(r)
	require.NoError(t, err)
	value, err := c.ReadObject(object.Hash)
	require.NoError(t, err)
	require.Equal(t, 50*1024*1024, len(value))
	value, err = c.ReadObject(object.Hash)
	require.NoError(t, err)
	require.Equal(t, 50*1024*1024, len(value))
}

func getPachClient(t testing.TB) *client.APIClient {
	client, err := client.NewFromAddress("0.0.0.0:30650")
	require.NoError(t, err)
	return client
}
<commit_msg>Makes TestTags harder.<commit_after>package server

import (
	"math/rand"
	"strings"
	"testing"
	"time"

	"github.com/pachyderm/pachyderm/src/client"
	"github.com/pachyderm/pachyderm/src/client/pkg/require"
	"github.com/pachyderm/pachyderm/src/server/pkg/workload"
)

func TestPutGet(t *testing.T) {
	c := getPachClient(t)
	object, err := c.PutObject(strings.NewReader("foo"))
	require.NoError(t, err)
	value, err := c.ReadObject(object.Hash)
	require.NoError(t, err)
	require.Equal(t, []byte("foo"), value)
	objectInfo, err := c.InspectObject(object.Hash)
	require.NoError(t, err)
	require.Equal(t, uint64(3), objectInfo.BlockRef.Range.Upper-objectInfo.BlockRef.Range.Lower)
}

func TestTags(t *testing.T) {
	c := getPachClient(t)
	object, err := c.PutObject(strings.NewReader("foo"), "bar", "fizz")
	require.NoError(t, err)
	require.NoError(t, c.TagObject(object.Hash, "buzz"))
	_, err = c.PutObject(strings.NewReader("foo"), "quux")
	require.NoError(t, err)
	value, err := c.ReadTag("bar")
	require.NoError(t, err)
	require.Equal(t, []byte("foo"), value)
	value, err = c.ReadTag("fizz")
	require.NoError(t, err)
	require.Equal(t, []byte("foo"), value)
	value, err = c.ReadTag("buzz")
	require.NoError(t, err)
	require.Equal(t, []byte("foo"), value)
	value, err = c.ReadTag("quux")
	require.NoError(t, err)
	require.Equal(t, []byte("foo"), value)
}

func TestManyObjects(t *testing.T) {
	c := getPachClient(t)
	var objects []string
	for i := 0; i < 25; i++ {
		object, err := c.PutObject(strings.NewReader(string(i)), string(i))
		require.NoError(t, err)
		objects = append(objects, object.Hash)
	}
	require.NoError(t, c.Compact())
	for i, hash := range objects {
		value, err := c.ReadObject(hash)
		require.NoError(t, err)
		require.Equal(t, []byte(string(i)), value)
		value, err = c.ReadTag(string(i))
		require.NoError(t, err)
		require.Equal(t, []byte(string(i)), value)
	}
}

func TestBigObject(t *testing.T) {
	c := getPachClient(t)
	r := workload.NewReader(rand.New(rand.NewSource(time.Now().UnixNano())), 50*1024*1024)
	object, err := c.PutObject(r)
	require.NoError(t, err)
	value, err := c.ReadObject(object.Hash)
	require.NoError(t, err)
	require.Equal(t, 50*1024*1024, len(value))
	value, err = c.ReadObject(object.Hash)
	require.NoError(t, err)
	require.Equal(t, 50*1024*1024, len(value))
}

func getPachClient(t testing.TB) *client.APIClient {
	client, err := client.NewFromAddress("0.0.0.0:30650")
	require.NoError(t, err)
	return client
}
<|endoftext|>


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

// +build gc

// Package fieldtrack provides access to information in the current binary
// that tracks use of struct fields.
// This information is computed at build time for struct fields marked
// with the `go:"track"` tag. See http://go/fieldtrack for background.
package fieldtrack

import (
	"sort"
	"strings"
	"sync"
)

// tracked holds the raw field tracking information supplied by the linker,
// provided the linker is invoked with -k rsc.io/tmp/fieldtrack.tracked.
//
// The raw tracking information is a sequence of lines, each terminated by
// a \n and describing a single tracked field referred to by the program.
// Each line is made up of one or more tab-separated fields.
// The first field is the name of the tracked field, fully qualified,
// as in "my/pkg.T.F". Subsequent fields give a shortest path of
// reverse references from that field to main.init or main.main,
// corresponding to one way in which the program might reach that field.
var tracked string

// The sentinel type is a dummy type that we know should appear
// in the field tracking information, so that we can tell if field tracking
// was enabled during compilation.
type sentinel struct {
	F int `go:"track"`
}

// Enabled reports whether field tracking was enabled in the compiler
// when compiling the current binary.
func Enabled() bool {
	// Code to make the compiler think we refer to sentinel.F.
	// Complex enough that it won't be optimized away.
	f := Enabled
	alwaysFalse := f == nil
	if alwaysFalse {
		var x sentinel
		println(x.F)
	}

	// If there's tracking information available, then field tracking is turned on.
	// If not, then sentinel.F is missing so it must be disabled.
	return tracked != ""
}

// Tracked returns a sorted list of all tracked fields used by the current binary.
// The form of each entry is "full/import/path.TypeName.FieldName".
func Tracked() []string {
	trackedFields.once.Do(initTrackedFields)
	return trackedFields.list
}

var trackedFields struct {
	once sync.Once
	list []string
}

func initTrackedFields() {
	if !Enabled() {
		panic("fieldtrack: compiler is not tracking fields")
	}

	x := strings.Split(tracked, "\n")

	// Cut path information, which starts at the first tab on each line.
	for i, line := range x {
		j := strings.Index(line, "\t")
		if j >= 0 {
			x[i] = line[:j]
		}
	}

	// Remove reference to our internal sentinel.F
	// and remove the "" Split found after the final \n.
	w := 0
	for _, line := range x {
		if line != "rsc.io/tmp/fieldtrack.sentinel.F" && line != "" {
			x[w] = line
			w++
		}
	}
	x = x[:w]

	sort.Strings(x)
	trackedFields.list = x
}

// Ref returns the list of references explaining why the given field name is used
// by the current binary. The field name should be in the form returned by Tracked.
// The references start at a global symbol and end with the field.
// If the field is not used by the current binary, Ref returns nil.
func Ref(field string) []string {
	refFields.once.Do(initRefFields)
	return refFields.m[field]
}

var refFields struct {
	once sync.Once
	m    map[string][]string
}

func initRefFields() {
	if !Enabled() {
		panic("fieldtrack: compiler is not tracking fields")
	}

	m := make(map[string][]string)
	for _, line := range strings.Split(tracked, "\n") {
		if line == "" {
			// empty string after final \n
			continue
		}

		f := strings.Split(line, "\t")

		field := f[0]

		// The path is presented from field back to the global;
		// we want a path from the global to the field, so reverse it.
		for i, j := 0, len(f)-1; i < j; i, j = i+1, j-1 {
			f[i], f[j] = f[j], f[i]
		}

		// Cut items from list before "main.main" or "main.init"
		// to skip the runtime details that get into main
		// (or else it starts with a global variable, which is fine).
		for i, x := range f {
			if x == "main.main" || x == "main.init" {
				f = f[i:]
				break
			}
		}

		m[field] = f
	}

	refFields.m = m
}
<commit_msg>fieldtrack: add testing docs<commit_after>// Copyright 2016 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build gc

// Package fieldtrack provides access to information in the current binary
// that tracks use of struct fields.
// This information is computed at build time for struct fields marked
// with the `go:"track"` tag. See http://go/fieldtrack for background.
//
// To test run:
//
//     GOEXPERIMENT=fieldtrack ./make.bash
//     go test rsc.io/tmp/fieldtrack -ldflags=-k=rsc.io/tmp/fieldtrack.tracked
package fieldtrack

import (
	"sort"
	"strings"
	"sync"
)

// tracked holds the raw field tracking information supplied by the linker,
// provided the linker is invoked with -k rsc.io/tmp/fieldtrack.tracked.
//
// The raw tracking information is a sequence of lines, each terminated by
// a \n and describing a single tracked field referred to by the program.
// Each line is made up of one or more tab-separated fields.
// The first field is the name of the tracked field, fully qualified,
// as in "my/pkg.T.F". Subsequent fields give a shortest path of
// reverse references from that field to main.init or main.main,
// corresponding to one way in which the program might reach that field.
var tracked string

// The sentinel type is a dummy type that we know should appear
// in the field tracking information, so that we can tell if field tracking
// was enabled during compilation.
type sentinel struct {
	F int `go:"track"`
}

// Enabled reports whether field tracking was enabled in the compiler
// when compiling the current binary.
func Enabled() bool {
	// Code to make the compiler think we refer to sentinel.F.
	// Complex enough that it won't be optimized away.
	f := Enabled
	alwaysFalse := f == nil
	if alwaysFalse {
		var x sentinel
		println(x.F)
	}

	// If there's tracking information available, then field tracking is turned on.
	// If not, then sentinel.F is missing so it must be disabled.
	return tracked != ""
}

// Tracked returns a sorted list of all tracked fields used by the current binary.
// The form of each entry is "full/import/path.TypeName.FieldName".
func Tracked() []string {
	trackedFields.once.Do(initTrackedFields)
	return trackedFields.list
}

var trackedFields struct {
	once sync.Once
	list []string
}

func initTrackedFields() {
	if !Enabled() {
		panic("fieldtrack: compiler is not tracking fields")
	}

	x := strings.Split(tracked, "\n")

	// Cut path information, which starts at the first tab on each line.
	for i, line := range x {
		j := strings.Index(line, "\t")
		if j >= 0 {
			x[i] = line[:j]
		}
	}

	// Remove reference to our internal sentinel.F
	// and remove the "" Split found after the final \n.
	w := 0
	for _, line := range x {
		if line != "rsc.io/tmp/fieldtrack.sentinel.F" && line != "" {
			x[w] = line
			w++
		}
	}
	x = x[:w]

	sort.Strings(x)
	trackedFields.list = x
}

// Ref returns the list of references explaining why the given field name is used
// by the current binary. The field name should be in the form returned by Tracked.
// The references start at a global symbol and end with the field.
// If the field is not used by the current binary, Ref returns nil.
func Ref(field string) []string {
	refFields.once.Do(initRefFields)
	return refFields.m[field]
}

var refFields struct {
	once sync.Once
	m    map[string][]string
}

func initRefFields() {
	if !Enabled() {
		panic("fieldtrack: compiler is not tracking fields")
	}

	m := make(map[string][]string)
	for _, line := range strings.Split(tracked, "\n") {
		if line == "" {
			// empty string after final \n
			continue
		}

		f := strings.Split(line, "\t")

		field := f[0]

		// The path is presented from field back to the global;
		// we want a path from the global to the field, so reverse it.
		for i, j := 0, len(f)-1; i < j; i, j = i+1, j-1 {
			f[i], f[j] = f[j], f[i]
		}

		// Cut items from list before "main.main" or "main.init"
		// to skip the runtime details that get into main
		// (or else it starts with a global variable, which is fine).
		for i, x := range f {
			if x == "main.main" || x == "main.init" {
				f = f[i:]
				break
			}
		}

		m[field] = f
	}

	refFields.m = m
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/hex"
	"errors"
	"io"
	"io/ioutil"
	"math/rand"
	"mime"
	"net/http"
	"net/http/httptest"
	"net/url"
	"path"
	"strconv"
	"testing"
	"time"
)

func postDefaultContent(t *testing.T, targetUrl string) (res *http.Response, err error) {
	content := []byte("This is some content")
	u, _ := url.Parse(targetUrl)
	v := url.Values{}
	v.Set("name", "content.txt")
	u.RawQuery = v.Encode()
	req, err := http.NewRequest("POST", u.String(), bytes.NewReader(content))
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", "text/plain")
	req.Header.Set("Content-Length", strconv.Itoa(len(content)))
	return http.DefaultClient.Do(req)
}

func TestHandlePost(t *testing.T) {
	h := handler{newDummyStore()}
	ts := httptest.NewServer(h)

	res, err := postDefaultContent(t, ts.URL)
	if err != nil {
		t.Fatal(err)
	}

	if res.StatusCode != http.StatusCreated {
		t.Fatalf("got statuscode=%d, expected %d", res.StatusCode, http.StatusCreated)
	}
	if _, err := time.Parse(time.RFC1123, res.Header.Get("Date")); err != nil {
		t.Fatal("Couldn't decode Date header in response (%s): %v", res.Header.Get("Date"), err)
	}

	mt, _, err := mime.ParseMediaType(res.Header.Get("Content-Type"))
	if err != nil {
		t.Fatalf("Invalid Content-Type header(%s): %v", res.Header.Get("Content-Type"), err)
	}
	if mt != "text/plain" {
		t.Fatalf("got mimetype %s, expected text/plain", mt)
	}

	location := res.Header.Get("Location")
	expectedLocation := "/?name=75ed184249e9bc19675e4d1f766213da71b64278fed2cad5f18a247619205e30/content.txt"
	if location != expectedLocation {
		t.Fatalf("Invalid location header, got %s, expected %s", location, expectedLocation)
	}
}

// A thread-unsafe dummy store implementation, purely in-memory, good for tests
type file struct {
	name    string
	content []byte
	modTime time.Time
}

var _ store = &dummyStore{}

type dummyStore struct {
	files map[string]file
	r     *rand.Rand
}

func newDummyStore() *dummyStore {
	return &dummyStore{
		files: make(map[string]file),
		r:     rand.New(rand.NewSource(99)),
	}
}

func (ds *dummyStore) Post(name string, rd io.Reader, modTime time.Time) (newpath string, err error) {
	var randBytes [32]byte
	ds.r.Read(randBytes[:])
	fullpath := path.Join(hex.EncodeToString(randBytes[:]), name)
	content, err := ioutil.ReadAll(rd)
	if err != nil {
		return "", err
	}
	ds.files[fullpath] = file{
		name:    fullpath,
		content: content,
		modTime: modTime,
	}
	return fullpath, nil
}

func (ds *dummyStore) Get(name string) (rd readSeekCloser, modTime time.Time, err error) {
	f, ok := ds.files[name]
	if !ok {
		return nil, time.Now(), errors.New("Not found")
	}
	return nopCloser{bytes.NewReader(f.content)}, f.modTime, nil
}

type nopCloser struct {
	io.ReadSeeker
}

func (nc nopCloser) Close() error { return nil }

func (ds *dummyStore) Delete(name string) error {
	_, ok := ds.files[name]
	if !ok {
		return errors.New("Not found")
	}
	delete(ds.files, name)
	return nil
}
<commit_msg>Add HEAD and GET test for handler<commit_after>package main

import (
	"bytes"
	"encoding/hex"
	"errors"
	"io"
	"io/ioutil"
	"math/rand"
	"mime"
	"net/http"
	"net/http/httptest"
	"net/url"
	"path"
	"strconv"
	"testing"
	"time"
)

func postDefaultContent(t *testing.T, targetUrl string) (res *http.Response, content []byte, err error) {
	content = []byte("This is some content")
	u, _ := url.Parse(targetUrl)
	v := url.Values{}
	v.Set("name", "content.txt")
	u.RawQuery = v.Encode()
	req, err := http.NewRequest("POST", u.String(), bytes.NewReader(content))
	if err != nil {
		return nil, nil, err
	}
	req.Header.Set("Content-Type", "text/plain")
	req.Header.Set("Content-Length", strconv.Itoa(len(content)))
	res, err = http.DefaultClient.Do(req)
	return res, content, err
}

func TestHandlePost(t *testing.T) {
	h := handler{newDummyStore()}
	ts := httptest.NewServer(h)

	res, _, err := postDefaultContent(t, ts.URL)
	if err != nil {
		t.Fatal(err)
	}

	if res.StatusCode != http.StatusCreated {
		t.Fatalf("got statuscode=%d, expected %d", res.StatusCode, http.StatusCreated)
	}
	if _, err := time.Parse(time.RFC1123, res.Header.Get("Date")); err != nil {
		t.Fatal("Couldn't decode Date header in response (%s): %v", res.Header.Get("Date"), err)
	}

	mt, _, err := mime.ParseMediaType(res.Header.Get("Content-Type"))
	if err != nil {
		t.Fatalf("Invalid Content-Type header(%s): %v", res.Header.Get("Content-Type"), err)
	}
	if mt != "text/plain" {
		t.Fatalf("got mimetype %s, expected text/plain", mt)
	}

	location := res.Header.Get("Location")
	expectedLocation := "/?name=75ed184249e9bc19675e4d1f766213da71b64278fed2cad5f18a247619205e30/content.txt"
	if location != expectedLocation {
		t.Fatalf("Invalid location header, got %s, expected %s", location, expectedLocation)
	}
}

func TestHandleGetHead(t *testing.T) {
	h := handler{newDummyStore()}
	ts := httptest.NewServer(h)

	postRes, content, err := postDefaultContent(t, ts.URL)
	if err != nil {
		t.Fatal(err)
	}

	for _, method := range []string{"GET", "HEAD"} {
		targetUrl, _ := url.Parse(ts.URL)
		location, _ := url.Parse(postRes.Header.Get("Location"))
		targetUrl.RawQuery = location.RawQuery
		getReq, _ := http.NewRequest(method, targetUrl.String(), nil)
		getRes, err := http.DefaultClient.Do(getReq)
		if err != nil {
			t.Fatal(err)
		}

		if getRes.StatusCode != http.StatusOK {
			t.Fatalf("got status %d, expected %d", getRes.StatusCode, http.StatusOK)
		}
		actualSize, err := strconv.Atoi(getRes.Header.Get("Content-Length"))
		if err != nil {
			t.Fatalf("Couldn't parse Content-Length header (%s) as error: %v", getRes.Header.Get("Content-Length"), err)
		}
		if actualSize != len(content) {
			t.Fatalf("got size %d, expected %d", actualSize, len(content))
		}

		mt, _, err := mime.ParseMediaType(getRes.Header.Get("Content-Type"))
		if err != nil {
			t.Fatalf("Invalid Content-Type header(%s): %v", getRes.Header.Get("Content-Type"), err)
		}
		if mt != "text/plain" {
			t.Fatalf("got mimetype %s, expected text/plain", mt)
		}

		expectedEtag := "75ed184249e9bc19675e4d1f766213da71b64278fed2cad5f18a247619205e30"
		if getRes.Header.Get("Etag") != expectedEtag {
			t.Fatalf("got Etag %s, expected %s", getRes.Header.Get("Etag"), expectedEtag)
		}

		if method == "GET" {
			body, err := ioutil.ReadAll(getRes.Body)
			getRes.Body.Close()
			if err != nil {
				t.Fatal("Couldn't read body:", err)
			}
			if !bytes.Equal(body, content) {
				t.Fatalf("Invalid body, got %s, expected %s", body, content)
			}
		}
	}
}

// A thread-unsafe dummy store implementation, purely in-memory, good for tests
type file struct {
	name    string
	content []byte
	modTime time.Time
}

var _ store = &dummyStore{}

type dummyStore struct {
	files map[string]file
	r     *rand.Rand
}

func newDummyStore() *dummyStore {
	return &dummyStore{
		files: make(map[string]file),
		r:     rand.New(rand.NewSource(99)),
	}
}

func (ds *dummyStore) Post(name string, rd io.Reader, modTime time.Time) (newpath string, err error) {
	var randBytes [32]byte
	ds.r.Read(randBytes[:])
	fullpath := path.Join(hex.EncodeToString(randBytes[:]), name)
	content, err := ioutil.ReadAll(rd)
	if err != nil {
		return "", err
	}
	ds.files[fullpath] = file{
		name:    fullpath,
		content: content,
		modTime: modTime,
	}
	return fullpath, nil
}

func (ds *dummyStore) Get(name string) (rd readSeekCloser, modTime time.Time, err error) {
	f, ok := ds.files[name]
	if !ok {
		return nil, time.Now(), errors.New("Not found")
	}
	return nopCloser{bytes.NewReader(f.content)}, f.modTime, nil
}

type nopCloser struct {
	io.ReadSeeker
}

func (nc nopCloser) Close() error { return nil }

func (ds *dummyStore) Delete(name string) error {
	_, ok := ds.files[name]
	if !ok {
		return errors.New("Not found")
	}
	delete(ds.files, name)
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2018 The Kubernetes Authors.

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

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

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

package dynamic

import (
	"io"

	"k8s.io/apimachinery/pkg/api/meta"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/runtime/serializer/streaming"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/watch"
	"k8s.io/client-go/rest"
)

type dynamicClient struct {
	client *rest.RESTClient
}

var _ Interface = &dynamicClient{}

func NewForConfig(inConfig *rest.Config) (Interface, error) {
	config := rest.CopyConfig(inConfig)
	// for serializing the options
	config.GroupVersion = &schema.GroupVersion{}
	config.APIPath = "/if-you-see-this-search-for-the-break"
	config.AcceptContentTypes = "application/json"
	config.ContentType = "application/json"
	config.NegotiatedSerializer = basicNegotiatedSerializer{} // this gets used for discovery and error handling types
	if config.UserAgent == "" {
		config.UserAgent = rest.DefaultKubernetesUserAgent()
	}

	restClient, err := rest.RESTClientFor(config)
	if err != nil {
		return nil, err
	}

	return &dynamicClient{client: restClient}, nil
}

type dynamicResourceClient struct {
	client    *dynamicClient
	namespace string
	resource  schema.GroupVersionResource
}

func (c *dynamicClient) Resource(resource schema.GroupVersionResource) NamespaceableResourceInterface {
	return &dynamicResourceClient{client: c, resource: resource}
}

func (c *dynamicResourceClient) Namespace(ns string) ResourceInterface {
	ret := *c
	ret.namespace = ns
	return &ret
}

func (c *dynamicResourceClient) Create(obj *unstructured.Unstructured, subresources ...string) (*unstructured.Unstructured, error) {
	outBytes, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj)
	if err != nil {
		return nil, err
	}
	name := ""
	if len(subresources) > 0 {
		accessor, err := meta.Accessor(obj)
		if err != nil {
			return nil, err
		}
		name = accessor.GetName()
	}

	result := c.client.client.Post().AbsPath(append(c.makeURLSegments(name), subresources...)...).Body(outBytes).Do()
	if err := result.Error(); err != nil {
		return nil, err
	}

	retBytes, err := result.Raw()
	if err != nil {
		return nil, err
	}
	uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
	if err != nil {
		return nil, err
	}
	return uncastObj.(*unstructured.Unstructured), nil
}

func (c *dynamicResourceClient) Update(obj *unstructured.Unstructured, subresources ...string) (*unstructured.Unstructured, error) {
	accessor, err := meta.Accessor(obj)
	if err != nil {
		return nil, err
	}
	outBytes, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj)
	if err != nil {
		return nil, err
	}

	result := c.client.client.Put().AbsPath(append(c.makeURLSegments(accessor.GetName()), subresources...)...).Body(outBytes).Do()
	if err := result.Error(); err != nil {
		return nil, err
	}

	retBytes, err := result.Raw()
	if err != nil {
		return nil, err
	}
	uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
	if err != nil {
		return nil, err
	}
	return uncastObj.(*unstructured.Unstructured), nil
}

func (c *dynamicResourceClient) UpdateStatus(obj *unstructured.Unstructured) (*unstructured.Unstructured, error) {
	accessor, err := meta.Accessor(obj)
	if err != nil {
		return nil, err
	}

	outBytes, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj)
	if err != nil {
		return nil, err
	}

	result := c.client.client.Put().AbsPath(append(c.makeURLSegments(accessor.GetName()), "status")...).Body(outBytes).Do()
	if err := result.Error(); err != nil {
		return nil, err
	}

	retBytes, err := result.Raw()
	if err != nil {
		return nil, err
	}
	uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
	if err != nil {
		return nil, err
	}
	return uncastObj.(*unstructured.Unstructured), nil
}

func (c *dynamicResourceClient) Delete(name string, opts *metav1.DeleteOptions, subresources ...string) error {
	if opts == nil {
		opts = &metav1.DeleteOptions{}
	}
	deleteOptionsByte, err := runtime.Encode(deleteOptionsCodec.LegacyCodec(schema.GroupVersion{Version: "v1"}), opts)
	if err != nil {
		return err
	}

	result := c.client.client.Delete().AbsPath(append(c.makeURLSegments(name), subresources...)...).Body(deleteOptionsByte).Do()
	return result.Error()
}

func (c *dynamicResourceClient) DeleteCollection(opts *metav1.DeleteOptions, listOptions metav1.ListOptions) error {
	if opts == nil {
		opts = &metav1.DeleteOptions{}
	}
	deleteOptionsByte, err := runtime.Encode(deleteOptionsCodec.LegacyCodec(schema.GroupVersion{Version: "v1"}), opts)
	if err != nil {
		return err
	}

	result := c.client.client.Delete().AbsPath(c.makeURLSegments("")...).Body(deleteOptionsByte).SpecificallyVersionedParams(&listOptions, dynamicParameterCodec, versionV1).Do()
	return result.Error()
}

func (c *dynamicResourceClient) Get(name string, opts metav1.GetOptions, subresources ...string) (*unstructured.Unstructured, error) {
	result := c.client.client.Get().AbsPath(append(c.makeURLSegments(name), subresources...)...).SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).Do()
	if err := result.Error(); err != nil {
		return nil, err
	}
	retBytes, err := result.Raw()
	if err != nil {
		return nil, err
	}
	uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
	if err != nil {
		return nil, err
	}
	return uncastObj.(*unstructured.Unstructured), nil
}

func (c *dynamicResourceClient) List(opts metav1.ListOptions) (*unstructured.UnstructuredList, error) {
	result := c.client.client.Get().AbsPath(c.makeURLSegments("")...).SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).Do()
	if err := result.Error(); err != nil {
		return nil, err
	}
	retBytes, err := result.Raw()
	if err != nil {
		return nil, err
	}
	uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
	if err != nil {
		return nil, err
	}
	if list, ok := uncastObj.(*unstructured.UnstructuredList); ok {
		return list, nil
	}

	list, err := uncastObj.(*unstructured.Unstructured).ToList()
	if err != nil {
		return nil, err
	}
	return list, nil
}

func (c *dynamicResourceClient) Watch(opts metav1.ListOptions) (watch.Interface, error) {
	internalGV := schema.GroupVersions{
		{Group: c.resource.Group, Version: runtime.APIVersionInternal},
		// always include the legacy group as a decoding target to handle non-error `Status` return types
		{Group: "", Version: runtime.APIVersionInternal},
	}
	s := &rest.Serializers{
		Encoder: watchNegotiatedSerializerInstance.EncoderForVersion(watchJsonSerializerInfo.Serializer, c.resource.GroupVersion()),
		Decoder: watchNegotiatedSerializerInstance.DecoderToVersion(watchJsonSerializerInfo.Serializer, internalGV),

		RenegotiatedDecoder: func(contentType string, params map[string]string) (runtime.Decoder, error) {
			return watchNegotiatedSerializerInstance.DecoderToVersion(watchJsonSerializerInfo.Serializer, internalGV), nil
		},
		StreamingSerializer: watchJsonSerializerInfo.StreamSerializer.Serializer,
		Framer:              watchJsonSerializerInfo.StreamSerializer.Framer,
	}

	wrappedDecoderFn := func(body io.ReadCloser) streaming.Decoder {
		framer := s.Framer.NewFrameReader(body)
		return streaming.NewDecoder(framer, s.StreamingSerializer)
	}

	opts.Watch = true
	return c.client.client.Get().AbsPath(c.makeURLSegments("")...).
		SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).
		WatchWithSpecificDecoders(wrappedDecoderFn, unstructured.UnstructuredJSONScheme)
}

func (c *dynamicResourceClient) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (*unstructured.Unstructured, error) {
	result := c.client.client.Patch(pt).AbsPath(append(c.makeURLSegments(name), subresources...)...).Body(data).Do()
	if err := result.Error(); err != nil {
		return nil, err
	}
	retBytes, err := result.Raw()
	if err != nil {
		return nil, err
	}
	uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
	if err != nil {
		return nil, err
	}
	return uncastObj.(*unstructured.Unstructured), nil
}

func (c *dynamicResourceClient) makeURLSegments(name string) []string {
	url := []string{}
	if len(c.resource.Group) == 0 {
		url = append(url, "api")
	} else {
		url = append(url, "apis", c.resource.Group)
	}
	url = append(url, c.resource.Version)

	if len(c.namespace) > 0 {
		url = append(url, "namespaces", c.namespace)
	}
	url = append(url, c.resource.Resource)

	if len(name) > 0 {
		url = append(url, name)
	}

	return url
}
<commit_msg>add missing OrDie variant for dynamic client construction<commit_after>/*
Copyright 2018 The Kubernetes Authors.

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

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

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

package dynamic

import (
	"io"

	"k8s.io/apimachinery/pkg/api/meta"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/runtime/serializer/streaming"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/watch"
	"k8s.io/client-go/rest"
)

type dynamicClient struct {
	client *rest.RESTClient
}

var _ Interface = &dynamicClient{}

// NewForConfigOrDie creates a new Interface for the given config and
// panics if there is an error in the config.
func NewForConfigOrDie(c *rest.Config) Interface {
	ret, err := NewForConfig(c)
	if err != nil {
		panic(err)
	}
	return ret
}

func NewForConfig(inConfig *rest.Config) (Interface, error) {
	config := rest.CopyConfig(inConfig)
	// for serializing the options
	config.GroupVersion = &schema.GroupVersion{}
	config.APIPath = "/if-you-see-this-search-for-the-break"
	config.AcceptContentTypes = "application/json"
	config.ContentType = "application/json"
	config.NegotiatedSerializer = basicNegotiatedSerializer{} // this gets used for discovery and error handling types
	if config.UserAgent == "" {
		config.UserAgent = rest.DefaultKubernetesUserAgent()
	}

	restClient, err := rest.RESTClientFor(config)
	if err != nil {
		return nil, err
	}

	return &dynamicClient{client: restClient}, nil
}

type dynamicResourceClient struct {
	client    *dynamicClient
	namespace string
	resource  schema.GroupVersionResource
}

func (c *dynamicClient) Resource(resource schema.GroupVersionResource) NamespaceableResourceInterface {
	return &dynamicResourceClient{client: c, resource: resource}
}

func (c *dynamicResourceClient) Namespace(ns string) ResourceInterface {
	ret := *c
	ret.namespace = ns
	return &ret
}

func (c *dynamicResourceClient) Create(obj *unstructured.Unstructured, subresources ...string) (*unstructured.Unstructured, error) {
	outBytes, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj)
	if err != nil {
		return nil, err
	}
	name := ""
	if len(subresources) > 0 {
		accessor, err := meta.Accessor(obj)
		if err != nil {
			return nil, err
		}
		name = accessor.GetName()
	}

	result := c.client.client.Post().AbsPath(append(c.makeURLSegments(name), subresources...)...).Body(outBytes).Do()
	if err := result.Error(); err != nil {
		return nil, err
	}

	retBytes, err := result.Raw()
	if err != nil {
		return nil, err
	}
	uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
	if err != nil {
		return nil, err
	}
	return uncastObj.(*unstructured.Unstructured), nil
}

func (c *dynamicResourceClient) Update(obj *unstructured.Unstructured, subresources ...string) (*unstructured.Unstructured, error) {
	accessor, err := meta.Accessor(obj)
	if err != nil {
		return nil, err
	}
	outBytes, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj)
	if err != nil {
		return nil, err
	}

	result := c.client.client.Put().AbsPath(append(c.makeURLSegments(accessor.GetName()), subresources...)...).Body(outBytes).Do()
	if err := result.Error(); err != nil {
		return nil, err
	}

	retBytes, err := result.Raw()
	if err != nil {
		return nil, err
	}
	uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
	if err != nil {
		return nil, err
	}
	return uncastObj.(*unstructured.Unstructured), nil
}

func (c *dynamicResourceClient) UpdateStatus(obj *unstructured.Unstructured) (*unstructured.Unstructured, error) {
	accessor, err := meta.Accessor(obj)
	if err != nil {
		return nil, err
	}

	outBytes, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj)
	if err != nil {
		return nil, err
	}

	result := c.client.client.Put().AbsPath(append(c.makeURLSegments(accessor.GetName()), "status")...).Body(outBytes).Do()
	if err := result.Error(); err != nil {
		return nil, err
	}

	retBytes, err := result.Raw()
	if err != nil {
		return nil, err
	}
	uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
	if err != nil {
		return nil, err
	}
	return uncastObj.(*unstructured.Unstructured), nil
}

func (c *dynamicResourceClient) Delete(name string, opts *metav1.DeleteOptions, subresources ...string) error {
	if opts == nil {
		opts = &metav1.DeleteOptions{}
	}
	deleteOptionsByte, err := runtime.Encode(deleteOptionsCodec.LegacyCodec(schema.GroupVersion{Version: "v1"}), opts)
	if err != nil {
		return err
	}

	result := c.client.client.Delete().AbsPath(append(c.makeURLSegments(name), subresources...)...).Body(deleteOptionsByte).Do()
	return result.Error()
}

func (c *dynamicResourceClient) DeleteCollection(opts *metav1.DeleteOptions, listOptions metav1.ListOptions) error {
	if opts == nil {
		opts = &metav1.DeleteOptions{}
	}
	deleteOptionsByte, err := runtime.Encode(deleteOptionsCodec.LegacyCodec(schema.GroupVersion{Version: "v1"}), opts)
	if err != nil {
		return err
	}

	result := c.client.client.Delete().AbsPath(c.makeURLSegments("")...).Body(deleteOptionsByte).SpecificallyVersionedParams(&listOptions, dynamicParameterCodec, versionV1).Do()
	return result.Error()
}

func (c *dynamicResourceClient) Get(name string, opts metav1.GetOptions, subresources ...string) (*unstructured.Unstructured, error) {
	result := c.client.client.Get().AbsPath(append(c.makeURLSegments(name), subresources...)...).SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).Do()
	if err := result.Error(); err != nil {
		return nil, err
	}
	retBytes, err := result.Raw()
	if err != nil {
		return nil, err
	}
	uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
	if err != nil {
		return nil, err
	}
	return uncastObj.(*unstructured.Unstructured), nil
}

func (c *dynamicResourceClient) List(opts metav1.ListOptions) (*unstructured.UnstructuredList, error) {
	result := c.client.client.Get().AbsPath(c.makeURLSegments("")...).SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).Do()
	if err := result.Error(); err != nil {
		return nil, err
	}
	retBytes, err := result.Raw()
	if err != nil {
		return nil, err
	}
	uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
	if err != nil {
		return nil, err
	}
	if list, ok := uncastObj.(*unstructured.UnstructuredList); ok {
		return list, nil
	}

	list, err := uncastObj.(*unstructured.Unstructured).ToList()
	if err != nil {
		return nil, err
	}
	return list, nil
}

func (c *dynamicResourceClient) Watch(opts metav1.ListOptions) (watch.Interface, error) {
	internalGV := schema.GroupVersions{
		{Group: c.resource.Group, Version: runtime.APIVersionInternal},
		// always include the legacy group as a decoding target to handle non-error `Status` return types
		{Group: "", Version: runtime.APIVersionInternal},
	}
	s := &rest.Serializers{
		Encoder: watchNegotiatedSerializerInstance.EncoderForVersion(watchJsonSerializerInfo.Serializer, c.resource.GroupVersion()),
		Decoder: watchNegotiatedSerializerInstance.DecoderToVersion(watchJsonSerializerInfo.Serializer, internalGV),

		RenegotiatedDecoder: func(contentType string, params map[string]string) (runtime.Decoder, error) {
			return watchNegotiatedSerializerInstance.DecoderToVersion(watchJsonSerializerInfo.Serializer, internalGV), nil
		},
		StreamingSerializer: watchJsonSerializerInfo.StreamSerializer.Serializer,
		Framer:              watchJsonSerializerInfo.StreamSerializer.Framer,
	}

	wrappedDecoderFn := func(body io.ReadCloser) streaming.Decoder {
		framer := s.Framer.NewFrameReader(body)
		return streaming.NewDecoder(framer, s.StreamingSerializer)
	}

	opts.Watch = true
	return c.client.client.Get().AbsPath(c.makeURLSegments("")...).
		SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).
		WatchWithSpecificDecoders(wrappedDecoderFn, unstructured.UnstructuredJSONScheme)
}

func (c *dynamicResourceClient) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (*unstructured.Unstructured, error) {
	result := c.client.client.Patch(pt).AbsPath(append(c.makeURLSegments(name), subresources...)...).Body(data).Do()
	if err := result.Error(); err != nil {
		return nil, err
	}
	retBytes, err := result.Raw()
	if err != nil {
		return nil, err
	}
	uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
	if err != nil {
		return nil, err
	}
	return uncastObj.(*unstructured.Unstructured), nil
}

func (c *dynamicResourceClient) makeURLSegments(name string) []string {
	url := []string{}
	if len(c.resource.Group) == 0 {
		url = append(url, "api")
	} else {
		url = append(url, "apis", c.resource.Group)
	}
	url = append(url, c.resource.Version)

	if len(c.namespace) > 0 {
		url = append(url, "namespaces", c.namespace)
	}
	url = append(url, c.resource.Resource)

	if len(name) > 0 {
		url = append(url, name)
	}

	return url
}
<|endoftext|>


<commit_before>// Copyright (C) 2014 Daniel Harrison

package hfile

import "bytes"
import "encoding/binary"
import "errors"
import "github.com/edsrzf/mmap-go"
import "os"

type Reader struct {
	mmap      mmap.MMap
	version   Version
	header    Header
	dataIndex DataIndex
}

func NewReader(file *os.File) (Reader, error) {
	hfile := Reader{}
	var err error
	hfile.mmap, err = mmap.Map(file, mmap.RDONLY, 0)
	if err != nil {
		return hfile, err
	}

	versionIndex := len(hfile.mmap) - 4
	hfile.version, err = newVersion(bytes.NewReader(hfile.mmap[versionIndex:]))
	hfile.header, err = hfile.version.newHeader(hfile.mmap)
	hfile.dataIndex, err = hfile.header.newDataIndex(hfile.mmap)

	return hfile, nil
}
func (hfile *Reader) String() string {
	return "hfile"
}
func getDataBlock(key []byte, blocks *[]DataBlock) (*DataBlock, error) {
	// TODO(dan): Binary search instead.
	for i := len(*blocks) - 1; i >= 0; i-- {
		block := (*blocks)[i]
		if cmp := bytes.Compare(key, block.firstKeyBytes); cmp == 0 || cmp == 1 {
			return &block, nil
		}
	}
	return nil, errors.New("key not found")
}
func (hfile *Reader) Get(key []byte) ([]byte, error) {
	dataBlock, err := getDataBlock(key, &hfile.dataIndex.dataBlocks)
	if err != nil {
		return key, err
	}
	return dataBlock.get(key)
}

type Version struct {
	buf          *bytes.Reader
	majorVersion uint32
	minorVersion uint32
}

func newVersion(versionBuf *bytes.Reader) (Version, error) {
	version := Version{buf: versionBuf}
	var rawByte uint32
	binary.Read(version.buf, binary.BigEndian, &rawByte)
	version.majorVersion = rawByte & 0x00ffffff
	version.minorVersion = rawByte >> 24
	return version, nil
}
func (version *Version) newHeader(mmap mmap.MMap) (Header, error) {
	header := Header{}

	if version.majorVersion != 1 || version.minorVersion != 0 {
		return header, errors.New("wrong version")
	}

	header.index = len(mmap) - 60
	header.buf = bytes.NewReader(mmap[header.index:])
	headerMagic := make([]byte, 8)
	header.buf.Read(headerMagic)
	if bytes.Compare(headerMagic, []byte("TRABLK\"$")) != 0 {
		return header, errors.New("bad header magic")
	}

	binary.Read(header.buf, binary.BigEndian, &header.fileInfoOffset)
	binary.Read(header.buf, binary.BigEndian, &header.dataIndexOffset)
	binary.Read(header.buf, binary.BigEndian, &header.dataIndexCount)
	binary.Read(header.buf, binary.BigEndian, &header.metaIndexOffset)
	binary.Read(header.buf, binary.BigEndian, &header.metaIndexCount)
	binary.Read(header.buf, binary.BigEndian, &header.totalUncompressedDataBytes)
	binary.Read(header.buf, binary.BigEndian, &header.entryCount)
	binary.Read(header.buf, binary.BigEndian, &header.compressionCodec)
	return header, nil
}

type Header struct {
	buf   *bytes.Reader
	index int

	fileInfoOffset             uint64
	dataIndexOffset            uint64
	dataIndexCount             uint32
	metaIndexOffset            uint64
	metaIndexCount             uint32
	totalUncompressedDataBytes uint64
	entryCount                 uint32
	compressionCodec           uint32
}

func (header *Header) newDataIndex(mmap mmap.MMap) (DataIndex, error) {
	dataIndex := DataIndex{}
	dataIndexEnd := header.metaIndexOffset
	if header.metaIndexOffset == 0 {
		dataIndexEnd = uint64(header.index)
	}
	dataIndex.buf = bytes.NewReader(mmap[header.dataIndexOffset:dataIndexEnd])

	dataIndexMagic := make([]byte, 8)
	dataIndex.buf.Read(dataIndexMagic)
	if bytes.Compare(dataIndexMagic, []byte("IDXBLK)+")) != 0 {
		return dataIndex, errors.New("bad data index magic")
	}

	for dataIndex.buf.Len() > 0 {
		dataBlock := DataBlock{}

		binary.Read(dataIndex.buf, binary.BigEndian, &dataBlock.offset)
		binary.Read(dataIndex.buf, binary.BigEndian, &dataBlock.size)

		dataBlock.buf = bytes.NewReader(mmap[dataBlock.offset : dataBlock.offset+uint64(dataBlock.size)])
		dataBlockMagic := make([]byte, 8)
		dataBlock.buf.Read(dataBlockMagic)
		if bytes.Compare(dataBlockMagic, []byte("DATABLK*")) != 0 {
			return dataIndex, errors.New("bad data block magic")
		}

		firstKeyLen, _ := binary.ReadUvarint(dataIndex.buf)
		dataBlock.firstKeyBytes = make([]byte, firstKeyLen)
		dataIndex.buf.Read(dataBlock.firstKeyBytes)

		dataIndex.dataBlocks = append(dataIndex.dataBlocks, dataBlock)
	}

	return dataIndex, nil
}

type DataIndex struct {
	buf        *bytes.Reader
	dataBlocks []DataBlock
}

type DataBlock struct {
	buf           *bytes.Reader
	offset        uint64
	size          uint32
	firstKeyBytes []byte
}

func (dataBlock *DataBlock) reset() {
	dataBlock.buf.Seek(8, 0)
}
func (dataBlock *DataBlock) get(key []byte) ([]byte, error) {
	dataBlock.reset()
	for dataBlock.buf.Len() > 0 {
		var keyLen, valLen uint32
		binary.Read(dataBlock.buf, binary.BigEndian, &keyLen)
		binary.Read(dataBlock.buf, binary.BigEndian, &valLen)
		keyBytes := make([]byte, keyLen)
		valBytes := make([]byte, valLen)
		dataBlock.buf.Read(keyBytes)
		dataBlock.buf.Read(valBytes)
		if bytes.Compare(key, keyBytes) == 0 {
			return valBytes, nil
		}
	}
	return key, errors.New("key not found")
}
<commit_msg>check errors in reader creation<commit_after>// Copyright (C) 2014 Daniel Harrison

package hfile

import "bytes"
import "encoding/binary"
import "errors"
import "github.com/edsrzf/mmap-go"
import "os"

type Reader struct {
	mmap      mmap.MMap
	version   Version
	header    Header
	dataIndex DataIndex
}

func NewReader(file *os.File) (Reader, error) {
	hfile := Reader{}
	var err error
	hfile.mmap, err = mmap.Map(file, mmap.RDONLY, 0)
	if err != nil {
		return hfile, err
	}

	versionIndex := len(hfile.mmap) - 4
	hfile.version, err = newVersion(bytes.NewReader(hfile.mmap[versionIndex:]))
	if err != nil {
		return hfile, err
	}
	hfile.header, err = hfile.version.newHeader(hfile.mmap)
	if err != nil {
		return hfile, err
	}
	hfile.dataIndex, err = hfile.header.newDataIndex(hfile.mmap)
	if err != nil {
		return hfile, err
	}

	return hfile, nil
}
func (hfile *Reader) String() string {
	return "hfile"
}
func getDataBlock(key []byte, blocks *[]DataBlock) (*DataBlock, error) {
	// TODO(dan): Binary search instead.
	for i := len(*blocks) - 1; i >= 0; i-- {
		block := (*blocks)[i]
		if cmp := bytes.Compare(key, block.firstKeyBytes); cmp == 0 || cmp == 1 {
			return &block, nil
		}
	}
	return nil, errors.New("key not found")
}
func (hfile *Reader) Get(key []byte) ([]byte, error) {
	dataBlock, err := getDataBlock(key, &hfile.dataIndex.dataBlocks)
	if err != nil {
		return key, err
	}
	return dataBlock.get(key)
}

type Version struct {
	buf          *bytes.Reader
	majorVersion uint32
	minorVersion uint32
}

func newVersion(versionBuf *bytes.Reader) (Version, error) {
	version := Version{buf: versionBuf}
	var rawByte uint32
	binary.Read(version.buf, binary.BigEndian, &rawByte)
	version.majorVersion = rawByte & 0x00ffffff
	version.minorVersion = rawByte >> 24
	return version, nil
}
func (version *Version) newHeader(mmap mmap.MMap) (Header, error) {
	header := Header{}

	if version.majorVersion != 1 || version.minorVersion != 0 {
		return header, errors.New("wrong version")
	}

	header.index = len(mmap) - 60
	header.buf = bytes.NewReader(mmap[header.index:])
	headerMagic := make([]byte, 8)
	header.buf.Read(headerMagic)
	if bytes.Compare(headerMagic, []byte("TRABLK\"$")) != 0 {
		return header, errors.New("bad header magic")
	}

	binary.Read(header.buf, binary.BigEndian, &header.fileInfoOffset)
	binary.Read(header.buf, binary.BigEndian, &header.dataIndexOffset)
	binary.Read(header.buf, binary.BigEndian, &header.dataIndexCount)
	binary.Read(header.buf, binary.BigEndian, &header.metaIndexOffset)
	binary.Read(header.buf, binary.BigEndian, &header.metaIndexCount)
	binary.Read(header.buf, binary.BigEndian, &header.totalUncompressedDataBytes)
	binary.Read(header.buf, binary.BigEndian, &header.entryCount)
	binary.Read(header.buf, binary.BigEndian, &header.compressionCodec)
	return header, nil
}

type Header struct {
	buf   *bytes.Reader
	index int

	fileInfoOffset             uint64
	dataIndexOffset            uint64
	dataIndexCount             uint32
	metaIndexOffset            uint64
	metaIndexCount             uint32
	totalUncompressedDataBytes uint64
	entryCount                 uint32
	compressionCodec           uint32
}

func (header *Header) newDataIndex(mmap mmap.MMap) (DataIndex, error) {
	dataIndex := DataIndex{}
	dataIndexEnd := header.metaIndexOffset
	if header.metaIndexOffset == 0 {
		dataIndexEnd = uint64(header.index)
	}
	dataIndex.buf = bytes.NewReader(mmap[header.dataIndexOffset:dataIndexEnd])

	dataIndexMagic := make([]byte, 8)
	dataIndex.buf.Read(dataIndexMagic)
	if bytes.Compare(dataIndexMagic, []byte("IDXBLK)+")) != 0 {
		return dataIndex, errors.New("bad data index magic")
	}

	for dataIndex.buf.Len() > 0 {
		dataBlock := DataBlock{}

		binary.Read(dataIndex.buf, binary.BigEndian, &dataBlock.offset)
		binary.Read(dataIndex.buf, binary.BigEndian, &dataBlock.size)

		dataBlock.buf = bytes.NewReader(mmap[dataBlock.offset : dataBlock.offset+uint64(dataBlock.size)])
		dataBlockMagic := make([]byte, 8)
		dataBlock.buf.Read(dataBlockMagic)
		if bytes.Compare(dataBlockMagic, []byte("DATABLK*")) != 0 {
			return dataIndex, errors.New("bad data block magic")
		}

		firstKeyLen, _ := binary.ReadUvarint(dataIndex.buf)
		dataBlock.firstKeyBytes = make([]byte, firstKeyLen)
		dataIndex.buf.Read(dataBlock.firstKeyBytes)

		dataIndex.dataBlocks = append(dataIndex.dataBlocks, dataBlock)
	}

	return dataIndex, nil
}

type DataIndex struct {
	buf        *bytes.Reader
	dataBlocks []DataBlock
}

type DataBlock struct {
	buf           *bytes.Reader
	offset        uint64
	size          uint32
	firstKeyBytes []byte
}

func (dataBlock *DataBlock) reset() {
	dataBlock.buf.Seek(8, 0)
}
func (dataBlock *DataBlock) get(key []byte) ([]byte, error) {
	dataBlock.reset()
	for dataBlock.buf.Len() > 0 {
		var keyLen, valLen uint32
		binary.Read(dataBlock.buf, binary.BigEndian, &keyLen)
		binary.Read(dataBlock.buf, binary.BigEndian, &valLen)
		keyBytes := make([]byte, keyLen)
		valBytes := make([]byte, valLen)
		dataBlock.buf.Read(keyBytes)
		dataBlock.buf.Read(valBytes)
		if bytes.Compare(key, keyBytes) == 0 {
			return valBytes, nil
		}
	}
	return key, errors.New("key not found")
}
<|endoftext|>


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

package e2e

import (
	"testing"

	"github.com/golang/glog"
	"github.com/onsi/ginkgo"
	"github.com/onsi/ginkgo/config"
	"github.com/onsi/gomega"
	_ "k8s.io/client-go/plugin/pkg/client/auth"

	"github.com/jetstack/cert-manager/pkg/logs"
	_ "github.com/jetstack/cert-manager/test/e2e/certificate"
	_ "github.com/jetstack/cert-manager/test/e2e/clusterissuer"
	"github.com/jetstack/cert-manager/test/e2e/framework"
	_ "github.com/jetstack/cert-manager/test/e2e/issuer"
)

// TestE2E checks configuration parameters (specified through flags) and then runs
// E2E tests using the Ginkgo runner.
func RunE2ETests(t *testing.T) {
	logs.InitLogs()
	defer logs.FlushLogs()

	gomega.RegisterFailHandler(ginkgo.Fail)
	// Disable skipped tests unless they are explicitly requested.
	if config.GinkgoConfig.FocusString == "" && config.GinkgoConfig.SkipString == "" {
		config.GinkgoConfig.SkipString = `\[Flaky\]|\[Feature:.+\]`
	}

	glog.Infof("Starting e2e run %q on Ginkgo node %d", framework.RunId, config.GinkgoConfig.ParallelNode)
	ginkgo.RunSpecs(t, "cert-manager e2e suite")
}
<commit_msg>Import ingress e2e test suite<commit_after>/*
Copyright 2015 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package e2e

import (
	"testing"

	"github.com/golang/glog"
	"github.com/onsi/ginkgo"
	"github.com/onsi/ginkgo/config"
	"github.com/onsi/gomega"
	_ "k8s.io/client-go/plugin/pkg/client/auth"

	"github.com/jetstack/cert-manager/pkg/logs"
	_ "github.com/jetstack/cert-manager/test/e2e/certificate"
	_ "github.com/jetstack/cert-manager/test/e2e/clusterissuer"
	"github.com/jetstack/cert-manager/test/e2e/framework"
	_ "github.com/jetstack/cert-manager/test/e2e/ingress"
	_ "github.com/jetstack/cert-manager/test/e2e/issuer"
)

// TestE2E checks configuration parameters (specified through flags) and then runs
// E2E tests using the Ginkgo runner.
func RunE2ETests(t *testing.T) {
	logs.InitLogs()
	defer logs.FlushLogs()

	gomega.RegisterFailHandler(ginkgo.Fail)
	// Disable skipped tests unless they are explicitly requested.
	if config.GinkgoConfig.FocusString == "" && config.GinkgoConfig.SkipString == "" {
		config.GinkgoConfig.SkipString = `\[Flaky\]|\[Feature:.+\]`
	}

	glog.Infof("Starting e2e run %q on Ginkgo node %d", framework.RunId, config.GinkgoConfig.ParallelNode)
	ginkgo.RunSpecs(t, "cert-manager e2e suite")
}
<|endoftext|>


<commit_before>package test_helper

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"math/rand"
	"os"
	"os/exec"
	"path/filepath"
	"reflect"
	"runtime"
	"testing"

	"github.com/restic/restic/backend"
	"github.com/restic/restic/backend/local"
	"github.com/restic/restic/repository"
)

// Assert fails the test if the condition is false.
func Assert(tb testing.TB, condition bool, msg string, v ...interface{}) {
	if !condition {
		_, file, line, _ := runtime.Caller(1)
		fmt.Printf("\033[31m%s:%d: "+msg+"\033[39m\n\n", append([]interface{}{filepath.Base(file), line}, v...)...)
		tb.FailNow()
	}
}

// OK fails the test if an err is not nil.
func OK(tb testing.TB, err error) {
	if err != nil {
		_, file, line, _ := runtime.Caller(1)
		fmt.Printf("\033[31m%s:%d: unexpected error: %s\033[39m\n\n", filepath.Base(file), line, err.Error())
		tb.FailNow()
	}
}

// OKs fails the test if any error from errs is not nil.
func OKs(tb testing.TB, errs []error) {
	errFound := false
	for _, err := range errs {
		if err != nil {
			errFound = true
			_, file, line, _ := runtime.Caller(1)
			fmt.Printf("\033[31m%s:%d: unexpected error: %s\033[39m\n\n", filepath.Base(file), line, err.Error())
		}
	}
	if errFound {
		tb.FailNow()
	}
}

// Equals fails the test if exp is not equal to act.
func Equals(tb testing.TB, exp, act interface{}) {
	if !reflect.DeepEqual(exp, act) {
		_, file, line, _ := runtime.Caller(1)
		fmt.Printf("\033[31m%s:%d:\n\n\texp: %#v\n\n\tgot: %#v\033[39m\n\n", filepath.Base(file), line, exp, act)
		tb.FailNow()
	}
}

// ParseID parses s as a backend.ID and panics if that fails.
func ParseID(s string) backend.ID {
	id, err := backend.ParseID(s)
	if err != nil {
		panic(err)
	}

	return id
}

// Random returns size bytes of pseudo-random data derived from the seed.
func Random(seed, count int) []byte {
	buf := make([]byte, count)

	rnd := rand.New(rand.NewSource(int64(seed)))
	for i := 0; i < count; i++ {
		buf[i] = byte(rnd.Uint32())
	}

	return buf
}

// RandomReader returns a reader that returns size bytes of pseudo-random data
// derived from the seed.
func RandomReader(seed, size int) *bytes.Reader {
	return bytes.NewReader(Random(seed, size))
}

// SetupTarTestFixture extracts the tarFile to outputDir.
func SetupTarTestFixture(t testing.TB, outputDir, tarFile string) {
	f, err := os.Open(tarFile)
	defer f.Close()
	OK(t, err)

	cmd := exec.Command("tar", "xzf", "-")
	cmd.Dir = outputDir

	cmd.Stdin = f
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	OK(t, cmd.Run())
}

// WithTestEnvironment creates a test environment, extracts the repository
// fixture and and calls f with the repository dir.
func WithTestEnvironment(t testing.TB, repoFixture string, f func(repodir string)) {
	tempdir, err := ioutil.TempDir(TestTempDir, "restic-test-")
	OK(t, err)

	fd, err := os.Open(repoFixture)
	if err != nil {
		panic(err)
	}
	OK(t, fd.Close())

	SetupTarTestFixture(t, tempdir, repoFixture)

	f(filepath.Join(tempdir, "repo"))

	if !TestCleanup {
		t.Logf("leaving temporary directory %v used for test", tempdir)
		return
	}

	RemoveAll(t, tempdir)
}

// OpenLocalRepo opens the local repository located at dir.
func OpenLocalRepo(t testing.TB, dir string) *repository.Repository {
	be, err := local.Open(dir)
	OK(t, err)

	repo := repository.New(be)
	err = repo.SearchKey(TestPassword)
	OK(t, err)

	return repo
}

func isFile(fi os.FileInfo) bool {
	return fi.Mode()&(os.ModeType|os.ModeCharDevice) == 0
}

// ResetReadOnly recursively resets the read-only flag recursively for dir.
// This is mainly used for tests on Windows, which is unable to delete a file
// set read-only.
func ResetReadOnly(t testing.TB, dir string) {
	OK(t, filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error {
		if fi.IsDir() {
			return os.Chmod(path, 0777)
		}

		if isFile(fi) {
			return os.Chmod(path, 0666)
		}

		return nil
	}))
}

// RemoveAll recursively resets the read-only flag of all files and dirs and
// afterwards uses os.RemoveAll() to remove the path.
func RemoveAll(t testing.TB, path string) {
	ResetReadOnly(t, path)
	OK(t, os.RemoveAll(path))
}
<commit_msg>tests: use internal bzip2/gzip implementation<commit_after>package test_helper

import (
	"bytes"
	"compress/bzip2"
	"compress/gzip"
	"fmt"
	"io"
	"io/ioutil"
	"math/rand"
	"os"
	"os/exec"
	"path/filepath"
	"reflect"
	"runtime"
	"testing"

	"github.com/restic/restic/backend"
	"github.com/restic/restic/backend/local"
	"github.com/restic/restic/repository"
)

// Assert fails the test if the condition is false.
func Assert(tb testing.TB, condition bool, msg string, v ...interface{}) {
	if !condition {
		_, file, line, _ := runtime.Caller(1)
		fmt.Printf("\033[31m%s:%d: "+msg+"\033[39m\n\n", append([]interface{}{filepath.Base(file), line}, v...)...)
		tb.FailNow()
	}
}

// OK fails the test if an err is not nil.
func OK(tb testing.TB, err error) {
	if err != nil {
		_, file, line, _ := runtime.Caller(1)
		fmt.Printf("\033[31m%s:%d: unexpected error: %s\033[39m\n\n", filepath.Base(file), line, err.Error())
		tb.FailNow()
	}
}

// OKs fails the test if any error from errs is not nil.
func OKs(tb testing.TB, errs []error) {
	errFound := false
	for _, err := range errs {
		if err != nil {
			errFound = true
			_, file, line, _ := runtime.Caller(1)
			fmt.Printf("\033[31m%s:%d: unexpected error: %s\033[39m\n\n", filepath.Base(file), line, err.Error())
		}
	}
	if errFound {
		tb.FailNow()
	}
}

// Equals fails the test if exp is not equal to act.
func Equals(tb testing.TB, exp, act interface{}) {
	if !reflect.DeepEqual(exp, act) {
		_, file, line, _ := runtime.Caller(1)
		fmt.Printf("\033[31m%s:%d:\n\n\texp: %#v\n\n\tgot: %#v\033[39m\n\n", filepath.Base(file), line, exp, act)
		tb.FailNow()
	}
}

// ParseID parses s as a backend.ID and panics if that fails.
func ParseID(s string) backend.ID {
	id, err := backend.ParseID(s)
	if err != nil {
		panic(err)
	}

	return id
}

// Random returns size bytes of pseudo-random data derived from the seed.
func Random(seed, count int) []byte {
	buf := make([]byte, count)

	rnd := rand.New(rand.NewSource(int64(seed)))
	for i := 0; i < count; i++ {
		buf[i] = byte(rnd.Uint32())
	}

	return buf
}

// RandomReader returns a reader that returns size bytes of pseudo-random data
// derived from the seed.
func RandomReader(seed, size int) *bytes.Reader {
	return bytes.NewReader(Random(seed, size))
}

// SetupTarTestFixture extracts the tarFile to outputDir.
func SetupTarTestFixture(t testing.TB, outputDir, tarFile string) {
	input, err := os.Open(tarFile)
	defer input.Close()
	OK(t, err)

	var rd io.Reader
	switch filepath.Ext(tarFile) {
	case ".gz":
		r, err := gzip.NewReader(input)
		OK(t, err)

		defer r.Close()
		rd = r
	case ".bzip2":
		rd = bzip2.NewReader(input)
	default:
		rd = input
	}

	cmd := exec.Command("tar", "xf", "-")
	cmd.Dir = outputDir

	cmd.Stdin = rd
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	OK(t, cmd.Run())
}

// WithTestEnvironment creates a test environment, extracts the repository
// fixture and and calls f with the repository dir.
func WithTestEnvironment(t testing.TB, repoFixture string, f func(repodir string)) {
	tempdir, err := ioutil.TempDir(TestTempDir, "restic-test-")
	OK(t, err)

	fd, err := os.Open(repoFixture)
	if err != nil {
		panic(err)
	}
	OK(t, fd.Close())

	SetupTarTestFixture(t, tempdir, repoFixture)

	f(filepath.Join(tempdir, "repo"))

	if !TestCleanup {
		t.Logf("leaving temporary directory %v used for test", tempdir)
		return
	}

	RemoveAll(t, tempdir)
}

// OpenLocalRepo opens the local repository located at dir.
func OpenLocalRepo(t testing.TB, dir string) *repository.Repository {
	be, err := local.Open(dir)
	OK(t, err)

	repo := repository.New(be)
	err = repo.SearchKey(TestPassword)
	OK(t, err)

	return repo
}

func isFile(fi os.FileInfo) bool {
	return fi.Mode()&(os.ModeType|os.ModeCharDevice) == 0
}

// ResetReadOnly recursively resets the read-only flag recursively for dir.
// This is mainly used for tests on Windows, which is unable to delete a file
// set read-only.
func ResetReadOnly(t testing.TB, dir string) {
	OK(t, filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error {
		if fi.IsDir() {
			return os.Chmod(path, 0777)
		}

		if isFile(fi) {
			return os.Chmod(path, 0666)
		}

		return nil
	}))
}

// RemoveAll recursively resets the read-only flag of all files and dirs and
// afterwards uses os.RemoveAll() to remove the path.
func RemoveAll(t testing.TB, path string) {
	ResetReadOnly(t, path)
	OK(t, os.RemoveAll(path))
}
<|endoftext|>


<commit_before>package horcrux

import (
	"fmt"
	"testing"
)

func TestFragmentStringer(t *testing.T) {
	f := Fragment{
		ID:       1,
		N:        2,
		R:        3,
		P:        4,
		K:        5,
		Question: "Q",
		Nonce:    []byte{10},
		Salt:     []byte{11},
		Value:    []byte{12},
	}

	expected := "1/5:Q:2:3:4:0b:0c"
	actual := f.String()
	if actual != expected {
		t.Fatalf("Expected %v but was %v", expected, actual)
	}
}

func TestAnswerStringer(t *testing.T) {
	a := Answer{
		Fragment: Fragment{
			ID:       1,
			N:        2,
			R:        3,
			P:        4,
			K:        5,
			Question: "Q",
			Nonce:    []byte{10},
			Salt:     []byte{11},
			Value:    []byte{12},
		},
		Answer: "A",
	}

	expected := "1/5:Q:2:3:4:0b:0c:A"
	actual := a.String()
	if actual != expected {
		t.Fatalf("Expected %v but was %v", expected, actual)
	}
}

func Example() {
	secret := []byte("my favorite password")
	questions := map[string]string{
		"What's your first pet's name?":     "Spot",
		"What's your least favorite food?":  "broccoli",
		"What's your mother's maiden name?": "Hernandez",
		"What's your real name?":            "Rumplestiltskin",
	}

	// Split into four fragments, any two of which can be combined to recover
	// the secret.
	frags, err := Split(secret, questions, 2, 2<<14, 8, 1)
	if err != nil {
		fmt.Println(err)
		return
	}

	// Answer two of the security questions.
	answers := make([]Answer, 2)
	for i := range answers {
		answers[i] = Answer{
			Fragment: frags[i],
			Answer:   questions[frags[i].Question],
		}
	}

	// Recover the original secret.
	s, err := Recover(answers)
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println(string(s))
	// Output:
	// my favorite password
}

var (
	secret    = []byte("my favorite password")
	questions = map[string]string{
		"What's your first pet's name?":     "Spot",
		"What's your least favorite food?":  "broccoli",
		"What's your mother's maiden name?": "Hernandez",
		"What's your real name?":            "Rumplestiltskin",
	}
)

func TestRoundTrip(t *testing.T) {
	frags, err := Split(secret, questions, 2, 2<<10, 8, 1)
	if err != nil {
		t.Fatal(err)
	}

	answers := make([]Answer, 2)
	for i := range answers {
		answers[i] = Answer{
			Fragment: frags[i],
			Answer:   questions[frags[i].Question],
		}
	}

	s, err := Recover(answers)
	if err != nil {
		t.Fatal(err)
	}

	expected := string(s)
	actual := string(secret)
	if actual != expected {
		t.Fatalf("Expected %v but was %v", expected, actual)
	}
}

func TestRecoverTooFewAnswers(t *testing.T) {
	frags, err := Split(secret, questions, 2, 2<<10, 8, 1)
	if err != nil {
		t.Fatal(err)
	}

	answers := make([]Answer, 1)
	for i := range answers {
		answers[i] = Answer{
			Fragment: frags[i],
			Answer:   questions[frags[i].Question],
		}
	}

	s, err := Recover(answers)
	if s != nil {
		t.Fatalf("Expected nil, but was %v", s)
	}

	expected := "horcrux: need at least 2 answers but only have 1"
	actual := err.Error()
	if actual != expected {
		t.Fatalf("Expected %v but was %v", expected, actual)
	}
}

func TestRecoverBadAnswers(t *testing.T) {
	frags, err := Split(secret, questions, 2, 2<<10, 8, 1)
	if err != nil {
		t.Fatal(err)
	}

	answers := make([]Answer, 2)
	for i := range answers {
		answers[i] = Answer{
			Fragment: frags[i],
			Answer:   questions[frags[i].Question] + "woo",
		}
	}

	s, err := Recover(answers)
	if s != nil {
		t.Fatalf("Expected nil, but was %v", s)
	}

	expected := "chacha20poly1305: message authentication failed"
	actual := err.Error()
	if actual != expected {
		t.Fatalf("Expected %v but was %v", expected, actual)
	}
}
<commit_msg>Add tests for split errors.<commit_after>package horcrux

import (
	"fmt"
	"testing"
)

func TestFragmentStringer(t *testing.T) {
	f := Fragment{
		ID:       1,
		N:        2,
		R:        3,
		P:        4,
		K:        5,
		Question: "Q",
		Nonce:    []byte{10},
		Salt:     []byte{11},
		Value:    []byte{12},
	}

	expected := "1/5:Q:2:3:4:0b:0c"
	actual := f.String()
	if actual != expected {
		t.Fatalf("Expected %v but was %v", expected, actual)
	}
}

func TestAnswerStringer(t *testing.T) {
	a := Answer{
		Fragment: Fragment{
			ID:       1,
			N:        2,
			R:        3,
			P:        4,
			K:        5,
			Question: "Q",
			Nonce:    []byte{10},
			Salt:     []byte{11},
			Value:    []byte{12},
		},
		Answer: "A",
	}

	expected := "1/5:Q:2:3:4:0b:0c:A"
	actual := a.String()
	if actual != expected {
		t.Fatalf("Expected %v but was %v", expected, actual)
	}
}

func Example() {
	secret := []byte("my favorite password")
	questions := map[string]string{
		"What's your first pet's name?":     "Spot",
		"What's your least favorite food?":  "broccoli",
		"What's your mother's maiden name?": "Hernandez",
		"What's your real name?":            "Rumplestiltskin",
	}

	// Split into four fragments, any two of which can be combined to recover
	// the secret.
	frags, err := Split(secret, questions, 2, 2<<14, 8, 1)
	if err != nil {
		fmt.Println(err)
		return
	}

	// Answer two of the security questions.
	answers := make([]Answer, 2)
	for i := range answers {
		answers[i] = Answer{
			Fragment: frags[i],
			Answer:   questions[frags[i].Question],
		}
	}

	// Recover the original secret.
	s, err := Recover(answers)
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println(string(s))
	// Output:
	// my favorite password
}

var (
	secret    = []byte("my favorite password")
	questions = map[string]string{
		"What's your first pet's name?":     "Spot",
		"What's your least favorite food?":  "broccoli",
		"What's your mother's maiden name?": "Hernandez",
		"What's your real name?":            "Rumplestiltskin",
	}
)

func TestSplitBadSssParams(t *testing.T) {
	frags, err := Split(secret, questions, -1, 2<<10, 8, 1)
	if err == nil {
		t.Fatalf("Expected error but got %v", frags)
	}

	expected := "sss: K must be > 1"
	actual := err.Error()
	if actual != expected {
		t.Fatalf("Expected %v but was %v", expected, actual)
	}
}

func TestSplitBadScryptParams(t *testing.T) {
	frags, err := Split(secret, questions, 2, 7, 8, 1)
	if err == nil {
		t.Fatalf("Expected error but got %v", frags)
	}

	expected := "scrypt: N must be > 1 and a power of 2"
	actual := err.Error()
	if actual != expected {
		t.Fatalf("Expected %v but was %v", expected, actual)
	}
}

func TestRecoverTooFewAnswers(t *testing.T) {
	frags, err := Split(secret, questions, 2, 2<<10, 8, 1)
	if err != nil {
		t.Fatal(err)
	}

	answers := make([]Answer, 1)
	for i := range answers {
		answers[i] = Answer{
			Fragment: frags[i],
			Answer:   questions[frags[i].Question],
		}
	}

	s, err := Recover(answers)
	if s != nil {
		t.Fatalf("Expected nil, but was %v", s)
	}

	expected := "horcrux: need at least 2 answers but only have 1"
	actual := err.Error()
	if actual != expected {
		t.Fatalf("Expected %v but was %v", expected, actual)
	}
}

func TestRecoverBadAnswers(t *testing.T) {
	frags, err := Split(secret, questions, 2, 2<<10, 8, 1)
	if err != nil {
		t.Fatal(err)
	}

	answers := make([]Answer, 2)
	for i := range answers {
		answers[i] = Answer{
			Fragment: frags[i],
			Answer:   questions[frags[i].Question] + "woo",
		}
	}

	s, err := Recover(answers)
	if s != nil {
		t.Fatalf("Expected nil, but was %v", s)
	}

	expected := "chacha20poly1305: message authentication failed"
	actual := err.Error()
	if actual != expected {
		t.Fatalf("Expected %v but was %v", expected, actual)
	}
}
<|endoftext|>


<commit_before>// run

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

package main

func main() {
	ok := true
	for _, tt := range tests {
		func() {
			defer func() {
				if err := recover(); err == nil {
					println(tt.name, "did not panic")
					ok = false
				}
			}()
			tt.fn()
		}()
	}
	if !ok {
		println("BUG")
	}
}

var intp *int
var slicep *[]byte
var a10p *[10]int
var a10Mp *[1<<20]int
var structp *Struct
var bigstructp *BigStruct
var i int
var m *M
var m1 *M1
var m2 *M2

func use(interface{}) {
}

var tests = []struct{
	name string
	fn func()
}{
	// Edit .+1,/^}/s/^[^	].+/	{"&", func() { println(&) }},\n	{"\&&", func() { println(\&&) }},/g
	{"*intp", func() { println(*intp) }},
	{"&*intp", func() { println(&*intp) }},
	{"*slicep", func() { println(*slicep) }},
	{"&*slicep", func() { println(&*slicep) }},
	{"(*slicep)[0]", func() { println((*slicep)[0]) }},
	{"&(*slicep)[0]", func() { println(&(*slicep)[0]) }},
	{"(*slicep)[i]", func() { println((*slicep)[i]) }},
	{"&(*slicep)[i]", func() { println(&(*slicep)[i]) }},
	{"*a10p", func() { use(*a10p) }},
	{"&*a10p", func() { println(&*a10p) }},
	{"a10p[0]", func() { println(a10p[0]) }},
	{"&a10p[0]", func() { println(&a10p[0]) }},
	{"a10p[i]", func() { println(a10p[i]) }},
	{"&a10p[i]", func() { println(&a10p[i]) }},
	{"*structp", func() { use(*structp) }},
	{"&*structp", func() { println(&*structp) }},
	{"structp.i", func() { println(structp.i) }},
	{"&structp.i", func() { println(&structp.i) }},
	{"structp.j", func() { println(structp.j) }},
	{"&structp.j", func() { println(&structp.j) }},
	{"structp.k", func() { println(structp.k) }},
	{"&structp.k", func() { println(&structp.k) }},
	{"structp.x[0]", func() { println(structp.x[0]) }},
	{"&structp.x[0]", func() { println(&structp.x[0]) }},
	{"structp.x[i]", func() { println(structp.x[i]) }},
	{"&structp.x[i]", func() { println(&structp.x[i]) }},
	{"structp.x[9]", func() { println(structp.x[9]) }},
	{"&structp.x[9]", func() { println(&structp.x[9]) }},
	{"structp.l", func() { println(structp.l) }},
	{"&structp.l", func() { println(&structp.l) }},
	{"*bigstructp", func() { use(*bigstructp) }},
	{"&*bigstructp", func() { println(&*bigstructp) }},
	{"bigstructp.i", func() { println(bigstructp.i) }},
	{"&bigstructp.i", func() { println(&bigstructp.i) }},
	{"bigstructp.j", func() { println(bigstructp.j) }},
	{"&bigstructp.j", func() { println(&bigstructp.j) }},
	{"bigstructp.k", func() { println(bigstructp.k) }},
	{"&bigstructp.k", func() { println(&bigstructp.k) }},
	{"bigstructp.x[0]", func() { println(bigstructp.x[0]) }},
	{"&bigstructp.x[0]", func() { println(&bigstructp.x[0]) }},
	{"bigstructp.x[i]", func() { println(bigstructp.x[i]) }},
	{"&bigstructp.x[i]", func() { println(&bigstructp.x[i]) }},
	{"bigstructp.x[9]", func() { println(bigstructp.x[9]) }},
	{"&bigstructp.x[9]", func() { println(&bigstructp.x[9]) }},
	{"bigstructp.x[200<<20]", func() { println(bigstructp.x[200<<20]) }},
	{"&bigstructp.x[200<<20]", func() { println(&bigstructp.x[200<<20]) }},
	{"bigstructp.l", func() { println(bigstructp.l) }},
	{"&bigstructp.l", func() { println(&bigstructp.l) }},
	{"m1.F()", func() { println(m1.F()) }},
	{"m1.M.F()", func() { println(m1.M.F()) }},
	{"m2.F()", func() { println(m2.F()) }},
	{"m2.M.F()", func() { println(m2.M.F()) }},
}

type Struct struct {
	i int
	j float64
	k string
	x [10]int
	l []byte
}

type BigStruct struct {
	i int
	j float64
	k string
	x [256<<20]byte
	l []byte
}

type M struct {
}

func (m *M) F() int {return 0}

type M1 struct {
	M
}

type M2 struct {
	x int
	M
}
<commit_msg>test: say that nilptr2.go requires 256+MB stack Fixes issue 6161.<commit_after>// run

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

package main

func main() {
	ok := true
	for _, tt := range tests {
		func() {
			defer func() {
				if err := recover(); err == nil {
					println(tt.name, "did not panic")
					ok = false
				}
			}()
			tt.fn()
		}()
	}
	if !ok {
		println("BUG")
	}
}

var intp *int
var slicep *[]byte
var a10p *[10]int
var a10Mp *[1<<20]int
var structp *Struct
var bigstructp *BigStruct
var i int
var m *M
var m1 *M1
var m2 *M2

func use(interface{}) {
}

var tests = []struct{
	name string
	fn func()
}{
	// Edit .+1,/^}/s/^[^	].+/	{"&", func() { println(&) }},\n	{"\&&", func() { println(\&&) }},/g
	{"*intp", func() { println(*intp) }},
	{"&*intp", func() { println(&*intp) }},
	{"*slicep", func() { println(*slicep) }},
	{"&*slicep", func() { println(&*slicep) }},
	{"(*slicep)[0]", func() { println((*slicep)[0]) }},
	{"&(*slicep)[0]", func() { println(&(*slicep)[0]) }},
	{"(*slicep)[i]", func() { println((*slicep)[i]) }},
	{"&(*slicep)[i]", func() { println(&(*slicep)[i]) }},
	{"*a10p", func() { use(*a10p) }},
	{"&*a10p", func() { println(&*a10p) }},
	{"a10p[0]", func() { println(a10p[0]) }},
	{"&a10p[0]", func() { println(&a10p[0]) }},
	{"a10p[i]", func() { println(a10p[i]) }},
	{"&a10p[i]", func() { println(&a10p[i]) }},
	{"*structp", func() { use(*structp) }},
	{"&*structp", func() { println(&*structp) }},
	{"structp.i", func() { println(structp.i) }},
	{"&structp.i", func() { println(&structp.i) }},
	{"structp.j", func() { println(structp.j) }},
	{"&structp.j", func() { println(&structp.j) }},
	{"structp.k", func() { println(structp.k) }},
	{"&structp.k", func() { println(&structp.k) }},
	{"structp.x[0]", func() { println(structp.x[0]) }},
	{"&structp.x[0]", func() { println(&structp.x[0]) }},
	{"structp.x[i]", func() { println(structp.x[i]) }},
	{"&structp.x[i]", func() { println(&structp.x[i]) }},
	{"structp.x[9]", func() { println(structp.x[9]) }},
	{"&structp.x[9]", func() { println(&structp.x[9]) }},
	{"structp.l", func() { println(structp.l) }},
	{"&structp.l", func() { println(&structp.l) }},
	{"*bigstructp", func() { use(*bigstructp) }},
	{"&*bigstructp", func() { println(&*bigstructp) }},
	{"bigstructp.i", func() { println(bigstructp.i) }},
	{"&bigstructp.i", func() { println(&bigstructp.i) }},
	{"bigstructp.j", func() { println(bigstructp.j) }},
	{"&bigstructp.j", func() { println(&bigstructp.j) }},
	{"bigstructp.k", func() { println(bigstructp.k) }},
	{"&bigstructp.k", func() { println(&bigstructp.k) }},
	{"bigstructp.x[0]", func() { println(bigstructp.x[0]) }},
	{"&bigstructp.x[0]", func() { println(&bigstructp.x[0]) }},
	{"bigstructp.x[i]", func() { println(bigstructp.x[i]) }},
	{"&bigstructp.x[i]", func() { println(&bigstructp.x[i]) }},
	{"bigstructp.x[9]", func() { println(bigstructp.x[9]) }},
	{"&bigstructp.x[9]", func() { println(&bigstructp.x[9]) }},
	{"bigstructp.x[100<<20]", func() { println(bigstructp.x[100<<20]) }},
	{"&bigstructp.x[100<<20]", func() { println(&bigstructp.x[100<<20]) }},
	{"bigstructp.l", func() { println(bigstructp.l) }},
	{"&bigstructp.l", func() { println(&bigstructp.l) }},
	{"m1.F()", func() { println(m1.F()) }},
	{"m1.M.F()", func() { println(m1.M.F()) }},
	{"m2.F()", func() { println(m2.F()) }},
	{"m2.M.F()", func() { println(m2.M.F()) }},
}

type Struct struct {
	i int
	j float64
	k string
	x [10]int
	l []byte
}

type BigStruct struct {
	i int
	j float64
	k string
	x [128<<20]byte
	l []byte
}

type M struct {
}

func (m *M) F() int {return 0}

type M1 struct {
	M
}

type M2 struct {
	x int
	M
}
<|endoftext|>


<commit_before>package http

import (
	"fmt"
	"image"
	"net/http"

	"github.com/disintegration/imaging"
	"github.com/gorilla/mux"

	"github.com/filebrowser/filebrowser/v2/files"
)

const (
	sizeThumb = "thumb"
	sizeBig   = "big"
)

type imageProcessor func(src image.Image) (image.Image, error)

var previewHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
	if !d.user.Perm.Download {
		return http.StatusAccepted, nil
	}
	vars := mux.Vars(r)
	size := vars["size"]
	if size != sizeBig && size != sizeThumb {
		return http.StatusNotImplemented, nil
	}

	file, err := files.NewFileInfo(files.FileOptions{
		Fs:      d.user.Fs,
		Path:    "/" + vars["path"],
		Modify:  d.user.Perm.Modify,
		Expand:  true,
		Checker: d,
	})
	if err != nil {
		return errToStatus(err), err
	}

	setContentDisposition(w, r, file)

	switch file.Type {
	case "image":
		return handleImagePreview(w, r, file, size)
	default:
		return http.StatusNotImplemented, fmt.Errorf("can't create preview for %s type", file.Type)
	}
})

func handleImagePreview(w http.ResponseWriter, r *http.Request, file *files.FileInfo, size string) (int, error) {
	format, err := imaging.FormatFromExtension(file.Extension)
	if err != nil {
		// Unsupported extensions directly return the raw data
		if err == imaging.ErrUnsupportedFormat {
			return rawFileHandler(w, r, file)
		}
		return errToStatus(err), err
	}

	var imgProcessor imageProcessor
	switch size {
	case sizeBig:
		imgProcessor = func(img image.Image) (image.Image, error) {
			return imaging.Fit(img, 1080, 1080, imaging.Lanczos), nil
		}
	case sizeThumb:
		imgProcessor = func(img image.Image) (image.Image, error) {
			return imaging.Thumbnail(img, 128, 128, imaging.Box), nil
		}
	default:
		return http.StatusBadRequest, fmt.Errorf("unsupported preview size %s", size)
	}

	fd, err := file.Fs.Open(file.Path)
	if err != nil {
		return errToStatus(err), err
	}
	defer fd.Close()

	img, err := imaging.Decode(fd, imaging.AutoOrientation(true))
	if err != nil {
		return errToStatus(err), err
	}
	img, err = imgProcessor(img)
	if err != nil {
		return errToStatus(err), err
	}
	if imaging.Encode(w, img, format) != nil {
		return errToStatus(err), err
	}
	return 0, nil
}
<commit_msg>fix: add preview bypass for .gif files (#1012)<commit_after>package http

import (
	"fmt"
	"image"
	"net/http"

	"github.com/disintegration/imaging"
	"github.com/gorilla/mux"

	"github.com/filebrowser/filebrowser/v2/files"
)

const (
	sizeThumb = "thumb"
	sizeBig   = "big"
)

type imageProcessor func(src image.Image) (image.Image, error)

var previewHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
	if !d.user.Perm.Download {
		return http.StatusAccepted, nil
	}
	vars := mux.Vars(r)
	size := vars["size"]
	if size != sizeBig && size != sizeThumb {
		return http.StatusNotImplemented, nil
	}

	file, err := files.NewFileInfo(files.FileOptions{
		Fs:      d.user.Fs,
		Path:    "/" + vars["path"],
		Modify:  d.user.Perm.Modify,
		Expand:  true,
		Checker: d,
	})
	if err != nil {
		return errToStatus(err), err
	}

	setContentDisposition(w, r, file)

	switch file.Type {
	case "image":
		return handleImagePreview(w, r, file, size)
	default:
		return http.StatusNotImplemented, fmt.Errorf("can't create preview for %s type", file.Type)
	}
})

func handleImagePreview(w http.ResponseWriter, r *http.Request, file *files.FileInfo, size string) (int, error) {
	format, err := imaging.FormatFromExtension(file.Extension)
	if err != nil {
		// Unsupported extensions directly return the raw data
		if err == imaging.ErrUnsupportedFormat {
			return rawFileHandler(w, r, file)
		}
		return errToStatus(err), err
	}

	fd, err := file.Fs.Open(file.Path)
	if err != nil {
		return errToStatus(err), err
	}
	defer fd.Close()

	if format == imaging.GIF && size == sizeBig {
		if _, err := rawFileHandler(w, r, file); err != nil { //nolint: govet
			return errToStatus(err), err
		}
		return 0, nil
	}

	var imgProcessor imageProcessor
	switch size {
	case sizeBig:
		imgProcessor = func(img image.Image) (image.Image, error) {
			return imaging.Fit(img, 1080, 1080, imaging.Lanczos), nil
		}
	case sizeThumb:
		imgProcessor = func(img image.Image) (image.Image, error) {
			return imaging.Thumbnail(img, 128, 128, imaging.Box), nil
		}
	default:
		return http.StatusBadRequest, fmt.Errorf("unsupported preview size %s", size)
	}

	img, err := imaging.Decode(fd, imaging.AutoOrientation(true))
	if err != nil {
		return errToStatus(err), err
	}
	img, err = imgProcessor(img)
	if err != nil {
		return errToStatus(err), err
	}
	if imaging.Encode(w, img, format) != nil {
		return errToStatus(err), err
	}
	return 0, nil
}
<|endoftext|>


<commit_before>package http

import (
	nethttp "net/http"
	neturl "net/url"
)

type Request struct {
	Session *Session
	req     *nethttp.Request
	URL     *neturl.URL
	Method  string
	Cookies map[string]*nethttp.Cookie
}

func CreateRequest(session *Session, request *nethttp.Request) *Request {
	req := &Request{
		Session: session,
		req:     request,
		URL:     request.URL,
		Method:  request.Method,
		Cookies: make(map[string]*nethttp.Cookie),
	}

	for _, cookie := range request.Cookies() {
		req.Cookies[cookie.Name] = cookie
	}

	return req
}
<commit_msg>Add form functions<commit_after>package http

import (
	nethttp "net/http"
	"net/url"
	"mime/multipart"
)

type Request struct {
	Session      *Session
	req          *nethttp.Request
	URL          *url.URL
	Method       string
	Cookies      map[string]*nethttp.Cookie
}

func CreateRequest(session *Session, request *nethttp.Request) *Request {
	req := &Request{
		Session: session,
		req:     request,
		URL:     request.URL,
		Method:  request.Method,
		Cookies: make(map[string]*nethttp.Cookie),
	}

	for _, cookie := range request.Cookies() {
		req.Cookies[cookie.Name] = cookie
	}

	return req
}

func (r *Request) Form() url.Values {
	r.req.ParseForm()
	return r.req.Form
}

func (r *Request) PostForm() url.Values {
	r.req.ParseForm()
	return r.req.PostForm
}

func (r *Request) MultipartForm() *multipart.Form {
	r.req.ParseMultipartForm(1024000) // FIXME
	return r.req.MultipartForm
}

func (r *Request) Header() nethttp.Header {
	return r.req.Header
}
<|endoftext|>


<commit_before>package hyperion

import (
	`encoding/json`
	`io`
	`net`
	`reflect`
	`strconv`
	`time`
	`github.com/pdf/xbmc-callback-daemon/logger`
)

var (
	connAddress string
	conn        net.Conn
	encoder     *json.Encoder
	decoder     *json.Decoder
)

// Response stores Hyperion results for RPC calls.
type Response struct {
	Success bool    `json:"success"`
	Error   *string `json:"error"`
}

// qtfloat64 is a float64 class to ensure marshalling as floats as QT expects
// them.
// Seriously, fuck you QT.
type qtfloat64 float64

// Custom marshaller for correct float output
func (f qtfloat64) MarshalText() ([]byte, error) {
	v := reflect.ValueOf(f)
	return []byte(strconv.FormatFloat(v.Float(), 'f', 6, 64)), nil
}

// Custom marshaller for correct float output
func (f qtfloat64) MarshalJSON() ([]byte, error) {
	v := reflect.ValueOf(f)
	return []byte(strconv.FormatFloat(v.Float(), 'f', 6, 64)), nil
}

// Connect establishes a TCP connection to the specified address and attaches
// JSON encoders/decoders.
func Connect(address string) {
	if connAddress == `` {
		connAddress = address
	}
	conn, err := net.Dial(`tcp`, address)
	for err != nil {
		logger.Error(`Connecting to Hyperion: `, err)
		logger.Info(`Attempting reconnect...`)
		time.Sleep(time.Second)
		conn, err = net.Dial(`tcp`, address)
	}
	logger.Info(`Connected to Hyperion`)
	encoder = json.NewEncoder(conn)
	decoder = json.NewDecoder(conn)
}

// Close Hyperion connection
func Close() {
	conn.Close()
}

// coerce takes a key/value pair and recurses down the value, replacing any
// float64 values with qtfloat64 conversions and returns the result.
// Some known non-float values are instead converted to integers.
// Seriously, fuck you QT.
func coerce(key string, value interface{}) interface{} {
	switch value.(type) {
	case float64:
		switch key {
		case `priority`:
			return uint16(value.(float64))
		case `color`:
			return uint8(value.(float64))
		default:
			return qtfloat64(value.(float64))
		}
	case []interface{}:
		result, ok := value.([]interface{})
		if ok == false {
			logger.Panic(`Could not parse array, check configuration near `, value)
		}
		for i := range result {
			result[i] = coerce(key, result[i])
		}
		return result
	case map[string]interface{}:
		result, ok := value.(map[string]interface{})
		if ok == false {
			logger.Panic(`Could not parse object, check configuration near `, value)
		}
		for k, v := range result {
			result[k] = coerce(k, v)
		}
		return result
	default:
		return value
	}
}

// Read and decode JSON from the XBMC connection into the notification pointer.
func Read(response *Response) {
	err := decoder.Decode(&response)
	// Kick off the connection again on EOF, eat any decoding errors otherwise.
	// TODO: This probably needs to be more robust.
	if err == io.EOF {
		logger.Error(`Reading from Hyperion: `, err)
		Connect(connAddress)
	} else if err != nil {
		logger.Error(`Decoding response from Hyperion: `, err)
		return
	}
}

// Execute takes the callback and performs a JSON-RPC request over the
// established Hyperion connection.
func Execute(callback map[string]interface{}) {
	response := &Response{}

	// Drop properties that the backend doesn't understand, and coerce float64/int
	cb := make(map[string]interface{}, 0)
	for k, v := range callback {
		switch k {
		case `backend`, `types`:
			continue
		default:
			cb[k] = coerce(k, v)
		}
	}

	logger.Debug(`Sending request to Hyperion: `, cb)
	// Encode and send request
	if err := encoder.Encode(&cb); err != nil {
		logger.Error(`Sending to Hyperion: `, err)
	}
	// Check response and log any failure responses from Hyperion
	Read(response)
	logger.Debug(`Received response from Hyperion: `, response)
	if response.Success == false && response.Error != nil {
		logger.Warn(`Error received from Hyperion: `, response.Error)
	}
}
<commit_msg>Use pointer for stuct functions<commit_after>package hyperion

import (
	`encoding/json`
	`io`
	`net`
	`reflect`
	`strconv`
	`time`
	`github.com/pdf/xbmc-callback-daemon/logger`
)

var (
	connAddress string
	conn        net.Conn
	encoder     *json.Encoder
	decoder     *json.Decoder
)

// Response stores Hyperion results for RPC calls.
type Response struct {
	Success bool    `json:"success"`
	Error   *string `json:"error"`
}

// qtfloat64 is a float64 class to ensure marshalling as floats as QT expects
// them.
// Seriously, fuck you QT.
type qtfloat64 float64

// Custom marshaller for correct float output
func (f *qtfloat64) MarshalText() ([]byte, error) {
	v := reflect.ValueOf(f)
	return []byte(strconv.FormatFloat(v.Float(), 'f', 6, 64)), nil
}

// Custom marshaller for correct float output
func (f *qtfloat64) MarshalJSON() ([]byte, error) {
	v := reflect.ValueOf(f)
	return []byte(strconv.FormatFloat(v.Float(), 'f', 6, 64)), nil
}

// Connect establishes a TCP connection to the specified address and attaches
// JSON encoders/decoders.
func Connect(address string) {
	if connAddress == `` {
		connAddress = address
	}
	conn, err := net.Dial(`tcp`, address)
	for err != nil {
		logger.Error(`Connecting to Hyperion: `, err)
		logger.Info(`Attempting reconnect...`)
		time.Sleep(time.Second)
		conn, err = net.Dial(`tcp`, address)
	}
	logger.Info(`Connected to Hyperion`)
	encoder = json.NewEncoder(conn)
	decoder = json.NewDecoder(conn)
}

// Close Hyperion connection
func Close() {
	conn.Close()
}

// coerce takes a key/value pair and recurses down the value, replacing any
// float64 values with qtfloat64 conversions and returns the result.
// Some known non-float values are instead converted to integers.
// Seriously, fuck you QT.
func coerce(key string, value interface{}) interface{} {
	switch value.(type) {
	case float64:
		switch key {
		case `priority`:
			return uint16(value.(float64))
		case `color`:
			return uint8(value.(float64))
		default:
			return qtfloat64(value.(float64))
		}
	case []interface{}:
		result, ok := value.([]interface{})
		if ok == false {
			logger.Panic(`Could not parse array, check configuration near `, value)
		}
		for i := range result {
			result[i] = coerce(key, result[i])
		}
		return result
	case map[string]interface{}:
		result, ok := value.(map[string]interface{})
		if ok == false {
			logger.Panic(`Could not parse object, check configuration near `, value)
		}
		for k, v := range result {
			result[k] = coerce(k, v)
		}
		return result
	default:
		return value
	}
}

// Read and decode JSON from the XBMC connection into the notification pointer.
func Read(response *Response) {
	err := decoder.Decode(&response)
	// Kick off the connection again on EOF, eat any decoding errors otherwise.
	// TODO: This probably needs to be more robust.
	if err == io.EOF {
		logger.Error(`Reading from Hyperion: `, err)
		Connect(connAddress)
	} else if err != nil {
		logger.Error(`Decoding response from Hyperion: `, err)
		return
	}
}

// Execute takes the callback and performs a JSON-RPC request over the
// established Hyperion connection.
func Execute(callback map[string]interface{}) {
	response := &Response{}

	// Drop properties that the backend doesn't understand, and coerce float64/int
	cb := make(map[string]interface{}, 0)
	for k, v := range callback {
		switch k {
		case `backend`, `types`:
			continue
		default:
			cb[k] = coerce(k, v)
		}
	}

	logger.Debug(`Sending request to Hyperion: `, cb)
	// Encode and send request
	if err := encoder.Encode(&cb); err != nil {
		logger.Error(`Sending to Hyperion: `, err)
	}
	// Check response and log any failure responses from Hyperion
	Read(response)
	logger.Debug(`Received response from Hyperion: `, response)
	if response.Success == false && response.Error != nil {
		logger.Warn(`Error received from Hyperion: `, response.Error)
	}
}
<|endoftext|>