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

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

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

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

package generator

import (
	"reflect"
	"testing"

	"k8s.io/kube-state-metrics/pkg/allow"
	"k8s.io/kube-state-metrics/pkg/metric"
)

func TestFilterMetricFamiliesLabels(t *testing.T) {
	tests := []struct {
		name             string
		allowLabels      allow.Labels
		familyGenerators []FamilyGenerator
		results          []FamilyGenerator
	}{
		{
			name:        "Returns all the metric's keys and values if not annotation/label metric by default",
			allowLabels: allow.Labels(map[string][]string{}),
			familyGenerators: []FamilyGenerator{
				{
					Name: "node_info",
					Help: "some help",
					Type: metric.Gauge,
					GenerateFunc: func(obj interface{}) *metric.Family {
						return &metric.Family{
							Metrics: []*metric.Metric{
								{
									LabelKeys:   []string{"one", "two", "three"},
									LabelValues: []string{"value-one", "value-two", "value-three"},
									Value:       1,
								},
							},
						}
					},
				},
			},
			results: []FamilyGenerator{
				{
					Name: "node_info",
					Help: "some help",
					Type: metric.Gauge,
					GenerateFunc: func(obj interface{}) *metric.Family {
						return &metric.Family{
							Metrics: []*metric.Metric{
								{
									LabelKeys:   []string{"one", "two", "three"},
									LabelValues: []string{"value-one", "value-two", "value-three"},
									Value:       1,
								},
							},
						}
					},
				},
			},
		},
		{
			name:        "Returns no labels if it's an annotation metric and no allowed labels specified",
			allowLabels: allow.Labels(map[string][]string{}),
			familyGenerators: []FamilyGenerator{
				{
					Name: "node_annotations",
					Help: "some help",
					Type: metric.Gauge,
					GenerateFunc: func(obj interface{}) *metric.Family {
						return &metric.Family{
							Metrics: []*metric.Metric{
								{
									LabelKeys:   []string{"one", "two", "three"},
									LabelValues: []string{"value-one", "value-two", "value-three"},
									Value:       1,
								},
							},
						}
					},
				},
			},
			results: []FamilyGenerator{
				{
					Name: "node_annotations",
					Help: "some help",
					Type: metric.Gauge,
					GenerateFunc: func(obj interface{}) *metric.Family {
						return &metric.Family{
							Metrics: []*metric.Metric{
								{
									Value: 1,
								},
							},
						}
					},
				},
			},
		},
		{
			name:        "Returns no labels if it's an label metric and no allowed labels specified",
			allowLabels: allow.Labels(map[string][]string{}),
			familyGenerators: []FamilyGenerator{
				{
					Name: "node_labels",
					Help: "some help",
					Type: metric.Gauge,
					GenerateFunc: func(obj interface{}) *metric.Family {
						return &metric.Family{
							Metrics: []*metric.Metric{
								{
									LabelKeys:   []string{"one", "two", "three"},
									LabelValues: []string{"value-one", "value-two", "value-three"},
									Value:       1,
								},
							},
						}
					},
				},
			},
			results: []FamilyGenerator{
				{
					Name: "node_labels",
					Help: "some help",
					Type: metric.Gauge,
					GenerateFunc: func(obj interface{}) *metric.Family {
						return &metric.Family{
							Metrics: []*metric.Metric{
								{
									Value: 1,
								},
							},
						}
					},
				},
			},
		},
		{
			name: "Returns allowed labels for metric and label and value pairs are correct",
			allowLabels: allow.Labels(map[string][]string{
				"node_info": {
					"two",
					"one",
				},
			}),
			familyGenerators: []FamilyGenerator{
				{
					Name: "node_info",
					Help: "some help",
					Type: metric.Gauge,
					GenerateFunc: func(obj interface{}) *metric.Family {
						return &metric.Family{
							Metrics: []*metric.Metric{
								{
									LabelKeys:   []string{"one", "two", "three"},
									LabelValues: []string{"value-one", "value-two", "value-three"},
									Value:       1,
								},
							},
						}
					},
				},
			},
			results: []FamilyGenerator{
				{
					Name: "node_info",
					Help: "some help",
					Type: metric.Gauge,
					GenerateFunc: func(obj interface{}) *metric.Family {
						return &metric.Family{
							Metrics: []*metric.Metric{
								{
									LabelKeys:   []string{"two", "one"},
									LabelValues: []string{"value-two", "value-one"},
									Value:       1,
								},
							},
						}
					},
				},
			},
		},
		{
			name: "Returns allowed labels for metric",
			allowLabels: allow.Labels(map[string][]string{
				"node_labels": {
					"one",
					"two",
				},
			}),
			familyGenerators: []FamilyGenerator{
				{
					Name: "node_labels",
					Help: "some help",
					Type: metric.Gauge,
					GenerateFunc: func(obj interface{}) *metric.Family {
						return &metric.Family{
							Metrics: []*metric.Metric{
								{
									LabelKeys:   []string{"one", "two", "three"},
									LabelValues: []string{"value-one", "value-two", "value-three"},
									Value:       1,
								},
							},
						}
					},
				},
			},
			results: []FamilyGenerator{
				{
					Name: "node_labels",
					Help: "some help",
					Type: metric.Gauge,
					GenerateFunc: func(obj interface{}) *metric.Family {
						return &metric.Family{
							Metrics: []*metric.Metric{
								{
									LabelKeys:   []string{"one", "two"},
									LabelValues: []string{"value-one", "value-two"},
									Value:       1,
								},
							},
						}
					},
				},
			},
		},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			results := FilterMetricFamiliesLabels(test.allowLabels, test.familyGenerators)
			if len(results) != len(test.results) {
				t.Fatalf("expected %v, got %v", len(test.results), len(results))
			}

			for i := range results {
				result := results[i].GenerateFunc(nil)
				expected := test.results[i].GenerateFunc(nil)
				if !reflect.DeepEqual(result, expected) {
					t.Fatalf("Families don't equal, got %v, expected %v", result, expected)
				}
			}
		})
	}
}
<commit_msg>Fix test as sometimes metrics keys and values are generated in different order<commit_after>/*
Copyright 2020 The Kubernetes Authors All rights reserved.

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

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

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

package generator

import (
	"reflect"
	"sort"
	"testing"

	"k8s.io/kube-state-metrics/pkg/allow"
	"k8s.io/kube-state-metrics/pkg/metric"
)

func TestFilterMetricFamiliesLabels(t *testing.T) {
	tests := []struct {
		name             string
		allowLabels      allow.Labels
		familyGenerators []FamilyGenerator
		results          []FamilyGenerator
	}{
		{
			name:        "Returns all the metric's keys and values if not annotation/label metric by default",
			allowLabels: allow.Labels(map[string][]string{}),
			familyGenerators: []FamilyGenerator{
				{
					Name: "node_info",
					Help: "some help",
					Type: metric.Gauge,
					GenerateFunc: func(obj interface{}) *metric.Family {
						return &metric.Family{
							Metrics: []*metric.Metric{
								{
									LabelKeys:   []string{"one", "two", "three"},
									LabelValues: []string{"value-one", "value-two", "value-three"},
									Value:       1,
								},
							},
						}
					},
				},
			},
			results: []FamilyGenerator{
				{
					Name: "node_info",
					Help: "some help",
					Type: metric.Gauge,
					GenerateFunc: func(obj interface{}) *metric.Family {
						return &metric.Family{
							Metrics: []*metric.Metric{
								{
									LabelKeys:   []string{"one", "two", "three"},
									LabelValues: []string{"value-one", "value-two", "value-three"},
									Value:       1,
								},
							},
						}
					},
				},
			},
		},
		{
			name:        "Returns no labels if it's an annotation metric and no allowed labels specified",
			allowLabels: allow.Labels(map[string][]string{}),
			familyGenerators: []FamilyGenerator{
				{
					Name: "node_annotations",
					Help: "some help",
					Type: metric.Gauge,
					GenerateFunc: func(obj interface{}) *metric.Family {
						return &metric.Family{
							Metrics: []*metric.Metric{
								{
									LabelKeys:   []string{"one", "two", "three"},
									LabelValues: []string{"value-one", "value-two", "value-three"},
									Value:       1,
								},
							},
						}
					},
				},
			},
			results: []FamilyGenerator{
				{
					Name: "node_annotations",
					Help: "some help",
					Type: metric.Gauge,
					GenerateFunc: func(obj interface{}) *metric.Family {
						return &metric.Family{
							Metrics: []*metric.Metric{
								{
									Value: 1,
								},
							},
						}
					},
				},
			},
		},
		{
			name:        "Returns no labels if it's an label metric and no allowed labels specified",
			allowLabels: allow.Labels(map[string][]string{}),
			familyGenerators: []FamilyGenerator{
				{
					Name: "node_labels",
					Help: "some help",
					Type: metric.Gauge,
					GenerateFunc: func(obj interface{}) *metric.Family {
						return &metric.Family{
							Metrics: []*metric.Metric{
								{
									LabelKeys:   []string{"one", "two", "three"},
									LabelValues: []string{"value-one", "value-two", "value-three"},
									Value:       1,
								},
							},
						}
					},
				},
			},
			results: []FamilyGenerator{
				{
					Name: "node_labels",
					Help: "some help",
					Type: metric.Gauge,
					GenerateFunc: func(obj interface{}) *metric.Family {
						return &metric.Family{
							Metrics: []*metric.Metric{
								{
									Value: 1,
								},
							},
						}
					},
				},
			},
		},
		{
			name: "Returns allowed labels for metric and label and value pairs are correct",
			allowLabels: allow.Labels(map[string][]string{
				"node_info": {
					"two",
					"one",
				},
			}),
			familyGenerators: []FamilyGenerator{
				{
					Name: "node_info",
					Help: "some help",
					Type: metric.Gauge,
					GenerateFunc: func(obj interface{}) *metric.Family {
						return &metric.Family{
							Metrics: []*metric.Metric{
								{
									LabelKeys:   []string{"one", "two", "three"},
									LabelValues: []string{"value-one", "value-two", "value-three"},
									Value:       1,
								},
							},
						}
					},
				},
			},
			results: []FamilyGenerator{
				{
					Name: "node_info",
					Help: "some help",
					Type: metric.Gauge,
					GenerateFunc: func(obj interface{}) *metric.Family {
						return &metric.Family{
							Metrics: []*metric.Metric{
								{
									LabelKeys:   []string{"two", "one"},
									LabelValues: []string{"value-two", "value-one"},
									Value:       1,
								},
							},
						}
					},
				},
			},
		},
		{
			name: "Returns allowed labels for metric",
			allowLabels: allow.Labels(map[string][]string{
				"node_labels": {
					"one",
					"two",
				},
			}),
			familyGenerators: []FamilyGenerator{
				{
					Name: "node_labels",
					Help: "some help",
					Type: metric.Gauge,
					GenerateFunc: func(obj interface{}) *metric.Family {
						return &metric.Family{
							Metrics: []*metric.Metric{
								{
									LabelKeys:   []string{"one", "two", "three"},
									LabelValues: []string{"value-one", "value-two", "value-three"},
									Value:       1,
								},
							},
						}
					},
				},
			},
			results: []FamilyGenerator{
				{
					Name: "node_labels",
					Help: "some help",
					Type: metric.Gauge,
					GenerateFunc: func(obj interface{}) *metric.Family {
						return &metric.Family{
							Metrics: []*metric.Metric{
								{
									LabelKeys:   []string{"one", "two"},
									LabelValues: []string{"value-one", "value-two"},
									Value:       1,
								},
							},
						}
					},
				},
			},
		},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			results := FilterMetricFamiliesLabels(test.allowLabels, test.familyGenerators)
			if len(results) != len(test.results) {
				t.Fatalf("expected %v, got %v", len(test.results), len(results))
			}

			for i := range results {
				result := results[i].GenerateFunc(nil)
				expected := test.results[i].GenerateFunc(nil)
				for _, resultMetric := range result.Metrics {
					for _, expectedMetric := range expected.Metrics {
						assertEqualSlices(t, expectedMetric.LabelKeys, resultMetric.LabelKeys, "keys")
						assertEqualSlices(t, expectedMetric.LabelValues, resultMetric.LabelValues, "values")

						if expectedMetric.Value != resultMetric.Value {
							t.Fatalf("value - expected %v, got %v", expectedMetric.Value, resultMetric.Value)
						}
					}
				}
			}
		})
	}
}

func assertEqualSlices(t *testing.T, expected, actual []string, kind string) {
	sort.Strings(expected)
	sort.Strings(actual)
	if !reflect.DeepEqual(expected, actual) {
		t.Fatalf("%s - expected %v, got %v", kind, expected, actual)
	}
}
<|endoftext|>


<commit_before>package camli

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"time"

	"camlistore.org/pkg/blob"
	"camlistore.org/pkg/client"
	"camlistore.org/pkg/schema"
	"camlistore.org/pkg/search"
)

// Repo is our Camlistore scheme to model the state of a
// particular repo at a particular point in time.
type Repo struct {
	Name      string
	Parent    string
	Retrieved time.Time
	Refs      map[string]string
	Packfiles []string
}

// PutRepo stores a Repo in Camlistore.
func (u *Uploader) PutRepo(r *Repo) error {
	bb := schema.NewBuilder()
	bb.SetType("git-repo")
	bb.SetRawStringField("parent", r.Parent)
	bb.SetRawStringField("retrieved", schema.RFC3339FromTime(r.Retrieved))
	if refs, err := json.Marshal(r.Refs); err == nil {
		// TODO The builder just escapes this. We need the actual map as a
		// json object.
		bb.SetRawStringField("refs", string(refs))
	} else {
		return err
	}
	if packfiles, err := json.Marshal(r.Packfiles); err == nil {
		// TODO The builder just escapes this. We need the actual map as a
		// json object.
		bb.SetRawStringField("packfiles", string(packfiles))
	} else {
		return err
	}

	j := bb.Blob().JSON()
	reporef := blob.SHA1FromString(j)
	_, err := uploadString(u.c, reporef, j)

	log.Printf("stored repo: %s on %s", r.Name, reporef)

	// Update or create its permanode.
	pn, _, err := u.findRepo(r.Name)
	if err != nil {
		// Create a new one.
		res, err := u.c.UploadNewPermanode()
		if err != nil {
			return err
		}
		pn = res.BlobRef
		log.Printf("created permanode: %s", pn)

		titleattr := schema.NewSetAttributeClaim(pn, "title", r.Name)
		claimTime := time.Now()
		titleattr.SetClaimDate(claimTime)
		signer, err := u.c.Signer()
		if err != nil {
			return err
		}
		signed, err := titleattr.SignAt(signer, claimTime)
		if err != nil {
			return fmt.Errorf("couldn't to sign title claim")
		}
		_, err = u.c.Upload(client.NewUploadHandleFromString(signed))
	}
	contentattr := schema.NewSetAttributeClaim(pn, "camliContent", reporef.String())
	claimTime := time.Now()
	contentattr.SetClaimDate(claimTime)
	signer, err := u.c.Signer()
	if err != nil {
		return err
	}
	signed, err := contentattr.SignAt(signer, claimTime)
	if err != nil {
		return fmt.Errorf("couldn't to sign content claim")
	}
	_, err = u.c.Upload(client.NewUploadHandleFromString(signed))
	return err
}

var repoNotFoundErr = errors.New("repo not found")

func (u *Uploader) findRepo(name string) (blob.Ref, search.MetaMap, error) {
	res, err := u.c.Query(&search.SearchQuery{
		Limit: 1,
		Constraint: &search.Constraint{
			Permanode: &search.PermanodeConstraint{
				Attr: "title", Value: name,
			},
		},
		Describe: &search.DescribeRequest{},
	})
	if err != nil {
		return blob.Ref{}, nil, err
	}
	if len(res.Blobs) < 1 {
		return blob.Ref{}, nil, repoNotFoundErr
	}
	return res.Blobs[0].Blob, res.Describe.Meta, nil
}

// GetRepo querys for a repo permanode with name, and returns its
// Repo object.
func (u *Uploader) GetRepo(name string) (*Repo, error) {
	pn, meta, err := u.findRepo(name)
	if err == repoNotFoundErr {
		return nil, nil
	} else if err != nil {
		return nil, err
	}
	ref, ok := meta[pn.String()].ContentRef()
	if !ok {
		return nil, errors.New("couldn't find repo data (but there's a permanode)")
	}
	r, _, err := u.c.Fetch(ref)
	if err != nil {
		return nil, err
	}
	body, err := ioutil.ReadAll(r)
	if err != nil {
		return nil, err
	}

	var repo Repo
	err = json.Unmarshal(body, &repo)
	return &repo, err
}
<commit_msg>camli: use bb.SetRawStringField<commit_after>package camli

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"time"

	"camlistore.org/pkg/blob"
	"camlistore.org/pkg/client"
	"camlistore.org/pkg/schema"
	"camlistore.org/pkg/search"
)

// Repo is our Camlistore scheme to model the state of a
// particular repo at a particular point in time.
type Repo struct {
	Name      string
	Parent    string
	Retrieved time.Time
	Refs      map[string]string
	Packfiles []string
}

// PutRepo stores a Repo in Camlistore.
func (u *Uploader) PutRepo(r *Repo) error {
	bb := schema.NewBuilder()
	bb.SetType("git-repo")
	bb.SetRawStringField("parent", r.Parent)
	bb.SetRawStringField("retrieved", schema.RFC3339FromTime(r.Retrieved))
	if refs, err := schema.NewJSONObject(r.Refs); err == nil {
		bb.SetRawField("refs", refs)
	} else {
		return err
	}
	if packfiles, err := schema.NewJSONObject(r.Packfiles); err == nil {
		bb.SetRawField("packfiles", packfiles)
	} else {
		return err
	}

	j := bb.Blob().JSON()
	reporef := blob.SHA1FromString(j)
	_, err := uploadString(u.c, reporef, j)

	log.Printf("stored repo: %s on %s", r.Name, reporef)

	// Update or create its permanode.
	pn, _, err := u.findRepo(r.Name)
	if err != nil {
		// Create a new one.
		res, err := u.c.UploadNewPermanode()
		if err != nil {
			return err
		}
		pn = res.BlobRef
		log.Printf("created permanode: %s", pn)

		titleattr := schema.NewSetAttributeClaim(pn, "title", r.Name)
		claimTime := time.Now()
		titleattr.SetClaimDate(claimTime)
		signer, err := u.c.Signer()
		if err != nil {
			return err
		}
		signed, err := titleattr.SignAt(signer, claimTime)
		if err != nil {
			return fmt.Errorf("couldn't to sign title claim")
		}
		_, err = u.c.Upload(client.NewUploadHandleFromString(signed))
	}
	contentattr := schema.NewSetAttributeClaim(pn, "camliContent", reporef.String())
	claimTime := time.Now()
	contentattr.SetClaimDate(claimTime)
	signer, err := u.c.Signer()
	if err != nil {
		return err
	}
	signed, err := contentattr.SignAt(signer, claimTime)
	if err != nil {
		return fmt.Errorf("couldn't to sign content claim")
	}
	_, err = u.c.Upload(client.NewUploadHandleFromString(signed))
	return err
}

var repoNotFoundErr = errors.New("repo not found")

func (u *Uploader) findRepo(name string) (blob.Ref, search.MetaMap, error) {
	res, err := u.c.Query(&search.SearchQuery{
		Limit: 1,
		Constraint: &search.Constraint{
			Permanode: &search.PermanodeConstraint{
				Attr: "title", Value: name,
			},
		},
		Describe: &search.DescribeRequest{},
	})
	if err != nil {
		return blob.Ref{}, nil, err
	}
	if len(res.Blobs) < 1 {
		return blob.Ref{}, nil, repoNotFoundErr
	}
	return res.Blobs[0].Blob, res.Describe.Meta, nil
}

// GetRepo querys for a repo permanode with name, and returns its
// Repo object.
func (u *Uploader) GetRepo(name string) (*Repo, error) {
	pn, meta, err := u.findRepo(name)
	if err == repoNotFoundErr {
		return nil, nil
	} else if err != nil {
		return nil, err
	}
	ref, ok := meta[pn.String()].ContentRef()
	if !ok {
		return nil, errors.New("couldn't find repo data (but there's a permanode)")
	}
	r, _, err := u.c.Fetch(ref)
	if err != nil {
		return nil, err
	}
	body, err := ioutil.ReadAll(r)
	if err != nil {
		return nil, err
	}

	var repo Repo
	err = json.Unmarshal(body, &repo)
	return &repo, err
}
<|endoftext|>


<commit_before>// Copyright © 2021 Steve Francia <spf@spf13.com>.
//
// 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 tpl

func MainTemplate() []byte {
	return []byte(`/*
{{ .Copyright }}
{{ if .Legal.Header }}{{ .Legal.Header }}{{ end }}
*/
package main

