<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 fake

import (
	"strings"

	"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/labels"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/runtime/serializer"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/watch"
	"k8s.io/client-go/dynamic"
	"k8s.io/client-go/testing"
)

func NewSimpleDynamicClient(scheme *runtime.Scheme, objects ...runtime.Object) *FakeDynamicClient {
	// In order to use List with this client, you have to have the v1.List registered in your scheme. Neat thing though
	// it does NOT have to be the *same* list
	scheme.AddKnownTypeWithName(schema.GroupVersionKind{Group: "fake-dynamic-client-group", Version: "v1", Kind: "List"}, &unstructured.UnstructuredList{})

	codecs := serializer.NewCodecFactory(scheme)
	o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder())
	for _, obj := range objects {
		if err := o.Add(obj); err != nil {
			panic(err)
		}
	}

	cs := &FakeDynamicClient{}
	cs.AddReactor("*", "*", testing.ObjectReaction(o))
	cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) {
		gvr := action.GetResource()
		ns := action.GetNamespace()
		watch, err := o.Watch(gvr, ns)
		if err != nil {
			return false, nil, err
		}
		return true, watch, nil
	})

	return cs
}

// Clientset implements clientset.Interface. Meant to be embedded into a
// struct to get a default implementation. This makes faking out just the method
// you want to test easier.
type FakeDynamicClient struct {
	testing.Fake
	scheme *runtime.Scheme
}

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

var _ dynamic.Interface = &FakeDynamicClient{}

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

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

func (c *dynamicResourceClient) Create(obj *unstructured.Unstructured, opts metav1.CreateOptions, subresources ...string) (*unstructured.Unstructured, error) {
	var uncastRet runtime.Object
	var err error
	switch {
	case len(c.namespace) == 0 && len(subresources) == 0:
		uncastRet, err = c.client.Fake.
			Invokes(testing.NewRootCreateAction(c.resource, obj), obj)

	case len(c.namespace) == 0 && len(subresources) > 0:
		accessor, err := meta.Accessor(obj)
		if err != nil {
			return nil, err
		}
		name := accessor.GetName()
		uncastRet, err = c.client.Fake.
			Invokes(testing.NewRootCreateSubresourceAction(c.resource, name, strings.Join(subresources, "/"), obj), obj)

	case len(c.namespace) > 0 && len(subresources) == 0:
		uncastRet, err = c.client.Fake.
			Invokes(testing.NewCreateAction(c.resource, c.namespace, obj), obj)

	case len(c.namespace) > 0 && len(subresources) > 0:
		accessor, err := meta.Accessor(obj)
		if err != nil {
			return nil, err
		}
		name := accessor.GetName()
		uncastRet, err = c.client.Fake.
			Invokes(testing.NewCreateSubresourceAction(c.resource, name, strings.Join(subresources, "/"), c.namespace, obj), obj)

	}

	if err != nil {
		return nil, err
	}
	if uncastRet == nil {
		return nil, err
	}

	ret := &unstructured.Unstructured{}
	if err := c.client.scheme.Convert(uncastRet, ret, nil); err != nil {
		return nil, err
	}
	return ret, err
}

func (c *dynamicResourceClient) Update(obj *unstructured.Unstructured, opts metav1.UpdateOptions, subresources ...string) (*unstructured.Unstructured, error) {
	var uncastRet runtime.Object
	var err error
	switch {
	case len(c.namespace) == 0 && len(subresources) == 0:
		uncastRet, err = c.client.Fake.
			Invokes(testing.NewRootUpdateAction(c.resource, obj), obj)

	case len(c.namespace) == 0 && len(subresources) > 0:
		uncastRet, err = c.client.Fake.
			Invokes(testing.NewRootUpdateSubresourceAction(c.resource, strings.Join(subresources, "/"), obj), obj)

	case len(c.namespace) > 0 && len(subresources) == 0:
		uncastRet, err = c.client.Fake.
			Invokes(testing.NewUpdateAction(c.resource, c.namespace, obj), obj)

	case len(c.namespace) > 0 && len(subresources) > 0:
		uncastRet, err = c.client.Fake.
			Invokes(testing.NewUpdateSubresourceAction(c.resource, strings.Join(subresources, "/"), c.namespace, obj), obj)

	}

	if err != nil {
		return nil, err
	}
	if uncastRet == nil {
		return nil, err
	}

	ret := &unstructured.Unstructured{}
	if err := c.client.scheme.Convert(uncastRet, ret, nil); err != nil {
		return nil, err
	}
	return ret, err
}

func (c *dynamicResourceClient) UpdateStatus(obj *unstructured.Unstructured, opts metav1.UpdateOptions) (*unstructured.Unstructured, error) {
	var uncastRet runtime.Object
	var err error
	switch {
	case len(c.namespace) == 0:
		uncastRet, err = c.client.Fake.
			Invokes(testing.NewRootUpdateSubresourceAction(c.resource, "status", obj), obj)

	case len(c.namespace) > 0:
		uncastRet, err = c.client.Fake.
			Invokes(testing.NewUpdateSubresourceAction(c.resource, "status", c.namespace, obj), obj)

	}

	if err != nil {
		return nil, err
	}
	if uncastRet == nil {
		return nil, err
	}

	ret := &unstructured.Unstructured{}
	if err := c.client.scheme.Convert(uncastRet, ret, nil); err != nil {
		return nil, err
	}
	return ret, err
}

func (c *dynamicResourceClient) Delete(name string, opts *metav1.DeleteOptions, subresources ...string) error {
	var err error
	switch {
	case len(c.namespace) == 0 && len(subresources) == 0:
		_, err = c.client.Fake.
			Invokes(testing.NewRootDeleteAction(c.resource, name), &metav1.Status{Status: "dynamic delete fail"})

	case len(c.namespace) == 0 && len(subresources) > 0:
		_, err = c.client.Fake.
			Invokes(testing.NewRootDeleteSubresourceAction(c.resource, strings.Join(subresources, "/"), name), &metav1.Status{Status: "dynamic delete fail"})

	case len(c.namespace) > 0 && len(subresources) == 0:
		_, err = c.client.Fake.
			Invokes(testing.NewDeleteAction(c.resource, c.namespace, name), &metav1.Status{Status: "dynamic delete fail"})

	case len(c.namespace) > 0 && len(subresources) > 0:
		_, err = c.client.Fake.
			Invokes(testing.NewDeleteSubresourceAction(c.resource, strings.Join(subresources, "/"), c.namespace, name), &metav1.Status{Status: "dynamic delete fail"})
	}

	return err
}

func (c *dynamicResourceClient) DeleteCollection(opts *metav1.DeleteOptions, listOptions metav1.ListOptions) error {
	var err error
	switch {
	case len(c.namespace) == 0:
		action := testing.NewRootDeleteCollectionAction(c.resource, listOptions)
		_, err = c.client.Fake.Invokes(action, &metav1.Status{Status: "dynamic deletecollection fail"})

	case len(c.namespace) > 0:
		action := testing.NewDeleteCollectionAction(c.resource, c.namespace, listOptions)
		_, err = c.client.Fake.Invokes(action, &metav1.Status{Status: "dynamic deletecollection fail"})

	}

	return err
}

func (c *dynamicResourceClient) Get(name string, opts metav1.GetOptions, subresources ...string) (*unstructured.Unstructured, error) {
	var uncastRet runtime.Object
	var err error
	switch {
	case len(c.namespace) == 0 && len(subresources) == 0:
		uncastRet, err = c.client.Fake.
			Invokes(testing.NewRootGetAction(c.resource, name), &metav1.Status{Status: "dynamic get fail"})

	case len(c.namespace) == 0 && len(subresources) > 0:
		uncastRet, err = c.client.Fake.
			Invokes(testing.NewRootGetSubresourceAction(c.resource, strings.Join(subresources, "/"), name), &metav1.Status{Status: "dynamic get fail"})

	case len(c.namespace) > 0 && len(subresources) == 0:
		uncastRet, err = c.client.Fake.
			Invokes(testing.NewGetAction(c.resource, c.namespace, name), &metav1.Status{Status: "dynamic get fail"})

	case len(c.namespace) > 0 && len(subresources) > 0:
		uncastRet, err = c.client.Fake.
			Invokes(testing.NewGetSubresourceAction(c.resource, c.namespace, strings.Join(subresources, "/"), name), &metav1.Status{Status: "dynamic get fail"})
	}

	if err != nil {
		return nil, err
	}
	if uncastRet == nil {
		return nil, err
	}

	ret := &unstructured.Unstructured{}
	if err := c.client.scheme.Convert(uncastRet, ret, nil); err != nil {
		return nil, err
	}
	return ret, err
}

func (c *dynamicResourceClient) List(opts metav1.ListOptions) (*unstructured.UnstructuredList, error) {
	var obj runtime.Object
	var err error
	switch {
	case len(c.namespace) == 0:
		obj, err = c.client.Fake.
			Invokes(testing.NewRootListAction(c.resource, schema.GroupVersionKind{Group: "fake-dynamic-client-group", Version: "v1", Kind: "" /*List is appended by the tracker automatically*/}, opts), &metav1.Status{Status: "dynamic list fail"})

	case len(c.namespace) > 0:
		obj, err = c.client.Fake.
			Invokes(testing.NewListAction(c.resource, schema.GroupVersionKind{Group: "fake-dynamic-client-group", Version: "v1", Kind: "" /*List is appended by the tracker automatically*/}, c.namespace, opts), &metav1.Status{Status: "dynamic list fail"})

	}

	if obj == nil {
		return nil, err
	}

	label, _, _ := testing.ExtractFromListOptions(opts)
	if label == nil {
		label = labels.Everything()
	}

	retUnstructured := &unstructured.Unstructured{}
	if err := c.client.scheme.Convert(obj, retUnstructured, nil); err != nil {
		return nil, err
	}
	entireList, err := retUnstructured.ToList()
	if err != nil {
		return nil, err
	}

	list := &unstructured.UnstructuredList{}
	for i := range entireList.Items {
		item := &entireList.Items[i]
		metadata, err := meta.Accessor(item)
		if err != nil {
			return nil, err
		}
		if label.Matches(labels.Set(metadata.GetLabels())) {
			list.Items = append(list.Items, *item)
		}
	}
	return list, nil
}

func (c *dynamicResourceClient) Watch(opts metav1.ListOptions) (watch.Interface, error) {
	switch {
	case len(c.namespace) == 0:
		return c.client.Fake.
			InvokesWatch(testing.NewRootWatchAction(c.resource, opts))

	case len(c.namespace) > 0:
		return c.client.Fake.
			InvokesWatch(testing.NewWatchAction(c.resource, c.namespace, opts))

	}

	panic("math broke")
}

func (c *dynamicResourceClient) Patch(name string, pt types.PatchType, data []byte, opts metav1.UpdateOptions, subresources ...string) (*unstructured.Unstructured, error) {
	var uncastRet runtime.Object
	var err error
	switch {
	case len(c.namespace) == 0 && len(subresources) == 0:
		uncastRet, err = c.client.Fake.
			Invokes(testing.NewRootPatchAction(c.resource, name, data), &metav1.Status{Status: "dynamic patch fail"})

	case len(c.namespace) == 0 && len(subresources) > 0:
		uncastRet, err = c.client.Fake.
			Invokes(testing.NewRootPatchSubresourceAction(c.resource, name, data, subresources...), &metav1.Status{Status: "dynamic patch fail"})

	case len(c.namespace) > 0 && len(subresources) == 0:
		uncastRet, err = c.client.Fake.
			Invokes(testing.NewPatchAction(c.resource, c.namespace, name, data), &metav1.Status{Status: "dynamic patch fail"})

	case len(c.namespace) > 0 && len(subresources) > 0:
		uncastRet, err = c.client.Fake.
			Invokes(testing.NewPatchSubresourceAction(c.resource, c.namespace, name, data, subresources...), &metav1.Status{Status: "dynamic patch fail"})

	}

	if err != nil {
		return nil, err
	}
	if uncastRet == nil {
		return nil, err
	}

	ret := &unstructured.Unstructured{}
	if err := c.client.scheme.Convert(uncastRet, ret, nil); err != nil {
		return nil, err
	}
	return ret, err
}
<commit_msg>Populates the fake dynamic client scheme<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 fake

import (
	"strings"

	"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/labels"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/runtime/serializer"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/watch"
	"k8s.io/client-go/dynamic"
	"k8s.io/client-go/testing"
)

