<commit_before>/*
Copyright 2016 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 certificates

import (
	"context"
	"fmt"
	"io"

	"github.com/spf13/cobra"

	certificatesv1beta1 "k8s.io/api/certificates/v1beta1"
	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/cli-runtime/pkg/genericclioptions"
	"k8s.io/cli-runtime/pkg/printers"
	"k8s.io/cli-runtime/pkg/resource"
	certificatesv1beta1client "k8s.io/client-go/kubernetes/typed/certificates/v1beta1"
	cmdutil "k8s.io/kubectl/pkg/cmd/util"
	"k8s.io/kubectl/pkg/scheme"
	"k8s.io/kubectl/pkg/util/i18n"
	"k8s.io/kubectl/pkg/util/templates"
)

func NewCmdCertificate(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
	cmd := &cobra.Command{
		Use:                   "certificate SUBCOMMAND",
		DisableFlagsInUseLine: true,
		Short:                 i18n.T("Modify certificate resources."),
		Long:                  "Modify certificate resources.",
		Run: func(cmd *cobra.Command, args []string) {
			cmd.Help()
		},
	}

	cmd.AddCommand(NewCmdCertificateApprove(f, ioStreams))
	cmd.AddCommand(NewCmdCertificateDeny(f, ioStreams))

	return cmd
}

type CertificateOptions struct {
	resource.FilenameOptions

	PrintFlags *genericclioptions.PrintFlags
	PrintObj   printers.ResourcePrinterFunc

	csrNames    []string
	outputStyle string

	clientSet certificatesv1beta1client.CertificatesV1beta1Interface
	builder   *resource.Builder

	genericclioptions.IOStreams
}

// NewCertificateOptions creates the options for certificate
func NewCertificateOptions(ioStreams genericclioptions.IOStreams, operation string) *CertificateOptions {
	return &CertificateOptions{
		PrintFlags: genericclioptions.NewPrintFlags(operation).WithTypeSetter(scheme.Scheme),
		IOStreams:  ioStreams,
	}
}

func (o *CertificateOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
	o.csrNames = args
	o.outputStyle = cmdutil.GetFlagString(cmd, "output")

	printer, err := o.PrintFlags.ToPrinter()
	if err != nil {
		return err
	}

	o.PrintObj = func(obj runtime.Object, out io.Writer) error {
		return printer.PrintObj(obj, out)
	}

	o.builder = f.NewBuilder()

	clientConfig, err := f.ToRESTConfig()
	if err != nil {
		return err
	}
	o.clientSet, err = certificatesv1beta1client.NewForConfig(clientConfig)
	if err != nil {
		return err
	}

	return nil
}

func (o *CertificateOptions) Validate() error {
	if len(o.csrNames) < 1 && cmdutil.IsFilenameSliceEmpty(o.Filenames, o.Kustomize) {
		return fmt.Errorf("one or more CSRs must be specified as <name> or -f <filename>")
	}
	return nil
}

func NewCmdCertificateApprove(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
	o := NewCertificateOptions(ioStreams, "approved")

	cmd := &cobra.Command{
		Use:                   "approve (-f FILENAME | NAME)",
		DisableFlagsInUseLine: true,
		Short:                 i18n.T("Approve a certificate signing request"),
		Long: templates.LongDesc(`
		Approve a certificate signing request.

		kubectl certificate approve allows a cluster admin to approve a certificate
		signing request (CSR). This action tells a certificate signing controller to
		issue a certificate to the requestor with the attributes requested in the CSR.

		SECURITY NOTICE: Depending on the requested attributes, the issued certificate
		can potentially grant a requester access to cluster resources or to authenticate
		as a requested identity. Before approving a CSR, ensure you understand what the
		signed certificate can do.
		`),
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(o.Complete(f, cmd, args))
			cmdutil.CheckErr(o.Validate())
			cmdutil.CheckErr(o.RunCertificateApprove(cmdutil.GetFlagBool(cmd, "force")))
		},
	}

	o.PrintFlags.AddFlags(cmd)

	cmd.Flags().Bool("force", false, "Update the CSR even if it is already approved.")
	cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, "identifying the resource to update")

	return cmd
}

func (o *CertificateOptions) RunCertificateApprove(force bool) error {
	return o.modifyCertificateCondition(o.builder, o.clientSet, force, func(csr *certificatesv1beta1.CertificateSigningRequest) (*certificatesv1beta1.CertificateSigningRequest, bool) {
		var alreadyApproved bool
		for _, c := range csr.Status.Conditions {
			if c.Type == certificatesv1beta1.CertificateApproved {
				alreadyApproved = true
			}
		}
		if alreadyApproved {
			return csr, true
		}
		csr.Status.Conditions = append(csr.Status.Conditions, certificatesv1beta1.CertificateSigningRequestCondition{
			Type:           certificatesv1beta1.CertificateApproved,
			Reason:         "KubectlApprove",
			Message:        "This CSR was approved by kubectl certificate approve.",
			LastUpdateTime: metav1.Now(),
		})
		return csr, false
	})
}

func NewCmdCertificateDeny(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
	o := NewCertificateOptions(ioStreams, "denied")

	cmd := &cobra.Command{
		Use:                   "deny (-f FILENAME | NAME)",
		DisableFlagsInUseLine: true,
		Short:                 i18n.T("Deny a certificate signing request"),
		Long: templates.LongDesc(`
		Deny a certificate signing request.

		kubectl certificate deny allows a cluster admin to deny a certificate
		signing request (CSR). This action tells a certificate signing controller to
		not to issue a certificate to the requestor.
		`),
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(o.Complete(f, cmd, args))
			cmdutil.CheckErr(o.Validate())
			cmdutil.CheckErr(o.RunCertificateDeny(cmdutil.GetFlagBool(cmd, "force")))
		},
	}

	o.PrintFlags.AddFlags(cmd)

	cmd.Flags().Bool("force", false, "Update the CSR even if it is already denied.")
	cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, "identifying the resource to update")

	return cmd
}

func (o *CertificateOptions) RunCertificateDeny(force bool) error {
	return o.modifyCertificateCondition(o.builder, o.clientSet, force, func(csr *certificatesv1beta1.CertificateSigningRequest) (*certificatesv1beta1.CertificateSigningRequest, bool) {
		var alreadyDenied bool
		for _, c := range csr.Status.Conditions {
			if c.Type == certificatesv1beta1.CertificateDenied {
				alreadyDenied = true
			}
		}
		if alreadyDenied {
			return csr, true
		}
		csr.Status.Conditions = append(csr.Status.Conditions, certificatesv1beta1.CertificateSigningRequestCondition{
			Type:           certificatesv1beta1.CertificateDenied,
			Reason:         "KubectlDeny",
			Message:        "This CSR was denied by kubectl certificate deny.",
			LastUpdateTime: metav1.Now(),
		})
		return csr, false
	})
}

func (o *CertificateOptions) modifyCertificateCondition(builder *resource.Builder, clientSet certificatesv1beta1client.CertificatesV1beta1Interface, force bool, modify func(csr *certificatesv1beta1.CertificateSigningRequest) (*certificatesv1beta1.CertificateSigningRequest, bool)) error {
	var found int
	r := builder.
		WithScheme(scheme.Scheme, scheme.Scheme.PrioritizedVersionsAllGroups()...).
		ContinueOnError().
		FilenameParam(false, &o.FilenameOptions).
		ResourceNames("certificatesigningrequest", o.csrNames...).
		RequireObject(true).
		Flatten().
		Latest().
		Do()
	err := r.Visit(func(info *resource.Info, err error) error {
		if err != nil {
			return err
		}
		for i := 0; ; i++ {
			csr := info.Object.(*certificatesv1beta1.CertificateSigningRequest)
			csr, hasCondition := modify(csr)
			if !hasCondition || force {
				_, err = clientSet.CertificateSigningRequests().UpdateApproval(context.TODO(), csr, metav1.UpdateOptions{})
				if errors.IsConflict(err) && i < 10 {
					if err := info.Get(); err != nil {
						return err
					}
					continue
				}
				if err != nil {
					return err
				}
			}
			break
		}
		found++

		return o.PrintObj(info.Object, o.Out)
	})
	if found == 0 {
		fmt.Fprintf(o.Out, "No resources found\n")
	}
	return err
}
<commit_msg>Make kubectl tolerate other versions of the CSR API<commit_after>/*
Copyright 2016 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 certificates

import (
	"context"
	"fmt"
	"io"

	"github.com/spf13/cobra"

	certificatesv1beta1 "k8s.io/api/certificates/v1beta1"
	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/cli-runtime/pkg/genericclioptions"
	"k8s.io/cli-runtime/pkg/printers"
	"k8s.io/cli-runtime/pkg/resource"
	certificatesv1beta1client "k8s.io/client-go/kubernetes/typed/certificates/v1beta1"
	cmdutil "k8s.io/kubectl/pkg/cmd/util"
	"k8s.io/kubectl/pkg/scheme"
	"k8s.io/kubectl/pkg/util/i18n"
	"k8s.io/kubectl/pkg/util/templates"
)

func NewCmdCertificate(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
	cmd := &cobra.Command{
		Use:                   "certificate SUBCOMMAND",
		DisableFlagsInUseLine: true,
		Short:                 i18n.T("Modify certificate resources."),
		Long:                  "Modify certificate resources.",
		Run: func(cmd *cobra.Command, args []string) {
			cmd.Help()
		},
	}

	cmd.AddCommand(NewCmdCertificateApprove(f, ioStreams))
	cmd.AddCommand(NewCmdCertificateDeny(f, ioStreams))

	return cmd
}

type CertificateOptions struct {
	resource.FilenameOptions

	PrintFlags *genericclioptions.PrintFlags
	PrintObj   printers.ResourcePrinterFunc

	csrNames    []string
	outputStyle string

	clientSet certificatesv1beta1client.CertificatesV1beta1Interface
	builder   *resource.Builder

	genericclioptions.IOStreams
}

// NewCertificateOptions creates the options for certificate
func NewCertificateOptions(ioStreams genericclioptions.IOStreams, operation string) *CertificateOptions {
	return &CertificateOptions{
		PrintFlags: genericclioptions.NewPrintFlags(operation).WithTypeSetter(scheme.Scheme),
		IOStreams:  ioStreams,
	}
}

func (o *CertificateOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
	o.csrNames = args
	o.outputStyle = cmdutil.GetFlagString(cmd, "output")

	printer, err := o.PrintFlags.ToPrinter()
	if err != nil {
		return err
	}

	o.PrintObj = func(obj runtime.Object, out io.Writer) error {
		return printer.PrintObj(obj, out)
	}

	o.builder = f.NewBuilder()

	clientConfig, err := f.ToRESTConfig()
	if err != nil {
		return err
	}
	o.clientSet, err = certificatesv1beta1client.NewForConfig(clientConfig)
	if err != nil {
		return err
	}

	return nil
}

func (o *CertificateOptions) Validate() error {
	if len(o.csrNames) < 1 && cmdutil.IsFilenameSliceEmpty(o.Filenames, o.Kustomize) {
		return fmt.Errorf("one or more CSRs must be specified as <name> or -f <filename>")
	}
	return nil
}

func NewCmdCertificateApprove(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
	o := NewCertificateOptions(ioStreams, "approved")

	cmd := &cobra.Command{
		Use:                   "approve (-f FILENAME | NAME)",
		DisableFlagsInUseLine: true,
		Short:                 i18n.T("Approve a certificate signing request"),
		Long: templates.LongDesc(`
		Approve a certificate signing request.

		kubectl certificate approve allows a cluster admin to approve a certificate
		signing request (CSR). This action tells a certificate signing controller to
		issue a certificate to the requestor with the attributes requested in the CSR.

		SECURITY NOTICE: Depending on the requested attributes, the issued certificate
		can potentially grant a requester access to cluster resources or to authenticate
		as a requested identity. Before approving a CSR, ensure you understand what the
		signed certificate can do.
		`),
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(o.Complete(f, cmd, args))
			cmdutil.CheckErr(o.Validate())
			cmdutil.CheckErr(o.RunCertificateApprove(cmdutil.GetFlagBool(cmd, "force")))
		},
	}

	o.PrintFlags.AddFlags(cmd)

	cmd.Flags().Bool("force", false, "Update the CSR even if it is already approved.")
	cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, "identifying the resource to update")

	return cmd
}

func (o *CertificateOptions) RunCertificateApprove(force bool) error {
	return o.modifyCertificateCondition(o.builder, o.clientSet, force, func(csr *certificatesv1beta1.CertificateSigningRequest) (*certificatesv1beta1.CertificateSigningRequest, bool) {
		var alreadyApproved bool
		for _, c := range csr.Status.Conditions {
			if c.Type == certificatesv1beta1.CertificateApproved {
				alreadyApproved = true
			}
		}
		if alreadyApproved {
			return csr, true
		}
		csr.Status.Conditions = append(csr.Status.Conditions, certificatesv1beta1.CertificateSigningRequestCondition{
			Type:           certificatesv1beta1.CertificateApproved,
			Reason:         "KubectlApprove",
			Message:        "This CSR was approved by kubectl certificate approve.",
			LastUpdateTime: metav1.Now(),
		})
		return csr, false
	})
}

func NewCmdCertificateDeny(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
	o := NewCertificateOptions(ioStreams, "denied")

	cmd := &cobra.Command{
		Use:                   "deny (-f FILENAME | NAME)",
		DisableFlagsInUseLine: true,
		Short:                 i18n.T("Deny a certificate signing request"),
		Long: templates.LongDesc(`
		Deny a certificate signing request.

		kubectl certificate deny allows a cluster admin to deny a certificate
		signing request (CSR). This action tells a certificate signing controller to
		not to issue a certificate to the requestor.
		`),
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(o.Complete(f, cmd, args))
			cmdutil.CheckErr(o.Validate())
			cmdutil.CheckErr(o.RunCertificateDeny(cmdutil.GetFlagBool(cmd, "force")))
		},
	}

	o.PrintFlags.AddFlags(cmd)

	cmd.Flags().Bool("force", false, "Update the CSR even if it is already denied.")
	cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, "identifying the resource to update")

	return cmd
}

func (o *CertificateOptions) RunCertificateDeny(force bool) error {
	return o.modifyCertificateCondition(o.builder, o.clientSet, force, func(csr *certificatesv1beta1.CertificateSigningRequest) (*certificatesv1beta1.CertificateSigningRequest, bool) {
		var alreadyDenied bool
		for _, c := range csr.Status.Conditions {
			if c.Type == certificatesv1beta1.CertificateDenied {
				alreadyDenied = true
			}
		}
		if alreadyDenied {
			return csr, true
		}
		csr.Status.Conditions = append(csr.Status.Conditions, certificatesv1beta1.CertificateSigningRequestCondition{
			Type:           certificatesv1beta1.CertificateDenied,
			Reason:         "KubectlDeny",
			Message:        "This CSR was denied by kubectl certificate deny.",
			LastUpdateTime: metav1.Now(),
		})
		return csr, false
	})
}

func (o *CertificateOptions) modifyCertificateCondition(builder *resource.Builder, clientSet certificatesv1beta1client.CertificatesV1beta1Interface, force bool, modify func(csr *certificatesv1beta1.CertificateSigningRequest) (*certificatesv1beta1.CertificateSigningRequest, bool)) error {
	var found int
	r := builder.
		WithScheme(scheme.Scheme, scheme.Scheme.PrioritizedVersionsAllGroups()...).
		ContinueOnError().
		FilenameParam(false, &o.FilenameOptions).
		ResourceNames("certificatesigningrequests.v1beta1.certificates.k8s.io", o.csrNames...).
		RequireObject(true).
		Flatten().
		Latest().
		Do()
	err := r.Visit(func(info *resource.Info, err error) error {
		if err != nil {
			return err
		}
		for i := 0; ; i++ {
			csr, ok := info.Object.(*certificatesv1beta1.CertificateSigningRequest)
			if !ok {
				return fmt.Errorf("can only handle certificates.k8s.io/v1beta1 certificate signing requests")
			}
			csr, hasCondition := modify(csr)
			if !hasCondition || force {
				_, err = clientSet.CertificateSigningRequests().UpdateApproval(context.TODO(), csr, metav1.UpdateOptions{})
				if errors.IsConflict(err) && i < 10 {
					if err := info.Get(); err != nil {
						return err
					}
					continue
				}
				if err != nil {
					return err
				}
			}
			break
		}
		found++

		return o.PrintObj(info.Object, o.Out)
	})
	if found == 0 {
		fmt.Fprintf(o.Out, "No resources found\n")
	}
	return err
}
<|endoftext|>


<commit_before>package bundlec

import (
	"context"
	"sync"
	"time"

	"github.com/ash2k/stager/wait"
	"github.com/atlassian/ctrl"
	"github.com/atlassian/ctrl/handlers"
	smith_v1 "github.com/atlassian/smith/pkg/apis/smith/v1"
	smithClient_v1 "github.com/atlassian/smith/pkg/client/clientset_generated/clientset/typed/smith/v1"
	"github.com/atlassian/smith/pkg/plugin"
	"github.com/atlassian/smith/pkg/statuschecker"
	"github.com/atlassian/smith/pkg/store"
	"github.com/pkg/errors"
	"github.com/prometheus/client_golang/prometheus"
	"go.uber.org/zap"
	apps_v1 "k8s.io/api/apps/v1"
	core_v1 "k8s.io/api/core/v1"
	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/client-go/kubernetes"
	core_v1_client "k8s.io/client-go/kubernetes/typed/core/v1"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/tools/record"
)

const (
	byConfigMapNamespaceNameIndexName = "ByConfigMap"
	bySecretNamespaceNameIndexName    = "BySecret"
)

type byIndexFunc func(indexName, indexKey string) ([]interface{}, error)
type indexKeyFunc func(namespace, name string) string

type Controller struct {
	// wg.Wait() is called from Run() and first wg.Add() may be called concurrently from CRD listener
	// to start an Informer. This is a data race. This mutex is used to ensure ordering.
	// See https://github.com/atlassian/smith/issues/156
	// See https://github.com/golang/go/blob/fbc8973a6bc88b50509ea738f475b36ef756bf90/src/sync/waitgroup.go#L123-L126
	wgLock   sync.Mutex
	wg       wait.Group
	stopping bool

	crdContext       context.Context
	crdContextCancel context.CancelFunc

	Logger *zap.Logger

	ReadyForWork func()
	MainClient   kubernetes.Interface
	BundleClient smithClient_v1.BundlesGetter
	BundleStore  BundleStore
	SmartClient  SmartClient
	Rc           statuschecker.Interface
	Store        Store
	SpecChecker  SpecChecker
	WorkQueue    ctrl.WorkQueueProducer

	// CRD
	CrdResyncPeriod time.Duration
	Namespace       string

	PluginContainers map[smith_v1.PluginName]plugin.Container
	Scheme           *runtime.Scheme

	Catalog *store.Catalog

	// Metrics
	BundleTransitionCounter         *prometheus.CounterVec
	BundleResourceTransitionCounter *prometheus.CounterVec

	Broadcaster record.EventBroadcaster
	Recorder    record.EventRecorder
}

// Prepare prepares the controller to be run.
func (c *Controller) Prepare(crdInf cache.SharedIndexInformer, resourceInfs map[schema.GroupVersionKind]cache.SharedIndexInformer) error {
	c.crdContext, c.crdContextCancel = context.WithCancel(context.Background())
	crdInf.AddEventHandler(&crdEventHandler{
		controller: c,
		watchers:   make(map[string]watchState),
	})
	deploymentInf := resourceInfs[apps_v1.SchemeGroupVersion.WithKind("Deployment")]
	err := deploymentInf.AddIndexers(cache.Indexers{
		byConfigMapNamespaceNameIndexName: byConfigMapNamespaceNameIndex,
		bySecretNamespaceNameIndexName:    bySecretNamespaceNameIndex,
	})
	if err != nil {
		return errors.WithStack(err)
	}
	deploymentByIndex := deploymentInf.GetIndexer().ByIndex
	// ConfigMap -> Deployment -> Bundle event propagation
	configMapGVK := core_v1.SchemeGroupVersion.WithKind("ConfigMap")
	configMapInf := resourceInfs[configMapGVK]
	configMapInf.AddEventHandler(&handlers.LookupHandler{
		Logger:    c.Logger,
		WorkQueue: c.WorkQueue,
		Gvk:       configMapGVK,
		Lookup:    c.lookupBundleByDeploymentByIndex(deploymentByIndex, byConfigMapNamespaceNameIndexName, byConfigMapNamespaceNameIndexKey),
	})
	// Secret -> Deployment -> Bundle event propagation
	secretGVK := core_v1.SchemeGroupVersion.WithKind("Secret")
	secretInf := resourceInfs[secretGVK]
	secretInf.AddEventHandler(&handlers.LookupHandler{
		Logger:    c.Logger,
		WorkQueue: c.WorkQueue,
		Gvk:       secretGVK,
		Lookup:    c.lookupBundleByDeploymentByIndex(deploymentByIndex, bySecretNamespaceNameIndexName, bySecretNamespaceNameIndexKey),
	})
	// Standard handler
	for gvk, resourceInf := range resourceInfs {
		resourceInf.AddEventHandler(&handlers.ControlledResourceHandler{
			Logger:          c.Logger,
			WorkQueue:       c.WorkQueue,
			ControllerIndex: &controllerIndexAdapter{bundleStore: c.BundleStore},
			ControllerGvk:   smith_v1.BundleGVK,
			Gvk:             gvk,
		})
	}
	return nil
}

// Run begins watching and syncing.
// All informers must be synced before this method is invoked.
func (c *Controller) Run(ctx context.Context) {
	defer c.wg.Wait()
	defer c.crdContextCancel() // should be executed after stopping is set to true
	defer func() {
		c.wgLock.Lock()
		defer c.wgLock.Unlock()
		c.stopping = true
	}()

	c.Logger.Info("Starting Bundle controller")
	defer c.Logger.Info("Shutting down Bundle controller")

	sink := core_v1_client.EventSinkImpl{
		Interface: c.MainClient.CoreV1().Events(meta_v1.NamespaceNone),
	}
	recordingWatch := c.Broadcaster.StartRecordingToSink(&sink)
	defer recordingWatch.Stop()

	c.ReadyForWork()

	<-ctx.Done()
}

// lookupBundleByDeploymentByIndex returns a function that can be used to perform lookups of Bundles that contain
// Deployment objects that reference ConfigMap/Secret objects.
func (c *Controller) lookupBundleByDeploymentByIndex(byIndex byIndexFunc, indexName string, indexKey indexKeyFunc) func(runtime.Object) ([]runtime.Object, error) {
	deploymentGK := schema.GroupKind{
		Group: apps_v1.GroupName,
		Kind:  "Deployment",
	}
	return func(obj runtime.Object) ([]runtime.Object /*bundles*/, error) {
		// obj is ConfigMap or Secret
		objMeta := obj.(meta_v1.Object)
		// find all Deployments that reference this obj
		deploymentsFromIndex, err := byIndex(indexName, indexKey(objMeta.GetNamespace(), objMeta.GetName()))
		if err != nil {
			return nil, err
		}
		var bundles []runtime.Object
		for _, deploymentInterface := range deploymentsFromIndex {
			deployment := deploymentInterface.(*apps_v1.Deployment)
			// find all Bundles that reference this Deployment
			bundlesForDeployment, err := c.BundleStore.GetBundlesByObject(deploymentGK, deployment.Namespace, deployment.Name)
			if err != nil {
				return nil, err
			}
			for _, bundle := range bundlesForDeployment {
				bundles = append(bundles, bundle)
			}
		}
		return bundles, nil
	}
}