import "{{ .PkgName }}/cmd"

func main() {
	cmd.Execute()
}
`)
}

func RootTemplate() []byte {
	return []byte(`/*
{{ .Copyright }}
{{ if .Legal.Header }}{{ .Legal.Header }}{{ end }}
*/
package cmd

import (
{{- if .Viper }}
	"fmt"
	"os"
{{ end }}
	"github.com/spf13/cobra"
{{- if .Viper }}
	"github.com/spf13/viper"{{ end }}
)

{{ if .Viper -}}
var cfgFile string
{{- end }}

// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
	Use:   "{{ .AppName }}",
	Short: "A brief description of your application",
	Long: ` + "`" + `A longer description that spans multiple lines and likely contains
examples and usage of using your application. For example:

Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.` + "`" + `,
	// Uncomment the following line if your bare application
	// has an action associated with it:
	// Run: func(cmd *cobra.Command, args []string) { },
}

// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	cobra.CheckErr(rootCmd.Execute())
}

func init() {
{{- if .Viper }}
	cobra.OnInitialize(initConfig)
{{ end }}
	// Here you will define your flags and configuration settings.
	// Cobra supports persistent flags, which, if defined here,
	// will be global for your application.
{{ if .Viper }}
	rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.{{ .AppName }}.yaml)")
{{ else }}
	// rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.{{ .AppName }}.yaml)")
{{ end }}
	// Cobra also supports local flags, which will only run
	// when this action is called directly.
	rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

{{ if .Viper -}}
// initConfig reads in config file and ENV variables if set.
func initConfig() {
	if cfgFile != "" {
		// Use config file from the flag.
		viper.SetConfigFile(cfgFile)
	} else {
		// Find home directory.
		home, err := os.UserHomeDir()
		cobra.CheckErr(err)

		// Search config in home directory with name ".{{ .AppName }}" (without extension).
		viper.AddConfigPath(home)
		viper.SetConfigType("yaml")
		viper.SetConfigName(".{{ .AppName }}")
	}

	viper.AutomaticEnv() // read in environment variables that match

	// If a config file is found, read it in.
	if err := viper.ReadInConfig(); err == nil {
		fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed())
	}
}
{{- end }}
`)
}

func AddCommandTemplate() []byte {
	return []byte(`/*
{{ .Project.Copyright }}
{{ if .Legal.Header }}{{ .Legal.Header }}{{ end }}
*/
package cmd

import (
	"fmt"

	"github.com/spf13/cobra"
)

// {{ .CmdName }}Cmd represents the {{ .CmdName }} command
var {{ .CmdName }}Cmd = &cobra.Command{
	Use:   "{{ .CmdName }}",
	Short: "A brief description of your command",
	Long: ` + "`" + `A longer description that spans multiple lines and likely contains examples
and usage of using your command. For example:

Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.` + "`" + `,
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Println("{{ .CmdName }} called")
	},
}