func NewSimpleDynamicClient(scheme *runtime.Scheme, objects ...runtime.Object) *FakeDynamicClient {
	// In order to use List with this client, you have to have the v1.List registered in your scheme. Neat thing though
	// it does NOT have to be the *same* list
	scheme.AddKnownTypeWithName(schema.GroupVersionKind{Group: "fake-dynamic-client-group", Version: "v1", Kind: "List"}, &unstructured.UnstructuredList{})

	codecs := serializer.NewCodecFactory(scheme)
	o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder())
	for _, obj := range objects {
		if err := o.Add(obj); err != nil {
			panic(err)
		}
	}

	cs := &FakeDynamicClient{scheme: scheme}
	cs.AddReactor("*", "*", testing.ObjectReaction(o))
	cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) {
		gvr := action.GetResource()
		ns := action.GetNamespace()
		watch, err := o.Watch(gvr, ns)
		if err != nil {
			return false, nil, err
		}
		return true, watch, nil
	})

	return cs
}

// Clientset implements clientset.Interface. Meant to be embedded into a
// struct to get a default implementation. This makes faking out just the method
// you want to test easier.
type FakeDynamicClient struct {
	testing.Fake
	scheme *runtime.Scheme
}

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

var _ dynamic.Interface = &FakeDynamicClient{}

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

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

func (c *dynamicResourceClient) Create(obj *unstructured.Unstructured, opts metav1.CreateOptions, subresources ...string) (*unstructured.Unstructured, error) {
	var uncastRet runtime.Object
	var err error
	switch {
	case len(c.namespace) == 0 && len(subresources) == 0:
		uncastRet, err = c.client.Fake.
			Invokes(testing.NewRootCreateAction(c.resource, obj), obj)

	case len(c.namespace) == 0 && len(subresources) > 0:
		accessor, err := meta.Accessor(obj)
		if err != nil {
			return nil, err
		}
		name := accessor.GetName()
		uncastRet, err = c.client.Fake.
			Invokes(testing.NewRootCreateSubresourceAction(c.resource, name, strings.Join(subresources, "/"), obj), obj)

	case len(c.namespace) > 0 && len(subresources) == 0:
		uncastRet, err = c.client.Fake.
			Invokes(testing.NewCreateAction(c.resource, c.namespace, obj), obj)

	case len(c.namespace) > 0 && len(subresources) > 0:
		accessor, err := meta.Accessor(obj)
		if err != nil {
			return nil, err
		}
		name := accessor.GetName()
		uncastRet, err = c.client.Fake.
			Invokes(testing.NewCreateSubresourceAction(c.resource, name, strings.Join(subresources, "/"), c.namespace, obj), obj)

	}

	if err != nil {
		return nil, err
	}
	if uncastRet == nil {
		return nil, err
	}

	ret := &unstructured.Unstructured{}
	if err := c.client.scheme.Convert(uncastRet, ret, nil); err != nil {
		return nil, err
	}
	return ret, err
}

func (c *dynamicResourceClient) Update(obj *unstructured.Unstructured, opts metav1.UpdateOptions, subresources ...string) (*unstructured.Unstructured, error) {
	var uncastRet runtime.Object
	var err error
	switch {
	case len(c.namespace) == 0 && len(subresources) == 0:
		uncastRet, err = c.client.Fake.
			Invokes(testing.NewRootUpdateAction(c.resource, obj), obj)

	case len(c.namespace) == 0 && len(subresources) > 0:
		uncastRet, err = c.client.Fake.
			Invokes(testing.NewRootUpdateSubresourceAction(c.resource, strings.Join(subresources, "/"), obj), obj)

	case len(c.namespace) > 0 && len(subresources) == 0:
		uncastRet, err = c.client.Fake.
			Invokes(testing.NewUpdateAction(c.resource, c.namespace, obj), obj)

	case len(c.namespace) > 0 && len(subresources) > 0:
		uncastRet, err = c.client.Fake.
			Invokes(testing.NewUpdateSubresourceAction(c.resource, strings.Join(subresources, "/"), c.namespace, obj), obj)

	}

	if err != nil {
		return nil, err
	}
	if uncastRet == nil {
		return nil, err
	}

	ret := &unstructured.Unstructured{}
	if err := c.client.scheme.Convert(uncastRet, ret, nil); err != nil {
		return nil, err
	}
	return ret, err
}

func (c *dynamicResourceClient) UpdateStatus(obj *unstructured.Unstructured, opts metav1.UpdateOptions) (*unstructured.Unstructured, error) {
	var uncastRet runtime.Object
	var err error
	switch {
	case len(c.namespace) == 0:
		uncastRet, err = c.client.Fake.
			Invokes(testing.NewRootUpdateSubresourceAction(c.resource, "status", obj), obj)

	case len(c.namespace) > 0:
		uncastRet, err = c.client.Fake.
			Invokes(testing.NewUpdateSubresourceAction(c.resource, "status", c.namespace, obj), obj)

	}

	if err != nil {
		return nil, err
	}
	if uncastRet == nil {
		return nil, err
	}

	ret := &unstructured.Unstructured{}
	if err := c.client.scheme.Convert(uncastRet, ret, nil); err != nil {
		return nil, err
	}
	return ret, err
}

func (c *dynamicResourceClient) Delete(name string, opts *metav1.DeleteOptions, subresources ...string) error {
	var err error
	switch {
	case len(c.namespace) == 0 && len(subresources) == 0:
		_, err = c.client.Fake.
			Invokes(testing.NewRootDeleteAction(c.resource, name), &metav1.Status{Status: "dynamic delete fail"})

	case len(c.namespace) == 0 && len(subresources) > 0:
		_, err = c.client.Fake.
			Invokes(testing.NewRootDeleteSubresourceAction(c.resource, strings.Join(subresources, "/"), name), &metav1.Status{Status: "dynamic delete fail"})

	case len(c.namespace) > 0 && len(subresources) == 0:
		_, err = c.client.Fake.
			Invokes(testing.NewDeleteAction(c.resource, c.namespace, name), &metav1.Status{Status: "dynamic delete fail"})

	case len(c.namespace) > 0 && len(subresources) > 0:
		_, err = c.client.Fake.
			Invokes(testing.NewDeleteSubresourceAction(c.resource, strings.Join(subresources, "/"), c.namespace, name), &metav1.Status{Status: "dynamic delete fail"})
	}

	return err
}

func (c *dynamicResourceClient) DeleteCollection(opts *metav1.DeleteOptions, listOptions metav1.ListOptions) error {
	var err error
	switch {
	case len(c.namespace) == 0:
		action := testing.NewRootDeleteCollectionAction(c.resource, listOptions)
		_, err = c.client.Fake.Invokes(action, &metav1.Status{Status: "dynamic deletecollection fail"})

	case len(c.namespace) > 0:
		action := testing.NewDeleteCollectionAction(c.resource, c.namespace, listOptions)
		_, err = c.client.Fake.Invokes(action, &metav1.Status{Status: "dynamic deletecollection fail"})

	}

	return err
}

func (c *dynamicResourceClient) Get(name string, opts metav1.GetOptions, subresources ...string) (*unstructured.Unstructured, error) {
	var uncastRet runtime.Object
	var err error
	switch {
	case len(c.namespace) == 0 && len(subresources) == 0:
		uncastRet, err = c.client.Fake.
			Invokes(testing.NewRootGetAction(c.resource, name), &metav1.Status{Status: "dynamic get fail"})

	case len(c.namespace) == 0 && len(subresources) > 0:
		uncastRet, err = c.client.Fake.
			Invokes(testing.NewRootGetSubresourceAction(c.resource, strings.Join(subresources, "/"), name), &metav1.Status{Status: "dynamic get fail"})

	case len(c.namespace) > 0 && len(subresources) == 0:
		uncastRet, err = c.client.Fake.
			Invokes(testing.NewGetAction(c.resource, c.namespace, name), &metav1.Status{Status: "dynamic get fail"})

	case len(c.namespace) > 0 && len(subresources) > 0:
		uncastRet, err = c.client.Fake.
			Invokes(testing.NewGetSubresourceAction(c.resource, c.namespace, strings.Join(subresources, "/"), name), &metav1.Status{Status: "dynamic get fail"})
	}

	if err != nil {
		return nil, err
	}
	if uncastRet == nil {
		return nil, err
	}

	ret := &unstructured.Unstructured{}
	if err := c.client.scheme.Convert(uncastRet, ret, nil); err != nil {
		return nil, err
	}
	return ret, err
}

func (c *dynamicResourceClient) List(opts metav1.ListOptions) (*unstructured.UnstructuredList, error) {
	var obj runtime.Object
	var err error
	switch {
	case len(c.namespace) == 0:
		obj, err = c.client.Fake.
			Invokes(testing.NewRootListAction(c.resource, schema.GroupVersionKind{Group: "fake-dynamic-client-group", Version: "v1", Kind: "" /*List is appended by the tracker automatically*/}, opts), &metav1.Status{Status: "dynamic list fail"})

	case len(c.namespace) > 0:
		obj, err = c.client.Fake.
			Invokes(testing.NewListAction(c.resource, schema.GroupVersionKind{Group: "fake-dynamic-client-group", Version: "v1", Kind: "" /*List is appended by the tracker automatically*/}, c.namespace, opts), &metav1.Status{Status: "dynamic list fail"})

	}

	if obj == nil {
		return nil, err
	}

	label, _, _ := testing.ExtractFromListOptions(opts)
	if label == nil {
		label = labels.Everything()
	}

	retUnstructured := &unstructured.Unstructured{}
	if err := c.client.scheme.Convert(obj, retUnstructured, nil); err != nil {
		return nil, err
	}
	entireList, err := retUnstructured.ToList()
	if err != nil {
		return nil, err
	}

	list := &unstructured.UnstructuredList{}
	for i := range entireList.Items {
		item := &entireList.Items[i]
		metadata, err := meta.Accessor(item)
		if err != nil {
			return nil, err
		}
		if label.Matches(labels.Set(metadata.GetLabels())) {
			list.Items = append(list.Items, *item)
		}
	}
	return list, nil
}

func (c *dynamicResourceClient) Watch(opts metav1.ListOptions) (watch.Interface, error) {
	switch {
	case len(c.namespace) == 0:
		return c.client.Fake.
			InvokesWatch(testing.NewRootWatchAction(c.resource, opts))

	case len(c.namespace) > 0:
		return c.client.Fake.
			InvokesWatch(testing.NewWatchAction(c.resource, c.namespace, opts))

	}

	panic("math broke")
}

func (c *dynamicResourceClient) Patch(name string, pt types.PatchType, data []byte, opts metav1.UpdateOptions, subresources ...string) (*unstructured.Unstructured, error) {
	var uncastRet runtime.Object
	var err error
	switch {
	case len(c.namespace) == 0 && len(subresources) == 0:
		uncastRet, err = c.client.Fake.
			Invokes(testing.NewRootPatchAction(c.resource, name, data), &metav1.Status{Status: "dynamic patch fail"})

	case len(c.namespace) == 0 && len(subresources) > 0:
		uncastRet, err = c.client.Fake.
			Invokes(testing.NewRootPatchSubresourceAction(c.resource, name, data, subresources...), &metav1.Status{Status: "dynamic patch fail"})

	case len(c.namespace) > 0 && len(subresources) == 0:
		uncastRet, err = c.client.Fake.
			Invokes(testing.NewPatchAction(c.resource, c.namespace, name, data), &metav1.Status{Status: "dynamic patch fail"})

	case len(c.namespace) > 0 && len(subresources) > 0:
		uncastRet, err = c.client.Fake.
			Invokes(testing.NewPatchSubresourceAction(c.resource, c.namespace, name, data, subresources...), &metav1.Status{Status: "dynamic patch fail"})

	}

	if err != nil {
		return nil, err
	}
	if uncastRet == nil {
		return nil, err
	}

	ret := &unstructured.Unstructured{}
	if err := c.client.scheme.Convert(uncastRet, ret, nil); err != nil {
		return nil, err
	}
	return ret, err
}
<|endoftext|>


<commit_before>package fsutil

import (
	"testing"

	"github.com/rjeczalik/tools/fs/memfs"
)