type controllerIndexAdapter struct {
	bundleStore BundleStore
}

func (c *controllerIndexAdapter) ControllerByObject(gk schema.GroupKind, namespace, name string) ([]runtime.Object, error) {
	bundles, err := c.bundleStore.GetBundlesByObject(gk, namespace, name)
	if err != nil {
		return nil, err
	}
	objs := make([]runtime.Object, 0, len(bundles))
	for _, bundle := range bundles {
		objs = append(objs, bundle)
	}
	return objs, nil
}

func byConfigMapNamespaceNameIndex(obj interface{}) ([]string, error) {
	d := obj.(*apps_v1.Deployment)
	index := configMapNamespaceNameIndexKeysForContainers(d.Namespace, d.Spec.Template.Spec.Containers)
	index = append(index, configMapNamespaceNameIndexKeysForContainers(d.Namespace, d.Spec.Template.Spec.InitContainers)...)
	return index, nil
}

func configMapNamespaceNameIndexKeysForContainers(namespace string, containers []core_v1.Container) []string {
	var indexKeys []string
	for _, container := range containers {
		for _, envFrom := range container.EnvFrom {
			configMapRef := envFrom.ConfigMapRef
			if configMapRef == nil {
				continue
			}
			indexKeys = append(indexKeys, bySecretNamespaceNameIndexKey(namespace, configMapRef.Name))
		}
		for _, env := range container.Env {
			valueFrom := env.ValueFrom
			if valueFrom == nil {
				continue
			}

			configMapKeyRef := valueFrom.ConfigMapKeyRef
			if configMapKeyRef == nil {
				continue
			}
			indexKeys = append(indexKeys, bySecretNamespaceNameIndexKey(namespace, configMapKeyRef.Name))
		}
	}
	return indexKeys
}

func byConfigMapNamespaceNameIndexKey(configMapNamespace, configMapName string) string {
	return configMapNamespace + "/" + configMapName
}

func bySecretNamespaceNameIndex(obj interface{}) ([]string, error) {
	d := obj.(*apps_v1.Deployment)
	index := secretNamespaceNameIndexKeysForContainers(d.Namespace, d.Spec.Template.Spec.Containers)
	index = append(index, secretNamespaceNameIndexKeysForContainers(d.Namespace, d.Spec.Template.Spec.InitContainers)...)
	return index, nil
}

func secretNamespaceNameIndexKeysForContainers(namespace string, containers []core_v1.Container) []string {
	var indexKeys []string
	for _, container := range containers {
		for _, envFrom := range container.EnvFrom {
			secretRef := envFrom.SecretRef
			if secretRef == nil {
				continue
			}
			indexKeys = append(indexKeys, bySecretNamespaceNameIndexKey(namespace, secretRef.Name))
		}
		for _, env := range container.Env {
			valueFrom := env.ValueFrom
			if valueFrom == nil {
				continue
			}

			secretKeyRef := valueFrom.SecretKeyRef
			if secretKeyRef == nil {
				continue
			}
			indexKeys = append(indexKeys, bySecretNamespaceNameIndexKey(namespace, secretKeyRef.Name))
		}
	}
	return indexKeys
}

func bySecretNamespaceNameIndexKey(secretNamespace, secretName string) string {
	return secretNamespace + "/" + secretName
}
<commit_msg>Use correct functions for configmap case<commit_after>package bundlec