func init() {
	{{ .CmdParent }}.AddCommand({{ .CmdName }}Cmd)

	// Here you will define your flags and configuration settings.

	// Cobra supports Persistent Flags which will work for this command
	// and all subcommands, e.g.:
	// {{ .CmdName }}Cmd.PersistentFlags().String("foo", "", "A help for foo")

	// Cobra supports local flags which will only run when this command
	// is called directly, e.g.:
	// {{ .CmdName }}Cmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}
`)
}
<commit_msg>fix: Duplicate error message from cobra init boilerplates (#1463)<commit_after>// Copyright © 2021 Steve Francia <spf@spf13.com>.
//
// 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 tpl

func MainTemplate() []byte {
	return []byte(`/*
{{ .Copyright }}
{{ if .Legal.Header }}{{ .Legal.Header }}{{ end }}
*/
package main

import "{{ .PkgName }}/cmd"

func main() {
	cmd.Execute()
}
`)
}

func RootTemplate() []byte {
	return []byte(`/*
{{ .Copyright }}
{{ if .Legal.Header }}{{ .Legal.Header }}{{ end }}
*/
package cmd

import (
{{- if .Viper }}
	"fmt"
	"os"
{{ end }}
	"github.com/spf13/cobra"
{{- if .Viper }}
	"github.com/spf13/viper"{{ end }}
)

{{ if .Viper -}}
var cfgFile string
{{- end }}

// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
	Use:   "{{ .AppName }}",
	Short: "A brief description of your application",
	Long: ` + "`" + `A longer description that spans multiple lines and likely contains
examples and usage of using your application. For example:

Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.` + "`" + `,
	// Uncomment the following line if your bare application
	// has an action associated with it:
	// Run: func(cmd *cobra.Command, args []string) { },
}

// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	err := rootCmd.Execute()
	if err != nil {
		os.Exit(1)
	}
}

func init() {
{{- if .Viper }}
	cobra.OnInitialize(initConfig)
{{ end }}
	// Here you will define your flags and configuration settings.
	// Cobra supports persistent flags, which, if defined here,
	// will be global for your application.
{{ if .Viper }}
	rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.{{ .AppName }}.yaml)")
{{ else }}
	// rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.{{ .AppName }}.yaml)")
{{ end }}
	// Cobra also supports local flags, which will only run
	// when this action is called directly.
	rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

{{ if .Viper -}}
// initConfig reads in config file and ENV variables if set.
func initConfig() {
	if cfgFile != "" {
		// Use config file from the flag.
		viper.SetConfigFile(cfgFile)
	} else {
		// Find home directory.
		home, err := os.UserHomeDir()
		cobra.CheckErr(err)

		// Search config in home directory with name ".{{ .AppName }}" (without extension).
		viper.AddConfigPath(home)
		viper.SetConfigType("yaml")
		viper.SetConfigName(".{{ .AppName }}")
	}

	viper.AutomaticEnv() // read in environment variables that match

	// If a config file is found, read it in.
	if err := viper.ReadInConfig(); err == nil {
		fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed())
	}
}
{{- end }}
`)
}

func AddCommandTemplate() []byte {
	return []byte(`/*
{{ .Project.Copyright }}
{{ if .Legal.Header }}{{ .Legal.Header }}{{ end }}
*/
package cmd

import (
	"fmt"

	"github.com/spf13/cobra"
)

// {{ .CmdName }}Cmd represents the {{ .CmdName }} command
var {{ .CmdName }}Cmd = &cobra.Command{
	Use:   "{{ .CmdName }}",
	Short: "A brief description of your command",
	Long: ` + "`" + `A longer description that spans multiple lines and likely contains examples
and usage of using your command. For example:

Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.` + "`" + `,
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Println("{{ .CmdName }} called")
	},
}

func init() {
	{{ .CmdParent }}.AddCommand({{ .CmdName }}Cmd)

	// Here you will define your flags and configuration settings.

	// Cobra supports Persistent Flags which will work for this command
	// and all subcommands, e.g.:
	// {{ .CmdName }}Cmd.PersistentFlags().String("foo", "", "A help for foo")

	// Cobra supports local flags which will only run when this command
	// is called directly, e.g.:
	// {{ .CmdName }}Cmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}
`)
}
<|endoftext|>


<commit_before>package a

import (
	. "github.com/alecthomas/chroma" // nolint
	"github.com/alecthomas/chroma/lexers/internal"
)

// Al lexer.
var Al = internal.Register(MustNewLazyLexer(
	&Config{
		Name:            "AL",
		Aliases:         []string{"al"},
		Filenames:       []string{"*.al", "*.dal"},
		MimeTypes:       []string{"text/x-al"},
		DotAll:          true,
		CaseInsensitive: true,
	},
	alRules,
))

// https://github.com/microsoft/AL/blob/master/grammar/alsyntax.tmlanguage
func alRules() Rules {
	return Rules{
		"root": {
			{`\s+`, TextWhitespace, nil},
			{`(?s)\/\*.*?\\*\*\/`, CommentMultiline, nil},
			{`(?s)//.*?\n`, CommentSingle, nil},
			{`\"([^\"])*\"`, Text, nil},
			{`'([^'])*'`, LiteralString, nil},
			{`\b(?i:(ARRAY|ASSERTERROR|BEGIN|BREAK|CASE|DO|DOWNTO|ELSE|END|EVENT|EXIT|FOR|FOREACH|FUNCTION|IF|IMPLEMENTS|IN|INDATASET|INTERFACE|INTERNAL|LOCAL|OF|PROCEDURE|PROGRAM|PROTECTED|REPEAT|RUNONCLIENT|SECURITYFILTERING|SUPPRESSDISPOSE|TEMPORARY|THEN|TO|TRIGGER|UNTIL|VAR|WHILE|WITH|WITHEVENTS))\b`, Keyword, nil},
			{`\b(?i:(AND|DIV|MOD|NOT|OR|XOR))\b`, OperatorWord, nil},
			{`\b(?i:(AVERAGE|CONST|COUNT|EXIST|FIELD|FILTER|LOOKUP|MAX|MIN|ORDER|SORTING|SUM|TABLEDATA|UPPERLIMIT|WHERE|ASCENDING|DESCENDING))\b`, Keyword, nil},
			// Added new objects types of BC 2021 wave 1 (REPORTEXTENSION|Entitlement|PermissionSet|PermissionSetExtension)
			{`\b(?i:(CODEUNIT|PAGE|PAGEEXTENSION|PAGECUSTOMIZATION|DOTNET|ENUM|ENUMEXTENSION|VALUE|QUERY|REPORT|TABLE|TABLEEXTENSION|XMLPORT|PROFILE|CONTROLADDIN|REPORTEXTENSION|Entitlement|PermissionSet|PermissionSetExtension))\b`, Keyword, nil},
			{`\b(?i:(Action|Array|Automation|BigInteger|BigText|Blob|Boolean|Byte|Char|ClientType|Code|Codeunit|CompletionTriggerErrorLevel|ConnectionType|Database|DataClassification|DataScope|Date|DateFormula|DateTime|Decimal|DefaultLayout|Dialog|Dictionary|DotNet|DotNetAssembly|DotNetTypeDeclaration|Duration|Enum|ErrorInfo|ErrorType|ExecutionContext|ExecutionMode|FieldClass|FieldRef|FieldType|File|FilterPageBuilder|Guid|InStream|Integer|Joker|KeyRef|List|ModuleDependencyInfo|ModuleInfo|None|Notification|NotificationScope|ObjectType|Option|OutStream|Page|PageResult|Query|Record|RecordId|RecordRef|Report|ReportFormat|SecurityFilter|SecurityFiltering|Table|TableConnectionType|TableFilter|TestAction|TestField|TestFilterField|TestPage|TestPermissions|TestRequestPage|Text|TextBuilder|TextConst|TextEncoding|Time|TransactionModel|TransactionType|Variant|Verbosity|Version|XmlPort|HttpContent|HttpHeaders|HttpClient|HttpRequestMessage|HttpResponseMessage|JsonToken|JsonValue|JsonArray|JsonObject|View|Views|XmlAttribute|XmlAttributeCollection|XmlComment|XmlCData|XmlDeclaration|XmlDocument|XmlDocumentType|XmlElement|XmlNamespaceManager|XmlNameTable|XmlNode|XmlNodeList|XmlProcessingInstruction|XmlReadOptions|XmlText|XmlWriteOptions|WebServiceActionContext|WebServiceActionResultCode|SessionSettings))\b`, Keyword, nil},
			{`\b([<>]=|<>|<|>)\b?`, Operator, nil},
			{`\b(\-|\+|\/|\*)\b`, Operator, nil},
			{`\s*(\:=|\+=|-=|\/=|\*=)\s*?`, Operator, nil},
			{`\b(?i:(ADDFIRST|ADDLAST|ADDAFTER|ADDBEFORE|ACTION|ACTIONS|AREA|ASSEMBLY|CHARTPART|CUEGROUP|CUSTOMIZES|COLUMN|DATAITEM|DATASET|ELEMENTS|EXTENDS|FIELD|FIELDGROUP|FIELDATTRIBUTE|FIELDELEMENT|FIELDGROUPS|FIELDS|FILTER|FIXED|GRID|GROUP|MOVEAFTER|MOVEBEFORE|KEY|KEYS|LABEL|LABELS|LAYOUT|MODIFY|MOVEFIRST|MOVELAST|MOVEBEFORE|MOVEAFTER|PART|REPEATER|USERCONTROL|REQUESTPAGE|SCHEMA|SEPARATOR|SYSTEMPART|TABLEELEMENT|TEXTATTRIBUTE|TEXTELEMENT|TYPE))\b`, Keyword, nil},
			{`\s*[(\.\.)&\|]\s*`, Operator, nil},
			{`\b((0(x|X)[0-9a-fA-F]*)|(([0-9]+\.?[0-9]*)|(\.[0-9]+))((e|E)(\+|-)?[0-9]+)?)(L|l|UL|ul|u|U|F|f|ll|LL|ull|ULL)?\b`, LiteralNumber, nil},
			{`[;:,]`, Punctuation, nil},
			{`#[ \t]*(if|else|elif|endif|define|undef|region|endregion|pragma)\b.*?\n`, CommentPreproc, nil},
			{`\w+`, Text, nil},
			{`.`, Text, nil},
		},
	}
}
<commit_msg>Update to the last version of microsoft grammar file<commit_after>package a

import (
	. "github.com/alecthomas/chroma" // nolint
	"github.com/alecthomas/chroma/lexers/internal"
)

// Al lexer.
var Al = internal.Register(MustNewLazyLexer(
	&Config{
		Name:            "AL",
		Aliases:         []string{"al"},
		Filenames:       []string{"*.al", "*.dal"},
		MimeTypes:       []string{"text/x-al"},
		DotAll:          true,
		CaseInsensitive: true,
	},
	alRules,
))