var tree = []byte(".\na\n\tb1\n\t\tc1\n\t\t\tc1.txt\n\t\tc2\n\t\t\tc2.txt\n\t\t" +
	"c3\n\t\t\tc3.txt\n\t\t\td1\n\t\t\t\te1\n\t\t\t\t\t_\n\t\t\t\t\t\t_.txt" +
	"\n\t\t\t\t\te1.txt\n\t\t\t\t\te2.txt\n\t\t\t\t\te/\n\tb2\n\t\tc1\n\t\t" +
	"\td1.txt\n\t\t\td2/\n\t\t\td3.txt\na.txt\nw\n\tw.txt\n\tx\n\t\ty\n\t\t" +
	"\tz\n\t\t\t\t1.txt\n\t\ty.txt\n")

func TestTee(t *testing.T) {
	fs := memfs.Must(memfs.TabTree(tree))
	cases := [...]struct {
		open []string
		read []string
		fs   []byte
	}{{
		open: []string{"/w/x/y/z"},
		fs:   []byte(".\nw\n\tx\n\t\ty\n\t\t\tz/"),
	}, {
		open: []string{"/a.txt", "/w/w.txt", "/a"},
		fs:   []byte(".\na/\na.txt\nw\n\tw.txt"),
	}, {
		read: []string{"/a/b2/c1"},
		fs:   []byte(".\na\n\tb2\n\t\tc1\n\t\t\td1.txt\n\t\t\td2/\n\t\t\td3.txt"),
	}, {
		read: []string{"/a/b1/c1", "/a/b1/c2", "/a/b1/c3"},
		fs: []byte(".\na\n\tb1\n\t\tc1\n\t\t\tc1.txt\n\t\tc2\n\t\t\tc2.txt\n\t\t" +
			"c3\n\t\t\tc3.txt\n\t\t\td1/"),
		// TODO(rjeczalik)
		// }, {
		//	read: []string{"/w", "/w/x/y", "/w/x/y/z", "/w/x"},
		//	fs:   []byte(".\nw\n\tw.txt\n\tx\n\t\ty\n\t\t\tz\n\t\t\t\t1.txt\n\t\ty.txt"),
	}}
LOOP:
	for i, cas := range cases {
		spy := memfs.FS{Tree: memfs.Directory{}}
		tee := TeeFilesystem(fs, spy)
		for j, path := range cas.open {
			if _, err := tee.Open(path); err != nil {
				t.Errorf("want err=nil; got %q (i=%d, j=%d)", err, i, j)
				continue LOOP
			}
		}
		for j, path := range cas.read {
			f, err := tee.Open(path)
			if err != nil {
				t.Errorf("want err=nil; got %q (i=%d, j=%d)", err, i, j)
				continue LOOP
			}
			if _, err = f.Readdir(0); err != nil {
				t.Errorf("want err=nil; got %q (i=%d, j=%d)", err, i, j)
				continue LOOP
			}
		}
		x := memfs.Must(memfs.TabTree(cas.fs))
		if !memfs.Compare(spy, x) {
			t.Errorf("want Compare(...)=true; got false (i=%d)", i)
		}
	}
}
<commit_msg>fs/fsutil: Add a test-case for TeeFilesystem<commit_after>package fsutil

import (
	"testing"

	"github.com/rjeczalik/tools/fs/memfs"
)

var tree = []byte(".\na\n\tb1\n\t\tc1\n\t\t\tc1.txt\n\t\tc2\n\t\t\tc2.txt\n\t\t" +
	"c3\n\t\t\tc3.txt\n\t\t\td1\n\t\t\t\te1\n\t\t\t\t\t_\n\t\t\t\t\t\t_.txt" +
	"\n\t\t\t\t\te1.txt\n\t\t\t\t\te2.txt\n\t\t\t\t\te/\n\tb2\n\t\tc1\n\t\t" +
	"\td1.txt\n\t\t\td2/\n\t\t\td3.txt\na.txt\nw\n\tw.txt\n\tx\n\t\ty\n\t\t" +
	"\tz\n\t\t\t\t1.txt\n\t\ty.txt\n")

func TestTee(t *testing.T) {
	fs := memfs.Must(memfs.TabTree(tree))
	cases := [...]struct {
		open []string
		read []string
		fs   []byte
	}{
		0: {
			open: []string{"/w/x/y/z"},
			fs:   []byte(".\nw\n\tx\n\t\ty\n\t\t\tz/"),
		},
		1: {
			open: []string{"/a.txt", "/w/w.txt", "/a"},
			fs:   []byte(".\na/\na.txt\nw\n\tw.txt"),
		},
		2: {
			read: []string{"/a/b2/c1"},
			fs:   []byte(".\na\n\tb2\n\t\tc1\n\t\t\td1.txt\n\t\t\td2/\n\t\t\td3.txt"),
		},
		3: {
			read: []string{"/a/b1/c1", "/a/b1/c2", "/a/b1/c3"},
			fs: []byte(".\na\n\tb1\n\t\tc1\n\t\t\tc1.txt\n\t\tc2\n\t\t\tc2.txt\n\t\t" +
				"c3\n\t\t\tc3.txt\n\t\t\td1/"),
		},
		4: {
			read: []string{"/w", "/w/x/y", "/w/x/y/z", "/w/x"},
			fs:   []byte(".\nw\n\tw.txt\n\tx\n\t\ty\n\t\t\tz\n\t\t\t\t1.txt\n\t\ty.txt"),
		}}
LOOP:
	for i, cas := range cases {
		if i != 4 {
			continue
		}
		spy := memfs.New()
		tee := TeeFilesystem(fs, spy)
		for j, path := range cas.open {
			if _, err := tee.Open(path); err != nil {
				t.Errorf("want err=nil; got %q (i=%d, j=%d)", err, i, j)
				continue LOOP
			}
		}
		for j, path := range cas.read {
			f, err := tee.Open(path)
			if err != nil {
				t.Errorf("want err=nil; got %q (i=%d, j=%d)", err, i, j)
				continue LOOP
			}
			if _, err = f.Readdir(0); err != nil {
				t.Errorf("want err=nil; got %q (i=%d, j=%d)", err, i, j)
				continue LOOP
			}
		}
		if !memfs.Compare(spy, memfs.Must(memfs.TabTree(cas.fs))) {
			t.Errorf("want Compare(...)=true; got false (i=%d)", i)
		}
	}
}
<|endoftext|>


<commit_before>package generator

import (
	"fmt"
	"log"
)

// getQueryInterface is going to cast the array of string to an array of
// interfaces adding the default parameter isPage in the position 0
func getQueryInterface(isPage bool, args ...string) []interface{} {
	// This funny casting is needed to call the sql .Query()
	sqlArgs := make([]interface{}, len(args)+1)
	sqlArgs[0] = interface{}(0)
	if isPage {
		sqlArgs[0] = interface{}(1)
	}
	for i, v := range args {
		sqlArgs[i+1] = interface{}(v)
	}
	return sqlArgs
}

func (site Site) Query(isPage bool, where string, args ...string) (files []*ParsedFile) {
	// In case that a where clausule needs to be added, add the AND at the beginning
	if where != "" {
		where = fmt.Sprintf("AND %s", where)
	}
	query := fmt.Sprintf(`
        SELECT title, slug, content, category, tags, date, summary
        FROM files
        WHERE is_page = ?
        AND status != 'draft'
        %s
        ORDER BY datetime(date) DESC
    `, where)

	sqlArgs := getQueryInterface(isPage, args...)
	rows, err := site.db.connection.Query(query, sqlArgs...)
	if err != nil {
		log.Panicf("Error querying '%s'\n%v", query, err)
	}

	for rows.Next() {
		file := &ParsedFile{isPage: isPage}
		rows.Scan(&file.Title, &file.Slug, &file.Content, &file.Category, &file.tags, &file.Date, &file.summary)
		files = append(files, file)
	}

	return files
}

func (site Site) QueryArticles(where string, args ...string) []*ParsedFile {
	return site.Query(false, where, args...)
}

func (site Site) QueryPages(where string, args ...string) []*ParsedFile {
	return site.Query(true, where, args...)
}
<commit_msg>Remove pointless casting<commit_after>package generator

import (
	"fmt"
	"log"
)

// getQueryInterface is going to cast the array of string to an array of
// interfaces adding the default parameter isPage in the position 0
func getQueryInterface(isPage bool, args ...string) []interface{} {
	// This funny casting is needed to call the sql .Query()
	sqlArgs := make([]interface{}, len(args)+1)
	sqlArgs[0] = 0
	if isPage {
		sqlArgs[0] = 1
	}
	for i, v := range args {
		sqlArgs[i+1] = interface{}(v)
	}
	return sqlArgs
}

func (site Site) Query(isPage bool, where string, args ...string) (files []*ParsedFile) {
	// In case that a where clausule needs to be added, add the AND at the beginning
	if where != "" {
		where = fmt.Sprintf("AND %s", where)
	}
	query := fmt.Sprintf(`
        SELECT title, slug, content, category, tags, date, summary
        FROM files
        WHERE is_page = ?
        AND status != 'draft'
        %s
        ORDER BY datetime(date) DESC
    `, where)

	sqlArgs := getQueryInterface(isPage, args...)
	rows, err := site.db.connection.Query(query, sqlArgs...)
	if err != nil {
		log.Panicf("Error querying '%s'\n%v", query, err)
	}

	for rows.Next() {
		file := &ParsedFile{isPage: isPage}
		rows.Scan(&file.Title, &file.Slug, &file.Content, &file.Category, &file.tags, &file.Date, &file.summary)
		files = append(files, file)
	}

	return files
}

func (site Site) QueryArticles(where string, args ...string) []*ParsedFile {
	return site.Query(false, where, args...)
}

func (site Site) QueryPages(where string, args ...string) []*ParsedFile {
	return site.Query(true, where, args...)
}
<|endoftext|>