import (
	"context"
	"sync"
	"time"

	"github.com/ash2k/stager/wait"
	"github.com/atlassian/ctrl"
	"github.com/atlassian/ctrl/handlers"
	smith_v1 "github.com/atlassian/smith/pkg/apis/smith/v1"
	smithClient_v1 "github.com/atlassian/smith/pkg/client/clientset_generated/clientset/typed/smith/v1"
	"github.com/atlassian/smith/pkg/plugin"
	"github.com/atlassian/smith/pkg/statuschecker"
	"github.com/atlassian/smith/pkg/store"
	"github.com/pkg/errors"
	"github.com/prometheus/client_golang/prometheus"
	"go.uber.org/zap"
	apps_v1 "k8s.io/api/apps/v1"
	core_v1 "k8s.io/api/core/v1"
	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/client-go/kubernetes"
	core_v1_client "k8s.io/client-go/kubernetes/typed/core/v1"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/tools/record"
)

const (
	byConfigMapNamespaceNameIndexName = "ByConfigMap"
	bySecretNamespaceNameIndexName    = "BySecret"
)

type byIndexFunc func(indexName, indexKey string) ([]interface{}, error)
type indexKeyFunc func(namespace, name string) string

type Controller struct {
	// wg.Wait() is called from Run() and first wg.Add() may be called concurrently from CRD listener
	// to start an Informer. This is a data race. This mutex is used to ensure ordering.
	// See https://github.com/atlassian/smith/issues/156
	// See https://github.com/golang/go/blob/fbc8973a6bc88b50509ea738f475b36ef756bf90/src/sync/waitgroup.go#L123-L126
	wgLock   sync.Mutex
	wg       wait.Group
	stopping bool

	crdContext       context.Context
	crdContextCancel context.CancelFunc

	Logger *zap.Logger

	ReadyForWork func()
	MainClient   kubernetes.Interface
	BundleClient smithClient_v1.BundlesGetter
	BundleStore  BundleStore
	SmartClient  SmartClient
	Rc           statuschecker.Interface
	Store        Store
	SpecChecker  SpecChecker
	WorkQueue    ctrl.WorkQueueProducer

	// CRD
	CrdResyncPeriod time.Duration
	Namespace       string

	PluginContainers map[smith_v1.PluginName]plugin.Container
	Scheme           *runtime.Scheme

	Catalog *store.Catalog

	// Metrics
	BundleTransitionCounter         *prometheus.CounterVec
	BundleResourceTransitionCounter *prometheus.CounterVec

	Broadcaster record.EventBroadcaster
	Recorder    record.EventRecorder
}

// Prepare prepares the controller to be run.
func (c *Controller) Prepare(crdInf cache.SharedIndexInformer, resourceInfs map[schema.GroupVersionKind]cache.SharedIndexInformer) error {
	c.crdContext, c.crdContextCancel = context.WithCancel(context.Background())
	crdInf.AddEventHandler(&crdEventHandler{
		controller: c,
		watchers:   make(map[string]watchState),
	})
	deploymentInf := resourceInfs[apps_v1.SchemeGroupVersion.WithKind("Deployment")]
	err := deploymentInf.AddIndexers(cache.Indexers{
		byConfigMapNamespaceNameIndexName: byConfigMapNamespaceNameIndex,
		bySecretNamespaceNameIndexName:    bySecretNamespaceNameIndex,
	})
	if err != nil {
		return errors.WithStack(err)
	}
	deploymentByIndex := deploymentInf.GetIndexer().ByIndex
	// ConfigMap -> Deployment -> Bundle event propagation
	configMapGVK := core_v1.SchemeGroupVersion.WithKind("ConfigMap")
	configMapInf := resourceInfs[configMapGVK]
	configMapInf.AddEventHandler(&handlers.LookupHandler{
		Logger:    c.Logger,
		WorkQueue: c.WorkQueue,
		Gvk:       configMapGVK,
		Lookup:    c.lookupBundleByDeploymentByIndex(deploymentByIndex, byConfigMapNamespaceNameIndexName, byConfigMapNamespaceNameIndexKey),
	})
	// Secret -> Deployment -> Bundle event propagation
	secretGVK := core_v1.SchemeGroupVersion.WithKind("Secret")
	secretInf := resourceInfs[secretGVK]
	secretInf.AddEventHandler(&handlers.LookupHandler{
		Logger:    c.Logger,
		WorkQueue: c.WorkQueue,
		Gvk:       secretGVK,
		Lookup:    c.lookupBundleByDeploymentByIndex(deploymentByIndex, bySecretNamespaceNameIndexName, bySecretNamespaceNameIndexKey),
	})
	// Standard handler
	for gvk, resourceInf := range resourceInfs {
		resourceInf.AddEventHandler(&handlers.ControlledResourceHandler{
			Logger:          c.Logger,
			WorkQueue:       c.WorkQueue,
			ControllerIndex: &controllerIndexAdapter{bundleStore: c.BundleStore},
			ControllerGvk:   smith_v1.BundleGVK,
			Gvk:             gvk,
		})
	}
	return nil
}

// Run begins watching and syncing.
// All informers must be synced before this method is invoked.
func (c *Controller) Run(ctx context.Context) {
	defer c.wg.Wait()
	defer c.crdContextCancel() // should be executed after stopping is set to true
	defer func() {
		c.wgLock.Lock()
		defer c.wgLock.Unlock()
		c.stopping = true
	}()

	c.Logger.Info("Starting Bundle controller")
	defer c.Logger.Info("Shutting down Bundle controller")

	sink := core_v1_client.EventSinkImpl{
		Interface: c.MainClient.CoreV1().Events(meta_v1.NamespaceNone),
	}
	recordingWatch := c.Broadcaster.StartRecordingToSink(&sink)
	defer recordingWatch.Stop()

	c.ReadyForWork()

	<-ctx.Done()
}

// lookupBundleByDeploymentByIndex returns a function that can be used to perform lookups of Bundles that contain
// Deployment objects that reference ConfigMap/Secret objects.
func (c *Controller) lookupBundleByDeploymentByIndex(byIndex byIndexFunc, indexName string, indexKey indexKeyFunc) func(runtime.Object) ([]runtime.Object, error) {
	deploymentGK := schema.GroupKind{
		Group: apps_v1.GroupName,
		Kind:  "Deployment",
	}
	return func(obj runtime.Object) ([]runtime.Object /*bundles*/, error) {
		// obj is ConfigMap or Secret
		objMeta := obj.(meta_v1.Object)
		// find all Deployments that reference this obj
		deploymentsFromIndex, err := byIndex(indexName, indexKey(objMeta.GetNamespace(), objMeta.GetName()))
		if err != nil {
			return nil, err
		}
		var bundles []runtime.Object
		for _, deploymentInterface := range deploymentsFromIndex {
			deployment := deploymentInterface.(*apps_v1.Deployment)
			// find all Bundles that reference this Deployment
			bundlesForDeployment, err := c.BundleStore.GetBundlesByObject(deploymentGK, deployment.Namespace, deployment.Name)
			if err != nil {
				return nil, err
			}
			for _, bundle := range bundlesForDeployment {
				bundles = append(bundles, bundle)
			}
		}
		return bundles, nil
	}
}

type controllerIndexAdapter struct {
	bundleStore BundleStore
}

func (c *controllerIndexAdapter) ControllerByObject(gk schema.GroupKind, namespace, name string) ([]runtime.Object, error) {
	bundles, err := c.bundleStore.GetBundlesByObject(gk, namespace, name)
	if err != nil {
		return nil, err
	}
	objs := make([]runtime.Object, 0, len(bundles))
	for _, bundle := range bundles {
		objs = append(objs, bundle)
	}
	return objs, nil
}

func byConfigMapNamespaceNameIndex(obj interface{}) ([]string, error) {
	d := obj.(*apps_v1.Deployment)
	index := configMapNamespaceNameIndexKeysForContainers(d.Namespace, d.Spec.Template.Spec.Containers)
	index = append(index, configMapNamespaceNameIndexKeysForContainers(d.Namespace, d.Spec.Template.Spec.InitContainers)...)
	return index, nil
}

func configMapNamespaceNameIndexKeysForContainers(namespace string, containers []core_v1.Container) []string {
	var indexKeys []string
	for _, container := range containers {
		for _, envFrom := range container.EnvFrom {
			configMapRef := envFrom.ConfigMapRef
			if configMapRef == nil {
				continue
			}
			indexKeys = append(indexKeys, byConfigMapNamespaceNameIndexKey(namespace, configMapRef.Name))
		}
		for _, env := range container.Env {
			valueFrom := env.ValueFrom
			if valueFrom == nil {
				continue
			}

			configMapKeyRef := valueFrom.ConfigMapKeyRef
			if configMapKeyRef == nil {
				continue
			}
			indexKeys = append(indexKeys, byConfigMapNamespaceNameIndexKey(namespace, configMapKeyRef.Name))
		}
	}
	return indexKeys
}

func byConfigMapNamespaceNameIndexKey(configMapNamespace, configMapName string) string {
	return configMapNamespace + "/" + configMapName
}

func bySecretNamespaceNameIndex(obj interface{}) ([]string, error) {
	d := obj.(*apps_v1.Deployment)
	index := secretNamespaceNameIndexKeysForContainers(d.Namespace, d.Spec.Template.Spec.Containers)
	index = append(index, secretNamespaceNameIndexKeysForContainers(d.Namespace, d.Spec.Template.Spec.InitContainers)...)
	return index, nil
}

func secretNamespaceNameIndexKeysForContainers(namespace string, containers []core_v1.Container) []string {
	var indexKeys []string
	for _, container := range containers {
		for _, envFrom := range container.EnvFrom {
			secretRef := envFrom.SecretRef
			if secretRef == nil {
				continue
			}
			indexKeys = append(indexKeys, bySecretNamespaceNameIndexKey(namespace, secretRef.Name))
		}
		for _, env := range container.Env {
			valueFrom := env.ValueFrom
			if valueFrom == nil {
				continue
			}

			secretKeyRef := valueFrom.SecretKeyRef
			if secretKeyRef == nil {
				continue
			}
			indexKeys = append(indexKeys, bySecretNamespaceNameIndexKey(namespace, secretKeyRef.Name))
		}
	}
	return indexKeys
}

func bySecretNamespaceNameIndexKey(secretNamespace, secretName string) string {
	return secretNamespace + "/" + secretName
}
<|endoftext|>