// https://github.com/microsoft/AL/blob/master/grammar/alsyntax.tmlanguage
func alRules() Rules {
	return Rules{
		"root": {
			{`\s+`, TextWhitespace, nil},
			{`(?s)\/\*.*?\\*\*\/`, CommentMultiline, nil},
			{`(?s)//.*?\n`, CommentSingle, nil},
			{`\"([^\"])*\"`, Text, nil},
			{`'([^'])*'`, LiteralString, nil},
			{`\b(?i:(ARRAY|ASSERTERROR|BEGIN|BREAK|CASE|DO|DOWNTO|ELSE|END|EVENT|EXIT|FOR|FOREACH|FUNCTION|IF|IMPLEMENTS|IN|INDATASET|INTERFACE|INTERNAL|LOCAL|OF|PROCEDURE|PROGRAM|PROTECTED|REPEAT|RUNONCLIENT|SECURITYFILTERING|SUPPRESSDISPOSE|TEMPORARY|THEN|TO|TRIGGER|UNTIL|VAR|WHILE|WITH|WITHEVENTS))\b`, Keyword, nil},
			{`\b(?i:(AND|DIV|MOD|NOT|OR|XOR))\b`, OperatorWord, nil},
			{`\b(?i:(AVERAGE|CONST|COUNT|EXIST|FIELD|FILTER|LOOKUP|MAX|MIN|ORDER|SORTING|SUM|TABLEDATA|UPPERLIMIT|WHERE|ASCENDING|DESCENDING))\b`, Keyword, nil},
			{`\b(?i:(CODEUNIT|PAGE|PAGEEXTENSION|PAGECUSTOMIZATION|DOTNET|ENUM|ENUMEXTENSION|VALUE|QUERY|REPORT|TABLE|TABLEEXTENSION|XMLPORT|PROFILE|CONTROLADDIN|REPORTEXTENSION|INTERFACE|PERMISSIONSET|PERMISSIONSETEXTENSION|ENTITLEMENT))\b`, Keyword, nil},
			{`\b(?i:(Action|Array|Automation|BigInteger|BigText|Blob|Boolean|Byte|Char|ClientType|Code|Codeunit|CompletionTriggerErrorLevel|ConnectionType|Database|DataClassification|DataScope|Date|DateFormula|DateTime|Decimal|DefaultLayout|Dialog|Dictionary|DotNet|DotNetAssembly|DotNetTypeDeclaration|Duration|Enum|ErrorInfo|ErrorType|ExecutionContext|ExecutionMode|FieldClass|FieldRef|FieldType|File|FilterPageBuilder|Guid|InStream|Integer|Joker|KeyRef|List|ModuleDependencyInfo|ModuleInfo|None|Notification|NotificationScope|ObjectType|Option|OutStream|Page|PageResult|Query|Record|RecordId|RecordRef|Report|ReportFormat|SecurityFilter|SecurityFiltering|Table|TableConnectionType|TableFilter|TestAction|TestField|TestFilterField|TestPage|TestPermissions|TestRequestPage|Text|TextBuilder|TextConst|TextEncoding|Time|TransactionModel|TransactionType|Variant|Verbosity|Version|XmlPort|HttpContent|HttpHeaders|HttpClient|HttpRequestMessage|HttpResponseMessage|JsonToken|JsonValue|JsonArray|JsonObject|View|Views|XmlAttribute|XmlAttributeCollection|XmlComment|XmlCData|XmlDeclaration|XmlDocument|XmlDocumentType|XmlElement|XmlNamespaceManager|XmlNameTable|XmlNode|XmlNodeList|XmlProcessingInstruction|XmlReadOptions|XmlText|XmlWriteOptions|WebServiceActionContext|WebServiceActionResultCode|SessionSettings))\b`, Keyword, nil},
			{`\b([<>]=|<>|<|>)\b?`, Operator, nil},
			{`\b(\-|\+|\/|\*)\b`, Operator, nil},
			{`\s*(\:=|\+=|-=|\/=|\*=)\s*?`, Operator, nil},
			{`\b(?i:(ADD|ADDFIRST|ADDLAST|ADDAFTER|ADDBEFORE|ACTION|ACTIONS|AREA|ASSEMBLY|CHARTPART|CUEGROUP|CUSTOMIZES|COLUMN|DATAITEM|DATASET|ELEMENTS|EXTENDS|FIELD|FIELDGROUP|FIELDATTRIBUTE|FIELDELEMENT|FIELDGROUPS|FIELDS|FILTER|FIXED|GRID|GROUP|MOVEAFTER|MOVEBEFORE|KEY|KEYS|LABEL|LABELS|LAYOUT|MODIFY|MOVEFIRST|MOVELAST|MOVEBEFORE|MOVEAFTER|PART|REPEATER|USERCONTROL|REQUESTPAGE|SCHEMA|SEPARATOR|SYSTEMPART|TABLEELEMENT|TEXTATTRIBUTE|TEXTELEMENT|TYPE))\b`, Keyword, nil},
			{`\s*[(\.\.)&\|]\s*`, Operator, nil},
			{`\b((0(x|X)[0-9a-fA-F]*)|(([0-9]+\.?[0-9]*)|(\.[0-9]+))((e|E)(\+|-)?[0-9]+)?)(L|l|UL|ul|u|U|F|f|ll|LL|ull|ULL)?\b`, LiteralNumber, nil},
			{`[;:,]`, Punctuation, nil},
			{`#[ \t]*(if|else|elif|endif|define|undef|region|endregion|pragma)\b.*?\n`, CommentPreproc, nil},
			{`\w+`, Text, nil},
			{`.`, Text, nil},
		},
	}
}
<|endoftext|>


<commit_before>package api

import (
	"io/ioutil"
	"path/filepath"
	"testing"
	"time"

	"github.com/NebulousLabs/Sia/build"
	"github.com/NebulousLabs/Sia/crypto"
	"github.com/NebulousLabs/Sia/types"
)

// TestIntegrationHosting tests that the host correctly receives payment for
// hosting files.
func TestIntegrationHosting(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}

	st, err := createServerTester("TestIntegrationHosting")
	if err != nil {
		t.Fatal(err)
	}

	// announce the host
	err = st.stdGetAPI("/host/announce?address=" + string(st.host.Address()))
	if err != nil {
		t.Fatal(err)
	}
	// we need to announce twice, or the renter will complain about not having enough hosts
	loopAddr := "127.0.0.1:" + st.host.Address().Port()
	err = st.stdGetAPI("/host/announce?address=" + loopAddr)
	if err != nil {
		t.Fatal(err)
	}

	// wait for announcement to register
	st.miner.AddBlock()
	var hosts ActiveHosts
	st.getAPI("/hostdb/hosts/active", &hosts)
	if len(hosts.Hosts) == 0 {
		t.Fatal("host announcement not seen")
	}

	// create a file
	path := filepath.Join(build.SiaTestingDir, "api", "TestIntegrationHosting", "test.dat")
	data, err := crypto.RandBytes(1024)
	if err != nil {
		t.Fatal(err)
	}
	err = ioutil.WriteFile(path, data, 0600)
	if err != nil {
		t.Fatal(err)
	}

	// upload to host
	err = st.stdGetAPI("/renter/files/upload?nickname=test&duration=10&source=" + path)
	if err != nil {
		t.Fatal(err)
	}
	var fi []FileInfo
	var loops int
	for len(fi) != 1 || fi[0].UploadProgress != 100 {
		st.getAPI("/renter/files/list", &fi)
		time.Sleep(3 * time.Second)
		loops++
	}

	// mine blocks until storage proof is complete
	for i := 0; i < 50+int(types.MaturityDelay); i++ {
		st.miner.AddBlock()
	}

	// check balance
	var wi WalletGET
	st.getAPI("/wallet", &wi)
	expBal := "16499494999617870000000002429474"
	if wi.ConfirmedSiacoinBalance.String() != expBal {
		t.Fatalf("host's balance was not affected: expected %v, got %v", expBal, wi.ConfirmedSiacoinBalance)
	}
}
<commit_msg>use host.Profit in host test instead of wallet<commit_after>package api

import (
	"io/ioutil"
	"path/filepath"
	"testing"
	"time"

	"github.com/NebulousLabs/Sia/build"
	"github.com/NebulousLabs/Sia/crypto"
	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/types"
)

// TestIntegrationHosting tests that the host correctly receives payment for
// hosting files.
func TestIntegrationHosting(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}

	st, err := createServerTester("TestIntegrationHosting")
	if err != nil {
		t.Fatal(err)
	}

	// announce the host
	err = st.stdGetAPI("/host/announce?address=" + string(st.host.Address()))
	if err != nil {
		t.Fatal(err)
	}
	// we need to announce twice, or the renter will complain about not having enough hosts
	loopAddr := "127.0.0.1:" + st.host.Address().Port()
	err = st.stdGetAPI("/host/announce?address=" + loopAddr)
	if err != nil {
		t.Fatal(err)
	}

	// wait for announcement to register
	st.miner.AddBlock()
	var hosts ActiveHosts
	st.getAPI("/hostdb/hosts/active", &hosts)
	if len(hosts.Hosts) == 0 {
		t.Fatal("host announcement not seen")
	}

	// create a file
	path := filepath.Join(build.SiaTestingDir, "api", "TestIntegrationHosting", "test.dat")
	data, err := crypto.RandBytes(1024)
	if err != nil {
		t.Fatal(err)
	}
	err = ioutil.WriteFile(path, data, 0600)
	if err != nil {
		t.Fatal(err)
	}

	// upload to host
	err = st.stdGetAPI("/renter/files/upload?nickname=test&duration=10&source=" + path)
	if err != nil {
		t.Fatal(err)
	}
	var fi []FileInfo
	for len(fi) != 1 || fi[0].UploadProgress != 100 {
		st.getAPI("/renter/files/list", &fi)
		time.Sleep(3 * time.Second)
	}

	// mine blocks until storage proof is complete
	for i := 0; i < 20+int(types.MaturityDelay); i++ {
		st.miner.AddBlock()
	}

	// check profit
	var hi modules.HostInfo
	st.getAPI("/host/status", &hi)
	expProfit := "382129999999997570526"
	if hi.Profit.String() != expProfit {
		t.Log(hi)
		t.Fatalf("host's profit was not affected: expected %v, got %v", expProfit, hi.Profit)
	}
}
<|endoftext|>


<commit_before>package manager