<commit_before>/*

The analysis package defines the interface between a modular static
analysis and an analysis driver program.

THIS INTERFACE IS EXPERIMENTAL AND SUBJECT TO CHANGE.
We aim to finalize it by November 2018.

Background

A static analysis is a function that inspects a package of Go code and
reports a set of diagnostics (typically mistakes in the code), and
perhaps produces other results as well, such as suggested refactorings
or other facts. An analysis that reports mistakes is informally called a
"checker". For example, the printf checker reports mistakes in
fmt.Printf format strings.

A "modular" analysis is one that inspects one package at a time but can
save information from a lower-level package and use it when inspecting a
higher-level package, analogous to separate compilation in a toolchain.
The printf checker is modular: when it discovers that a function such as
log.Fatalf delegates to fmt.Printf, it records this fact, and checks
calls to that function too, including calls made from another package.

By implementing a common interface, checkers from a variety of sources
can be easily selected, incorporated, and reused in a wide range of
driver programs including command-line tools (such as vet), text editors and
IDEs, build and test systems (such as go build, Bazel, or Buck), test
frameworks, code review tools, code-base indexers (such as SourceGraph),
documentation viewers (such as godoc), batch pipelines for large code
bases, and so on.

Analyzer

The primary type in the API is Analyzer. An Analyzer statically
describes an analysis function: its name, documentation, flags,
relationship to other analyzers, and of course, its logic.

To define an analysis, a user declares a (logically constant) variable
of type Analyzer. Here is a typical example from one of the analyzers in
the go/analysis/passes/ subdirectory:

	package unusedresult

	var Analyzer = &analysis.Analyzer{
		Name:	"unusedresult",
		Doc:	"check for unused results of calls to some functions",
		Run:    run,
		...
	}

	func run(pass *analysis.Pass) (interface{}, error) {
		...
	}

An analysis driver is a program such as vet that runs a set of
analyses and prints the diagnostics that they report.
The driver program must import the list of Analyzers it needs.
Typically each Analyzer resides in a separate package.
To add a new Analyzer to an existing driver, add another item to the list:

	import ( "unusedresult"; "nilness"; "printf" )

	var analyses = []*analysis.Analyzer{
		unusedresult.Analyzer,
		nilness.Analyzer,
		printf.Analyzer,
	}

A driver may use the name, flags, and documentation to provide on-line
help that describes the analyses its performs.
The doc comment contains a brief one-line summary,
optionally followed by paragraphs of explanation.
The vet command, shown below, is an example of a driver that runs
multiple analyzers. It is based on the multichecker package
(see the "Standalone commands" section for details).

	$ go build golang.org/x/tools/go/analysis/cmd/vet
	$ ./vet help
	vet is a tool for static analysis of Go programs.

	Usage: vet [-flag] [package]

	Registered analyzers:

	    asmdecl      report mismatches between assembly files and Go declarations
	    assign       check for useless assignments
	    atomic       check for common mistakes using the sync/atomic package
	    ...
	    unusedresult check for unused results of calls to some functions

	$ ./vet help unusedresult
	unusedresult: check for unused results of calls to some functions

	Analyzer flags:

	  -unusedresult.funcs value
	        comma-separated list of functions whose results must be used (default Error,String)
	  -unusedresult.stringmethods value
	        comma-separated list of names of methods of type func() string whose results must be used

	Some functions like fmt.Errorf return a result and have no side effects,
	so it is always a mistake to discard the result. This analyzer reports
	calls to certain functions in which the result of the call is ignored.

	The set of functions may be controlled using flags.

The Analyzer type has more fields besides those shown above:

	type Analyzer struct {
		Name			string
		Doc			string
		Flags			flag.FlagSet
		Run			func(*Pass) (interface{}, error)
		RunDespiteErrors	bool
		ResultType		reflect.Type
		Requires		[]*Analyzer
		FactTypes		[]Fact
	}

The Flags field declares a set of named (global) flag variables that
control analysis behavior. Unlike vet, analysis flags are not declared
directly in the command line FlagSet; it is up to the driver to set the
flag variables. A driver for a single analysis, a, might expose its flag
f directly on the command line as -f, whereas a driver for multiple
analyses might prefix the flag name by the analysis name (-a.f) to avoid
ambiguity. An IDE might expose the flags through a graphical interface,
and a batch pipeline might configure them from a config file.
See the "findcall" analyzer for an example of flags in action.

The RunDespiteErrors flag indicates whether the analysis is equipped to
handle ill-typed code. If not, the driver will skip the analysis if
there were parse or type errors.
The optional ResultType field specifies the type of the result value
computed by this analysis and made available to other analyses.
The Requires field specifies a list of analyses upon which
this one depends and whose results it may access, and it constrains the
order in which a driver may run analyses.
The FactTypes field is discussed in the section on Modularity.
The analysis package provides a Validate function to perform basic
sanity checks on an Analyzer, such as that its Requires graph is
acyclic, its fact and result types are unique, and so on.

Finally, the Run field contains a function to be called by the driver to
execute the analysis on a single package. The driver passes it an
instance of the Pass type.

Pass

A Pass describes a single unit of work: the application of a particular
Analyzer to a particular package of Go code.
The Pass provides information to the Analyzer's Run function about the
package being analyzed, and provides operations to the Run function for
reporting diagnostics and other information back to the driver.

	type Pass struct {
		Fset   		*token.FileSet
		Files		[]*ast.File
		OtherFiles	[]string
		Pkg		*types.Package
		TypesInfo	*types.Info
		ResultOf	map[*Analyzer]interface{}
		Report		func(Diagnostic)
		...
	}

The Fset, Files, Pkg, and TypesInfo fields provide the syntax trees,
type information, and source positions for a single package of Go code.

The OtherFiles field provides the names, but not the contents, of non-Go
files such as assembly that are part of this package. See the "asmdecl"
or "buildtags" analyzers for examples of loading non-Go files and report
diagnostics against them.

The ResultOf field provides the results computed by the analyzers
required by this one, as expressed in its Analyzer.Requires field. The
driver runs the required analyzers first and makes their results
available in this map. Each Analyzer must return a value of the type
described in its Analyzer.ResultType field.
For example, the "ctrlflow" analyzer returns a *ctrlflow.CFGs, which
provides a control-flow graph for each function in the package (see
golang.org/x/tools/go/cfg); the "inspect" analyzer returns a value that
enables other Analyzers to traverse the syntax trees of the package more
efficiently; and the "buildssa" analyzer constructs an SSA-form
intermediate representation.
Each of these Analyzers extends the capabilities of later Analyzers
without adding a dependency to the core API, so an analysis tool pays
only for the extensions it needs.

The Report function emits a diagnostic, a message associated with a
source position. For most analyses, diagnostics are their primary
result.
For convenience, Pass provides a helper method, Reportf, to report a new
diagnostic by formatting a string.
Diagnostic is defined as:

	type Diagnostic struct {
		Pos      token.Pos
		Category string // optional
		Message  string
	}

The optional Category field is a short identifier that classifies the
kind of message when an analysis produces several kinds of diagnostic.

Most Analyzers inspect typed Go syntax trees, but a few, such as asmdecl
and buildtag, inspect the raw text of Go source files or even non-Go
files such as assembly. To report a diagnostic against a line of a
raw text file, use the following sequence:

	content, err := ioutil.ReadFile(filename)
	if err != nil { ... }
	tf := fset.AddFile(filename, -1, len(content))
	tf.SetLinesForContent(content)
	...
	pass.Reportf(tf.LineStart(line), "oops")

Modular analysis with Facts

To improve efficiency and scalability, large programs are routinely
built using separate compilation: units of the program are compiled
separately, and recompiled only when one of their dependencies changes;
independent modules may be compiled in parallel. The same technique may
be applied to static analyses, for the same benefits. Such analyses are
described as "modular".

A compiler’s type checker is an example of a modular static analysis.
Many other checkers we would like to apply to Go programs can be
understood as alternative or non-standard type systems. For example,
vet's printf checker infers whether a function has the "printf wrapper"
type, and it applies stricter checks to calls of such functions. In
addition, it records which functions are printf wrappers for use by
later analysis units to identify other printf wrappers by induction.
A result such as “f is a printf wrapper” that is not interesting by
itself but serves as a stepping stone to an interesting result (such as
a diagnostic) is called a "fact".

The analysis API allows an analysis to define new types of facts, to
associate facts of these types with objects (named entities) declared
within the current package, or with the package as a whole, and to query
for an existing fact of a given type associated with an object or
package.

An Analyzer that uses facts must declare their types:

	var Analyzer = &analysis.Analyzer{
		Name:       "printf",
		FactTypes: []reflect.Type{reflect.TypeOf(new(isWrapper))},
		...
	}

	type isWrapper struct{} // => *types.Func f “is a printf wrapper”

A driver program ensures that facts for a pass’s dependencies are
generated before analyzing the pass and are responsible for propagating
facts between from one pass to another, possibly across address spaces.
Consequently, Facts must be serializable. The API requires that drivers
use the gob encoding, an efficient, robust, self-describing binary
protocol. A fact type may implement the GobEncoder/GobDecoder interfaces
if the default encoding is unsuitable. Facts should be stateless.

The Pass type has functions to import and export facts,
associated either with an object or with a package:

	type Pass struct {
		...
		ExportObjectFact func(types.Object, Fact)
		ImportObjectFact func(types.Object, Fact) bool

		ExportPackageFact func(fact Fact)
		ImportPackageFact func(*types.Package, Fact) bool
	}

An Analyzer may only export facts associated with the current package or
its objects, though it may import facts from any package or object that
is an import dependency of the current package.

Conceptually, ExportObjectFact(obj, fact) inserts fact into a hidden map keyed by
the pair (obj, TypeOf(fact)), and the ImportObjectFact function
retrieves the entry from this map and copies its value into the variable
pointed to by fact. This scheme assumes that the concrete type of fact
is a pointer; this assumption is checked by the Validate function.
See the "printf" analyzer for an example of object facts in action.

Some driver implementations (such as those based on Bazel and Blaze) do
not currently apply analyzers to packages of the standard library.
Therefore, for best results, analyzer authors should not rely on
analysis facts being available for standard packages.
For example, although the printf checker is capable of deducing during
analysis of the log package that log.Printf is a printf-wrapper,
this fact is built in to the analyzer so that it correctly checks
calls to log.Printf even when run in a driver that does not apply
it to standard packages. We plan to remove this limitation in future.

Testing an Analyzer

The analysistest subpackage provides utilities for testing an Analyzer.
In a few lines of code, it is possible to run an analyzer on a package
of testdata files and check that it reported all the expected
diagnostics and facts (and no more). Expectations are expressed using
"// want ..." comments in the input code.

Standalone commands

Analyzers are provided in the form of packages that a driver program is
expected to import. The vet command imports a set of several analyzers,
but users may wish to define their own analysis commands that perform
additional checks. To simplify the task of creating an analysis command,
either for a single analyzer or for a whole suite, we provide the
singlechecker and multichecker subpackages.

The singlechecker package provides the main function for a command that
runs one analyzer. By convention, each analyzer such as
go/passes/findcall should be accompanied by a singlechecker-based
command such as go/analysis/passes/findcall/cmd/findcall, defined in its
entirety as:

	package main

	import (
		"golang.org/x/tools/go/analysis/passes/findcall"
		"golang.org/x/tools/go/analysis/singlechecker"
	)

	func main() { singlechecker.Main(findcall.Analyzer) }

A tool that provides multiple analyzers can use multichecker in a
similar way, giving it the list of Analyzers.

*/
package analysis
<commit_msg>go/analysis: remove "experimental" warning<commit_after>/*

The analysis package defines the interface between a modular static
analysis and an analysis driver program.

Background

A static analysis is a function that inspects a package of Go code and
reports a set of diagnostics (typically mistakes in the code), and
perhaps produces other results as well, such as suggested refactorings
or other facts. An analysis that reports mistakes is informally called a
"checker". For example, the printf checker reports mistakes in
fmt.Printf format strings.

A "modular" analysis is one that inspects one package at a time but can
save information from a lower-level package and use it when inspecting a
higher-level package, analogous to separate compilation in a toolchain.
The printf checker is modular: when it discovers that a function such as
log.Fatalf delegates to fmt.Printf, it records this fact, and checks
calls to that function too, including calls made from another package.

By implementing a common interface, checkers from a variety of sources
can be easily selected, incorporated, and reused in a wide range of
driver programs including command-line tools (such as vet), text editors and
IDEs, build and test systems (such as go build, Bazel, or Buck), test
frameworks, code review tools, code-base indexers (such as SourceGraph),
documentation viewers (such as godoc), batch pipelines for large code
bases, and so on.

Analyzer

The primary type in the API is Analyzer. An Analyzer statically
describes an analysis function: its name, documentation, flags,
relationship to other analyzers, and of course, its logic.

To define an analysis, a user declares a (logically constant) variable
of type Analyzer. Here is a typical example from one of the analyzers in
the go/analysis/passes/ subdirectory:

	package unusedresult

	var Analyzer = &analysis.Analyzer{
		Name:	"unusedresult",
		Doc:	"check for unused results of calls to some functions",
		Run:    run,
		...
	}

	func run(pass *analysis.Pass) (interface{}, error) {
		...
	}

An analysis driver is a program such as vet that runs a set of
analyses and prints the diagnostics that they report.
The driver program must import the list of Analyzers it needs.
Typically each Analyzer resides in a separate package.
To add a new Analyzer to an existing driver, add another item to the list:

	import ( "unusedresult"; "nilness"; "printf" )

	var analyses = []*analysis.Analyzer{
		unusedresult.Analyzer,
		nilness.Analyzer,
		printf.Analyzer,
	}

A driver may use the name, flags, and documentation to provide on-line
help that describes the analyses its performs.
The doc comment contains a brief one-line summary,
optionally followed by paragraphs of explanation.
The vet command, shown below, is an example of a driver that runs
multiple analyzers. It is based on the multichecker package
(see the "Standalone commands" section for details).

	$ go build golang.org/x/tools/go/analysis/cmd/vet
	$ ./vet help
	vet is a tool for static analysis of Go programs.

	Usage: vet [-flag] [package]

	Registered analyzers:

	    asmdecl      report mismatches between assembly files and Go declarations
	    assign       check for useless assignments
	    atomic       check for common mistakes using the sync/atomic package
	    ...
	    unusedresult check for unused results of calls to some functions

	$ ./vet help unusedresult
	unusedresult: check for unused results of calls to some functions

	Analyzer flags:

	  -unusedresult.funcs value
	        comma-separated list of functions whose results must be used (default Error,String)
	  -unusedresult.stringmethods value
	        comma-separated list of names of methods of type func() string whose results must be used

	Some functions like fmt.Errorf return a result and have no side effects,
	so it is always a mistake to discard the result. This analyzer reports
	calls to certain functions in which the result of the call is ignored.

	The set of functions may be controlled using flags.

The Analyzer type has more fields besides those shown above:

	type Analyzer struct {
		Name			string
		Doc			string
		Flags			flag.FlagSet
		Run			func(*Pass) (interface{}, error)
		RunDespiteErrors	bool
		ResultType		reflect.Type
		Requires		[]*Analyzer
		FactTypes		[]Fact
	}

The Flags field declares a set of named (global) flag variables that
control analysis behavior. Unlike vet, analysis flags are not declared
directly in the command line FlagSet; it is up to the driver to set the
flag variables. A driver for a single analysis, a, might expose its flag
f directly on the command line as -f, whereas a driver for multiple
analyses might prefix the flag name by the analysis name (-a.f) to avoid
ambiguity. An IDE might expose the flags through a graphical interface,
and a batch pipeline might configure them from a config file.
See the "findcall" analyzer for an example of flags in action.

The RunDespiteErrors flag indicates whether the analysis is equipped to
handle ill-typed code. If not, the driver will skip the analysis if
there were parse or type errors.
The optional ResultType field specifies the type of the result value
computed by this analysis and made available to other analyses.
The Requires field specifies a list of analyses upon which
this one depends and whose results it may access, and it constrains the
order in which a driver may run analyses.
The FactTypes field is discussed in the section on Modularity.
The analysis package provides a Validate function to perform basic
sanity checks on an Analyzer, such as that its Requires graph is
acyclic, its fact and result types are unique, and so on.

Finally, the Run field contains a function to be called by the driver to
execute the analysis on a single package. The driver passes it an
instance of the Pass type.

Pass

A Pass describes a single unit of work: the application of a particular
Analyzer to a particular package of Go code.
The Pass provides information to the Analyzer's Run function about the
package being analyzed, and provides operations to the Run function for
reporting diagnostics and other information back to the driver.

	type Pass struct {
		Fset   		*token.FileSet
		Files		[]*ast.File
		OtherFiles	[]string
		Pkg		*types.Package
		TypesInfo	*types.Info
		ResultOf	map[*Analyzer]interface{}
		Report		func(Diagnostic)
		...
	}

The Fset, Files, Pkg, and TypesInfo fields provide the syntax trees,
type information, and source positions for a single package of Go code.

The OtherFiles field provides the names, but not the contents, of non-Go
files such as assembly that are part of this package. See the "asmdecl"
or "buildtags" analyzers for examples of loading non-Go files and report
diagnostics against them.

The ResultOf field provides the results computed by the analyzers
required by this one, as expressed in its Analyzer.Requires field. The
driver runs the required analyzers first and makes their results
available in this map. Each Analyzer must return a value of the type
described in its Analyzer.ResultType field.
For example, the "ctrlflow" analyzer returns a *ctrlflow.CFGs, which
provides a control-flow graph for each function in the package (see
golang.org/x/tools/go/cfg); the "inspect" analyzer returns a value that
enables other Analyzers to traverse the syntax trees of the package more
efficiently; and the "buildssa" analyzer constructs an SSA-form
intermediate representation.
Each of these Analyzers extends the capabilities of later Analyzers
without adding a dependency to the core API, so an analysis tool pays
only for the extensions it needs.

The Report function emits a diagnostic, a message associated with a
source position. For most analyses, diagnostics are their primary
result.
For convenience, Pass provides a helper method, Reportf, to report a new
diagnostic by formatting a string.
Diagnostic is defined as:

	type Diagnostic struct {
		Pos      token.Pos
		Category string // optional
		Message  string
	}

The optional Category field is a short identifier that classifies the
kind of message when an analysis produces several kinds of diagnostic.

Most Analyzers inspect typed Go syntax trees, but a few, such as asmdecl
and buildtag, inspect the raw text of Go source files or even non-Go
files such as assembly. To report a diagnostic against a line of a
raw text file, use the following sequence:

	content, err := ioutil.ReadFile(filename)
	if err != nil { ... }
	tf := fset.AddFile(filename, -1, len(content))
	tf.SetLinesForContent(content)
	...
	pass.Reportf(tf.LineStart(line), "oops")

Modular analysis with Facts

To improve efficiency and scalability, large programs are routinely
built using separate compilation: units of the program are compiled
separately, and recompiled only when one of their dependencies changes;
independent modules may be compiled in parallel. The same technique may
be applied to static analyses, for the same benefits. Such analyses are
described as "modular".

A compiler’s type checker is an example of a modular static analysis.
Many other checkers we would like to apply to Go programs can be
understood as alternative or non-standard type systems. For example,
vet's printf checker infers whether a function has the "printf wrapper"
type, and it applies stricter checks to calls of such functions. In
addition, it records which functions are printf wrappers for use by
later analysis units to identify other printf wrappers by induction.
A result such as “f is a printf wrapper” that is not interesting by
itself but serves as a stepping stone to an interesting result (such as
a diagnostic) is called a "fact".

The analysis API allows an analysis to define new types of facts, to
associate facts of these types with objects (named entities) declared
within the current package, or with the package as a whole, and to query
for an existing fact of a given type associated with an object or
package.

An Analyzer that uses facts must declare their types:

	var Analyzer = &analysis.Analyzer{
		Name:       "printf",
		FactTypes: []reflect.Type{reflect.TypeOf(new(isWrapper))},
		...
	}

	type isWrapper struct{} // => *types.Func f “is a printf wrapper”

A driver program ensures that facts for a pass’s dependencies are
generated before analyzing the pass and are responsible for propagating
facts between from one pass to another, possibly across address spaces.
Consequently, Facts must be serializable. The API requires that drivers
use the gob encoding, an efficient, robust, self-describing binary
protocol. A fact type may implement the GobEncoder/GobDecoder interfaces
if the default encoding is unsuitable. Facts should be stateless.

The Pass type has functions to import and export facts,
associated either with an object or with a package:

	type Pass struct {
		...
		ExportObjectFact func(types.Object, Fact)
		ImportObjectFact func(types.Object, Fact) bool

		ExportPackageFact func(fact Fact)
		ImportPackageFact func(*types.Package, Fact) bool
	}

An Analyzer may only export facts associated with the current package or
its objects, though it may import facts from any package or object that
is an import dependency of the current package.

Conceptually, ExportObjectFact(obj, fact) inserts fact into a hidden map keyed by
the pair (obj, TypeOf(fact)), and the ImportObjectFact function
retrieves the entry from this map and copies its value into the variable
pointed to by fact. This scheme assumes that the concrete type of fact
is a pointer; this assumption is checked by the Validate function.
See the "printf" analyzer for an example of object facts in action.

Some driver implementations (such as those based on Bazel and Blaze) do
not currently apply analyzers to packages of the standard library.
Therefore, for best results, analyzer authors should not rely on
analysis facts being available for standard packages.
For example, although the printf checker is capable of deducing during
analysis of the log package that log.Printf is a printf-wrapper,
this fact is built in to the analyzer so that it correctly checks
calls to log.Printf even when run in a driver that does not apply
it to standard packages. We plan to remove this limitation in future.

Testing an Analyzer

The analysistest subpackage provides utilities for testing an Analyzer.
In a few lines of code, it is possible to run an analyzer on a package
of testdata files and check that it reported all the expected
diagnostics and facts (and no more). Expectations are expressed using
"// want ..." comments in the input code.

Standalone commands

Analyzers are provided in the form of packages that a driver program is
expected to import. The vet command imports a set of several analyzers,
but users may wish to define their own analysis commands that perform
additional checks. To simplify the task of creating an analysis command,
either for a single analyzer or for a whole suite, we provide the
singlechecker and multichecker subpackages.

The singlechecker package provides the main function for a command that
runs one analyzer. By convention, each analyzer such as
go/passes/findcall should be accompanied by a singlechecker-based
command such as go/analysis/passes/findcall/cmd/findcall, defined in its
entirety as:

	package main

	import (
		"golang.org/x/tools/go/analysis/passes/findcall"
		"golang.org/x/tools/go/analysis/singlechecker"
	)

	func main() { singlechecker.Main(findcall.Analyzer) }

A tool that provides multiple analyzers can use multichecker in a
similar way, giving it the list of Analyzers.

*/
package analysis
<|endoftext|>