<commit_before>/*
Copyright 2014 The Camlistore 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 fastjpeg_test

import (
	"bytes"
	"image"
	"os"
	"os/exec"
	"reflect"
	"runtime"
	"strconv"
	"testing"

	"camlistore.org/pkg/images/fastjpeg"
	"camlistore.org/third_party/go/pkg/image/jpeg"
)

const (
	width  = 3840
	height = 1280
)

// testImage hold an image and the encoded jpeg bytes for the image.
type testImage struct {
	im  image.Image
	buf []byte
}

// makeTestImages generates an RGBA and a grayscale image and returns
// testImages containing the JPEG encoded form as bytes and the expected color
// model of the image when decoded.
func makeTestImages() ([]testImage, error) {
	var ims []testImage
	w := bytes.NewBuffer(nil)
	im1 := image.NewRGBA(image.Rect(0, 0, width, height))
	for i := range im1.Pix {
		switch {
		case i%4 == 3:
			im1.Pix[i] = 255
		default:
			im1.Pix[i] = uint8(i)
		}
	}
	if err := jpeg.Encode(w, im1, nil); err != nil {
		return nil, err
	}
	ims = append(ims, testImage{im: im1, buf: w.Bytes()})

	w = bytes.NewBuffer(nil)
	im2 := image.NewGray(image.Rect(0, 0, width, height))
	for i := range im2.Pix {
		im2.Pix[i] = uint8(i)
	}
	if err := jpeg.Encode(w, im2, nil); err != nil {
		return nil, err
	}
	ims = append(ims, testImage{im: im2, buf: w.Bytes()})
	return ims, nil

}

func TestDecodeDownsample(t *testing.T) {
	if !fastjpeg.Available() {
		t.Skip("djpeg isn't available.")
	}

	tis, err := makeTestImages()
	if err != nil {
		t.Fatal(err)
	}

	if _, err := fastjpeg.DecodeDownsample(bytes.NewReader(tis[0].buf), 0); err == nil {
		t.Errorf("Expect error for invalid sample factor 0")
	}
	for i, ti := range tis {
		for factor := 1; factor <= 8; factor *= 2 {
			im, err := fastjpeg.DecodeDownsample(bytes.NewReader(ti.buf), factor)
			if err != nil {
				t.Errorf("%d: Sample factor %d failed: %v", i, factor, err)
				continue
			}
			wantW := width / factor
			wantH := height / factor
			b := im.Bounds()
			gotW := b.Dx()
			gotH := b.Dy()

			if wantW != gotW || wantH != gotH || reflect.TypeOf(im) != reflect.TypeOf(ti.im) {
				t.Errorf("%d: Sample factor %d want image %dx%d %T got %dx%d %T", i, factor, wantW, wantH, ti.im, gotW, gotH, im)
			}
		}
	}
}

// TestUnavailable verifies the behavior of Available and DecodeDownsample
// when djpeg is not available.
// It sets the environment variable CAMLI_DISABLE_DJPEG and spawns
// a subprocess to simulate unavailability.
func TestUnavailable(t *testing.T) {
	if ok, _ := strconv.ParseBool(os.Getenv("CAMLI_DISABLE_DJPEG")); !ok {
		os.Setenv("CAMLI_DISABLE_DJPEG", "1")
		out, err := exec.Command(os.Args[0], "-test.v",
			"-test.run=TestUnavailable$").CombinedOutput()
		if err != nil {
			t.Fatalf("%v: %s", err, out)
		}
		return
	}

	if fastjpeg.Available() {
		t.Fatal("djpeg shouldn't be available when run with CAMLI_DISABLE_DJPEG set.")
	}

	tis, err := makeTestImages()
	if err != nil {
		t.Fatal(err)
	}
	if _, err := fastjpeg.DecodeDownsample(bytes.NewReader(tis[0].buf), 2); err != fastjpeg.ErrDjpegNotFound {
		t.Errorf("Wanted ErrDjpegNotFound, got %v", err)
	}
}

func TestFailed(t *testing.T) {
	switch runtime.GOOS {
	case "darwin", "freebsd", "linux":
	default:
		t.Skip("test only runs on UNIX")
	}
	oldPath := os.Getenv("PATH")
	defer os.Setenv("PATH", oldPath)
	// Use djpeg that exits after calling false.
	os.Setenv("PATH", "testdata")

	tis, err := makeTestImages()
	if err != nil {
		t.Fatal(err)
	}
	_, err = fastjpeg.DecodeDownsample(bytes.NewReader(tis[0].buf), 2)
	if _, ok := err.(fastjpeg.DjpegFailedError); !ok {
		t.Errorf("Got err type %T want ErrDjpegFailed, ", err)
	}
}

func TestFactor(t *testing.T) {
	if !fastjpeg.Available() {
		t.Skip("djpeg isn't available.")
	}

	const (
		width  = 3840
		height = 1280
	)
	testCases := []struct {
		w, h int
		want int
	}{
		{width + 1, height, 1},
		{width, height + 1, 1},
		{width, height, 1},
		{width - 1, height, 1},
		{width, height - 1, 1},
		{width/2 + 1, height / 2, 1},
		{width / 2, height/2 + 1, 1},

		{width / 2, height / 2, 2},
		{width/2 - 1, height / 2, 2},
		{width / 2, height/2 - 1, 2},

		{width / 8, height/8 + 1, 4},
		{width/8 + 1, height / 8, 4},

		{width / 8, height / 8, 8},
		{width / 8, height/8 - 1, 8},
		{width/8 - 1, height / 8, 8},
		{width/8 - 1, height/8 - 1, 8},
	}
	for _, tc := range testCases {
		if got := fastjpeg.Factor(width, height, tc.w, tc.h); got != tc.want {
			t.Errorf("%dx%d -> %dx%d got %d want %d", width, height,
				tc.w, tc.h, got, tc.want)
		}
	}
}
<commit_msg>images/fastjpeg: reset checkAvailability in tests.<commit_after>/*
Copyright 2014 The Camlistore 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 fastjpeg

import (
	"bytes"
	"image"
	"os"
	"os/exec"
	"path/filepath"
	"reflect"
	"runtime"
	"strconv"
	"sync"
	"testing"

	"camlistore.org/third_party/go/pkg/image/jpeg"
)

const (
	width  = 3840
	height = 1280
)

// testImage hold an image and the encoded jpeg bytes for the image.
type testImage struct {
	im  image.Image
	buf []byte
}

// makeTestImages generates an RGBA and a grayscale image and returns
// testImages containing the JPEG encoded form as bytes and the expected color
// model of the image when decoded.
func makeTestImages() ([]testImage, error) {
	var ims []testImage
	w := bytes.NewBuffer(nil)
	im1 := image.NewRGBA(image.Rect(0, 0, width, height))
	for i := range im1.Pix {
		switch {
		case i%4 == 3:
			im1.Pix[i] = 255
		default:
			im1.Pix[i] = uint8(i)
		}
	}
	if err := jpeg.Encode(w, im1, nil); err != nil {
		return nil, err
	}
	ims = append(ims, testImage{im: im1, buf: w.Bytes()})

	w = bytes.NewBuffer(nil)
	im2 := image.NewGray(image.Rect(0, 0, width, height))
	for i := range im2.Pix {
		im2.Pix[i] = uint8(i)
	}
	if err := jpeg.Encode(w, im2, nil); err != nil {
		return nil, err
	}
	ims = append(ims, testImage{im: im2, buf: w.Bytes()})
	return ims, nil

}

func TestDecodeDownsample(t *testing.T) {
	checkAvailability = sync.Once{}
	if !Available() {
		t.Skip("djpeg isn't available.")
	}

	tis, err := makeTestImages()
	if err != nil {
		t.Fatal(err)
	}

	if _, err := DecodeDownsample(bytes.NewReader(tis[0].buf), 0); err == nil {
		t.Errorf("Expect error for invalid sample factor 0")
	}
	for i, ti := range tis {
		for factor := 1; factor <= 8; factor *= 2 {
			im, err := DecodeDownsample(bytes.NewReader(ti.buf), factor)
			if err != nil {
				t.Errorf("%d: Sample factor %d failed: %v", i, factor, err)
				continue
			}
			wantW := width / factor
			wantH := height / factor
			b := im.Bounds()
			gotW := b.Dx()
			gotH := b.Dy()

			if wantW != gotW || wantH != gotH || reflect.TypeOf(im) != reflect.TypeOf(ti.im) {
				t.Errorf("%d: Sample factor %d want image %dx%d %T got %dx%d %T", i, factor, wantW, wantH, ti.im, gotW, gotH, im)
			}
		}
	}
}

// TestUnavailable verifies the behavior of Available and DecodeDownsample
// when djpeg is not available.
// It sets the environment variable CAMLI_DISABLE_DJPEG and spawns
// a subprocess to simulate unavailability.
func TestUnavailable(t *testing.T) {
	checkAvailability = sync.Once{}
	defer os.Setenv("CAMLI_DISABLE_DJPEG", "0")
	if ok, _ := strconv.ParseBool(os.Getenv("CAMLI_DISABLE_DJPEG")); !ok {
		os.Setenv("CAMLI_DISABLE_DJPEG", "1")
		out, err := exec.Command(os.Args[0], "-test.v",
			"-test.run=TestUnavailable$").CombinedOutput()
		if err != nil {
			t.Fatalf("%v: %s", err, out)
		}
		return
	}

	if Available() {
		t.Fatal("djpeg shouldn't be available when run with CAMLI_DISABLE_DJPEG set.")
	}

	tis, err := makeTestImages()
	if err != nil {
		t.Fatal(err)
	}
	if _, err := DecodeDownsample(bytes.NewReader(tis[0].buf), 2); err != ErrDjpegNotFound {
		t.Errorf("Wanted ErrDjpegNotFound, got %v", err)
	}
}

func TestFailed(t *testing.T) {
	checkAvailability = sync.Once{}
	switch runtime.GOOS {
	case "darwin", "freebsd", "linux":
	default:
		t.Skip("test only runs on UNIX")
	}
	oldPath := os.Getenv("PATH")
	defer os.Setenv("PATH", oldPath)
	// Use djpeg that exits after calling false.
	newPath, err := filepath.Abs("testdata")
	if err != nil {
		t.Fatal(err)
	}
	os.Setenv("PATH", newPath)
	t.Log("PATH", os.Getenv("PATH"))
	t.Log(exec.LookPath("djpeg"))

	tis, err := makeTestImages()
	if err != nil {
		t.Fatal(err)
	}
	_, err = DecodeDownsample(bytes.NewReader(tis[0].buf), 2)
	if _, ok := err.(DjpegFailedError); !ok {
		t.Errorf("Got err type %T want ErrDjpegFailed: %v", err, err)
	}
}

func TestFactor(t *testing.T) {
	checkAvailability = sync.Once{}
	if !Available() {
		t.Skip("djpeg isn't available.")
	}

	const (
		width  = 3840
		height = 1280
	)
	testCases := []struct {
		w, h int
		want int
	}{
		{width + 1, height, 1},
		{width, height + 1, 1},
		{width, height, 1},
		{width - 1, height, 1},
		{width, height - 1, 1},
		{width/2 + 1, height / 2, 1},
		{width / 2, height/2 + 1, 1},

		{width / 2, height / 2, 2},
		{width/2 - 1, height / 2, 2},
		{width / 2, height/2 - 1, 2},

		{width / 8, height/8 + 1, 4},
		{width/8 + 1, height / 8, 4},

		{width / 8, height / 8, 8},
		{width / 8, height/8 - 1, 8},
		{width/8 - 1, height / 8, 8},
		{width/8 - 1, height/8 - 1, 8},
	}
	for _, tc := range testCases {
		if got := Factor(width, height, tc.w, tc.h); got != tc.want {
			t.Errorf("%dx%d -> %dx%d got %d want %d", width, height,
				tc.w, tc.h, got, tc.want)
		}
	}
}
<|endoftext|>


<commit_before>package language

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

func TestLabelOperations(t *testing.T) {
	labelsBefore := NewLabelSet(map[string]string{"l1": "1", "l2": "2", "l3": "3"})

	ops := NewLabelOperations(
		map[string]string{"a": "b", "c": "d"},
		map[string]string{"l1": ""},
	)

	labelsAfter := labelsBefore.ApplyTransform(ops)

	assert.Equal(t, 4, len(labelsAfter.Labels), "Correct number of labels should be retained after transform")
	assert.Equal(t, "2", labelsAfter.Labels["l2"], "Label 'l2' should be retained")
	assert.Equal(t, "3", labelsAfter.Labels["l3"], "Label 'l3' should be retained")
	assert.Equal(t, "b", labelsAfter.Labels["a"], "Label 'a' should be added")
	assert.Equal(t, "d", labelsAfter.Labels["c"], "Label 'c' should be added")
	assert.Equal(t, "", labelsAfter.Labels["l1"], "Label 'l1' should not be present")

	labelsAfter = labelsAfter.ApplyTransform(nil)
	assert.Equal(t, 4, len(labelsAfter.Labels), "Correct number of labels should be retained after transform")
}
<commit_msg>100% unit test coverage for labels and label ops<commit_after>package language

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

func TestLabelSetOperations(t *testing.T) {
	labelsBefore := NewLabelSet(map[string]string{"l1": "1", "l2": "2", "l3": "3"})

	ops := NewLabelOperations(
		map[string]string{"a": "b", "c": "d"},
		map[string]string{"l1": ""},
	)

	labelsAfter := labelsBefore.ApplyTransform(ops)

	assert.Equal(t, 4, len(labelsAfter.Labels), "Correct number of labels should be retained after transform")
	assert.Equal(t, "2", labelsAfter.Labels["l2"], "Label 'l2' should be retained")
	assert.Equal(t, "3", labelsAfter.Labels["l3"], "Label 'l3' should be retained")
	assert.Equal(t, "b", labelsAfter.Labels["a"], "Label 'a' should be added")
	assert.Equal(t, "d", labelsAfter.Labels["c"], "Label 'c' should be added")
	assert.Equal(t, "", labelsAfter.Labels["l1"], "Label 'l1' should not be present")

	labelsAfter = labelsAfter.ApplyTransform(nil)
	assert.Equal(t, 4, len(labelsAfter.Labels), "Correct number of labels should be retained after transform")
}

func TestLabelSetOperationsSingleLabel(t *testing.T) {
	labelsBefore := NewLabelSet(map[string]string{"l1": "1", "l2": "2", "l3": "3"})
	ops := NewLabelOperationsSetSingleLabel("name", "value")

	labelsAfter := labelsBefore.ApplyTransform(ops)
	labelsEqual := NewLabelSet(map[string]string{"l1": "1", "l2": "2", "l3": "3", "name": "value"})
	assert.True(t, labelsAfter.Equal(labelsEqual), "Label sets ops when setting a single label should work")
}

func TestLabelSetEquals(t *testing.T) {
	labelsBefore := NewLabelSet(map[string]string{"a": "1", "b": "2", "c": "3"})

	ops := NewLabelOperations(
		map[string]string{"d": "4", "e": "5", "a": "aValue"},
		map[string]string{"c": ""},
	)

	labelsAfter := labelsBefore.ApplyTransform(ops)

	// check for equal
	labelsEqual := NewLabelSet(map[string]string{"a": "aValue", "b": "2", "d": "4", "e": "5"})
	assert.True(t, labelsAfter.Equal(labelsEqual), "Label sets should be equal")

	// check for not equal
	labelsNotEqual := NewLabelSet(map[string]string{"b": "2", "d": "someValue", "e": "5"})
	assert.False(t, labelsAfter.Equal(labelsNotEqual), "Label sets should not be equal")

	// check for equal (map with zero lengths and nil)
	labelsEmpty := NewLabelSet(map[string]string{})
	assert.True(t, labelsEmpty.Equal(NewLabelSet(nil)), "Empty label sets should be equal")
}

func TestLabelSetAdd(t *testing.T) {
	labels1 := NewLabelSet(map[string]string{"a": "1", "b": "2", "c": "3"})
	labels2 := NewLabelSet(map[string]string{"c": "4", "d": "5", "e": "6"})
	labelsAfter := labels1.AddLabels(labels2)

	// check for equal
	labelsEqual := NewLabelSet(map[string]string{"a": "1", "b": "2", "c": "4", "d": "5", "e": "6"})
	assert.True(t, labelsAfter.Equal(labelsEqual), "Label sets addition should work")
}

<|endoftext|>


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

package util

import (
	"strings"

	appsv1 "k8s.io/api/apps/v1"
	k8sv1 "k8s.io/api/core/v1"

	v1 "kubevirt.io/kubevirt/pkg/api/v1"
	"kubevirt.io/kubevirt/pkg/log"
)

func DaemonsetIsReady(kv *v1.KubeVirt, daemonset *appsv1.DaemonSet, stores Stores) bool {

	// ensure we're looking at the latest daemonset from cache
	obj, exists, _ := stores.DaemonSetCache.Get(daemonset)
	if exists {
		daemonset = obj.(*appsv1.DaemonSet)
	} else {
		// not in cache yet
		return false
	}

	if daemonset.Status.DesiredNumberScheduled == 0 ||
		daemonset.Status.DesiredNumberScheduled != daemonset.Status.NumberReady {

		log.Log.V(4).Infof("DaemonSet %v not ready yet", daemonset.Name)
		return false
	}

	// cross check that we have 'daemonset.Status.NumberReady' pods with
	// the desired version tag. This ensures we wait for rolling update to complete
	// before marking the infrastructure as 100% ready.
	var podsReady int32
	for _, obj := range stores.InfrastructurePodCache.List() {
		if pod, ok := obj.(*k8sv1.Pod); ok {
			if !podIsRunning(pod) {
				continue
			} else if !podHasNamePrefix(pod, daemonset.Name) {
				continue
			}

			if !podIsUpToDate(pod, kv) {
				log.Log.Infof("DaemonSet %v waiting for out of date pods to terminate.", daemonset.Name)
				return false
			}

			if podIsReady(pod) {
				podsReady++
			}
		}
	}

	if podsReady == 0 {
		log.Log.Infof("DaemonSet %v not ready yet. Waiting on at least one ready pod", daemonset.Name)
		return false
	}

	return true
}

func DeploymentIsReady(kv *v1.KubeVirt, deployment *appsv1.Deployment, stores Stores) bool {
	// ensure we're looking at the latest deployment from cache
	obj, exists, _ := stores.DeploymentCache.Get(deployment)
	if exists {
		deployment = obj.(*appsv1.Deployment)
	} else {
		// not in cache yet
		return false
	}

	var specReplicas int32 = 1
	if deployment.Spec.Replicas != nil {
		specReplicas = *deployment.Spec.Replicas
	}
	if specReplicas != deployment.Status.Replicas ||
		deployment.Status.Replicas != deployment.Status.ReadyReplicas {
		log.Log.V(4).Infof("Deployment %v not ready yet", deployment.Name)
		return false
	}

	// cross check that we have 'deployment.Status.ReadyReplicas' pods with
	// the desired version tag. This ensures we wait for rolling update to complete
	// before marking the infrastructure as 100% ready.
	var podsReady int32
	for _, obj := range stores.InfrastructurePodCache.List() {
		if pod, ok := obj.(*k8sv1.Pod); ok {
			if !podIsRunning(pod) {
				continue
			} else if !podHasNamePrefix(pod, deployment.Name) {
				continue
			}

			if !podIsUpToDate(pod, kv) {
				log.Log.Infof("Deployment %v waiting for out of date pods to terminate.", deployment.Name)
				return false
			}

			if podIsReady(pod) {
				podsReady++
			}
		}
	}

	if podsReady == 0 {
		log.Log.Infof("Deployment %v not ready yet. Waiting for at least one pod to become ready", deployment.Name)
		return false
	}
	return true
}

func podIsDown(pod *k8sv1.Pod) bool {
	return pod.Status.Phase == k8sv1.PodSucceeded || pod.Status.Phase == k8sv1.PodFailed
}

func podIsRunning(pod *k8sv1.Pod) bool {
	return pod.Status.Phase == k8sv1.PodRunning
}

func podHasNamePrefix(pod *k8sv1.Pod, namePrefix string) bool {
	if strings.Contains(pod.Name, namePrefix) {
		return true
	}
	return false
}

func podIsUpToDate(pod *k8sv1.Pod, kv *v1.KubeVirt) bool {
	if pod.Annotations == nil {
		return false
	}

	imageTag, ok := pod.Annotations[v1.InstallStrategyVersionAnnotation]
	if !ok || imageTag != kv.Status.TargetKubeVirtVersion {
		return false
	}

	imageRegistry, ok := pod.Annotations[v1.InstallStrategyRegistryAnnotation]
	if !ok || imageRegistry != kv.Status.TargetKubeVirtRegistry {
		return false
	}
	return true
}

func podIsReady(pod *k8sv1.Pod) bool {
	if pod.Status.Phase != k8sv1.PodRunning {
		return false
	}
	for _, containerStatus := range pod.Status.ContainerStatuses {
		if !containerStatus.Ready {
			return false
		}
	}
	return true
}
<commit_msg>remove unused code<commit_after>/*
 * This file is part of the KubeVirt project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Copyright 2019 Red Hat, Inc.
 *
 */