import (
	"github.com/rancher/types/apis/management.cattle.io/v3"
	"github.com/sirupsen/logrus"
	kerrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func (m *Manager) Sync(key string, obj *v3.Catalog) error {
	if obj == nil {
		return nil
	}
	if obj.DeletionTimestamp != nil {
		templates, err := m.getTemplateMap(obj.Name)
		if err != nil {
			return err
		}
		tvToDelete := map[string]struct{}{}
		for _, t := range templates {
			tvs, err := m.getTemplateVersion(t.Name)
			if err != nil {
				return err
			}
			for k := range tvs {
				tvToDelete[k] = struct{}{}
			}
		}
		go func() {
			for {
				for k := range templates {
					if err := m.templateClient.Delete(k, &metav1.DeleteOptions{}); err != nil && !kerrors.IsNotFound(err) {
						logrus.Warnf("Deleting template %v doesn't succeed. Continue loop", k)
						continue
					}
				}
				for k := range tvToDelete {
					if err := m.templateVersionClient.Delete(k, &metav1.DeleteOptions{}); err != nil && !kerrors.IsNotFound(err) {
						logrus.Warnf("Deleting templateVersion %v doesn't succeed. Continue loop", k)
						continue
					}
				}
				break
			}
		}()
		return nil
	}

	// always get a refresh catalog from etcd
	catalog, err := m.catalogClient.Get(key, metav1.GetOptions{})
	if err != nil {
		return err
	}

	repoPath, commit, err := m.prepareRepoPath(*catalog)
	if err != nil {
		v3.CatalogConditionRefreshed.False(catalog)
		v3.CatalogConditionRefreshed.ReasonAndMessageFromError(catalog, err)
		m.catalogClient.Update(catalog)
		return err
	}

	if commit == catalog.Status.Commit {
		logrus.Debugf("Catalog %s is already up to date", catalog.Name)
		if v3.CatalogConditionRefreshed.IsUnknown(catalog) {
			v3.CatalogConditionRefreshed.True(catalog)
			v3.CatalogConditionRefreshed.Reason(catalog, "")
			m.catalogClient.Update(catalog)
		}
		return nil
	}

	logrus.Infof("Updating catalog %s", catalog.Name)
	return m.traverseAndUpdate(repoPath, commit, catalog)
}
<commit_msg>check nil when deleting catalog<commit_after>package manager

import (
	"github.com/rancher/types/apis/management.cattle.io/v3"
	"github.com/sirupsen/logrus"
	kerrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func (m *Manager) Sync(key string, obj *v3.Catalog) error {
	if obj == nil {
		templates, err := m.getTemplateMap(key)
		if err != nil {
			return err
		}
		tvToDelete := map[string]struct{}{}
		for _, t := range templates {
			tvs, err := m.getTemplateVersion(t.Name)
			if err != nil {
				return err
			}
			for k := range tvs {
				tvToDelete[k] = struct{}{}
			}
		}
		go func() {
			for {
				for k := range templates {
					if err := m.templateClient.Delete(k, &metav1.DeleteOptions{}); err != nil && !kerrors.IsNotFound(err) {
						logrus.Warnf("Deleting template %v doesn't succeed. Continue loop", k)
						continue
					}
				}
				for k := range tvToDelete {
					if err := m.templateVersionClient.Delete(k, &metav1.DeleteOptions{}); err != nil && !kerrors.IsNotFound(err) {
						logrus.Warnf("Deleting templateVersion %v doesn't succeed. Continue loop", k)
						continue
					}
				}
				break
			}
		}()
		return nil
	}

	// always get a refresh catalog from etcd
	catalog, err := m.catalogClient.Get(key, metav1.GetOptions{})
	if err != nil {
		return err
	}

	repoPath, commit, err := m.prepareRepoPath(*catalog)
	if err != nil {
		v3.CatalogConditionRefreshed.False(catalog)
		v3.CatalogConditionRefreshed.ReasonAndMessageFromError(catalog, err)
		m.catalogClient.Update(catalog)
		return err
	}

	if commit == catalog.Status.Commit {
		logrus.Debugf("Catalog %s is already up to date", catalog.Name)
		if v3.CatalogConditionRefreshed.IsUnknown(catalog) {
			v3.CatalogConditionRefreshed.True(catalog)
			v3.CatalogConditionRefreshed.Reason(catalog, "")
			m.catalogClient.Update(catalog)
		}
		return nil
	}

	logrus.Infof("Updating catalog %s", catalog.Name)
	return m.traverseAndUpdate(repoPath, commit, catalog)
}
<|endoftext|>


<commit_before>package fsutil

import (
	"bufio"
	"bytes"
	"crypto/sha512"
	"fmt"
	"io"
)

func newChecksumReader(reader io.Reader) *ChecksumReader {
	r := new(ChecksumReader)
	r.checksummer = sha512.New()
	if _, ok := reader.(io.ByteReader); !ok {
		r.reader = bufio.NewReader(reader)
	} else {
		r.reader = reader
	}
	return r
}

func (r *ChecksumReader) read(p []byte) (int, error) {
	nRead, err := r.reader.Read(p)
	if err != nil {
		return 0, err
	}
	_, err = r.checksummer.Write(p[:nRead])
	return nRead, err
}

func (r *ChecksumReader) readByte() (byte, error) {
	buf := make([]byte, 1)
	_, err := r.read(buf)
	return buf[0], err
}

func (r *ChecksumReader) verifyChecksum() error {
	buf := make([]byte, r.checksummer.Size())
	nRead, err := r.reader.Read(buf)
	if err != nil {
		return err
	}
	if nRead != r.checksummer.Size() {
		return fmt.Errorf(
			"ChecksumReader.Checksum(): expected: %d got: %d bytes",
			r.checksummer.Size(), nRead)
	}
	if !bytes.Equal(buf, r.checksummer.Sum(nil)) {
		return ErrorChecksumMismatch
	}
	return nil
}

func newChecksumWriter(writer io.Writer) *ChecksumWriter {
	w := new(ChecksumWriter)
	w.checksummer = sha512.New()
	w.writer = writer
	return w
}

func (w *ChecksumWriter) write(p []byte) (int, error) {
	if _, err := w.checksummer.Write(p); err != nil {
		return 0, err
	}
	return w.writer.Write(p)
}

func (w *ChecksumWriter) writeChecksum() error {
	_, err := w.writer.Write(w.checksummer.Sum(nil))
	return err
}
<commit_msg>Fix short read bug in lib/fsutil.ChecksumReader.VerifyChecksum().<commit_after>package fsutil

import (
	"bufio"
	"bytes"
	"crypto/sha512"
	"fmt"
	"io"
)

func newChecksumReader(reader io.Reader) *ChecksumReader {
	r := new(ChecksumReader)
	r.checksummer = sha512.New()
	if _, ok := reader.(io.ByteReader); !ok {
		r.reader = bufio.NewReader(reader)
	} else {
		r.reader = reader
	}
	return r
}

func (r *ChecksumReader) read(p []byte) (int, error) {
	nRead, err := r.reader.Read(p)
	if err != nil {
		return 0, err
	}
	_, err = r.checksummer.Write(p[:nRead])
	return nRead, err
}

func (r *ChecksumReader) readByte() (byte, error) {
	buf := make([]byte, 1)
	_, err := r.read(buf)
	return buf[0], err
}

func (r *ChecksumReader) verifyChecksum() error {
	buf := make([]byte, r.checksummer.Size())
	nRead, err := io.ReadAtLeast(r.reader, buf, len(buf))
	if err != nil {
		return err
	}
	if nRead != r.checksummer.Size() {
		return fmt.Errorf(
			"ChecksumReader.Checksum(): expected: %d got: %d bytes",
			r.checksummer.Size(), nRead)
	}
	if !bytes.Equal(buf, r.checksummer.Sum(nil)) {
		return ErrorChecksumMismatch
	}
	return nil
}

func newChecksumWriter(writer io.Writer) *ChecksumWriter {
	w := new(ChecksumWriter)
	w.checksummer = sha512.New()
	w.writer = writer
	return w
}

func (w *ChecksumWriter) write(p []byte) (int, error) {
	if _, err := w.checksummer.Write(p); err != nil {
		return 0, err
	}
	return w.writer.Write(p)
}

func (w *ChecksumWriter) writeChecksum() error {
	_, err := w.writer.Write(w.checksummer.Sum(nil))
	return err
}
<|endoftext|>


<commit_before>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package timestampvm

import (
	"errors"
	"net/http"

	"github.com/ava-labs/gecko/ids"

	"github.com/ava-labs/gecko/utils/formatting"
)

var (
	errDBError     = errors.New("error getting data from database")
	errBadData     = errors.New("data must be base 58 repr. of 32 bytes")
	errNoSuchBlock = errors.New("couldn't get block from database. Does it exist?")
)

// Service is the API service for this VM
type Service struct{ vm *VM }

// ProposeBlockArgs are the arguments to function ProposeValue
type ProposeBlockArgs struct {
	// Data in the block. Must be base 58 encoding of 32 bytes.
	Data string `json:"data"`
}

// ProposeBlockReply is the reply from function ProposeBlock
type ProposeBlockReply struct{ Success bool }

// ProposeBlock is an API method to propose a new block whose data is [args].Data.
// [args].Data must be a string repr. of a 32 byte array
func (s *Service) ProposeBlock(_ *http.Request, args *ProposeBlockArgs, reply *ProposeBlockReply) error {
	byteFormatter := formatting.CB58{}
	if err := byteFormatter.FromString(args.Data); err != nil {
		return errBadData
	}
	dataSlice := byteFormatter.Bytes
	if len(dataSlice) != dataLen {
		return errBadData
	}
	var data [dataLen]byte             // The data as an array of bytes
	copy(data[:], dataSlice[:dataLen]) // Copy the bytes in dataSlice to data
	s.vm.proposeBlock(data)
	reply.Success = true
	return nil
}

// APIBlock is the API representation of a block
type APIBlock struct {
	Timestamp int64  `json:"timestamp"` // Timestamp of most recent block
	Data      string `json:"data"`      // Data in the most recent block. Base 58 repr. of 5 bytes.
	ID        string `json:"id"`        // String repr. of ID of the most recent block
	ParentID  string `json:"parentID"`  // String repr. of ID of the most recent block's parent
}

// GetBlockArgs are the arguments to GetBlock
type GetBlockArgs struct {
	// ID of the block we're getting.
	// If left blank, gets the latest block
	ID string
}

// GetBlockReply is the reply from GetBlock
type GetBlockReply struct {
	APIBlock
}

// GetBlock gets the block whose ID is [args.ID]
// If [args.ID] is empty, get the latest block
func (s *Service) GetBlock(_ *http.Request, args *GetBlockArgs, reply *GetBlockReply) error {
	var ID ids.ID
	var err error
	if args.ID == "" {
		ID = s.vm.LastAccepted()
	} else {
		ID, err = ids.FromString(args.ID)
		if err != nil {
			return errors.New("problem parsing ID")
		}
	}

	blockInterface, err := s.vm.GetBlock(ID)
	if err != nil {
		return errDatabase
	}

	block, ok := blockInterface.(*Block)
	if !ok {
		return errBadData
	}

	reply.APIBlock.ID = block.ID().String()
	reply.APIBlock.Timestamp = block.Timestamp
	reply.APIBlock.ParentID = block.ParentID().String()
	byteFormatter := formatting.CB58{Bytes: block.Data[:]}
	reply.Data = byteFormatter.String()

	return nil
}
<commit_msg>getBlock returns timestamp with quotes<commit_after>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package timestampvm

import (
	"errors"
	"net/http"

	"github.com/ava-labs/gecko/ids"
	"github.com/ava-labs/gecko/utils/json"

	"github.com/ava-labs/gecko/utils/formatting"
)

var (
	errDBError     = errors.New("error getting data from database")
	errBadData     = errors.New("data must be base 58 repr. of 32 bytes")
	errNoSuchBlock = errors.New("couldn't get block from database. Does it exist?")
)

// Service is the API service for this VM
type Service struct{ vm *VM }

// ProposeBlockArgs are the arguments to function ProposeValue
type ProposeBlockArgs struct {
	// Data in the block. Must be base 58 encoding of 32 bytes.
	Data string `json:"data"`
}

// ProposeBlockReply is the reply from function ProposeBlock
type ProposeBlockReply struct{ Success bool }

// ProposeBlock is an API method to propose a new block whose data is [args].Data.
// [args].Data must be a string repr. of a 32 byte array
func (s *Service) ProposeBlock(_ *http.Request, args *ProposeBlockArgs, reply *ProposeBlockReply) error {
	byteFormatter := formatting.CB58{}
	if err := byteFormatter.FromString(args.Data); err != nil {
		return errBadData
	}
	dataSlice := byteFormatter.Bytes
	if len(dataSlice) != dataLen {
		return errBadData
	}
	var data [dataLen]byte             // The data as an array of bytes
	copy(data[:], dataSlice[:dataLen]) // Copy the bytes in dataSlice to data
	s.vm.proposeBlock(data)
	reply.Success = true
	return nil
}

// APIBlock is the API representation of a block
type APIBlock struct {
	Timestamp json.Uint64 `json:"timestamp"` // Timestamp of most recent block
	Data      string      `json:"data"`      // Data in the most recent block. Base 58 repr. of 5 bytes.
	ID        string      `json:"id"`        // String repr. of ID of the most recent block
	ParentID  string      `json:"parentID"`  // String repr. of ID of the most recent block's parent
}

// GetBlockArgs are the arguments to GetBlock
type GetBlockArgs struct {
	// ID of the block we're getting.
	// If left blank, gets the latest block
	ID string
}

// GetBlockReply is the reply from GetBlock
type GetBlockReply struct {
	APIBlock
}

// GetBlock gets the block whose ID is [args.ID]
// If [args.ID] is empty, get the latest block
func (s *Service) GetBlock(_ *http.Request, args *GetBlockArgs, reply *GetBlockReply) error {
	var ID ids.ID
	var err error
	if args.ID == "" {
		ID = s.vm.LastAccepted()
	} else {
		ID, err = ids.FromString(args.ID)
		if err != nil {
			return errors.New("problem parsing ID")
		}
	}

	blockInterface, err := s.vm.GetBlock(ID)
	if err != nil {
		return errDatabase
	}

	block, ok := blockInterface.(*Block)
	if !ok {
		return errBadData
	}

	reply.APIBlock.ID = block.ID().String()
	reply.APIBlock.Timestamp = json.Uint64(block.Timestamp)
	reply.APIBlock.ParentID = block.ParentID().String()
	byteFormatter := formatting.CB58{Bytes: block.Data[:]}
	reply.Data = byteFormatter.String()

	return nil
}
<|endoftext|>


<commit_before>package sdees

import (
	"math/rand"
	"os"
	"regexp"
	"time"
)

// timeTrack from https://coderwall.com/p/cp5fya/measuring-execution-time-in-go
func timeTrack(start time.Time, name string) {
	elapsed := time.Since(start)
	logger.Debug("%s took %s", name, elapsed)
}

// RandStringBytesMaskImprSrc generates a random string using a alphabet and seed
// from SO
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
const (
	letterIdxBits = 6                    // 6 bits to represent a letter index
	letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
	letterIdxMax  = 63 / letterIdxBits   // # of letter indices fitting in 63 bits
)

func RandStringBytesMaskImprSrc(n int, seed int64) string {
	src := rand.NewSource(seed)
	b := make([]byte, n)
	// A src.Int63() generates 63 random bits, enough for letterIdxMax characters!
	for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 0; {
		if remain == 0 {
			cache, remain = src.Int63(), letterIdxMax
		}
		if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
			b[i] = letterBytes[idx]
			i--
		}
		cache >>= letterIdxBits
		remain--
	}

	return string(b)
}

// exists returns whether the given file or directory exists or not
// from http://stackoverflow.com/questions/10510691/how-to-check-whether-a-file-or-directory-denoted-by-a-path-exists-in-golang
func exists(path string) bool {
	_, err := os.Stat(path)
	if err == nil {
		return true
	}
	if os.IsNotExist(err) {
		return false
	}
	return true
}

// Shred writes random data to the file before erasing it
func Shred(fileName string) error {
	f, err := os.OpenFile(fileName, os.O_RDWR|os.O_APPEND, 0666)
	if err != nil {
		return err
	}
	fileData, err := f.Stat()
	if err != nil {
		return err
	}
	b := make([]byte, fileData.Size())
	_, err = rand.Read(b)
	if err != nil {
		return err
	}
	_, err = f.WriteAt(b, 0)
	if err != nil {
		return err
	}
	f.Close()
	err = os.Remove(fileName)
	if err != nil {
		return err
	}
	return nil
}

func GetWordsFromText(text string) []string {
	words := regexp.MustCompile("\\w+")
	return words.FindAllString(text, -1)
}
<commit_msg>Added GetRandomMD5Hash<commit_after>package sdees

import (
	"math/rand"
	"os"
	"regexp"
	"time"
)

// timeTrack from https://coderwall.com/p/cp5fya/measuring-execution-time-in-go
func timeTrack(start time.Time, name string) {
	elapsed := time.Since(start)
	logger.Debug("%s took %s", name, elapsed)
}

func GetRandomMD5Hash() string {
	hasher := md5.New()
	hasher.Write([]byte(RandStringBytesMaskImprSrc(10, time.Now().UnixNano())))
	return hex.EncodeToString(hasher.Sum(nil))[0:8]
}

// RandStringBytesMaskImprSrc generates a random string using a alphabet and seed
// from SO
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
const (
	letterIdxBits = 6                    // 6 bits to represent a letter index
	letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
	letterIdxMax  = 63 / letterIdxBits   // # of letter indices fitting in 63 bits
)

func RandStringBytesMaskImprSrc(n int, seed int64) string {
	src := rand.NewSource(seed)
	b := make([]byte, n)
	// A src.Int63() generates 63 random bits, enough for letterIdxMax characters!
	for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 0; {
		if remain == 0 {
			cache, remain = src.Int63(), letterIdxMax
		}
		if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
			b[i] = letterBytes[idx]
			i--
		}
		cache >>= letterIdxBits
		remain--
	}

	return string(b)
}