<commit_before>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package libkb

import (
	"time"

	keybase1 "github.com/keybase/client/go/protocol"
	jsonw "github.com/keybase/go-jsonw"
)

const (
	DeviceIDLen    = 16
	DeviceIDSuffix = 0x18
)

func NewDeviceID() (keybase1.DeviceID, error) {
	var b []byte
	b, err := RandBytes(DeviceIDLen)
	if err != nil {
		return "", err
	}
	b[DeviceIDLen-1] = DeviceIDSuffix
	return keybase1.DeviceIDFromSlice(b)
}

type DeviceStatus struct {
	Provisioned  bool
	Keyed        bool
	KeyAvailable bool
}

type Device struct {
	ID          keybase1.DeviceID `json:"id"`
	Kid         keybase1.KID      `json:"kid,omitempty"`
	Description *string           `json:"name,omitempty"`
	Status      *int              `json:"status,omitempty"`
	Type        string            `json:"type"`
	CTime       keybase1.Time     `json:"ctime"`
	MTime       keybase1.Time     `json:"mtime"`
}

// NewPaperDevice creates a new paper backup key device
func NewPaperDevice(passphrasePrefix string) (*Device, error) {
	did, err := NewDeviceID()
	if err != nil {
		return nil, err
	}
	s := DeviceStatusActive
	desc := passphrasePrefix

	d := &Device{
		ID:          did,
		Type:        DeviceTypePaper,
		Status:      &s,
		Description: &desc,
	}
	return d, nil
}

func ParseDevice(jw *jsonw.Wrapper, t time.Time) (ret *Device, err error) {
	var obj Device
	if err = jw.UnmarshalAgain(&obj); err == nil {
		ret = &obj
		ret.CTime = keybase1.ToTime(t)
		ret.MTime = keybase1.ToTime(t)
	}
	return
}

func (d *Device) Merge(d2 *Device) {
	d.Type = d2.Type
	if d2.Kid.Exists() {
		d.Kid = d2.Kid
	}
	if d2.Description != nil {
		d.Description = d2.Description
	}
	if d2.Status != nil {
		d.Status = d2.Status
	}
	if d2.CTime.Before(d.CTime) && !d2.CTime.IsZero() {
		d.CTime = d2.CTime
	}
	if d2.MTime.After(d.MTime) || d.MTime.IsZero() {
		d.MTime = d2.MTime
	}
}

func (d *Device) Export(lt LinkType) (*jsonw.Wrapper, error) {
	dw, err := jsonw.NewObjectWrapper(d)
	if err != nil {
		return nil, err
	}

	if lt == SubkeyType {
		// subkeys shouldn't have name or type
		if err := dw.DeleteKey("name"); err != nil {
			return nil, err
		}
		if err := dw.DeleteKey("type"); err != nil {
			return nil, err
		}
	}

	return dw, nil
}

func (d *Device) ProtExport() *keybase1.Device {
	ex := &keybase1.Device{
		Type:     d.Type,
		DeviceID: d.ID,
		CTime:    d.CTime,
		MTime:    d.MTime,
	}
	if d.Description != nil {
		ex.Name = *d.Description
	}
	if d.Status != nil {
		ex.Status = *d.Status
	}
	return ex
}

func (d *Device) IsActive() bool {
	if d.Status == nil {
		return false
	}
	return *d.Status == DeviceStatusActive
}

func (d *Device) StatusString() string {
	return DeviceStatusToString(d.Status)
}

func DeviceStatusToString(i *int) string {
	if i == nil {
		return "<nil>"
	}
	switch *i {
	case DeviceStatusNone:
		return "none"
	case DeviceStatusActive:
		return "active"
	case DeviceStatusDefunct:
		return "revoked"
	}
	return "unknown"
}
<commit_msg>despam sigchain device objects<commit_after>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package libkb

import (
	"time"

	keybase1 "github.com/keybase/client/go/protocol"
	jsonw "github.com/keybase/go-jsonw"
)

const (
	DeviceIDLen    = 16
	DeviceIDSuffix = 0x18
)

func NewDeviceID() (keybase1.DeviceID, error) {
	var b []byte
	b, err := RandBytes(DeviceIDLen)
	if err != nil {
		return "", err
	}
	b[DeviceIDLen-1] = DeviceIDSuffix
	return keybase1.DeviceIDFromSlice(b)
}

type DeviceStatus struct {
	Provisioned  bool
	Keyed        bool
	KeyAvailable bool
}

type Device struct {
	ID          keybase1.DeviceID `json:"id"`
	Kid         keybase1.KID      `json:"kid,omitempty"`
	Description *string           `json:"name,omitempty"`
	Status      *int              `json:"status,omitempty"`
	Type        string            `json:"type"`
	CTime       keybase1.Time     `json:"ctime"`
	MTime       keybase1.Time     `json:"mtime"`
}