package util

import (
	"strings"

	appsv1 "k8s.io/api/apps/v1"
	k8sv1 "k8s.io/api/core/v1"

	v1 "kubevirt.io/kubevirt/pkg/api/v1"
	"kubevirt.io/kubevirt/pkg/log"
)

func DaemonsetIsReady(kv *v1.KubeVirt, daemonset *appsv1.DaemonSet, stores Stores) bool {

	// ensure we're looking at the latest daemonset from cache
	obj, exists, _ := stores.DaemonSetCache.Get(daemonset)
	if exists {
		daemonset = obj.(*appsv1.DaemonSet)
	} else {
		// not in cache yet
		return false
	}

	if daemonset.Status.DesiredNumberScheduled == 0 ||
		daemonset.Status.DesiredNumberScheduled != daemonset.Status.NumberReady {

		log.Log.V(4).Infof("DaemonSet %v not ready yet", daemonset.Name)
		return false
	}

	// cross check that we have 'daemonset.Status.NumberReady' pods with
	// the desired version tag. This ensures we wait for rolling update to complete
	// before marking the infrastructure as 100% ready.
	var podsReady int32
	for _, obj := range stores.InfrastructurePodCache.List() {
		if pod, ok := obj.(*k8sv1.Pod); ok {
			if !podIsRunning(pod) {
				continue
			} else if !podHasNamePrefix(pod, daemonset.Name) {
				continue
			}

			if !podIsUpToDate(pod, kv) {
				log.Log.Infof("DaemonSet %v waiting for out of date pods to terminate.", daemonset.Name)
				return false
			}

			if podIsReady(pod) {
				podsReady++
			}
		}
	}

	if podsReady == 0 {
		log.Log.Infof("DaemonSet %v not ready yet. Waiting on at least one ready pod", daemonset.Name)
		return false
	}

	return true
}

func DeploymentIsReady(kv *v1.KubeVirt, deployment *appsv1.Deployment, stores Stores) bool {
	// ensure we're looking at the latest deployment from cache
	obj, exists, _ := stores.DeploymentCache.Get(deployment)
	if exists {
		deployment = obj.(*appsv1.Deployment)
	} else {
		// not in cache yet
		return false
	}

	var specReplicas int32 = 1
	if deployment.Spec.Replicas != nil {
		specReplicas = *deployment.Spec.Replicas
	}
	if specReplicas != deployment.Status.Replicas ||
		deployment.Status.Replicas != deployment.Status.ReadyReplicas {
		log.Log.V(4).Infof("Deployment %v not ready yet", deployment.Name)
		return false
	}

	// cross check that we have 'deployment.Status.ReadyReplicas' pods with
	// the desired version tag. This ensures we wait for rolling update to complete
	// before marking the infrastructure as 100% ready.
	var podsReady int32
	for _, obj := range stores.InfrastructurePodCache.List() {
		if pod, ok := obj.(*k8sv1.Pod); ok {
			if !podIsRunning(pod) {
				continue
			} else if !podHasNamePrefix(pod, deployment.Name) {
				continue
			}

			if !podIsUpToDate(pod, kv) {
				log.Log.Infof("Deployment %v waiting for out of date pods to terminate.", deployment.Name)
				return false
			}

			if podIsReady(pod) {
				podsReady++
			}
		}
	}

	if podsReady == 0 {
		log.Log.Infof("Deployment %v not ready yet. Waiting for at least one pod to become ready", deployment.Name)
		return false
	}
	return true
}

func podIsRunning(pod *k8sv1.Pod) bool {
	return pod.Status.Phase == k8sv1.PodRunning
}

func podHasNamePrefix(pod *k8sv1.Pod, namePrefix string) bool {
	if strings.Contains(pod.Name, namePrefix) {
		return true
	}
	return false
}

func podIsUpToDate(pod *k8sv1.Pod, kv *v1.KubeVirt) bool {
	if pod.Annotations == nil {
		return false
	}

	imageTag, ok := pod.Annotations[v1.InstallStrategyVersionAnnotation]
	if !ok || imageTag != kv.Status.TargetKubeVirtVersion {
		return false
	}

	imageRegistry, ok := pod.Annotations[v1.InstallStrategyRegistryAnnotation]
	if !ok || imageRegistry != kv.Status.TargetKubeVirtRegistry {
		return false
	}
	return true
}

func podIsReady(pod *k8sv1.Pod) bool {
	if pod.Status.Phase != k8sv1.PodRunning {
		return false
	}
	for _, containerStatus := range pod.Status.ContainerStatuses {
		if !containerStatus.Ready {
			return false
		}
	}
	return true
}
<|endoftext|>


<commit_before>package core

import (
	"testing"

	"strings"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/suite"
)

const regularDXF = `  0
SECTION
  2
HEADER
  9
$ACADVER
  1
AC1018
  9
$DWGCODEPAGE
  3
ANSI_1252
  0
ENDSEC
  0
EOF
`

const noEOFDXF = `  0
SECTION
  2
HEADER
  9
$ACADVER
  1
AC1018
  9
$DWGCODEPAGE
  3
ANSI_1252
  0
ENDSEC
`

const regularDXFComments = `999
Comment0
  0
SECTION
  2
HEADER
  9
$ACADVER
999
Comment1
  1
AC1018
  9
$DWGCODEPAGE
  3
ANSI_1252
  0
ENDSEC
  0
EOF
`

const regularDXFAppDataAndXData = `  0
SECTION
  2
HEADER
  9
$ACADVER
  1
AC1018
  9
$DWGCODEPAGE
  3
ANSI_1252
  102
{DXFGrabber
330
999
  102
}
  0
ENDSEC
  1001
DXFGRABBER
  1000
XDATA_STRING
  0
EOF
`

const dxfEllipse = ` 0
ELLIPSE
5
3D2
330
1F
100
AcDbEntity
8
0
100
AcDbEllipse
10
0.0
20
0.0
30
0.0
11
2.60
21
1.50
31
0.0
210
0.0
220
0.0
230
1.0
40
0.33
41
0.0
42
6.28
`

var expectedRegularDxfTags = []*Tag{
	&Tag{Code: 0, Value: &String{"SECTION"}},
	&Tag{Code: 2, Value: &String{"HEADER"}},
	&Tag{Code: 9, Value: &String{"$ACADVER"}},
	&Tag{Code: 1, Value: &String{"AC1018"}},
	&Tag{Code: 9, Value: &String{"$DWGCODEPAGE"}},
	&Tag{Code: 3, Value: &String{"ANSI_1252"}},
	&Tag{Code: 0, Value: &String{"ENDSEC"}},
	&Tag{Code: 0, Value: &String{"EOF"}},
}

func TestTagEquality(t *testing.T) {
	str1, _ := NewString("TEST")
	str2, _ := NewString("STRING")
	int1, _ := NewInteger("1001")
	int2, _ := NewInteger("9")
	float1, _ := NewFloat("10.01")
	float2, _ := NewFloat("0.33")

	assert.Equal(t, &Tag{Code: 1, Value: str1}, &Tag{Code: 1, Value: str1})
	assert.Equal(t, &Tag{Code: 2, Value: int1}, &Tag{Code: 2, Value: int1})
	assert.Equal(t, &Tag{Code: 3, Value: float1}, &Tag{Code: 3, Value: float1})

	assert.NotEqual(t, &Tag{Code: 1, Value: str1}, &Tag{Code: 1, Value: str2})
	assert.NotEqual(t, &Tag{Code: 0, Value: str1}, &Tag{Code: 1, Value: str1})
	assert.NotEqual(t, &Tag{Code: 0, Value: str1}, &Tag{Code: 0, Value: int1})
	assert.NotEqual(t, &Tag{Code: 0, Value: str1}, &Tag{Code: 0, Value: float1})

	assert.NotEqual(t, &Tag{Code: 1, Value: int1}, &Tag{Code: 1, Value: int2})
	assert.NotEqual(t, &Tag{Code: 0, Value: int1}, &Tag{Code: 1, Value: int1})
	assert.NotEqual(t, &Tag{Code: 0, Value: int1}, &Tag{Code: 0, Value: str1})
	assert.NotEqual(t, &Tag{Code: 0, Value: int1}, &Tag{Code: 0, Value: float1})

	assert.NotEqual(t, &Tag{Code: 1, Value: float1}, &Tag{Code: 1, Value: float2})
	assert.NotEqual(t, &Tag{Code: 0, Value: float1}, &Tag{Code: 1, Value: float1})
	assert.NotEqual(t, &Tag{Code: 0, Value: float1}, &Tag{Code: 0, Value: str1})
	assert.NotEqual(t, &Tag{Code: 0, Value: float1}, &Tag{Code: 0, Value: int1})
}

type TaggerTestSuite struct {
	suite.Suite
}

func (suite *TaggerTestSuite) SetupTest() {
}

func (suite *TaggerTestSuite) TestEmptyStream() {
	next := Tagger(strings.NewReader(""))
	tag, err := next()

	suite.Equal(&NoneTag, tag)
	suite.Equal(nil, err)
}

func (suite *TaggerTestSuite) TestNextTag() {
	next := Tagger(strings.NewReader(regularDXF))
	tag, err := next()

	suite.Equal(nil, err)
	suite.Equal(0, tag.Code)
	suite.Equal("SECTION", tag.Value.ToString())
}

func (suite *TaggerTestSuite) TestAllTags() {
	next := Tagger(strings.NewReader(regularDXF))
	suite.Equal(expectedRegularDxfTags, AllTags(next))
}