// exists returns whether the given file or directory exists or not
// from http://stackoverflow.com/questions/10510691/how-to-check-whether-a-file-or-directory-denoted-by-a-path-exists-in-golang
func exists(path string) bool {
	_, err := os.Stat(path)
	if err == nil {
		return true
	}
	if os.IsNotExist(err) {
		return false
	}
	return true
}

// Shred writes random data to the file before erasing it
func Shred(fileName string) error {
	f, err := os.OpenFile(fileName, os.O_RDWR|os.O_APPEND, 0666)
	if err != nil {
		return err
	}
	fileData, err := f.Stat()
	if err != nil {
		return err
	}
	b := make([]byte, fileData.Size())
	_, err = rand.Read(b)
	if err != nil {
		return err
	}
	_, err = f.WriteAt(b, 0)
	if err != nil {
		return err
	}
	f.Close()
	err = os.Remove(fileName)
	if err != nil {
		return err
	}
	return nil
}

func GetWordsFromText(text string) []string {
	words := regexp.MustCompile("\\w+")
	return words.FindAllString(text, -1)
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"fmt"
	"net/http"
	_ "net/http/pprof"
	"net/url"
	"os"
	"os/signal"
	"time"

	"github.com/Comcast/webpa-common/concurrent"
	"github.com/Comcast/webpa-common/secure"
	"github.com/Comcast/webpa-common/secure/handler"
	"github.com/Comcast/webpa-common/secure/key"
	"github.com/Comcast/webpa-common/server"
	"github.com/Comcast/webpa-common/webhook"
	"github.com/SermoDigital/jose/jwt"
	"github.com/gorilla/mux"
	"github.com/justinas/alice"
	"github.com/spf13/pflag"
	"github.com/spf13/viper"
)

const (
	applicationName = "caduceus"
	DEFAULT_KEY_ID  = "current"
)

// getValidator returns validator for JWT tokens
func getValidator(v *viper.Viper) (validator secure.Validator, err error) {
	default_validators := make(secure.Validators, 0, 0)
	var jwtVals []JWTValidator

	v.UnmarshalKey("jwtValidators", &jwtVals)

	// make sure there is at least one jwtValidator supplied
	if len(jwtVals) < 1 {
		validator = default_validators
		return
	}

	// if a JWTKeys section was supplied, configure a JWS validator
	// and append it to the chain of validators
	validators := make(secure.Validators, 0, len(jwtVals))

	for _, validatorDescriptor := range jwtVals {
		var keyResolver key.Resolver
		keyResolver, err = validatorDescriptor.Keys.NewResolver()
		if err != nil {
			validator = validators
			return
		}

		validators = append(
			validators,
			secure.JWSValidator{
				DefaultKeyId:  DEFAULT_KEY_ID,
				Resolver:      keyResolver,
				JWTValidators: []*jwt.Validator{validatorDescriptor.Custom.New()},
			},
		)
	}

	// TODO: This should really be part of the unmarshalled validators somehow
	basicAuth := v.GetStringSlice("authHeader")
	for _, authValue := range basicAuth {
		validators = append(
			validators,
			secure.ExactMatchValidator(authValue),
		)
	}

	validator = validators

	return
}

// caduceus is the driver function for Caduceus.  It performs everything main() would do,
// except for obtaining the command-line arguments (which are passed to it).
func caduceus(arguments []string) int {
	totalTime := time.Now()

	var (
		f = pflag.NewFlagSet(applicationName, pflag.ContinueOnError)
		v = viper.New()

		logger, webPA, err = server.Initialize(applicationName, arguments, f, v)
	)

	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to initialize Viper environment: %s\n", err)
		return 1
	}

	logger.Info("Using configuration file: %s", v.ConfigFileUsed())

	caduceusConfig := new(CaduceusConfig)
	err = v.Unmarshal(caduceusConfig)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to unmarshal configuration data into struct: %s\n", err)
		return 1
	}

	workerPool := WorkerPoolFactory{
		NumWorkers: caduceusConfig.NumWorkerThreads,
		QueueSize:  caduceusConfig.JobQueueSize,
	}.New()

	mainCaduceusProfilerFactory := ServerProfilerFactory{
		Frequency: caduceusConfig.ProfilerFrequency,
		Duration:  caduceusConfig.ProfilerDuration,
		QueueSize: caduceusConfig.ProfilerQueueSize,
		Logger:    logger,
	}

	// here we create a profiler specifically for our main server handler
	caduceusHandlerProfiler, err := mainCaduceusProfilerFactory.New("main")
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to profiler for main caduceus handler: %s\n", err)
		return 1
	}

	childCaduceusProfilerFactory := mainCaduceusProfilerFactory
	childCaduceusProfilerFactory.Parent = caduceusHandlerProfiler

	tr := &http.Transport{
		TLSClientConfig:       &tls.Config{InsecureSkipVerify: true},
		MaxIdleConnsPerHost:   caduceusConfig.SenderNumWorkersPerSender,
		ResponseHeaderTimeout: 10 * time.Second, // TODO Make this configurable
	}

	timeout := time.Duration(caduceusConfig.SenderClientTimeout) * time.Second

	// declare a new sender wrapper and pass it a profiler factory so that it can create
	// unique profilers on a per outboundSender basis
	caduceusSenderWrapper, err := SenderWrapperFactory{
		NumWorkersPerSender: caduceusConfig.SenderNumWorkersPerSender,
		QueueSizePerSender:  caduceusConfig.SenderQueueSizePerSender,
		CutOffPeriod:        time.Duration(caduceusConfig.SenderCutOffPeriod) * time.Second,
		Linger:              time.Duration(caduceusConfig.SenderLinger) * time.Second,
		ProfilerFactory:     childCaduceusProfilerFactory,
		Logger:              logger,
		Client:              &http.Client{Transport: tr, Timeout: timeout},
	}.New()

	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to initialize new caduceus sender wrapper: %s\n", err)
		return 1
	}

	serverWrapper := &ServerHandler{
		Logger: logger,
		caduceusHandler: &CaduceusHandler{
			handlerProfiler: caduceusHandlerProfiler,
			senderWrapper:   caduceusSenderWrapper,
			Logger:          logger,
		},
		doJob: workerPool.Send,
	}

	profileWrapper := &ProfileHandler{
		profilerData: caduceusHandlerProfiler,
		Logger:       logger,
	}

	validator, err := getValidator(v)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Validator error: %v\n", err)
		return 1
	}

	authHandler := handler.AuthorizationHandler{
		HeaderName:          "Authorization",
		ForbiddenStatusCode: 403,
		Validator:           validator,
		Logger:              logger,
	}

	caduceusHandler := alice.New(authHandler.Decorate)

	mux := mux.NewRouter()
	mux.Handle("/api/v1/notify", caduceusHandler.Then(serverWrapper))
	mux.Handle("/api/v1/profile", caduceusHandler.Then(profileWrapper))

	// Support the old endpoint too.
	mux.Handle("/api/v2/notify/{deviceid}/event/{eventtype:.*}", caduceusHandler.Then(serverWrapper))

	webhookFactory, err := webhook.NewFactory(v)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error creating new webhook factory: %s\n", err)
		return 1
	}
	webhookRegistry, webhookHandler := webhookFactory.NewRegistryAndHandler()
	webhookFactory.SetExternalUpdate(caduceusSenderWrapper.Update)

	// register webhook end points for api
	mux.Handle("/hook", caduceusHandler.ThenFunc(webhookRegistry.UpdateRegistry))
	mux.Handle("/hooks", caduceusHandler.ThenFunc(webhookRegistry.GetRegistry))

	selfURL := &url.URL{
		Scheme: "https",
		Host:   v.GetString("fqdn") + v.GetString("primary.address"),
	}

	webhookFactory.Initialize(mux, selfURL, webhookHandler, logger, nil)

	caduceusHealth := &CaduceusHealth{}
	var runnable concurrent.Runnable

	caduceusHealth.Monitor, runnable = webPA.Prepare(logger, nil, mux)
	serverWrapper.caduceusHealth = caduceusHealth

	waitGroup, shutdown, err := concurrent.Execute(runnable)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to start device manager: %s\n", err)
		return 1
	}

	logger.Debug("calling webhookFactory.PrepareAndStart")
	now := time.Now()
	webhookFactory.PrepareAndStart()
	logger.Debug("webhookFactory.PrepareAndStart done. elapsed time: %v", time.Since(now))

	// Attempt to obtain the current listener list from current system without having to wait for listener reregistration.
	logger.Debug("Attempting to obtain current listener list from %v", v.GetString("start.apiPath"))
	now = time.Now()
	startChan := make(chan webhook.Result, 1)
	webhookFactory.Start.GetCurrentSystemsHooks(startChan)
	var webhookStartResults webhook.Result = <-startChan
	if webhookStartResults.Error != nil {
		logger.Error(webhookStartResults.Error)
	} else {
		// todo: add message
		webhookFactory.SetList(webhook.NewList(webhookStartResults.Hooks))
		caduceusSenderWrapper.Update(webhookStartResults.Hooks)
	}
	logger.Debug("current listener retrieval, elapsed time: %v", time.Since(now))

	logger.Info("Caduceus is up and running! elapsed time: %v", time.Since(totalTime))

	var (
		signals = make(chan os.Signal, 1)
	)

	signal.Notify(signals)
	<-signals
	close(shutdown)
	waitGroup.Wait()

	// shutdown the sender wrapper gently so that all queued messages get serviced
	caduceusSenderWrapper.Shutdown(true)

	return 0
}