// NewPaperDevice creates a new paper backup key device
func NewPaperDevice(passphrasePrefix string) (*Device, error) {
	did, err := NewDeviceID()
	if err != nil {
		return nil, err
	}
	s := DeviceStatusActive
	desc := passphrasePrefix

	d := &Device{
		ID:          did,
		Type:        DeviceTypePaper,
		Status:      &s,
		Description: &desc,
	}
	return d, nil
}

func ParseDevice(jw *jsonw.Wrapper, t time.Time) (ret *Device, err error) {
	var obj Device
	if err = jw.UnmarshalAgain(&obj); err == nil {
		ret = &obj
		ret.CTime = keybase1.ToTime(t)
		ret.MTime = keybase1.ToTime(t)
	}
	return
}

func (d *Device) Merge(d2 *Device) {
	d.Type = d2.Type
	if d2.Kid.Exists() {
		d.Kid = d2.Kid
	}
	if d2.Description != nil {
		d.Description = d2.Description
	}
	if d2.Status != nil {
		d.Status = d2.Status
	}
	if d2.CTime.Before(d.CTime) && !d2.CTime.IsZero() {
		d.CTime = d2.CTime
	}
	if d2.MTime.After(d.MTime) || d.MTime.IsZero() {
		d.MTime = d2.MTime
	}
}

func (d *Device) Export(lt LinkType) (*jsonw.Wrapper, error) {
	dw, err := jsonw.NewObjectWrapper(d)
	if err != nil {
		return nil, err
	}

	if lt == SubkeyType {
		// subkeys shouldn't have name or type
		if err := dw.DeleteKey("name"); err != nil {
			return nil, err
		}
		if err := dw.DeleteKey("type"); err != nil {
			return nil, err
		}
	}

	// These were being set to 0, so don't include them
	dw.DeleteKey("mtime")
	dw.DeleteKey("ctime")

	return dw, nil
}

func (d *Device) ProtExport() *keybase1.Device {
	ex := &keybase1.Device{
		Type:     d.Type,
		DeviceID: d.ID,
		CTime:    d.CTime,
		MTime:    d.MTime,
	}
	if d.Description != nil {
		ex.Name = *d.Description
	}
	if d.Status != nil {
		ex.Status = *d.Status
	}
	return ex
}

func (d *Device) IsActive() bool {
	if d.Status == nil {
		return false
	}
	return *d.Status == DeviceStatusActive
}

func (d *Device) StatusString() string {
	return DeviceStatusToString(d.Status)
}

func DeviceStatusToString(i *int) string {
	if i == nil {
		return "<nil>"
	}
	switch *i {
	case DeviceStatusNone:
		return "none"
	case DeviceStatusActive:
		return "active"
	case DeviceStatusDefunct:
		return "revoked"
	}
	return "unknown"
}
<|endoftext|>


<commit_before>// Command p2b is a client for the pipetobrowser service. It pipes its
// standard input to a pipetobrowser service.
package main

import (
	"flag"
	"fmt"
	"io"
	"os"

	_ "v.io/core/veyron/profiles/static"
	"v.io/v23"
	"v.io/v23/vlog"

	"p2b/vdl"
)

const usage = `
%s is a Pipe To Browser client. It allows one to pipe any stdout stream from console to the browser.
Data being piped to the browser then is displayed in a graphical and formatted way by a "viewer".

Usage:

  %s [<name>/<viewer>]

  For example:

	ls -l | p2b google/p2b/jane/console

	or

	cat cat.jpg | p2b google/p2b/jane/image

  where <name> (google/p2b/jane) is the object name where p2b
  service is running in the browser. <viewer> (console, image) specifies what
  viewer should be used to display the data.

  To redirect stderr of a process, in *nix system you can use 2>&1 before piping to P2B.

  For example many daemons may write log lines to stderr instead of stdout:

  serverd -alsologtostderr=true 2>&1 | google/p2b/jane/vlog
`

func Usage() {
	fmt.Fprintf(os.Stdout, usage, os.Args[0], os.Args[0])
}

type sender interface {
	Send(p []byte) error
}

// viewerPipeStreamWriter adapts ViewerPipeStream to io.Writer
type viewerPipeStreamWriter struct {
	sender
}

func (w viewerPipeStreamWriter) Write(p []byte) (n int, err error) {
	w.Send(p)
	return len(p), nil
}

func main() {
	flag.Parse()
	flag.Usage = Usage

	if flag.NArg() != 1 {
		Usage()
		return
	}

	ctx, shutdown := v23.Init()
	defer shutdown()

	name := flag.Arg(0)

	// bind to the p2b service
	s := vdl.ViewerClient(name)

	stream, err := s.Pipe(ctx)
	if err != nil {
		vlog.Errorf("failed to pipe to '%s' please ensure p2b service is running in the browser and name is correct.\nERR:%v", name, err)
		return
	}

	w := viewerPipeStreamWriter{stream.SendStream()}

	_, err = io.Copy(w, os.Stdin)
	if err != nil {
		vlog.Errorf("failed to copy the stdin pipe to the outgoing stream\nERR:%v", err)
		return
	}

	_, err = stream.Finish()
	if err != nil {
		vlog.Errorf("error finishing stream: %v", err)
		return
	}

	fmt.Println("Finished piping to browser! Thanks for using p2b.")
}
<commit_msg>pipe2browser: moving vlog from release.go.v23 to release.go.x.lib<commit_after>// Command p2b is a client for the pipetobrowser service. It pipes its
// standard input to a pipetobrowser service.
package main

import (
	"flag"
	"fmt"
	"io"
	"os"

	_ "v.io/core/veyron/profiles/static"
	"v.io/v23"
	"v.io/x/lib/vlog"

	"p2b/vdl"
)

const usage = `
%s is a Pipe To Browser client. It allows one to pipe any stdout stream from console to the browser.
Data being piped to the browser then is displayed in a graphical and formatted way by a "viewer".

Usage:

  %s [<name>/<viewer>]

  For example:

	ls -l | p2b google/p2b/jane/console

	or

	cat cat.jpg | p2b google/p2b/jane/image

  where <name> (google/p2b/jane) is the object name where p2b
  service is running in the browser. <viewer> (console, image) specifies what
  viewer should be used to display the data.

  To redirect stderr of a process, in *nix system you can use 2>&1 before piping to P2B.

  For example many daemons may write log lines to stderr instead of stdout:

  serverd -alsologtostderr=true 2>&1 | google/p2b/jane/vlog
`

func Usage() {
	fmt.Fprintf(os.Stdout, usage, os.Args[0], os.Args[0])
}

type sender interface {
	Send(p []byte) error
}

// viewerPipeStreamWriter adapts ViewerPipeStream to io.Writer
type viewerPipeStreamWriter struct {
	sender
}

func (w viewerPipeStreamWriter) Write(p []byte) (n int, err error) {
	w.Send(p)
	return len(p), nil
}

func main() {
	flag.Parse()
	flag.Usage = Usage

	if flag.NArg() != 1 {
		Usage()
		return
	}

	ctx, shutdown := v23.Init()
	defer shutdown()

	name := flag.Arg(0)

	// bind to the p2b service
	s := vdl.ViewerClient(name)

	stream, err := s.Pipe(ctx)
	if err != nil {
		vlog.Errorf("failed to pipe to '%s' please ensure p2b service is running in the browser and name is correct.\nERR:%v", name, err)
		return
	}

	w := viewerPipeStreamWriter{stream.SendStream()}

	_, err = io.Copy(w, os.Stdin)
	if err != nil {
		vlog.Errorf("failed to copy the stdin pipe to the outgoing stream\nERR:%v", err)
		return
	}

	_, err = stream.Finish()
	if err != nil {
		vlog.Errorf("error finishing stream: %v", err)
		return
	}

	fmt.Println("Finished piping to browser! Thanks for using p2b.")
}
<|endoftext|>


<commit_before>package tchannel

// Copyright (c) 2015 Uber Technologies, Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

import (
	"github.com/uber/tchannel/golang/typed"
	"io"
	"time"
)

// Type of message
type messageType byte

const (
	messageTypeInitReq         messageType = 0x01
	messageTypeInitRes         messageType = 0x02
	messageTypeCallReq         messageType = 0x03
	messageTypeCallRes         messageType = 0x04
	messageTypeCallReqContinue messageType = 0x13
	messageTypeCallResContinue messageType = 0x14
	messageTypeError           messageType = 0xFF
)

var messageTypeNames = map[messageType]string{
	messageTypeInitReq:         "initReq",
	messageTypeInitRes:         "InitRes",
	messageTypeCallReq:         "CallReq",
	messageTypeCallReqContinue: "CallReqContinue",
	messageTypeCallRes:         "CallRes",
	messageTypeCallResContinue: "CallResContinue",
	messageTypeError:           "Error",
}

func (t messageType) String() string {
	return messageTypeNames[t]
}

// Base interface for messages.  Has an id and a type, and knows how to read and write onto a binary stream
type message interface {
	// The id of the message
	ID() uint32

	// The type of the message
	messageType() messageType

	read(r typed.ReadBuffer) error
	write(r typed.WriteBuffer) error
}

// Parameters to an initReq/InitRes
type initParams map[string]string

// Standard init params
const (
	InitParamHostPort    = "host_port"
	InitParamProcessName = "process_name"
)

type initMessage struct {
	id         uint32
	Version    uint16
	initParams initParams
}

func (m *initMessage) read(r typed.ReadBuffer) error {
	var err error
	m.Version, err = r.ReadUint16()
	if err != nil {
		return err
	}

	m.initParams = initParams{}
	for {
		klen, err := r.ReadUint16()
		if err == io.EOF {
			return nil
		}

		k, err := r.ReadString(int(klen))
		if err != nil {
			return err
		}

		vlen, err := r.ReadUint16()
		if err != nil {
			return err
		}

		v, err := r.ReadString(int(vlen))
		if err != nil {
			return err
		}

		m.initParams[k] = v
	}
}

func (m *initMessage) write(w typed.WriteBuffer) error {
	if err := w.WriteUint16(m.Version); err != nil {
		return err
	}

	for k, v := range m.initParams {
		if err := w.WriteUint16(uint16(len(k))); err != nil {
			return err
		}

		if err := w.WriteString(k); err != nil {
			return err
		}

		if err := w.WriteUint16(uint16(len(v))); err != nil {
			return err
		}

		if err := w.WriteString(v); err != nil {
			return err
		}
	}

	return nil
}

func (m *initMessage) ID() uint32 {
	return m.id
}

// An initReq, containing context information to exchange with peer
type initReq struct {
	initMessage
}

func (m *initReq) messageType() messageType { return messageTypeInitReq }

// An InitRes, containing context information to return to intiating peer
type initRes struct {
	initMessage
}

func (m *initRes) messageType() messageType { return messageTypeInitRes }

// Headers passed as part of a CallReq/CallRes
type callHeaders map[string]string

func (ch callHeaders) read(r typed.ReadBuffer) error {
	nh, err := r.ReadByte()
	if err != nil {
		return err
	}

	for i := 0; i < int(nh); i++ {
		klen, err := r.ReadByte()
		if err != nil {
			return err
		}

		k, err := r.ReadString(int(klen))
		if err != nil {
			return err
		}

		vlen, err := r.ReadByte()
		if err != nil {
			return err
		}

		v, err := r.ReadString(int(vlen))
		if err != nil {
			return err
		}

		ch[k] = v
	}

	return nil
}

func (ch callHeaders) write(w typed.WriteBuffer) error {
	if err := w.WriteByte(byte(len(ch))); err != nil {
		return err
	}

	for k, v := range ch {
		if err := w.WriteByte(byte(len(k))); err != nil {
			return err
		}

		if err := w.WriteString(k); err != nil {
			return err
		}

		if err := w.WriteByte(byte(len(v))); err != nil {
			return err
		}

		if err := w.WriteString(v); err != nil {
			return err
		}
	}

	return nil
}

// Tracing represents Zipkin-style tracing info
type Tracing struct {
	// The outer trace id.  Established at the outermost edge service and propagated through all calls
	TraceID uint64

	// The id of the parent span in this call graph
	ParentID uint64

	// The id of this specific RPC
	SpanID uint64
}

// A CallReq for service
type callReq struct {
	id         uint32
	TimeToLive time.Duration
	Tracing    Tracing
	TraceFlags byte
	Headers    callHeaders
	Service    []byte
}