func (suite *TaggerTestSuite) TestAllTagsWithoutEof() {
	next := Tagger(strings.NewReader(noEOFDXF))

	expected := []*Tag{
		&Tag{Code: 0, Value: &String{"SECTION"}},
		&Tag{Code: 2, Value: &String{"HEADER"}},
		&Tag{Code: 9, Value: &String{"$ACADVER"}},
		&Tag{Code: 1, Value: &String{"AC1018"}},
		&Tag{Code: 9, Value: &String{"$DWGCODEPAGE"}},
		&Tag{Code: 3, Value: &String{"ANSI_1252"}},
		&Tag{Code: 0, Value: &String{"ENDSEC"}},
	}

	suite.Equal(expected, AllTags(next))
}

func (suite *TaggerTestSuite) TestDXFWithComments() {
	next := Tagger(strings.NewReader(regularDXFComments))

	expected := []*Tag{
		&Tag{Code: 999, Value: &String{"Comment0"}},
		&Tag{Code: 0, Value: &String{"SECTION"}},
		&Tag{Code: 2, Value: &String{"HEADER"}},
		&Tag{Code: 9, Value: &String{"$ACADVER"}},
		&Tag{Code: 999, Value: &String{"Comment1"}},
		&Tag{Code: 1, Value: &String{"AC1018"}},
		&Tag{Code: 9, Value: &String{"$DWGCODEPAGE"}},
		&Tag{Code: 3, Value: &String{"ANSI_1252"}},
		&Tag{Code: 0, Value: &String{"ENDSEC"}},
		&Tag{Code: 0, Value: &String{"EOF"}},
	}

	suite.Equal(expected, AllTags(next))
}

func (suite *TaggerTestSuite) TestIntAndFloatTags() {
	intAndFloatTags := "  60\n1001\n  20\n15.54"
	next := Tagger(strings.NewReader(intAndFloatTags))

	expected := []*Tag{
		&Tag{Code: 60, Value: &Integer{1001}},
		&Tag{Code: 20, Value: &Float{15.54}},
	}

	suite.Equal(expected, AllTags(next))
}

func TestTaggerTestSuite(t *testing.T) {
	suite.Run(t, new(TaggerTestSuite))
}

type TagSliceTestSuite struct {
	suite.Suite
	tags TagSlice
}

func (suite *TagSliceTestSuite) SetupTest() {
	next := Tagger(strings.NewReader(regularDXF))
	suite.tags = TagSlice(AllTags(next))
}

func (suite *TagSliceTestSuite) TestTagIndex() {
	index := suite.tags.TagIndex(0, 0, len(suite.tags))
	suite.Equal(0, index)

	index = suite.tags.TagIndex(0, index+1, len(suite.tags))
	suite.Equal(6, index)
}

func (suite *TagSliceTestSuite) TestInexistentTagIndex() {
	suite.Equal(-1, suite.tags.TagIndex(50, 0, len(suite.tags)))
}

func (suite *TagSliceTestSuite) TestAllWithCode() {
	expected := []*Tag{
		&Tag{Code: 0, Value: &String{value: "SECTION"}},
		&Tag{Code: 0, Value: &String{value: "ENDSEC"}},
		&Tag{Code: 0, Value: &String{value: "EOF"}},
	}
	suite.Equal(expected, suite.tags.AllWithCode(0))
	suite.Equal([]*Tag{}, suite.tags.AllWithCode(50))
}

func (suite *TagSliceTestSuite) TestRegularTags() {
	next := Tagger(strings.NewReader(regularDXFAppDataAndXData))
	tags := TagSlice(AllTags(next))

	suite.Equal(expectedRegularDxfTags, tags.RegularTags())
}

func (suite *TagSliceTestSuite) TestXDataTags() {
	next := Tagger(strings.NewReader(regularDXFAppDataAndXData))
	tags := TagSlice(AllTags(next))

	expected := []*Tag{
		&Tag{Code: 1001, Value: &String{value: "DXFGRABBER"}},
		&Tag{Code: 1000, Value: &String{value: "XDATA_STRING"}},
	}

	suite.Equal(expected, tags.XDataTags())
}

func (suite *TagSliceTestSuite) TestAppDataTags() {
	next := Tagger(strings.NewReader(regularDXFAppDataAndXData))
	tags := TagSlice(AllTags(next))

	expected := []*Tag{
		&Tag{Code: 102, Value: &String{value: "{DXFGrabber"}},
		&Tag{Code: 330, Value: &String{value: "999"}},
		&Tag{Code: 102, Value: &String{value: "}"}},
	}
	appData := tags.AppDataTags()

	suite.Equal(expected, appData["{DXFGrabber"])
}

func (suite *TagSliceTestSuite) TestSubclassesTags() {
	next := Tagger(strings.NewReader(dxfEllipse))
	tags := TagSlice(AllTags(next))

	subclasses := tags.SubclassesTags()
	suite.Equal(3, len(subclasses))
	suite.Equal(3, len(subclasses["noname"]))
	suite.Equal(1, len(subclasses["AcDbEntity"]))
	suite.Equal(12, len(subclasses["AcDbEllipse"]))
}

func TestTagSliceTestSuite(t *testing.T) {
	suite.Run(t, new(TagSliceTestSuite))
}

func TestTagGroups(t *testing.T) {
	next := Tagger(strings.NewReader(regularDXF))
	tags := TagSlice(AllTags(next))

	groups := TagGroups(tags[2:len(tags)-2], 9)

	expected := []TagSlice{
		TagSlice{
			NewTag(9, NewStringValue("$ACADVER")),
			NewTag(1, NewStringValue("AC1018"))},

		TagSlice{
			NewTag(9, NewStringValue("$DWGCODEPAGE")),
			NewTag(3, NewStringValue("ANSI_1252"))},
	}

	assert.EqualValues(t, expected, groups)
}
<commit_msg>Cleanup tags test<commit_after>package core

import (
	"testing"

	"strings"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/suite"
)

const regularDXF = `  0
SECTION
  2
HEADER
  9
$ACADVER
  1
AC1018
  9
$DWGCODEPAGE
  3
ANSI_1252
  0
ENDSEC
  0
EOF
`

const noEOFDXF = `  0
SECTION
  2
HEADER
  9
$ACADVER
  1
AC1018
  9
$DWGCODEPAGE
  3
ANSI_1252
  0
ENDSEC
`

const regularDXFComments = `999
Comment0
  0
SECTION
  2
HEADER
  9
$ACADVER
999
Comment1
  1
AC1018
  9
$DWGCODEPAGE
  3
ANSI_1252
  0
ENDSEC
  0
EOF
`

const regularDXFAppDataAndXData = `  0
SECTION
  2
HEADER
  9
$ACADVER
  1
AC1018
  9
$DWGCODEPAGE
  3
ANSI_1252
  102
{DXFGrabber
330
999
  102
}
  0
ENDSEC
  1001
DXFGRABBER
  1000
XDATA_STRING
  0
EOF
`

const dxfEllipse = ` 0
ELLIPSE
5
3D2
330
1F
100
AcDbEntity
8
0
100
AcDbEllipse
10
0.0
20
0.0
30
0.0
11
2.60
21
1.50
31
0.0
210
0.0
220
0.0
230
1.0
40
0.33
41
0.0
42
6.28
`

var expectedRegularDxfTags = []*Tag{
	NewTag(0, NewStringValue("SECTION")),
	NewTag(2, NewStringValue("HEADER")),
	NewTag(9, NewStringValue("$ACADVER")),
	NewTag(1, NewStringValue("AC1018")),
	NewTag(9, NewStringValue("$DWGCODEPAGE")),
	NewTag(3, NewStringValue("ANSI_1252")),
	NewTag(0, NewStringValue("ENDSEC")),
	NewTag(0, NewStringValue("EOF")),
}

func TestTagEquality(t *testing.T) {
	str1 := NewStringValue("TEST")
	str2 := NewStringValue("STRING")
	int1 := NewIntegerValue(1001)
	int2 := NewIntegerValue(9)
	float1 := NewFloatValue(10.01)
	float2 := NewFloatValue(0.33)

	assert.Equal(t, NewTag(1, str1), NewTag(1, str1))
	assert.Equal(t, NewTag(2, int1), NewTag(2, int1))
	assert.Equal(t, NewTag(3, float1), NewTag(3, float1))

	assert.NotEqual(t, NewTag(1, str1), NewTag(1, str2))
	assert.NotEqual(t, NewTag(0, str1), NewTag(1, str1))
	assert.NotEqual(t, NewTag(0, str1), NewTag(0, int1))
	assert.NotEqual(t, NewTag(0, str1), NewTag(0, float1))

	assert.NotEqual(t, NewTag(1, int1), NewTag(1, int2))
	assert.NotEqual(t, NewTag(0, int1), NewTag(1, int1))
	assert.NotEqual(t, NewTag(0, int1), NewTag(0, str1))
	assert.NotEqual(t, NewTag(0, int1), NewTag(0, float1))

	assert.NotEqual(t, NewTag(1, float1), NewTag(1, float2))
	assert.NotEqual(t, NewTag(0, float1), NewTag(1, float1))
	assert.NotEqual(t, NewTag(0, float1), NewTag(0, str1))
	assert.NotEqual(t, NewTag(0, float1), NewTag(0, int1))
}

type TaggerTestSuite struct {
	suite.Suite
}

func (suite *TaggerTestSuite) SetupTest() {
}

func (suite *TaggerTestSuite) TestEmptyStream() {
	next := Tagger(strings.NewReader(""))
	tag, err := next()

	suite.Equal(&NoneTag, tag)
	suite.Equal(nil, err)
}

func (suite *TaggerTestSuite) TestNextTag() {
	next := Tagger(strings.NewReader(regularDXF))
	tag, err := next()

	suite.Equal(nil, err)
	suite.Equal(0, tag.Code)
	suite.Equal("SECTION", tag.Value.ToString())
}

func (suite *TaggerTestSuite) TestAllTags() {
	next := Tagger(strings.NewReader(regularDXF))
	suite.Equal(expectedRegularDxfTags, AllTags(next))
}

func (suite *TaggerTestSuite) TestAllTagsWithoutEof() {
	next := Tagger(strings.NewReader(noEOFDXF))

	expected := []*Tag{
		NewTag(0, NewStringValue("SECTION")),
		NewTag(2, NewStringValue("HEADER")),
		NewTag(9, NewStringValue("$ACADVER")),
		NewTag(1, NewStringValue("AC1018")),
		NewTag(9, NewStringValue("$DWGCODEPAGE")),
		NewTag(3, NewStringValue("ANSI_1252")),
		NewTag(0, NewStringValue("ENDSEC")),
	}

	suite.Equal(expected, AllTags(next))
}

func (suite *TaggerTestSuite) TestDXFWithComments() {
	next := Tagger(strings.NewReader(regularDXFComments))

	expected := []*Tag{
		NewTag(999, NewStringValue("Comment0")),
		NewTag(0, NewStringValue("SECTION")),
		NewTag(2, NewStringValue("HEADER")),
		NewTag(9, NewStringValue("$ACADVER")),
		NewTag(999, NewStringValue("Comment1")),
		NewTag(1, NewStringValue("AC1018")),
		NewTag(9, NewStringValue("$DWGCODEPAGE")),
		NewTag(3, NewStringValue("ANSI_1252")),
		NewTag(0, NewStringValue("ENDSEC")),
		NewTag(0, NewStringValue("EOF")),
	}

	suite.Equal(expected, AllTags(next))
}

func (suite *TaggerTestSuite) TestIntAndFloatTags() {
	intAndFloatTags := "  60\n1001\n  20\n15.54"
	next := Tagger(strings.NewReader(intAndFloatTags))

	expected := []*Tag{
		NewTag(60, NewIntegerValue(1001)),
		NewTag(20, NewFloatValue(15.54)),
	}

	suite.Equal(expected, AllTags(next))
}

func TestTaggerTestSuite(t *testing.T) {
	suite.Run(t, new(TaggerTestSuite))
}

type TagSliceTestSuite struct {
	suite.Suite
	tags TagSlice
}

func (suite *TagSliceTestSuite) SetupTest() {
	next := Tagger(strings.NewReader(regularDXF))
	suite.tags = TagSlice(AllTags(next))
}

func (suite *TagSliceTestSuite) TestTagIndex() {
	index := suite.tags.TagIndex(0, 0, len(suite.tags))
	suite.Equal(0, index)

	index = suite.tags.TagIndex(0, index+1, len(suite.tags))
	suite.Equal(6, index)
}

func (suite *TagSliceTestSuite) TestInexistentTagIndex() {
	suite.Equal(-1, suite.tags.TagIndex(50, 0, len(suite.tags)))
}

func (suite *TagSliceTestSuite) TestAllWithCode() {
	expected := []*Tag{
		NewTag(0, NewStringValue("SECTION")),
		NewTag(0, NewStringValue("ENDSEC")),
		NewTag(0, NewStringValue("EOF")),
	}
	suite.Equal(expected, suite.tags.AllWithCode(0))
	suite.Equal([]*Tag{}, suite.tags.AllWithCode(50))
}

func (suite *TagSliceTestSuite) TestRegularTags() {
	next := Tagger(strings.NewReader(regularDXFAppDataAndXData))
	tags := TagSlice(AllTags(next))

	suite.Equal(expectedRegularDxfTags, tags.RegularTags())
}

func (suite *TagSliceTestSuite) TestXDataTags() {
	next := Tagger(strings.NewReader(regularDXFAppDataAndXData))
	tags := TagSlice(AllTags(next))

	expected := []*Tag{
		NewTag(1001, NewStringValue("DXFGRABBER")),
		NewTag(1000, NewStringValue("XDATA_STRING")),
	}

	suite.Equal(expected, tags.XDataTags())
}