func main() {
	os.Exit(caduceus(os.Args))
}
<commit_msg>Change the new api to be v3 vs v1.<commit_after>package main

import (
	"crypto/tls"
	"fmt"
	"net/http"
	_ "net/http/pprof"
	"net/url"
	"os"
	"os/signal"
	"time"

	"github.com/Comcast/webpa-common/concurrent"
	"github.com/Comcast/webpa-common/secure"
	"github.com/Comcast/webpa-common/secure/handler"
	"github.com/Comcast/webpa-common/secure/key"
	"github.com/Comcast/webpa-common/server"
	"github.com/Comcast/webpa-common/webhook"
	"github.com/SermoDigital/jose/jwt"
	"github.com/gorilla/mux"
	"github.com/justinas/alice"
	"github.com/spf13/pflag"
	"github.com/spf13/viper"
)

const (
	applicationName = "caduceus"
	DEFAULT_KEY_ID  = "current"
)

// getValidator returns validator for JWT tokens
func getValidator(v *viper.Viper) (validator secure.Validator, err error) {
	default_validators := make(secure.Validators, 0, 0)
	var jwtVals []JWTValidator

	v.UnmarshalKey("jwtValidators", &jwtVals)

	// make sure there is at least one jwtValidator supplied
	if len(jwtVals) < 1 {
		validator = default_validators
		return
	}

	// if a JWTKeys section was supplied, configure a JWS validator
	// and append it to the chain of validators
	validators := make(secure.Validators, 0, len(jwtVals))

	for _, validatorDescriptor := range jwtVals {
		var keyResolver key.Resolver
		keyResolver, err = validatorDescriptor.Keys.NewResolver()
		if err != nil {
			validator = validators
			return
		}

		validators = append(
			validators,
			secure.JWSValidator{
				DefaultKeyId:  DEFAULT_KEY_ID,
				Resolver:      keyResolver,
				JWTValidators: []*jwt.Validator{validatorDescriptor.Custom.New()},
			},
		)
	}

	// TODO: This should really be part of the unmarshalled validators somehow
	basicAuth := v.GetStringSlice("authHeader")
	for _, authValue := range basicAuth {
		validators = append(
			validators,
			secure.ExactMatchValidator(authValue),
		)
	}

	validator = validators

	return
}

// caduceus is the driver function for Caduceus.  It performs everything main() would do,
// except for obtaining the command-line arguments (which are passed to it).
func caduceus(arguments []string) int {
	totalTime := time.Now()

	var (
		f = pflag.NewFlagSet(applicationName, pflag.ContinueOnError)
		v = viper.New()

		logger, webPA, err = server.Initialize(applicationName, arguments, f, v)
	)

	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to initialize Viper environment: %s\n", err)
		return 1
	}

	logger.Info("Using configuration file: %s", v.ConfigFileUsed())

	caduceusConfig := new(CaduceusConfig)
	err = v.Unmarshal(caduceusConfig)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to unmarshal configuration data into struct: %s\n", err)
		return 1
	}

	workerPool := WorkerPoolFactory{
		NumWorkers: caduceusConfig.NumWorkerThreads,
		QueueSize:  caduceusConfig.JobQueueSize,
	}.New()

	mainCaduceusProfilerFactory := ServerProfilerFactory{
		Frequency: caduceusConfig.ProfilerFrequency,
		Duration:  caduceusConfig.ProfilerDuration,
		QueueSize: caduceusConfig.ProfilerQueueSize,
		Logger:    logger,
	}

	// here we create a profiler specifically for our main server handler
	caduceusHandlerProfiler, err := mainCaduceusProfilerFactory.New("main")
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to profiler for main caduceus handler: %s\n", err)
		return 1
	}

	childCaduceusProfilerFactory := mainCaduceusProfilerFactory
	childCaduceusProfilerFactory.Parent = caduceusHandlerProfiler

	tr := &http.Transport{
		TLSClientConfig:       &tls.Config{InsecureSkipVerify: true},
		MaxIdleConnsPerHost:   caduceusConfig.SenderNumWorkersPerSender,
		ResponseHeaderTimeout: 10 * time.Second, // TODO Make this configurable
	}

	timeout := time.Duration(caduceusConfig.SenderClientTimeout) * time.Second

	// declare a new sender wrapper and pass it a profiler factory so that it can create
	// unique profilers on a per outboundSender basis
	caduceusSenderWrapper, err := SenderWrapperFactory{
		NumWorkersPerSender: caduceusConfig.SenderNumWorkersPerSender,
		QueueSizePerSender:  caduceusConfig.SenderQueueSizePerSender,
		CutOffPeriod:        time.Duration(caduceusConfig.SenderCutOffPeriod) * time.Second,
		Linger:              time.Duration(caduceusConfig.SenderLinger) * time.Second,
		ProfilerFactory:     childCaduceusProfilerFactory,
		Logger:              logger,
		Client:              &http.Client{Transport: tr, Timeout: timeout},
	}.New()

	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to initialize new caduceus sender wrapper: %s\n", err)
		return 1
	}

	serverWrapper := &ServerHandler{
		Logger: logger,
		caduceusHandler: &CaduceusHandler{
			handlerProfiler: caduceusHandlerProfiler,
			senderWrapper:   caduceusSenderWrapper,
			Logger:          logger,
		},
		doJob: workerPool.Send,
	}

	profileWrapper := &ProfileHandler{
		profilerData: caduceusHandlerProfiler,
		Logger:       logger,
	}

	validator, err := getValidator(v)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Validator error: %v\n", err)
		return 1
	}

	authHandler := handler.AuthorizationHandler{
		HeaderName:          "Authorization",
		ForbiddenStatusCode: 403,
		Validator:           validator,
		Logger:              logger,
	}

	caduceusHandler := alice.New(authHandler.Decorate)

	mux := mux.NewRouter()
	mux.Handle("/api/v3/notify", caduceusHandler.Then(serverWrapper))
	mux.Handle("/api/v3/profile", caduceusHandler.Then(profileWrapper))

	// Support the old endpoint too.
	mux.Handle("/api/v2/notify/{deviceid}/event/{eventtype:.*}", caduceusHandler.Then(serverWrapper))

	webhookFactory, err := webhook.NewFactory(v)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error creating new webhook factory: %s\n", err)
		return 1
	}
	webhookRegistry, webhookHandler := webhookFactory.NewRegistryAndHandler()
	webhookFactory.SetExternalUpdate(caduceusSenderWrapper.Update)

	// register webhook end points for api
	mux.Handle("/hook", caduceusHandler.ThenFunc(webhookRegistry.UpdateRegistry))
	mux.Handle("/hooks", caduceusHandler.ThenFunc(webhookRegistry.GetRegistry))

	selfURL := &url.URL{
		Scheme: "https",
		Host:   v.GetString("fqdn") + v.GetString("primary.address"),
	}

	webhookFactory.Initialize(mux, selfURL, webhookHandler, logger, nil)

	caduceusHealth := &CaduceusHealth{}
	var runnable concurrent.Runnable

	caduceusHealth.Monitor, runnable = webPA.Prepare(logger, nil, mux)
	serverWrapper.caduceusHealth = caduceusHealth

	waitGroup, shutdown, err := concurrent.Execute(runnable)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to start device manager: %s\n", err)
		return 1
	}

	logger.Debug("calling webhookFactory.PrepareAndStart")
	now := time.Now()
	webhookFactory.PrepareAndStart()
	logger.Debug("webhookFactory.PrepareAndStart done. elapsed time: %v", time.Since(now))

	// Attempt to obtain the current listener list from current system without having to wait for listener reregistration.
	logger.Debug("Attempting to obtain current listener list from %v", v.GetString("start.apiPath"))
	now = time.Now()
	startChan := make(chan webhook.Result, 1)
	webhookFactory.Start.GetCurrentSystemsHooks(startChan)
	var webhookStartResults webhook.Result = <-startChan
	if webhookStartResults.Error != nil {
		logger.Error(webhookStartResults.Error)
	} else {
		// todo: add message
		webhookFactory.SetList(webhook.NewList(webhookStartResults.Hooks))
		caduceusSenderWrapper.Update(webhookStartResults.Hooks)
	}
	logger.Debug("current listener retrieval, elapsed time: %v", time.Since(now))

	logger.Info("Caduceus is up and running! elapsed time: %v", time.Since(totalTime))

	var (
		signals = make(chan os.Signal, 1)
	)

	signal.Notify(signals)
	<-signals
	close(shutdown)
	waitGroup.Wait()

	// shutdown the sender wrapper gently so that all queued messages get serviced
	caduceusSenderWrapper.Shutdown(true)

	return 0
}

func main() {
	os.Exit(caduceus(os.Args))
}
<|endoftext|>


<commit_before>package stick