func (m *callReq) ID() uint32               { return m.id }
func (m *callReq) messageType() messageType { return messageTypeCallReq }
func (m *callReq) read(r typed.ReadBuffer) error {
	var err error
	ttl, err := r.ReadUint32()
	if err != nil {
		return err
	}

	m.TimeToLive = time.Duration(ttl) * time.Millisecond
	m.Tracing.TraceID, err = r.ReadUint64()
	if err != nil {
		return err
	}

	m.Tracing.ParentID, err = r.ReadUint64()
	if err != nil {
		return err
	}

	m.Tracing.SpanID, err = r.ReadUint64()
	if err != nil {
		return err
	}

	m.TraceFlags, err = r.ReadByte()
	if err != nil {
		return err
	}

	m.Headers = callHeaders{}
	if err := m.Headers.read(r); err != nil {
		return err
	}

	serviceNameLen, err := r.ReadUint16()
	if err != nil {
		return err
	}

	if m.Service, err = r.ReadBytes(int(serviceNameLen)); err != nil {
		return err
	}

	return nil
}

func (m *callReq) write(w typed.WriteBuffer) error {
	if err := w.WriteUint32(uint32(m.TimeToLive.Seconds() * 1000)); err != nil {
		return err
	}

	if err := w.WriteUint64(m.Tracing.TraceID); err != nil {
		return err
	}

	if err := w.WriteUint64(m.Tracing.ParentID); err != nil {
		return err
	}

	if err := w.WriteUint64(m.Tracing.SpanID); err != nil {
		return err
	}

	if err := w.WriteByte(m.TraceFlags); err != nil {
		return err
	}

	if err := m.Headers.write(w); err != nil {
		return err
	}

	if err := w.WriteUint16(uint16(len(m.Service))); err != nil {
		return err
	}

	if err := w.WriteBytes(m.Service); err != nil {
		return err
	}

	return nil
}

// A continuatin of a previous CallReq
type callReqContinue struct {
	id uint32
}

func (c *callReqContinue) ID() uint32                      { return c.id }
func (c *callReqContinue) messageType() messageType        { return messageTypeCallReqContinue }
func (c *callReqContinue) read(r typed.ReadBuffer) error   { return nil }
func (c *callReqContinue) write(w typed.WriteBuffer) error { return nil }

// ResponseCode to a CallReq
type ResponseCode byte

const (
	responseOK               ResponseCode = 0x00
	responseApplicationError ResponseCode = 0x01
)

// A response to a CallReq
type callRes struct {
	id           uint32
	ResponseCode ResponseCode
	Tracing      Tracing
	TraceFlags   byte
	Headers      callHeaders
}

func (m *callRes) ID() uint32               { return m.id }
func (m *callRes) messageType() messageType { return messageTypeCallRes }

func (m *callRes) read(r typed.ReadBuffer) error {
	var err error
	c, err := r.ReadByte()
	if err != nil {
		return err
	}
	m.ResponseCode = ResponseCode(c)
	m.Tracing.TraceID, err = r.ReadUint64()
	if err != nil {
		return err
	}

	m.Tracing.ParentID, err = r.ReadUint64()
	if err != nil {
		return err
	}

	m.Tracing.SpanID, err = r.ReadUint64()
	if err != nil {
		return err
	}

	m.TraceFlags, err = r.ReadByte()
	if err != nil {
		return err
	}

	m.Headers = callHeaders{}
	if err := m.Headers.read(r); err != nil {
		return err
	}

	return nil
}

func (m *callRes) write(w typed.WriteBuffer) error {
	if err := w.WriteByte(byte(m.ResponseCode)); err != nil {
		return err
	}

	if err := w.WriteUint64(m.Tracing.TraceID); err != nil {
		return err
	}

	if err := w.WriteUint64(m.Tracing.ParentID); err != nil {
		return err
	}

	if err := w.WriteUint64(m.Tracing.SpanID); err != nil {
		return err
	}

	if err := w.WriteByte(m.TraceFlags); err != nil {
		return err
	}

	if err := m.Headers.write(w); err != nil {
		return err
	}

	return nil
}

// A continuation of a previous CallRes
type callResContinue struct {
	id uint32
}

func (c *callResContinue) ID() uint32                      { return c.id }
func (c *callResContinue) messageType() messageType        { return messageTypeCallResContinue }
func (c *callResContinue) read(r typed.ReadBuffer) error   { return nil }
func (c *callResContinue) write(w typed.WriteBuffer) error { return nil }

// An Error message, a system-level error response to a request or a protocol level error
type errorMessage struct {
	id                uint32
	errorCode         SystemErrorCode
	originalMessageID uint32
	message           string
}

func (m *errorMessage) ID() uint32               { return m.id }
func (m *errorMessage) messageType() messageType { return messageTypeError }
func (m *errorMessage) read(r typed.ReadBuffer) error {
	errCode, err := r.ReadByte()
	if err != nil {
		return err
	}

	m.errorCode = SystemErrorCode(errCode)

	if m.originalMessageID, err = r.ReadUint32(); err != nil {
		return err
	}

	msgSize, err := r.ReadUint16()
	if err != nil {
		return err
	}

	if m.message, err = r.ReadString(int(msgSize)); err != nil {
		return err
	}

	return nil
}

func (m *errorMessage) write(w typed.WriteBuffer) error {
	if err := w.WriteByte(byte(m.errorCode)); err != nil {
		return err
	}

	if err := w.WriteUint32(m.originalMessageID); err != nil {
		return err
	}

	if err := w.WriteUint16(uint16(len(m.message))); err != nil {
		return err
	}

	if err := w.WriteString(m.message); err != nil {
		return err
	}

	return nil
}

func (m errorMessage) AsSystemError() error {
	// TODO(mmihic): Might be nice to return one of the well defined error types
	return NewSystemError(m.errorCode, m.message)
}
<commit_msg>Switch to service~1<commit_after>package tchannel

// Copyright (c) 2015 Uber Technologies, Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

import (
	"github.com/uber/tchannel/golang/typed"
	"io"
	"time"
)

// Type of message
type messageType byte

const (
	messageTypeInitReq         messageType = 0x01
	messageTypeInitRes         messageType = 0x02
	messageTypeCallReq         messageType = 0x03
	messageTypeCallRes         messageType = 0x04
	messageTypeCallReqContinue messageType = 0x13
	messageTypeCallResContinue messageType = 0x14
	messageTypeError           messageType = 0xFF
)

var messageTypeNames = map[messageType]string{
	messageTypeInitReq:         "initReq",
	messageTypeInitRes:         "InitRes",
	messageTypeCallReq:         "CallReq",
	messageTypeCallReqContinue: "CallReqContinue",
	messageTypeCallRes:         "CallRes",
	messageTypeCallResContinue: "CallResContinue",
	messageTypeError:           "Error",
}

func (t messageType) String() string {
	return messageTypeNames[t]
}

// Base interface for messages.  Has an id and a type, and knows how to read and write onto a binary stream
type message interface {
	// The id of the message
	ID() uint32

	// The type of the message
	messageType() messageType

	read(r typed.ReadBuffer) error
	write(r typed.WriteBuffer) error
}

// Parameters to an initReq/InitRes
type initParams map[string]string

// Standard init params
const (
	InitParamHostPort    = "host_port"
	InitParamProcessName = "process_name"
)

type initMessage struct {
	id         uint32
	Version    uint16
	initParams initParams
}

func (m *initMessage) read(r typed.ReadBuffer) error {
	var err error
	m.Version, err = r.ReadUint16()
	if err != nil {
		return err
	}

	m.initParams = initParams{}
	for {
		klen, err := r.ReadUint16()
		if err == io.EOF {
			return nil
		}

		k, err := r.ReadString(int(klen))
		if err != nil {
			return err
		}

		vlen, err := r.ReadUint16()
		if err != nil {
			return err
		}

		v, err := r.ReadString(int(vlen))
		if err != nil {
			return err
		}

		m.initParams[k] = v
	}
}

func (m *initMessage) write(w typed.WriteBuffer) error {
	if err := w.WriteUint16(m.Version); err != nil {
		return err
	}

	for k, v := range m.initParams {
		if err := w.WriteUint16(uint16(len(k))); err != nil {
			return err
		}

		if err := w.WriteString(k); err != nil {
			return err
		}

		if err := w.WriteUint16(uint16(len(v))); err != nil {
			return err
		}

		if err := w.WriteString(v); err != nil {
			return err
		}
	}

	return nil
}

func (m *initMessage) ID() uint32 {
	return m.id
}

// An initReq, containing context information to exchange with peer
type initReq struct {
	initMessage
}

func (m *initReq) messageType() messageType { return messageTypeInitReq }

// An InitRes, containing context information to return to intiating peer
type initRes struct {
	initMessage
}

func (m *initRes) messageType() messageType { return messageTypeInitRes }

// Headers passed as part of a CallReq/CallRes
type callHeaders map[string]string

func (ch callHeaders) read(r typed.ReadBuffer) error {
	nh, err := r.ReadByte()
	if err != nil {
		return err
	}

	for i := 0; i < int(nh); i++ {
		klen, err := r.ReadByte()
		if err != nil {
			return err
		}

		k, err := r.ReadString(int(klen))
		if err != nil {
			return err
		}

		vlen, err := r.ReadByte()
		if err != nil {
			return err
		}

		v, err := r.ReadString(int(vlen))
		if err != nil {
			return err
		}

		ch[k] = v
	}

	return nil
}

func (ch callHeaders) write(w typed.WriteBuffer) error {
	if err := w.WriteByte(byte(len(ch))); err != nil {
		return err
	}

	for k, v := range ch {
		if err := w.WriteByte(byte(len(k))); err != nil {
			return err
		}

		if err := w.WriteString(k); err != nil {
			return err
		}

		if err := w.WriteByte(byte(len(v))); err != nil {
			return err
		}

		if err := w.WriteString(v); err != nil {
			return err
		}
	}

	return nil
}

// Tracing represents Zipkin-style tracing info
type Tracing struct {
	// The outer trace id.  Established at the outermost edge service and propagated through all calls
	TraceID uint64

	// The id of the parent span in this call graph
	ParentID uint64

	// The id of this specific RPC
	SpanID uint64
}

// A CallReq for service
type callReq struct {
	id         uint32
	TimeToLive time.Duration
	Tracing    Tracing
	TraceFlags byte
	Headers    callHeaders
	Service    []byte
}

func (m *callReq) ID() uint32               { return m.id }
func (m *callReq) messageType() messageType { return messageTypeCallReq }
func (m *callReq) read(r typed.ReadBuffer) error {
	var err error
	ttl, err := r.ReadUint32()
	if err != nil {
		return err
	}

	m.TimeToLive = time.Duration(ttl) * time.Millisecond
	m.Tracing.TraceID, err = r.ReadUint64()
	if err != nil {
		return err
	}

	m.Tracing.ParentID, err = r.ReadUint64()
	if err != nil {
		return err
	}

	m.Tracing.SpanID, err = r.ReadUint64()
	if err != nil {
		return err
	}

	m.TraceFlags, err = r.ReadByte()
	if err != nil {
		return err
	}

	m.Headers = callHeaders{}
	if err := m.Headers.read(r); err != nil {
		return err
	}

	serviceNameLen, err := r.ReadByte()
	if err != nil {
		return err
	}

	if m.Service, err = r.ReadBytes(int(serviceNameLen)); err != nil {
		return err
	}

	return nil
}

func (m *callReq) write(w typed.WriteBuffer) error {
	if err := w.WriteUint32(uint32(m.TimeToLive.Seconds() * 1000)); err != nil {
		return err
	}

	if err := w.WriteUint64(m.Tracing.TraceID); err != nil {
		return err
	}

	if err := w.WriteUint64(m.Tracing.ParentID); err != nil {
		return err
	}

	if err := w.WriteUint64(m.Tracing.SpanID); err != nil {
		return err
	}

	if err := w.WriteByte(m.TraceFlags); err != nil {
		return err
	}

	if err := m.Headers.write(w); err != nil {
		return err
	}

	if err := w.WriteByte(byte(len(m.Service))); err != nil {
		return err
	}

	if err := w.WriteBytes(m.Service); err != nil {
		return err
	}

	return nil
}

// A continuatin of a previous CallReq
type callReqContinue struct {
	id uint32
}

func (c *callReqContinue) ID() uint32                      { return c.id }
func (c *callReqContinue) messageType() messageType        { return messageTypeCallReqContinue }
func (c *callReqContinue) read(r typed.ReadBuffer) error   { return nil }
func (c *callReqContinue) write(w typed.WriteBuffer) error { return nil }