func (suite *TagSliceTestSuite) TestAppDataTags() {
	next := Tagger(strings.NewReader(regularDXFAppDataAndXData))
	tags := TagSlice(AllTags(next))

	expected := []*Tag{
		NewTag(102, NewStringValue("{DXFGrabber")),
		NewTag(330, NewStringValue("999")),
		NewTag(102, NewStringValue("}")),
	}
	appData := tags.AppDataTags()

	suite.Equal(expected, appData["{DXFGrabber"])
}

func (suite *TagSliceTestSuite) TestSubclassesTags() {
	next := Tagger(strings.NewReader(dxfEllipse))
	tags := TagSlice(AllTags(next))

	subclasses := tags.SubclassesTags()
	suite.Equal(3, len(subclasses))
	suite.Equal(3, len(subclasses["noname"]))
	suite.Equal(1, len(subclasses["AcDbEntity"]))
	suite.Equal(12, len(subclasses["AcDbEllipse"]))
}

func TestTagSliceTestSuite(t *testing.T) {
	suite.Run(t, new(TagSliceTestSuite))
}

func TestTagGroups(t *testing.T) {
	next := Tagger(strings.NewReader(regularDXF))
	tags := TagSlice(AllTags(next))

	groups := TagGroups(tags[2:len(tags)-2], 9)

	expected := []TagSlice{
		{
			NewTag(9, NewStringValue("$ACADVER")),
			NewTag(1, NewStringValue("AC1018")),
		},
		{
			NewTag(9, NewStringValue("$DWGCODEPAGE")),
			NewTag(3, NewStringValue("ANSI_1252")),
		},
	}

	assert.EqualValues(t, expected, groups)
}
<|endoftext|>


<commit_before>package factomapi

import (
	"io"
	"github.com/FactomProject/gocoding"
	"github.com/FactomProject/gocoding/json"
	"github.com/FactomProject/gocoding/html"
	"github.com/FactomProject/FactomCode/notaryapi"
	"fmt"
	"errors"
)

func SafeMarshal(writer io.Writer, obj interface{}) error {
	marshaller := json.NewMarshaller()
	renderer := json.Render(writer)
	renderer.SetRecoverHandler(safeRecover)
	return marshaller.Marshal(renderer, obj)
}

func SafeMarshalHTML(writer io.Writer, obj interface{}) error {
	renderer := html.Render(writer)
	renderer.SetRecoverHandler(safeRecover)

	marshallerHTML := html.NewMarshaller()
	return marshallerHTML.Marshal(renderer, obj)
}

func SafeUnmarshal(reader gocoding.SliceableRuneReader, obj interface{}) error {
	scanner := json.Scan(reader)
	scanner.SetRecoverHandler(EXPLODE)
	unmarshaller := notaryapi.NewJSONUnmarshaller()
	return unmarshaller.Unmarshal(scanner, obj)
}
func safeRecover(obj interface{}) error {
	if err, ok := obj.(error); ok {
		return err
	}

	return errors.New(fmt.Sprint(obj))
}

func EXPLODE(obj interface{}) error {
	panic(obj)
}
<commit_msg>formatting on factomapi/wsapi.go<commit_after>package factomapi

import (
	"errors"
	"fmt"
	"github.com/FactomProject/FactomCode/notaryapi"
	"github.com/FactomProject/gocoding"
	"github.com/FactomProject/gocoding/html"
	"github.com/FactomProject/gocoding/json"
	"io"
)

func SafeMarshal(writer io.Writer, obj interface{}) error {
	marshaller := json.NewMarshaller()
	renderer := json.Render(writer)
	renderer.SetRecoverHandler(safeRecover)
	return marshaller.Marshal(renderer, obj)
}

func SafeMarshalHTML(writer io.Writer, obj interface{}) error {
	renderer := html.Render(writer)
	renderer.SetRecoverHandler(safeRecover)

	marshallerHTML := html.NewMarshaller()
	return marshallerHTML.Marshal(renderer, obj)
}

func SafeUnmarshal(reader gocoding.SliceableRuneReader, obj interface{}) error {
	scanner := json.Scan(reader)
	scanner.SetRecoverHandler(EXPLODE)
	unmarshaller := notaryapi.NewJSONUnmarshaller()
	return unmarshaller.Unmarshal(scanner, obj)
}

func safeRecover(obj interface{}) error {
	if err, ok := obj.(error); ok {
		return err
	}

	return errors.New(fmt.Sprint(obj))
}

func EXPLODE(obj interface{}) error {
	panic(obj)
}
<|endoftext|>


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

package srv

import (
	"syscall"
	"go9p.googlecode.com/hg/p"
)

func (srv *Srv) version(req *Req) {
	tc := req.Tc
	conn := req.Conn

	if tc.Msize < p.IOHDRSZ {
		req.RespondError(&p.Error{"msize too small", syscall.EINVAL})
		return
	}

	if tc.Msize < conn.Msize {
		conn.Msize = tc.Msize
	}

	conn.Dotu = tc.Version == "9P2000.u" && srv.Dotu
	ver := "9P2000"
	if conn.Dotu {
		ver = "9P2000.u"
	}

	/* make sure that the responses of all current requests will be ignored */
	conn.Lock()
	for tag, r := range conn.reqs {
		if tag == p.NOTAG {
			continue
		}

		for rr := r; rr != nil; rr = rr.next {
			rr.Lock()
			rr.status |= reqFlush
			rr.Unlock()
		}
	}
	conn.Unlock()

	req.RespondRversion(conn.Msize, ver)
}

func (srv *Srv) auth(req *Req) {
	tc := req.Tc
	conn := req.Conn
	if tc.Afid == p.NOFID {
		req.RespondError(Eunknownfid)
		return
	}

	req.Afid = conn.FidNew(tc.Afid)
	if req.Afid == nil {
		req.RespondError(Einuse)
		return
	}

	var user p.User = nil
	if tc.Unamenum != p.NOUID || conn.Dotu {
		user = srv.Upool.Uid2User(int(tc.Unamenum))
	} else if tc.Uname != "" {
		user = srv.Upool.Uname2User(tc.Uname)
	}

	if user == nil {
		req.RespondError(Enouser)
		return
	}

	req.Afid.User = user
	req.Afid.Type = p.QTAUTH
	if aop, ok := (srv.ops).(AuthOps); ok {
		aqid, err := aop.AuthInit(req.Afid, tc.Aname)
		if err != nil {
			req.RespondError(err)
		} else {
			aqid.Type |= p.QTAUTH // just in case
			req.RespondRauth(aqid)
		}
	} else {
		req.RespondError(Enoauth)
	}

}

func (srv *Srv) authPost(req *Req) {
	if req.Rc != nil && req.Rc.Type == p.Rattach {
		req.Afid.IncRef()
	}
}

func (srv *Srv) attach(req *Req) {
	tc := req.Tc
	conn := req.Conn
	if tc.Fid == p.NOFID {
		req.RespondError(Eunknownfid)
		return
	}

	req.Fid = conn.FidNew(tc.Fid)
	if req.Fid == nil {
		req.RespondError(Einuse)
		return
	}

	if tc.Afid != p.NOFID {
		req.Afid = conn.FidGet(tc.Afid)
		if req.Afid == nil {
			req.RespondError(Eunknownfid)
		}
	}

	var user p.User = nil
	if tc.Unamenum != p.NOUID || conn.Dotu {
		user = srv.Upool.Uid2User(int(tc.Unamenum))
	} else if tc.Uname != "" {
		user = srv.Upool.Uname2User(tc.Uname)
	}

	if user == nil {
		req.RespondError(Enouser)
		return
	}

	req.Fid.User = user
	if aop, ok := (srv.ops).(AuthOps); ok {
		err := aop.AuthCheck(req.Fid, req.Afid, tc.Aname)
		if err != nil {
			req.RespondError(err)
			return
		}
	}

	(srv.ops).(ReqOps).Attach(req)
}

func (srv *Srv) attachPost(req *Req) {
	if req.Rc != nil && req.Rc.Type == p.Rattach {
		req.Fid.Type = req.Rc.Qid.Type
		req.Fid.IncRef()
	}
}

func (srv *Srv) flush(req *Req) {
	conn := req.Conn
	tag := req.Tc.Oldtag
	p.PackRflush(req.Rc)
	conn.Lock()
	r := conn.reqs[tag]
	if r != nil {
		r.flushreq = req.flushreq
		req.flushreq = r
	}
	conn.Unlock()

	if r == nil {
		// there are no requests with that tag
		req.Respond()
		return
	}

	r.Lock()
	status := r.status
	if (status & (reqWork | reqSaved)) == 0 {
		/* the request is not worked on yet */
		r.status |= reqFlush
	}
	r.Unlock()

	if (status & (reqWork | reqSaved)) == 0 {
		r.Respond()
	} else {
		if op, ok := (srv.ops).(FlushOp); ok {
			op.Flush(r)
		}
	}
}

func (srv *Srv) walk(req *Req) {
	conn := req.Conn
	tc := req.Tc
	fid := req.Fid

	/* we can't walk regular files, only clone them */
	if len(tc.Wname) > 0 && (fid.Type&p.QTDIR) == 0 {
		req.RespondError(Enotdir)
		return
	}

	/* we can't walk open files */
	if fid.opened {
		req.RespondError(Ebaduse)
		return
	}

	if tc.Fid != tc.Newfid {
		req.Newfid = conn.FidNew(tc.Newfid)
		if req.Newfid == nil {
			req.RespondError(Einuse)
			return
		}

		req.Newfid.User = fid.User
		req.Newfid.Type = fid.Type
	} else {
		req.Newfid = req.Fid
		req.Newfid.IncRef()
	}

	(req.Conn.Srv.ops).(ReqOps).Walk(req)
}

func (srv *Srv) walkPost(req *Req) {
	rc := req.Rc
	if rc == nil || rc.Type != p.Rwalk || req.Newfid == nil {
		return
	}

	n := len(rc.Wqid)
	if n > 0 {
		req.Newfid.Type = rc.Wqid[n-1].Type
	} else {
		req.Newfid.Type = req.Fid.Type
	}

	if req.Newfid.fid != req.Fid.fid {
		req.Newfid.IncRef()
	}
}

func (srv *Srv) open(req *Req) {
	fid := req.Fid
	tc := req.Tc
	if fid.opened {
		req.RespondError(Eopen)
		return
	}

	if (fid.Type&p.QTDIR) != 0 && tc.Mode != p.OREAD {
		req.RespondError(Eperm)
		return
	}

	fid.Omode = tc.Mode
	(req.Conn.Srv.ops).(ReqOps).Open(req)
}

func (srv *Srv) openPost(req *Req) {
	if req.Fid != nil {
		req.Fid.opened = req.Rc != nil && req.Rc.Type == p.Ropen
	}
}

func (srv *Srv) create(req *Req) {
	fid := req.Fid
	tc := req.Tc
	if fid.opened {
		req.RespondError(Eopen)
		return
	}

	if (fid.Type & p.QTDIR) == 0 {
		req.RespondError(Enotdir)
		return
	}

	/* can't open directories for other than reading */
	if (tc.Perm&p.DMDIR) != 0 && tc.Mode != p.OREAD {
		req.RespondError(Eperm)
		return
	}

	/* can't create special files if not 9P2000.u */
	if (tc.Perm&(p.DMNAMEDPIPE|p.DMSYMLINK|p.DMLINK|p.DMDEVICE|p.DMSOCKET)) != 0 && !req.Conn.Dotu {
		req.RespondError(Eperm)
		return
	}

	fid.Omode = tc.Mode
	(req.Conn.Srv.ops).(ReqOps).Create(req)
}

func (srv *Srv) createPost(req *Req) {
	if req.Rc != nil && req.Rc.Type == p.Rcreate && req.Fid != nil {
		req.Fid.Type = req.Rc.Qid.Type
		req.Fid.opened = true
	}
}

func (srv *Srv) read(req *Req) {
	tc := req.Tc
	fid := req.Fid
	if tc.Count+p.IOHDRSZ > req.Conn.Msize {
		req.RespondError(Etoolarge)
		return
	}

	if (fid.Type & p.QTAUTH) != 0 {
		var n int

		rc := req.Tc
		err := p.InitRread(rc, tc.Count)
		if err != nil {
			req.RespondError(err)
			return
		}

		if op, ok := (req.Conn.Srv.ops).(AuthOps); ok {
			n, err = op.AuthRead(fid, tc.Offset, rc.Data)
			if err != nil {
				req.RespondError(err)
				return
			}

			p.SetRreadCount(rc, uint32(n))
			req.Respond()
		} else {
			req.RespondError(Enotimpl)
		}

		return
	}

	if (fid.Type & p.QTDIR) != 0 {
		if tc.Offset == 0 {
			fid.Diroffset = 0
		} else if tc.Offset != fid.Diroffset {
			req.RespondError(Ebadoffset)
			return
		}
	}

	(req.Conn.Srv.ops).(ReqOps).Read(req)
}

func (srv *Srv) readPost(req *Req) {
	if req.Rc != nil && req.Rc.Type == p.Rread && (req.Fid.Type&p.QTDIR) != 0 {
		req.Fid.Diroffset += uint64(req.Rc.Count)
	}
}

func (srv *Srv) write(req *Req) {
	fid := req.Fid
	tc := req.Tc
	if (fid.Type & p.QTAUTH) != 0 {
		tc := req.Tc
		if op, ok := (req.Conn.Srv.ops).(AuthOps); ok {
			n, err := op.AuthWrite(req.Fid, tc.Offset, tc.Data)
			if err != nil {
				req.RespondError(err)
			} else {
				req.RespondRwrite(uint32(n))
			}
		} else {
			req.RespondError(Enotimpl)
		}

		return
	}

	if !fid.opened || (fid.Type&p.QTDIR) != 0 || (fid.Omode&3) == p.OREAD {
		req.RespondError(Ebaduse)
		return
	}

	if tc.Count+p.IOHDRSZ > req.Conn.Msize {
		req.RespondError(Etoolarge)
		return
	}

	(req.Conn.Srv.ops).(ReqOps).Write(req)
}