import (
	"fmt"
	"regexp"
	"strings"
	"testing"

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

func TestF(t *testing.T) {
	err := F("foo %d", 42)

	str := err.Error()
	assert.Equal(t, `foo 42`, str)

	str = fmt.Sprintf("%s", err)
	assert.Equal(t, `foo 42`, str)

	str = fmt.Sprintf("%v", err)
	assert.Equal(t, `foo 42`, str)

	str = fmt.Sprintf("%+v", err)
	assert.Equal(t, []string{
		"foo 42",
		"github.com/256dpi/fire/stick.F",
		"  /Users/256dpi/Development/GitHub/256dpi/fire/stick/error.go:LN",
		"github.com/256dpi/fire/stick.TestF",
		"  /Users/256dpi/Development/GitHub/256dpi/fire/stick/error_test.go:LN",
		"testing.tRunner",
		"  /usr/local/Cellar/go/1.14.1/libexec/src/testing/testing.go:LN",
		"runtime.goexit",
		"  /usr/local/Cellar/go/1.14.1/libexec/src/runtime/asm_amd64.s:LN",
	}, splitTrace(str))
}

func TestWF(t *testing.T) {
	err := F("foo")
	err = WF(err, "bar %d", 42)

	str := err.Error()
	assert.Equal(t, `bar 42: foo`, str)

	str = fmt.Sprintf("%s", err)
	assert.Equal(t, `bar 42: foo`, str)

	str = fmt.Sprintf("%v", err)
	assert.Equal(t, `bar 42: foo`, str)

	str = fmt.Sprintf("%+v", err)
	assert.Equal(t, []string{
		"foo",
		"github.com/256dpi/fire/stick.F",
		"  /Users/256dpi/Development/GitHub/256dpi/fire/stick/error.go:LN",
		"github.com/256dpi/fire/stick.TestWF",
		"  /Users/256dpi/Development/GitHub/256dpi/fire/stick/error_test.go:LN",
		"testing.tRunner",
		"  /usr/local/Cellar/go/1.14.1/libexec/src/testing/testing.go:LN",
		"runtime.goexit",
		"  /usr/local/Cellar/go/1.14.1/libexec/src/runtime/asm_amd64.s:LN",
		"bar 42",
		"github.com/256dpi/fire/stick.WF",
		"  /Users/256dpi/Development/GitHub/256dpi/fire/stick/error.go:LN",
		"github.com/256dpi/fire/stick.TestWF",
		"  /Users/256dpi/Development/GitHub/256dpi/fire/stick/error_test.go:LN",
		"testing.tRunner",
		"  /usr/local/Cellar/go/1.14.1/libexec/src/testing/testing.go:LN",
		"runtime.goexit",
		"  /usr/local/Cellar/go/1.14.1/libexec/src/runtime/asm_amd64.s:LN",
	}, splitTrace(str))
}

func TestE(t *testing.T) {
	err := E("foo")
	assert.True(t, IsSafe(err))

	str := err.Error()
	assert.Equal(t, `foo`, str)

	str = fmt.Sprintf("%s", err)
	assert.Equal(t, `foo`, str)

	str = fmt.Sprintf("%v", err)
	assert.Equal(t, `foo`, str)

	str = fmt.Sprintf("%+v", err)
	assert.Equal(t, []string{
		"foo",
		"github.com/256dpi/fire/stick.F",
		"  /Users/256dpi/Development/GitHub/256dpi/fire/stick/error.go:LN",
		"github.com/256dpi/fire/stick.E",
		"  /Users/256dpi/Development/GitHub/256dpi/fire/stick/error.go:LN",
		"github.com/256dpi/fire/stick.TestE",
		"  /Users/256dpi/Development/GitHub/256dpi/fire/stick/error_test.go:LN",
		"testing.tRunner",
		"  /usr/local/Cellar/go/1.14.1/libexec/src/testing/testing.go:LN",
		"runtime.goexit",
		"  /usr/local/Cellar/go/1.14.1/libexec/src/runtime/asm_amd64.s:LN",
	}, splitTrace(str))

	/* wrapped */

	err = WF(err, "bar")
	assert.True(t, IsSafe(err))

	str = err.Error()
	assert.Equal(t, `bar: foo`, str)

	str = fmt.Sprintf("%s", err)
	assert.Equal(t, `bar: foo`, str)

	str = fmt.Sprintf("%v", err)
	assert.Equal(t, `bar: foo`, str)

	str = fmt.Sprintf("%+v", err)
	assert.Equal(t, []string{
		"foo",
		"github.com/256dpi/fire/stick.F",
		"  /Users/256dpi/Development/GitHub/256dpi/fire/stick/error.go:LN",
		"github.com/256dpi/fire/stick.E",
		"  /Users/256dpi/Development/GitHub/256dpi/fire/stick/error.go:LN",
		"github.com/256dpi/fire/stick.TestE",
		"  /Users/256dpi/Development/GitHub/256dpi/fire/stick/error_test.go:LN",
		"testing.tRunner",
		"  /usr/local/Cellar/go/1.14.1/libexec/src/testing/testing.go:LN",
		"runtime.goexit",
		"  /usr/local/Cellar/go/1.14.1/libexec/src/runtime/asm_amd64.s:LN",
		"bar",
		"github.com/256dpi/fire/stick.WF",
		"  /Users/256dpi/Development/GitHub/256dpi/fire/stick/error.go:LN",
		"github.com/256dpi/fire/stick.TestE",
		"  /Users/256dpi/Development/GitHub/256dpi/fire/stick/error_test.go:LN",
		"testing.tRunner",
		"  /usr/local/Cellar/go/1.14.1/libexec/src/testing/testing.go:LN",
		"runtime.goexit",
		"  /usr/local/Cellar/go/1.14.1/libexec/src/runtime/asm_amd64.s:LN",
	}, splitTrace(str))
}

func TestSafeError(t *testing.T) {
	err1 := F("foo")
	assert.False(t, IsSafe(err1))
	assert.Equal(t, "foo", err1.Error())
	assert.Nil(t, AsSafe(err1))

	err2 := Safe(err1)
	assert.True(t, IsSafe(err2))
	assert.Equal(t, "foo", err2.Error())
	assert.Equal(t, err2, AsSafe(err2))

	err3 := WF(err2, "bar")
	assert.True(t, IsSafe(err3))
	assert.Equal(t, "bar: foo", err3.Error())
	assert.Equal(t, err2, AsSafe(err3))
}

func splitTrace(str string) []string {
	str = strings.ReplaceAll(str, "\t", "  ")
	str = regexp.MustCompile(":\\d+").ReplaceAllString(str, ":LN")
	return strings.Split(str, "\n")
}
<commit_msg>fix test<commit_after>package stick

import (
	"fmt"
	"regexp"
	"strings"
	"testing"

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

func TestF(t *testing.T) {
	err := F("foo %d", 42)

	str := err.Error()
	assert.Equal(t, `foo 42`, str)

	str = fmt.Sprintf("%s", err)
	assert.Equal(t, `foo 42`, str)

	str = fmt.Sprintf("%v", err)
	assert.Equal(t, `foo 42`, str)

	str = fmt.Sprintf("%+v", err)
	assert.Equal(t, []string{
		"foo 42",
		"github.com/256dpi/fire/stick.F",
		"  /Users/256dpi/Development/GitHub/256dpi/fire/stick/errors.go:LN",
		"github.com/256dpi/fire/stick.TestF",
		"  /Users/256dpi/Development/GitHub/256dpi/fire/stick/errors_test.go:LN",
		"testing.tRunner",
		"  /usr/local/Cellar/go/1.14.1/libexec/src/testing/testing.go:LN",
		"runtime.goexit",
		"  /usr/local/Cellar/go/1.14.1/libexec/src/runtime/asm_amd64.s:LN",
	}, splitTrace(str))
}

func TestWF(t *testing.T) {
	err := F("foo")
	err = WF(err, "bar %d", 42)

	str := err.Error()
	assert.Equal(t, `bar 42: foo`, str)

	str = fmt.Sprintf("%s", err)
	assert.Equal(t, `bar 42: foo`, str)

	str = fmt.Sprintf("%v", err)
	assert.Equal(t, `bar 42: foo`, str)

	str = fmt.Sprintf("%+v", err)
	assert.Equal(t, []string{
		"foo",
		"github.com/256dpi/fire/stick.F",
		"  /Users/256dpi/Development/GitHub/256dpi/fire/stick/errors.go:LN",
		"github.com/256dpi/fire/stick.TestWF",
		"  /Users/256dpi/Development/GitHub/256dpi/fire/stick/errors_test.go:LN",
		"testing.tRunner",
		"  /usr/local/Cellar/go/1.14.1/libexec/src/testing/testing.go:LN",
		"runtime.goexit",
		"  /usr/local/Cellar/go/1.14.1/libexec/src/runtime/asm_amd64.s:LN",
		"bar 42",
		"github.com/256dpi/fire/stick.WF",
		"  /Users/256dpi/Development/GitHub/256dpi/fire/stick/errors.go:LN",
		"github.com/256dpi/fire/stick.TestWF",
		"  /Users/256dpi/Development/GitHub/256dpi/fire/stick/errors_test.go:LN",
		"testing.tRunner",
		"  /usr/local/Cellar/go/1.14.1/libexec/src/testing/testing.go:LN",
		"runtime.goexit",
		"  /usr/local/Cellar/go/1.14.1/libexec/src/runtime/asm_amd64.s:LN",
	}, splitTrace(str))
}

func TestE(t *testing.T) {
	err := E("foo")
	assert.True(t, IsSafe(err))

	str := err.Error()
	assert.Equal(t, `foo`, str)

	str = fmt.Sprintf("%s", err)
	assert.Equal(t, `foo`, str)

	str = fmt.Sprintf("%v", err)
	assert.Equal(t, `foo`, str)

	str = fmt.Sprintf("%+v", err)
	assert.Equal(t, []string{
		"foo",
		"github.com/256dpi/fire/stick.F",
		"  /Users/256dpi/Development/GitHub/256dpi/fire/stick/errors.go:LN",
		"github.com/256dpi/fire/stick.E",
		"  /Users/256dpi/Development/GitHub/256dpi/fire/stick/errors.go:LN",
		"github.com/256dpi/fire/stick.TestE",
		"  /Users/256dpi/Development/GitHub/256dpi/fire/stick/errors_test.go:LN",
		"testing.tRunner",
		"  /usr/local/Cellar/go/1.14.1/libexec/src/testing/testing.go:LN",
		"runtime.goexit",
		"  /usr/local/Cellar/go/1.14.1/libexec/src/runtime/asm_amd64.s:LN",
	}, splitTrace(str))

	/* wrapped */

	err = WF(err, "bar")
	assert.True(t, IsSafe(err))

	str = err.Error()
	assert.Equal(t, `bar: foo`, str)

	str = fmt.Sprintf("%s", err)
	assert.Equal(t, `bar: foo`, str)

	str = fmt.Sprintf("%v", err)
	assert.Equal(t, `bar: foo`, str)

	str = fmt.Sprintf("%+v", err)
	assert.Equal(t, []string{
		"foo",
		"github.com/256dpi/fire/stick.F",
		"  /Users/256dpi/Development/GitHub/256dpi/fire/stick/errors.go:LN",
		"github.com/256dpi/fire/stick.E",
		"  /Users/256dpi/Development/GitHub/256dpi/fire/stick/errors.go:LN",
		"github.com/256dpi/fire/stick.TestE",
		"  /Users/256dpi/Development/GitHub/256dpi/fire/stick/errors_test.go:LN",
		"testing.tRunner",
		"  /usr/local/Cellar/go/1.14.1/libexec/src/testing/testing.go:LN",
		"runtime.goexit",
		"  /usr/local/Cellar/go/1.14.1/libexec/src/runtime/asm_amd64.s:LN",
		"bar",
		"github.com/256dpi/fire/stick.WF",
		"  /Users/256dpi/Development/GitHub/256dpi/fire/stick/errors.go:LN",
		"github.com/256dpi/fire/stick.TestE",
		"  /Users/256dpi/Development/GitHub/256dpi/fire/stick/errors_test.go:LN",
		"testing.tRunner",
		"  /usr/local/Cellar/go/1.14.1/libexec/src/testing/testing.go:LN",
		"runtime.goexit",
		"  /usr/local/Cellar/go/1.14.1/libexec/src/runtime/asm_amd64.s:LN",
	}, splitTrace(str))
}

func TestSafeError(t *testing.T) {
	err1 := F("foo")
	assert.False(t, IsSafe(err1))
	assert.Equal(t, "foo", err1.Error())
	assert.Nil(t, AsSafe(err1))

	err2 := Safe(err1)
	assert.True(t, IsSafe(err2))
	assert.Equal(t, "foo", err2.Error())
	assert.Equal(t, err2, AsSafe(err2))

	err3 := WF(err2, "bar")
	assert.True(t, IsSafe(err3))
	assert.Equal(t, "bar: foo", err3.Error())
	assert.Equal(t, err2, AsSafe(err3))
}

func splitTrace(str string) []string {
	str = strings.ReplaceAll(str, "\t", "  ")
	str = regexp.MustCompile(":\\d+").ReplaceAllString(str, ":LN")
	return strings.Split(str, "\n")
}
<|endoftext|>