// ResponseCode to a CallReq
type ResponseCode byte

const (
	responseOK               ResponseCode = 0x00
	responseApplicationError ResponseCode = 0x01
)

// A response to a CallReq
type callRes struct {
	id           uint32
	ResponseCode ResponseCode
	Tracing      Tracing
	TraceFlags   byte
	Headers      callHeaders
}

func (m *callRes) ID() uint32               { return m.id }
func (m *callRes) messageType() messageType { return messageTypeCallRes }

func (m *callRes) read(r typed.ReadBuffer) error {
	var err error
	c, err := r.ReadByte()
	if err != nil {
		return err
	}
	m.ResponseCode = ResponseCode(c)
	m.Tracing.TraceID, err = r.ReadUint64()
	if err != nil {
		return err
	}

	m.Tracing.ParentID, err = r.ReadUint64()
	if err != nil {
		return err
	}

	m.Tracing.SpanID, err = r.ReadUint64()
	if err != nil {
		return err
	}

	m.TraceFlags, err = r.ReadByte()
	if err != nil {
		return err
	}

	m.Headers = callHeaders{}
	if err := m.Headers.read(r); err != nil {
		return err
	}

	return nil
}

func (m *callRes) write(w typed.WriteBuffer) error {
	if err := w.WriteByte(byte(m.ResponseCode)); err != nil {
		return err
	}

	if err := w.WriteUint64(m.Tracing.TraceID); err != nil {
		return err
	}

	if err := w.WriteUint64(m.Tracing.ParentID); err != nil {
		return err
	}

	if err := w.WriteUint64(m.Tracing.SpanID); err != nil {
		return err
	}

	if err := w.WriteByte(m.TraceFlags); err != nil {
		return err
	}

	if err := m.Headers.write(w); err != nil {
		return err
	}

	return nil
}

// A continuation of a previous CallRes
type callResContinue struct {
	id uint32
}

func (c *callResContinue) ID() uint32                      { return c.id }
func (c *callResContinue) messageType() messageType        { return messageTypeCallResContinue }
func (c *callResContinue) read(r typed.ReadBuffer) error   { return nil }
func (c *callResContinue) write(w typed.WriteBuffer) error { return nil }

// An Error message, a system-level error response to a request or a protocol level error
type errorMessage struct {
	id                uint32
	errorCode         SystemErrorCode
	originalMessageID uint32
	message           string
}

func (m *errorMessage) ID() uint32               { return m.id }
func (m *errorMessage) messageType() messageType { return messageTypeError }
func (m *errorMessage) read(r typed.ReadBuffer) error {
	errCode, err := r.ReadByte()
	if err != nil {
		return err
	}

	m.errorCode = SystemErrorCode(errCode)

	if m.originalMessageID, err = r.ReadUint32(); err != nil {
		return err
	}

	msgSize, err := r.ReadUint16()
	if err != nil {
		return err
	}

	if m.message, err = r.ReadString(int(msgSize)); err != nil {
		return err
	}

	return nil
}

func (m *errorMessage) write(w typed.WriteBuffer) error {
	if err := w.WriteByte(byte(m.errorCode)); err != nil {
		return err
	}

	if err := w.WriteUint32(m.originalMessageID); err != nil {
		return err
	}

	if err := w.WriteUint16(uint16(len(m.message))); err != nil {
		return err
	}

	if err := w.WriteString(m.message); err != nil {
		return err
	}

	return nil
}

func (m errorMessage) AsSystemError() error {
	// TODO(mmihic): Might be nice to return one of the well defined error types
	return NewSystemError(m.errorCode, m.message)
}
<|endoftext|>


<commit_before>package gpg

import (
	"bytes"
	"log"
	"os"
	"testing"

	"golang.org/x/crypto/openpgp"
)

const expectedIdentity = "TEST gpg-validation-server (For Testing Only) <test-gpg-validation@server.local>"
const prefix = "../test-keys/new-MacGPG2/TEST gpg-validation-server (For Testing Only) test-gpg-validation@server.local (0x87144E5E) "
const asciiKeyFilePublic = prefix + "pub.asc"
const asciiKeyFilePrivate = prefix + "sec.asc"
const binaryKeyFilePublic = prefix + "pub.asc.gpg"
const binaryKeyFilePrivate = prefix + "sec.asc.gpg"

func TestReadEntity(t *testing.T) {
	for _, path := range [2]string{binaryKeyFilePublic, binaryKeyFilePrivate} {
		keyFile, err := os.Open(path)
		if err != nil {
			log.Fatal("Could not open test key file: ", err)
		}

		entity, err := ReadEntity(keyFile, false)
		if err != nil {
			t.Error("Failed to read entity:", err)
		}

		_, ok := entity.Identities[expectedIdentity]
		if !ok {
			t.Error("Could not find identity:", expectedIdentity)
		}

		if entity.PrimaryKey == nil && entity.PrivateKey == nil {
			t.Error("No keys found")
		}
	}
}

func TestReadEntityArmored(t *testing.T) {
	for _, path := range [2]string{asciiKeyFilePublic, asciiKeyFilePrivate} {
		keyFile, err := os.Open(path)
		if err != nil {
			log.Fatal("Could not open test key file: ", err)
		}

		entity, err := ReadEntity(keyFile, true)
		if err != nil {
			t.Error("Failed to read entity:", err)
		}

		_, ok := entity.Identities[expectedIdentity]
		if !ok {
			t.Error("Could not find identity:", expectedIdentity)
		}

		if entity.PrimaryKey == nil && entity.PrivateKey == nil {
			t.Error("No keys found")
		}
	}
}

func readEntityFromFile(path string, armored bool) *openpgp.Entity {
	keyFile, err := os.Open(path)
	if err != nil {
		log.Fatal("Could not open test key file: ", err)
	}

	entity, err := ReadEntity(keyFile, armored)
	if err != nil {
		log.Fatal("Failed to read entity:", path)
	}
	return entity
}

func TestDecryptPrivateKeys(t *testing.T) {
	entity := readEntityFromFile(binaryKeyFilePrivate, false)

	err := DecryptPrivateKeys(entity, []byte("validation"))
	if err != nil {
		t.Fatal("Decryption failed:", err)
	}

	if entity.PrivateKey.Encrypted {
		t.Error("Private key still encrypted")
	}

	for _, subKey := range entity.Subkeys {
		if subKey.PrivateKey.Encrypted {
			t.Error("Private sub-key still encrypted")
		}
	}
}

const prefixClient = "../test-keys/new-MacGPG2/TEST-client gpg-validation-server (For Testing Only) test-gpg-validation@client.local (0xE93B112A) "
const asciiKeyFileClient = prefixClient + "pub.asc"
const binaryKeyFileClient = prefixClient + "pub.asc.gpg"

func TestSignClientPublicKey(t *testing.T) {
	serverEntity := readEntityFromFile(binaryKeyFilePrivate, false)

	err := DecryptPrivateKeys(serverEntity, []byte("validation"))

	clientEntity := readEntityFromFile(asciiKeyFileClient, true)
	if err != nil {
		t.Fatal("Failed to read entity:", err)
	}

	signedIdentity := ""
	for signedIdentity = range clientEntity.Identities {
		break
	}
	oldSigCount := len(clientEntity.Identities[signedIdentity].Signatures)

	buffer := new(bytes.Buffer)
	err = SignClientPublicKey(clientEntity, signedIdentity, serverEntity, buffer)
	if err != nil {
		t.Fatal("Signing failed:", err)
	}

	signedClientEntity, err := ReadEntity(buffer, true)
	if err != nil {
		t.Fatal("Failed to read signed key:", err)
	}

	newSigCount := len(signedClientEntity.Identities[signedIdentity].Signatures)

	if oldSigCount >= newSigCount {
		t.Error("No new signatures found")
	}

	serverPublicEntity := readEntityFromFile(binaryKeyFilePublic, false)

	for index, signature := range signedClientEntity.Identities[signedIdentity].Signatures {
		err = serverPublicEntity.PrimaryKey.VerifyUserIdSignature(signedIdentity, signedClientEntity.PrimaryKey, signature)
		if err != nil {
			t.Error("Signature", index, "not valid:", err)
		}
	}
}
<commit_msg>De-duplicate test code<commit_after>package gpg

import (
	"bytes"
	"log"
	"os"
	"testing"

	"golang.org/x/crypto/openpgp"
)

const expectedIdentity = "TEST gpg-validation-server (For Testing Only) <test-gpg-validation@server.local>"
const prefix = "../test-keys/new-MacGPG2/TEST gpg-validation-server (For Testing Only) test-gpg-validation@server.local (0x87144E5E) "
const asciiKeyFilePublic = prefix + "pub.asc"
const asciiKeyFilePrivate = prefix + "sec.asc"
const binaryKeyFilePublic = prefix + "pub.asc.gpg"
const binaryKeyFilePrivate = prefix + "sec.asc.gpg"

func readEntityTest(t *testing.T, path string, armored bool) {
	keyFile, err := os.Open(path)
	if err != nil {
		log.Fatal("Could not open test key file: ", err)
	}

	entity, err := ReadEntity(keyFile, armored)
	if err != nil {
		t.Error("Failed to read entity:", err)
	}

	_, ok := entity.Identities[expectedIdentity]
	if !ok {
		t.Error("Could not find identity:", expectedIdentity)
	}

	if entity.PrimaryKey == nil && entity.PrivateKey == nil {
		t.Error("No keys found")
	}
}

func TestReadEntity(t *testing.T) {
	for _, path := range [2]string{binaryKeyFilePublic, binaryKeyFilePrivate} {
		readEntityTest(t, path, false)
	}
}

func TestReadEntityArmored(t *testing.T) {
	for _, path := range [2]string{asciiKeyFilePublic, asciiKeyFilePrivate} {
		readEntityTest(t, path, true)
	}
}

func readEntityFromFile(path string, armored bool) *openpgp.Entity {
	keyFile, err := os.Open(path)
	if err != nil {
		log.Fatal("Could not open test key file: ", err)
	}

	entity, err := ReadEntity(keyFile, armored)
	if err != nil {
		log.Fatal("Failed to read entity:", path)
	}
	return entity
}

func TestDecryptPrivateKeys(t *testing.T) {
	entity := readEntityFromFile(binaryKeyFilePrivate, false)

	err := DecryptPrivateKeys(entity, []byte("validation"))
	if err != nil {
		t.Fatal("Decryption failed:", err)
	}

	if entity.PrivateKey.Encrypted {
		t.Error("Private key still encrypted")
	}

	for _, subKey := range entity.Subkeys {
		if subKey.PrivateKey.Encrypted {
			t.Error("Private sub-key still encrypted")
		}
	}
}

const prefixClient = "../test-keys/new-MacGPG2/TEST-client gpg-validation-server (For Testing Only) test-gpg-validation@client.local (0xE93B112A) "
const asciiKeyFileClient = prefixClient + "pub.asc"
const binaryKeyFileClient = prefixClient + "pub.asc.gpg"

func TestSignClientPublicKey(t *testing.T) {
	serverEntity := readEntityFromFile(binaryKeyFilePrivate, false)

	err := DecryptPrivateKeys(serverEntity, []byte("validation"))

	clientEntity := readEntityFromFile(asciiKeyFileClient, true)
	if err != nil {
		t.Fatal("Failed to read entity:", err)
	}

	signedIdentity := ""
	for signedIdentity = range clientEntity.Identities {
		break
	}
	oldSigCount := len(clientEntity.Identities[signedIdentity].Signatures)

	buffer := new(bytes.Buffer)
	err = SignClientPublicKey(clientEntity, signedIdentity, serverEntity, buffer)
	if err != nil {
		t.Fatal("Signing failed:", err)
	}

	signedClientEntity, err := ReadEntity(buffer, true)
	if err != nil {
		t.Fatal("Failed to read signed key:", err)
	}

	newSigCount := len(signedClientEntity.Identities[signedIdentity].Signatures)

	if oldSigCount >= newSigCount {
		t.Error("No new signatures found")
	}

	serverPublicEntity := readEntityFromFile(binaryKeyFilePublic, false)

	for index, signature := range signedClientEntity.Identities[signedIdentity].Signatures {
		err = serverPublicEntity.PrimaryKey.VerifyUserIdSignature(signedIdentity, signedClientEntity.PrimaryKey, signature)
		if err != nil {
			t.Error("Signature", index, "not valid:", err)
		}
	}
}
<|endoftext|>