func (srv *Srv) clunk(req *Req) {
	fid := req.Fid
	if (fid.Type & p.QTAUTH) != 0 {
		if op, ok := (req.Conn.Srv.ops).(AuthOps); ok {
			op.AuthDestroy(fid)
			req.RespondRclunk()
		} else {
			req.RespondError(Enotimpl)
		}

		return
	}

	(req.Conn.Srv.ops).(ReqOps).Clunk(req)
}

func (srv *Srv) clunkPost(req *Req) {
	if req.Rc != nil && req.Rc.Type == p.Rclunk && req.Fid != nil {
		req.Fid.DecRef()
	}
}

func (srv *Srv) remove(req *Req) { (req.Conn.Srv.ops).(ReqOps).Remove(req) }

func (srv *Srv) removePost(req *Req) {
	if req.Rc != nil && req.Fid != nil {
		req.Fid.DecRef()
	}
}

func (srv *Srv) stat(req *Req) { (req.Conn.Srv.ops).(ReqOps).Stat(req) }

func (srv *Srv) wstat(req *Req) {
	/*
		fid := req.Fid
		d := &req.Tc.Dir
		if d.Type != uint16(0xFFFF) || d.Dev != uint32(0xFFFFFFFF) || d.Version != uint32(0xFFFFFFFF) ||
			d.Path != uint64(0xFFFFFFFFFFFFFFFF) {
			req.RespondError(Eperm)
			return
		}

		if (d.Mode != 0xFFFFFFFF) && (((fid.Type&p.QTDIR) != 0 && (d.Mode&p.DMDIR) == 0) ||
			((d.Type&p.QTDIR) == 0 && (d.Mode&p.DMDIR) != 0)) {
			req.RespondError(Edirchange)
			return
		}
	*/

	(req.Conn.Srv.ops).(ReqOps).Wstat(req)
}
<commit_msg>fix bug in the flush handling<commit_after>// Copyright 2009 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package srv

import (
	"syscall"
	"go9p.googlecode.com/hg/p"
)

func (srv *Srv) version(req *Req) {
	tc := req.Tc
	conn := req.Conn

	if tc.Msize < p.IOHDRSZ {
		req.RespondError(&p.Error{"msize too small", syscall.EINVAL})
		return
	}

	if tc.Msize < conn.Msize {
		conn.Msize = tc.Msize
	}

	conn.Dotu = tc.Version == "9P2000.u" && srv.Dotu
	ver := "9P2000"
	if conn.Dotu {
		ver = "9P2000.u"
	}

	/* make sure that the responses of all current requests will be ignored */
	conn.Lock()
	for tag, r := range conn.reqs {
		if tag == p.NOTAG {
			continue
		}

		for rr := r; rr != nil; rr = rr.next {
			rr.Lock()
			rr.status |= reqFlush
			rr.Unlock()
		}
	}
	conn.Unlock()

	req.RespondRversion(conn.Msize, ver)
}

func (srv *Srv) auth(req *Req) {
	tc := req.Tc
	conn := req.Conn
	if tc.Afid == p.NOFID {
		req.RespondError(Eunknownfid)
		return
	}

	req.Afid = conn.FidNew(tc.Afid)
	if req.Afid == nil {
		req.RespondError(Einuse)
		return
	}

	var user p.User = nil
	if tc.Unamenum != p.NOUID || conn.Dotu {
		user = srv.Upool.Uid2User(int(tc.Unamenum))
	} else if tc.Uname != "" {
		user = srv.Upool.Uname2User(tc.Uname)
	}

	if user == nil {
		req.RespondError(Enouser)
		return
	}

	req.Afid.User = user
	req.Afid.Type = p.QTAUTH
	if aop, ok := (srv.ops).(AuthOps); ok {
		aqid, err := aop.AuthInit(req.Afid, tc.Aname)
		if err != nil {
			req.RespondError(err)
		} else {
			aqid.Type |= p.QTAUTH // just in case
			req.RespondRauth(aqid)
		}
	} else {
		req.RespondError(Enoauth)
	}

}

func (srv *Srv) authPost(req *Req) {
	if req.Rc != nil && req.Rc.Type == p.Rattach {
		req.Afid.IncRef()
	}
}

func (srv *Srv) attach(req *Req) {
	tc := req.Tc
	conn := req.Conn
	if tc.Fid == p.NOFID {
		req.RespondError(Eunknownfid)
		return
	}

	req.Fid = conn.FidNew(tc.Fid)
	if req.Fid == nil {
		req.RespondError(Einuse)
		return
	}

	if tc.Afid != p.NOFID {
		req.Afid = conn.FidGet(tc.Afid)
		if req.Afid == nil {
			req.RespondError(Eunknownfid)
		}
	}

	var user p.User = nil
	if tc.Unamenum != p.NOUID || conn.Dotu {
		user = srv.Upool.Uid2User(int(tc.Unamenum))
	} else if tc.Uname != "" {
		user = srv.Upool.Uname2User(tc.Uname)
	}

	if user == nil {
		req.RespondError(Enouser)
		return
	}

	req.Fid.User = user
	if aop, ok := (srv.ops).(AuthOps); ok {
		err := aop.AuthCheck(req.Fid, req.Afid, tc.Aname)
		if err != nil {
			req.RespondError(err)
			return
		}
	}

	(srv.ops).(ReqOps).Attach(req)
}

func (srv *Srv) attachPost(req *Req) {
	if req.Rc != nil && req.Rc.Type == p.Rattach {
		req.Fid.Type = req.Rc.Qid.Type
		req.Fid.IncRef()
	}
}

func (srv *Srv) flush(req *Req) {
	conn := req.Conn
	tag := req.Tc.Oldtag
	p.PackRflush(req.Rc)
	conn.Lock()
	r := conn.reqs[tag]
	if r != nil {
		req.flushreq = r.flushreq
		r.flushreq = req
	}
	conn.Unlock()

	if r == nil {
		// there are no requests with that tag
		req.Respond()
		return
	}

	r.Lock()
	status := r.status
	if (status & (reqWork | reqSaved)) == 0 {
		/* the request is not worked on yet */
		r.status |= reqFlush
	}
	r.Unlock()

	if (status & (reqWork | reqSaved)) == 0 {
		r.Respond()
	} else {
		if op, ok := (srv.ops).(FlushOp); ok {
			op.Flush(r)
		}
	}
}

func (srv *Srv) walk(req *Req) {
	conn := req.Conn
	tc := req.Tc
	fid := req.Fid

	/* we can't walk regular files, only clone them */
	if len(tc.Wname) > 0 && (fid.Type&p.QTDIR) == 0 {
		req.RespondError(Enotdir)
		return
	}

	/* we can't walk open files */
	if fid.opened {
		req.RespondError(Ebaduse)
		return
	}

	if tc.Fid != tc.Newfid {
		req.Newfid = conn.FidNew(tc.Newfid)
		if req.Newfid == nil {
			req.RespondError(Einuse)
			return
		}

		req.Newfid.User = fid.User
		req.Newfid.Type = fid.Type
	} else {
		req.Newfid = req.Fid
		req.Newfid.IncRef()
	}

	(req.Conn.Srv.ops).(ReqOps).Walk(req)
}

func (srv *Srv) walkPost(req *Req) {
	rc := req.Rc
	if rc == nil || rc.Type != p.Rwalk || req.Newfid == nil {
		return
	}

	n := len(rc.Wqid)
	if n > 0 {
		req.Newfid.Type = rc.Wqid[n-1].Type
	} else {
		req.Newfid.Type = req.Fid.Type
	}

	if req.Newfid.fid != req.Fid.fid {
		req.Newfid.IncRef()
	}
}

func (srv *Srv) open(req *Req) {
	fid := req.Fid
	tc := req.Tc
	if fid.opened {
		req.RespondError(Eopen)
		return
	}

	if (fid.Type&p.QTDIR) != 0 && tc.Mode != p.OREAD {
		req.RespondError(Eperm)
		return
	}

	fid.Omode = tc.Mode
	(req.Conn.Srv.ops).(ReqOps).Open(req)
}

func (srv *Srv) openPost(req *Req) {
	if req.Fid != nil {
		req.Fid.opened = req.Rc != nil && req.Rc.Type == p.Ropen
	}
}

func (srv *Srv) create(req *Req) {
	fid := req.Fid
	tc := req.Tc
	if fid.opened {
		req.RespondError(Eopen)
		return
	}

	if (fid.Type & p.QTDIR) == 0 {
		req.RespondError(Enotdir)
		return
	}

	/* can't open directories for other than reading */
	if (tc.Perm&p.DMDIR) != 0 && tc.Mode != p.OREAD {
		req.RespondError(Eperm)
		return
	}

	/* can't create special files if not 9P2000.u */
	if (tc.Perm&(p.DMNAMEDPIPE|p.DMSYMLINK|p.DMLINK|p.DMDEVICE|p.DMSOCKET)) != 0 && !req.Conn.Dotu {
		req.RespondError(Eperm)
		return
	}

	fid.Omode = tc.Mode
	(req.Conn.Srv.ops).(ReqOps).Create(req)
}

func (srv *Srv) createPost(req *Req) {
	if req.Rc != nil && req.Rc.Type == p.Rcreate && req.Fid != nil {
		req.Fid.Type = req.Rc.Qid.Type
		req.Fid.opened = true
	}
}

func (srv *Srv) read(req *Req) {
	tc := req.Tc
	fid := req.Fid
	if tc.Count+p.IOHDRSZ > req.Conn.Msize {
		req.RespondError(Etoolarge)
		return
	}

	if (fid.Type & p.QTAUTH) != 0 {
		var n int

		rc := req.Tc
		err := p.InitRread(rc, tc.Count)
		if err != nil {
			req.RespondError(err)
			return
		}

		if op, ok := (req.Conn.Srv.ops).(AuthOps); ok {
			n, err = op.AuthRead(fid, tc.Offset, rc.Data)
			if err != nil {
				req.RespondError(err)
				return
			}

			p.SetRreadCount(rc, uint32(n))
			req.Respond()
		} else {
			req.RespondError(Enotimpl)
		}

		return
	}

	if (fid.Type & p.QTDIR) != 0 {
		if tc.Offset == 0 {
			fid.Diroffset = 0
		} else if tc.Offset != fid.Diroffset {
			req.RespondError(Ebadoffset)
			return
		}
	}

	(req.Conn.Srv.ops).(ReqOps).Read(req)
}

func (srv *Srv) readPost(req *Req) {
	if req.Rc != nil && req.Rc.Type == p.Rread && (req.Fid.Type&p.QTDIR) != 0 {
		req.Fid.Diroffset += uint64(req.Rc.Count)
	}
}

func (srv *Srv) write(req *Req) {
	fid := req.Fid
	tc := req.Tc
	if (fid.Type & p.QTAUTH) != 0 {
		tc := req.Tc
		if op, ok := (req.Conn.Srv.ops).(AuthOps); ok {
			n, err := op.AuthWrite(req.Fid, tc.Offset, tc.Data)
			if err != nil {
				req.RespondError(err)
			} else {
				req.RespondRwrite(uint32(n))
			}
		} else {
			req.RespondError(Enotimpl)
		}

		return
	}

	if !fid.opened || (fid.Type&p.QTDIR) != 0 || (fid.Omode&3) == p.OREAD {
		req.RespondError(Ebaduse)
		return
	}

	if tc.Count+p.IOHDRSZ > req.Conn.Msize {
		req.RespondError(Etoolarge)
		return
	}

	(req.Conn.Srv.ops).(ReqOps).Write(req)
}

func (srv *Srv) clunk(req *Req) {
	fid := req.Fid
	if (fid.Type & p.QTAUTH) != 0 {
		if op, ok := (req.Conn.Srv.ops).(AuthOps); ok {
			op.AuthDestroy(fid)
			req.RespondRclunk()
		} else {
			req.RespondError(Enotimpl)
		}

		return
	}

	(req.Conn.Srv.ops).(ReqOps).Clunk(req)
}

func (srv *Srv) clunkPost(req *Req) {
	if req.Rc != nil && req.Rc.Type == p.Rclunk && req.Fid != nil {
		req.Fid.DecRef()
	}
}

func (srv *Srv) remove(req *Req) { (req.Conn.Srv.ops).(ReqOps).Remove(req) }

func (srv *Srv) removePost(req *Req) {
	if req.Rc != nil && req.Fid != nil {
		req.Fid.DecRef()
	}
}

func (srv *Srv) stat(req *Req) { (req.Conn.Srv.ops).(ReqOps).Stat(req) }

func (srv *Srv) wstat(req *Req) {
	/*
		fid := req.Fid
		d := &req.Tc.Dir
		if d.Type != uint16(0xFFFF) || d.Dev != uint32(0xFFFFFFFF) || d.Version != uint32(0xFFFFFFFF) ||
			d.Path != uint64(0xFFFFFFFFFFFFFFFF) {
			req.RespondError(Eperm)
			return
		}

		if (d.Mode != 0xFFFFFFFF) && (((fid.Type&p.QTDIR) != 0 && (d.Mode&p.DMDIR) == 0) ||
			((d.Type&p.QTDIR) == 0 && (d.Mode&p.DMDIR) != 0)) {
			req.RespondError(Edirchange)
			return
		}
	*/

	(req.Conn.Srv.ops).(ReqOps).Wstat(req)
}
<|endoftext|>