<commit_before>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"strconv"
	"strings"
	"text/tabwriter"

	"github.com/gonum/stat"
)

var noPercent = flag.Bool("nopercent", false, "don't use percentages, show the true value")

type benchResults struct {
	vals  []float64
	niter []float64
}

var benchVals = make(map[string]map[string]benchResults)

func main() {
	log.SetPrefix("benchsum: ")
	log.SetFlags(0)
	flag.Parse()
	if flag.NArg() == 0 {
		b, err := ioutil.ReadAll(os.Stdin)
		if err != nil {
			log.Fatal(err)
		}
		read(b)
	} else {
		for _, p := range flag.Args() {
			b, err := ioutil.ReadFile(p)
			if err != nil {
				log.Fatal(err)
			}
			read(b)
		}
	}

	w := tabwriter.NewWriter(os.Stdout, 8, 8, 1, ' ', 0)
	fmt.Fprint(w, "name\tmean\tstdev\tstat ...\n")
	for name, statmap := range benchVals {
		for st, results := range statmap {
			μ, σ := stat.MeanStdDev(results.vals, results.niter)
			if *noPercent {
				fmt.Fprintf(w, "%s\t%.2e\t±%.2e\t%s\n", name, μ, σ, st)
			} else {
				σPercent := 100 * σ / μ
				fmt.Fprintf(w, "%s\t%.2e\t±%.0f%%\t%s\n", name, μ, σPercent, st)
			}
		}
	}
	w.Flush()
}

func addVal(key, stat string, val, niter float64) {
	if benchVals[key] == nil {
		benchVals[key] = make(map[string]benchResults)
	}
	results := benchVals[key][stat]
	results.vals = append(results.vals, val)
	results.niter = append(results.niter, niter)
	benchVals[key][stat] = results
}

func read(data []byte) {
	for _, line := range strings.Split(string(data), "\n") {
		f := strings.Fields(line)
		if len(f) < 4 {
			continue
		}
		if !strings.HasPrefix(f[0], "Benchmark") {
			continue
		}
		name := strings.TrimPrefix(f[0], "Benchmark")
		niter, err := strconv.Atoi(f[1])
		if err != nil {
			continue
		}
		for i := 2; i+2 <= len(f); i += 2 {
			v, err := strconv.ParseFloat(f[i], 64)
			if err != nil {
				continue
			}
			addVal(name, f[i+1], v, float64(niter))
		}
	}
}
<commit_msg>perf/cmd/benchsum: sort resuts<commit_after>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"sort"
	"strconv"
	"strings"
	"text/tabwriter"

	"github.com/gonum/stat"
)

var noPercent = flag.Bool("nopercent", false, "don't use percentages, show the true value")

type benchResults struct {
	vals  []float64
	niter []float64
}

var benchVals = make(map[string]map[string]benchResults)

type statPair struct {
	stat    string
	results benchResults
}

type byStat []statPair

func (s byStat) Len() int           { return len(s) }
func (s byStat) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s byStat) Less(i, j int) bool { return s[i].stat < s[j].stat }

type benchValsPair struct {
	name  string
	stats []statPair
}

type byName []benchValsPair

func (s byName) Len() int           { return len(s) }
func (s byName) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s byName) Less(i, j int) bool { return s[i].name < s[j].name }

func main() {
	log.SetPrefix("benchsum: ")
	log.SetFlags(0)
	flag.Parse()
	if flag.NArg() == 0 {
		b, err := ioutil.ReadAll(os.Stdin)
		if err != nil {
			log.Fatal(err)
		}
		read(b)
	} else {
		for _, p := range flag.Args() {
			b, err := ioutil.ReadFile(p)
			if err != nil {
				log.Fatal(err)
			}
			read(b)
		}
	}

	w := tabwriter.NewWriter(os.Stdout, 8, 8, 1, ' ', 0)
	fmt.Fprint(w, "name\tmean\tstdev\tstat ...\n")
	var allVals []benchValsPair
	for name, statmap := range benchVals {
		var stats []statPair
		for st, results := range statmap {
			stats = append(stats, statPair{stat: st, results: results})
		}
		sort.Sort(byStat(stats))
		allVals = append(allVals, benchValsPair{name: name, stats: stats})
	}
	sort.Sort(byName(allVals))
	for _, p := range allVals {
		name := p.name
		for _, p2 := range p.stats {
			st := p2.stat
			results := p2.results
			μ, σ := stat.MeanStdDev(results.vals, results.niter)
			if *noPercent {
				fmt.Fprintf(w, "%s\t%.2e\t±%.2e\t%s\n", name, μ, σ, st)
			} else {
				σPercent := 100 * σ / μ
				fmt.Fprintf(w, "%s\t%.2e\t±%.0f%%\t%s\n", name, μ, σPercent, st)
			}
		}
	}
	w.Flush()
}

func addVal(key, stat string, val, niter float64) {
	if benchVals[key] == nil {
		benchVals[key] = make(map[string]benchResults)
	}
	results := benchVals[key][stat]
	results.vals = append(results.vals, val)
	results.niter = append(results.niter, niter)
	benchVals[key][stat] = results
}

func read(data []byte) {
	for _, line := range strings.Split(string(data), "\n") {
		f := strings.Fields(line)
		if len(f) < 4 {
			continue
		}
		if !strings.HasPrefix(f[0], "Benchmark") {
			continue
		}
		name := strings.TrimPrefix(f[0], "Benchmark")
		niter, err := strconv.Atoi(f[1])
		if err != nil {
			continue
		}
		for i := 2; i+2 <= len(f); i += 2 {
			v, err := strconv.ParseFloat(f[i], 64)
			if err != nil {
				continue
			}
			addVal(name, f[i+1], v, float64(niter))
		}
	}
}
<|endoftext|>


<commit_before>// Package docker provides a Pipe that creates and pushes a Docker image
package docker

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"text/template"

	"github.com/apex/log"
	"github.com/pkg/errors"
	"golang.org/x/sync/errgroup"

	"github.com/goreleaser/goreleaser/config"
	"github.com/goreleaser/goreleaser/context"
	"github.com/goreleaser/goreleaser/internal/artifact"
	"github.com/goreleaser/goreleaser/pipeline"
)

// ErrNoDocker is shown when docker cannot be found in $PATH
var ErrNoDocker = errors.New("docker not present in $PATH")

// Pipe for docker
type Pipe struct{}

func (Pipe) String() string {
	return "creating Docker images"
}

// Default sets the pipe defaults
func (Pipe) Default(ctx *context.Context) error {
	for i := range ctx.Config.Dockers {
		var docker = &ctx.Config.Dockers[i]
		if docker.OldTagTemplate != "" {
			// TODO: deprecate docker.tag_template in favor of docker.tag_templates
			docker.TagTemplates = append(docker.TagTemplates, docker.OldTagTemplate)
		}
		if len(docker.TagTemplates) == 0 {
			docker.TagTemplates = append(docker.TagTemplates, "{{ .Version }}")
		}
		if docker.Goos == "" {
			docker.Goos = "linux"
		}
		if docker.Goarch == "" {
			docker.Goarch = "amd64"
		}
		if docker.Latest {
			// TODO: deprecate docker.Latest in favor of multiple tags?
			docker.TagTemplates = append(docker.TagTemplates, "latest")
		}
	}
	// only set defaults if there is exacly 1 docker setup in the config file.
	if len(ctx.Config.Dockers) != 1 {
		return nil
	}
	if ctx.Config.Dockers[0].Binary == "" {
		ctx.Config.Dockers[0].Binary = ctx.Config.Builds[0].Binary
	}
	if ctx.Config.Dockers[0].Dockerfile == "" {
		ctx.Config.Dockers[0].Dockerfile = "Dockerfile"
	}
	return nil
}

// Run the pipe
func (Pipe) Run(ctx *context.Context) error {
	if len(ctx.Config.Dockers) == 0 || ctx.Config.Dockers[0].Image == "" {
		return pipeline.Skip("docker section is not configured")
	}
	_, err := exec.LookPath("docker")
	if err != nil {
		return ErrNoDocker
	}
	return doRun(ctx)
}

func doRun(ctx *context.Context) error {
	var g errgroup.Group
	sem := make(chan bool, ctx.Parallelism)
	for _, docker := range ctx.Config.Dockers {
		docker := docker
		sem <- true
		g.Go(func() error {
			defer func() {
				<-sem
			}()
			log.WithField("docker", docker).Debug("looking for binaries matching")
			var binaries = ctx.Artifacts.Filter(
				artifact.And(
					artifact.ByGoos(docker.Goos),
					artifact.ByGoarch(docker.Goarch),
					artifact.ByGoarm(docker.Goarm),
					artifact.ByType(artifact.Binary),
					func(a artifact.Artifact) bool {
						return a.Extra["Binary"] == docker.Binary
					},
				),
			).List()
			if len(binaries) == 0 {
				log.Warnf("no binaries found for %s", docker.Binary)
			}
			for _, binary := range binaries {
				if err := process(ctx, docker, binary); err != nil {
					return err
				}
			}
			return nil
		})
	}
	return g.Wait()
}

func tagName(ctx *context.Context, tagTemplate string) (string, error) {
	var out bytes.Buffer
	t, err := template.New("tag").Option("missingkey=error").Parse(tagTemplate)
	if err != nil {
		return "", err
	}
	data := struct {
		Version, Tag string
		Env          map[string]string
	}{
		Version: ctx.Version,
		Tag:     ctx.Git.CurrentTag,
		Env:     ctx.Env,
	}
	err = t.Execute(&out, data)
	return out.String(), err
}

func process(ctx *context.Context, docker config.Docker, artifact artifact.Artifact) error {
	var root = filepath.Dir(artifact.Path)
	var dockerfile = filepath.Join(root, filepath.Base(docker.Dockerfile))
	var images []string
	for _, tagTemplate := range docker.TagTemplates {
		tag, err := tagName(ctx, tagTemplate)
		if err != nil {
			return errors.Wrapf(err, "failed to execute tag template '%s'", tagTemplate)
		}
		images = append(images, fmt.Sprintf("%s:%s", docker.Image, tag))
	}
	if err := os.Link(docker.Dockerfile, dockerfile); err != nil {
		return errors.Wrap(err, "failed to link dockerfile")
	}
	for _, file := range docker.Files {
		if err := link(file, filepath.Join(root, filepath.Base(file))); err != nil {
			return errors.Wrapf(err, "failed to link extra file '%s'", file)
		}
	}
	if err := dockerBuild(ctx, root, dockerfile, images[0]); err != nil {
		return err
	}
	for _, img := range images[1:] {
		if err := dockerTag(ctx, images[0], img); err != nil {
			return err
		}
	}
	return publish(ctx, docker, images)
}

// walks the src, recreating dirs and hard-linking files
func link(src, dest string) error {
	return filepath.Walk(src, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		// We have the following:
		// - src = "a/b"
		// - dest = "dist/linuxamd64/b"
		// - path = "a/b/c.txt"
		// So we join "a/b" with "c.txt" and use it as the destination.
		var dst = filepath.Join(dest, strings.Replace(path, src, "", 1))
		log.WithFields(log.Fields{
			"src": path,
			"dst": dst,
		}).Info("extra file")
		if info.IsDir() {
			return os.MkdirAll(dst, info.Mode())
		}
		return os.Link(path, dst)
	})
}

func publish(ctx *context.Context, docker config.Docker, images []string) error {
	if !ctx.Publish {
		log.Warn("skipping push because --skip-publish is set")
		return nil
	}
	for _, image := range images {
		if err := dockerPush(ctx, docker, image); err != nil {
			return err
		}
	}
	return nil
}

func dockerBuild(ctx *context.Context, root, dockerfile, image string) error {
	log.WithField("image", image).Info("building docker image")
	/* #nosec */
	var cmd = exec.CommandContext(ctx, "docker", "build", "-f", dockerfile, "-t", image, root)
	log.WithField("cmd", cmd).Debug("executing")
	out, err := cmd.CombinedOutput()
	if err != nil {
		return errors.Wrapf(err, "failed to build docker image: \n%s", string(out))
	}
	log.Debugf("docker build output: \n%s", string(out))
	return nil
}

func dockerTag(ctx *context.Context, image, tag string) error {
	log.WithField("image", image).WithField("tag", tag).Info("tagging docker image")
	/* #nosec */
	var cmd = exec.CommandContext(ctx, "docker", "tag", image, tag)
	log.WithField("cmd", cmd).Debug("executing")
	out, err := cmd.CombinedOutput()
	if err != nil {
		return errors.Wrapf(err, "failed to tag docker image: \n%s", string(out))
	}
	log.Debugf("docker tag output: \n%s", string(out))
	return nil
}

func dockerPush(ctx *context.Context, docker config.Docker, image string) error {
	log.WithField("image", image).Info("pushing docker image")
	/* #nosec */
	var cmd = exec.CommandContext(ctx, "docker", "push", image)
	log.WithField("cmd", cmd).Debug("executing")
	out, err := cmd.CombinedOutput()
	if err != nil {
		return errors.Wrapf(err, "failed to push docker image: \n%s", string(out))
	}
	log.Debugf("docker push output: \n%s", string(out))
	ctx.Artifacts.Add(artifact.Artifact{
		Type:   artifact.DockerImage,
		Name:   image,
		Path:   image,
		Goarch: docker.Goarch,
		Goos:   docker.Goos,
		Goarm:  docker.Goarm,
	})
	return nil
}
<commit_msg>feat: added deprecation warnings<commit_after>// Package docker provides a Pipe that creates and pushes a Docker image
package docker

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"text/template"

	"github.com/apex/log"
	"github.com/fatih/color"
	"github.com/pkg/errors"
	"golang.org/x/sync/errgroup"

	"github.com/goreleaser/goreleaser/config"
	"github.com/goreleaser/goreleaser/context"
	"github.com/goreleaser/goreleaser/internal/artifact"
	"github.com/goreleaser/goreleaser/pipeline"
)

// ErrNoDocker is shown when docker cannot be found in $PATH
var ErrNoDocker = errors.New("docker not present in $PATH")

// Pipe for docker
type Pipe struct{}

func (Pipe) String() string {
	return "creating Docker images"
}

// Default sets the pipe defaults
func (Pipe) Default(ctx *context.Context) error {
	var deprecate = color.New(color.Bold, color.FgHiYellow)
	for i := range ctx.Config.Dockers {
		var docker = &ctx.Config.Dockers[i]
		if docker.OldTagTemplate != "" {
			log.Warn(deprecate.Sprintf("`dockers[%d].tag_template` is deprecated. Please consider using `dockers[%d].tag_templates` instead", i, i))
			docker.TagTemplates = append(docker.TagTemplates, docker.OldTagTemplate)
		}
		if len(docker.TagTemplates) == 0 {
			docker.TagTemplates = append(docker.TagTemplates, "{{ .Version }}")
		}
		if docker.Goos == "" {
			docker.Goos = "linux"
		}
		if docker.Goarch == "" {
			docker.Goarch = "amd64"
		}
		if docker.Latest {
			log.Warn(deprecate.Sprintf("`dockers[%d].latest` is deprecated. Please consider adding a `latest` tag to the `dockers[%d].tag_templates` list instead", i, i))
			docker.TagTemplates = append(docker.TagTemplates, "latest")
		}
	}
	// only set defaults if there is exacly 1 docker setup in the config file.
	if len(ctx.Config.Dockers) != 1 {
		return nil
	}
	if ctx.Config.Dockers[0].Binary == "" {
		ctx.Config.Dockers[0].Binary = ctx.Config.Builds[0].Binary
	}
	if ctx.Config.Dockers[0].Dockerfile == "" {
		ctx.Config.Dockers[0].Dockerfile = "Dockerfile"
	}
	return nil
}

// Run the pipe
func (Pipe) Run(ctx *context.Context) error {
	if len(ctx.Config.Dockers) == 0 || ctx.Config.Dockers[0].Image == "" {
		return pipeline.Skip("docker section is not configured")
	}
	_, err := exec.LookPath("docker")
	if err != nil {
		return ErrNoDocker
	}
	return doRun(ctx)
}

func doRun(ctx *context.Context) error {
	var g errgroup.Group
	sem := make(chan bool, ctx.Parallelism)
	for _, docker := range ctx.Config.Dockers {
		docker := docker
		sem <- true
		g.Go(func() error {
			defer func() {
				<-sem
			}()
			log.WithField("docker", docker).Debug("looking for binaries matching")
			var binaries = ctx.Artifacts.Filter(
				artifact.And(
					artifact.ByGoos(docker.Goos),
					artifact.ByGoarch(docker.Goarch),
					artifact.ByGoarm(docker.Goarm),
					artifact.ByType(artifact.Binary),
					func(a artifact.Artifact) bool {
						return a.Extra["Binary"] == docker.Binary
					},
				),
			).List()
			if len(binaries) == 0 {
				log.Warnf("no binaries found for %s", docker.Binary)
			}
			for _, binary := range binaries {
				if err := process(ctx, docker, binary); err != nil {
					return err
				}
			}
			return nil
		})
	}
	return g.Wait()
}

func tagName(ctx *context.Context, tagTemplate string) (string, error) {
	var out bytes.Buffer
	t, err := template.New("tag").Option("missingkey=error").Parse(tagTemplate)
	if err != nil {
		return "", err
	}
	data := struct {
		Version, Tag string
		Env          map[string]string
	}{
		Version: ctx.Version,
		Tag:     ctx.Git.CurrentTag,
		Env:     ctx.Env,
	}
	err = t.Execute(&out, data)
	return out.String(), err
}

func process(ctx *context.Context, docker config.Docker, artifact artifact.Artifact) error {
	var root = filepath.Dir(artifact.Path)
	var dockerfile = filepath.Join(root, filepath.Base(docker.Dockerfile))
	var images []string
	for _, tagTemplate := range docker.TagTemplates {
		tag, err := tagName(ctx, tagTemplate)
		if err != nil {
			return errors.Wrapf(err, "failed to execute tag template '%s'", tagTemplate)
		}
		images = append(images, fmt.Sprintf("%s:%s", docker.Image, tag))
	}
	if err := os.Link(docker.Dockerfile, dockerfile); err != nil {
		return errors.Wrap(err, "failed to link dockerfile")
	}
	for _, file := range docker.Files {
		if err := link(file, filepath.Join(root, filepath.Base(file))); err != nil {
			return errors.Wrapf(err, "failed to link extra file '%s'", file)
		}
	}
	if err := dockerBuild(ctx, root, dockerfile, images[0]); err != nil {
		return err
	}
	for _, img := range images[1:] {
		if err := dockerTag(ctx, images[0], img); err != nil {
			return err
		}
	}
	return publish(ctx, docker, images)
}

// walks the src, recreating dirs and hard-linking files
func link(src, dest string) error {
	return filepath.Walk(src, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		// We have the following:
		// - src = "a/b"
		// - dest = "dist/linuxamd64/b"
		// - path = "a/b/c.txt"
		// So we join "a/b" with "c.txt" and use it as the destination.
		var dst = filepath.Join(dest, strings.Replace(path, src, "", 1))
		log.WithFields(log.Fields{
			"src": path,
			"dst": dst,
		}).Info("extra file")
		if info.IsDir() {
			return os.MkdirAll(dst, info.Mode())
		}
		return os.Link(path, dst)
	})
}

func publish(ctx *context.Context, docker config.Docker, images []string) error {
	if !ctx.Publish {
		log.Warn("skipping push because --skip-publish is set")
		return nil
	}
	for _, image := range images {
		if err := dockerPush(ctx, docker, image); err != nil {
			return err
		}
	}
	return nil
}

func dockerBuild(ctx *context.Context, root, dockerfile, image string) error {
	log.WithField("image", image).Info("building docker image")
	/* #nosec */
	var cmd = exec.CommandContext(ctx, "docker", "build", "-f", dockerfile, "-t", image, root)
	log.WithField("cmd", cmd).Debug("executing")
	out, err := cmd.CombinedOutput()
	if err != nil {
		return errors.Wrapf(err, "failed to build docker image: \n%s", string(out))
	}
	log.Debugf("docker build output: \n%s", string(out))
	return nil
}

func dockerTag(ctx *context.Context, image, tag string) error {
	log.WithField("image", image).WithField("tag", tag).Info("tagging docker image")
	/* #nosec */
	var cmd = exec.CommandContext(ctx, "docker", "tag", image, tag)
	log.WithField("cmd", cmd).Debug("executing")
	out, err := cmd.CombinedOutput()
	if err != nil {
		return errors.Wrapf(err, "failed to tag docker image: \n%s", string(out))
	}
	log.Debugf("docker tag output: \n%s", string(out))
	return nil
}

func dockerPush(ctx *context.Context, docker config.Docker, image string) error {
	log.WithField("image", image).Info("pushing docker image")
	/* #nosec */
	var cmd = exec.CommandContext(ctx, "docker", "push", image)
	log.WithField("cmd", cmd).Debug("executing")
	out, err := cmd.CombinedOutput()
	if err != nil {
		return errors.Wrapf(err, "failed to push docker image: \n%s", string(out))
	}
	log.Debugf("docker push output: \n%s", string(out))
	ctx.Artifacts.Add(artifact.Artifact{
		Type:   artifact.DockerImage,
		Name:   image,
		Path:   image,
		Goarch: docker.Goarch,
		Goos:   docker.Goos,
		Goarm:  docker.Goarm,
	})
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"testing"
	"time"
)

const (
	LED      = 5  // Pin 29
	RELAY    = 13 // Pin 33
	CAP4700  = 19 // Pin 35: Also PCM capable
	CAP10000 = 6  // Pin 31
	SWITCH   = 26 // Pin 37
)

func GpioStr(g PiPin) string {
	switch g.Pin() {
	case LED:
		return "LED"
	case RELAY:
		return "RELAY"
	case CAP4700:
		return "CAP4700"
	case CAP10000:
		return "CAP10000"
	case SWITCH:
		return "SWITCH"
	default:
		return "UNKNOWN"
	}
	return ""
}

var Led PiPin        // Setup: GPIO -> <1k Resistor -> LED -> GND
var TestRelay *Relay // Setup GPIO -> 4.7k Resistor -> Relay Board
var Cap4700 PiPin    // Setup: +3.3v -> 4.7k Resistor -> GPIO -> 10uF capacitor -> GND
var Cap10000 PiPin   // Setup: +3.3v -> 10k Resistor -> GPIO -> 10uF capacitor -> GND
var Switch PiPin     // Setup: GPIO -> Button Switch -> GND

func ExpectedState(t *testing.T, gpio PiPin, exp GpioState) {
	if val := gpio.Read(); val != exp {
		t.Errorf("%s: Expected %s but found %s", GpioStr(gpio), exp, val)
	}
}

func TestInitilization(t *testing.T) {
	err := GpioInit()
	t.Run("Init Host", func(t *testing.T) {
		if err != nil {
			t.Errorf("Problem initializing gpio: %s", err.Error())
		}
	})

	// Initialized GPIOs
	Led = NewGpio(LED)
	ExpectedState(t, Led, Low)
}

func TestBlinkLed(t *testing.T) {
	Info("Running %s", t.Name())
	for i := 0; i < 6; i++ {
		time.Sleep(time.Second / 5)
		Led.Output(High)
		ExpectedState(t, Led, High)
		time.Sleep(time.Second / 5)
		Led.Output(Low)
		ExpectedState(t, Led, Low)
	}
}

func doStop(button *Button, b *bool, t time.Time) {
	*b = false
	button.Stop()
	*b = true
	Info("doStop - Stopped after %d ms", time.Now().Sub(t)/time.Millisecond)
}

func runRelayTestOn(t *testing.T, relay *Relay) {
	relay.TurnOn()
	Info("Testing Relay On: %s is %s", relay.Name(), relay.Status())
	if !relay.isOn() {
		t.Errorf("Relay(%s) is %s", relay.Name(), relay.Status())
	}
}

func runRelayTestOff(t *testing.T, relay *Relay) {
	relay.TurnOff()
	Info("Testing Relay Off: %s is %s", relay.Name(), relay.Status())
	if relay.isOn() {
		t.Errorf("Relay(%s) is %s", relay.Name(), relay.Status())
	}
}

func runRelayTest(t *testing.T, r *Relay, sleep time.Duration) {
	t.Run(fmt.Sprintf("%s.Test", r.Name()), func(t *testing.T) {
		Info("Running %s", t.Name())
		runRelayTestOn(t, r)
		time.Sleep(sleep)
		runRelayTestOff(t, r)
	})
}

func TestRelays(t *testing.T) {
	Info("Running %s", t.Name())
	TestRelay = NewRelay(RELAY, "Relay", "Testing")
	runRelayTest(t, TestRelay, time.Second)
}

func discharge_us(t *GpioThermometer, e Edge, p Pull) time.Duration {
	t.mutex.Lock()
	defer t.mutex.Unlock()

	//Discharge the capacitor (low temps could make this really long)
	t.pin.Output(Low)
	time.Sleep(300 * time.Millisecond)

	// Start polling
	start := time.Now()
	t.pin.InputEdge(p, e)
	if !t.pin.WaitForEdge(time.Second / 2) {
		Trace("Thermometer %s, Rising read timed out", t.Name())
		return 0.0
	}
	stop := time.Now()
	t.pin.Output(Low)
	return stop.Sub(start)
}

func TestDischargeStrategies(t *testing.T) {
	Info("Running %s", t.Name())
	therm := NewGpioThermometer("Fixed 4.7kOhm ResistorTest", "TestManufacturer", CAP4700)
	pulls := []Pull{PullDown, PullUp, Float}
	edges := []Edge{RisingEdge, FallingEdge, BothEdges}
	expected := 4700 * therm.microfarads
	for _, p := range pulls {
		for _, e := range edges {
			h := NewHistory(10)
			for i := 0; i < 10; i++ {
				dt := discharge_us(therm, e, p)
				Info("DischargeTime %f us,  %f k-ohms", us(dt), therm.getOhms(dt))
				h.Push(us(dt))
			}
			Info("Strategy(%s, %s): Expected %0.3fus %0.3fus stddev=%0.4f pct=%0.2f",
				p, e, expected, h.Average(), h.Stddev(), 100.0*h.Stddev()/h.Average())
		}
	}
}

func TestThermometer(t *testing.T) {
	t.Skip("Skipping TestThermometer until it is fixed")
	Info("Running %s", t.Name())
	therm := NewGpioThermometer("Fixed 4.7kOhm ResistorTest", "TestManufacturer", CAP4700)

	t.Run("Calibrate Cap4700", func(t *testing.T) {
		Info("Running %s", t.Name())
		c, err := therm.Calibrate(4700)
		if err != nil {
			t.Errorf("Failure to Calibrate successfully: %s", err.Error())
		}
		Debug("Setting calibration for %0.3f", c)
		therm.SetAdjustment(c)
	})
	t.Run("Temperature Cap4700", func(t *testing.T) {
		Info("Running %s", t.Name())
		err := therm.Update()
		if err != nil {
			t.Errorf("Thermometer update failed: %s", err.Error())
		}
		if therm.Temperature() > 44.1 || therm.Temperature() < 43.1 {
			t.Errorf("Thermometer value off: %0.1f, expected 43.6",
				therm.Temperature())
		}
	})

	therm = NewGpioThermometer("Fixed 10kOhm ResistorTest", "TestManufacturer", CAP10000)
	t.Run("Calibrate Cap10000", func(t *testing.T) {
		Info("Running %s", t.Name())
		c, err := therm.Calibrate(10000)
		if err != nil {
			t.Errorf("Failure to Calibrate successfully: %s", err.Error())
		}
		Debug("Setting calibration for %0.3f", c)
		therm.SetAdjustment(c)
	})
	t.Run("Temperature Cap4700", func(t *testing.T) {
		Info("Running %s", t.Name())
		err := therm.Update()
		if err != nil {
			t.Errorf("Thermometer update failed: %s", err.Error())
		}
		if therm.Temperature() > 25.4 || therm.Temperature() < 24.4 {
			t.Errorf("Thermometer value off: %0.1f, expected 24.9",
				therm.Temperature())
		}
	})
}

func TestPushButton(t *testing.T) {
	Info("Running %s", t.Name())
	wasRun := 0
	button := NewGpioButton(SWITCH, func() {
		wasRun++
		Info("Button Pushed %d!!!", wasRun)
	})

	Info("Starting button test, push it 3 times!")
	button.Start()
	for i := 0; i < 3; i++ {
		TestRelay.TurnOn()
		time.Sleep(time.Second / 3)
		TestRelay.TurnOff()
		time.Sleep(2 * time.Second)
	}
	if wasRun < 3 {
		t.Errorf("Expected 3 button pushes")
	}
	Info("Stopping button job")
	exited := false
	go doStop(button, &exited, time.Now())
	time.Sleep(time.Second)
	if !exited {
		t.Errorf("Button loop should have stopped within time allotted")
	}
	Info("Button job stopped")
}
<commit_msg>test sync<commit_after>package main

import (
	"fmt"
	"testing"
	"time"
)

const (
	LED      = 5  // Pin 29
	RELAY    = 13 // Pin 33
	CAP4700  = 19 // Pin 35: Also PCM capable
	CAP10000 = 6  // Pin 31
	SWITCH   = 26 // Pin 37
)

func GpioStr(g PiPin) string {
	switch g.Pin() {
	case LED:
		return "LED"
	case RELAY:
		return "RELAY"
	case CAP4700:
		return "CAP4700"
	case CAP10000:
		return "CAP10000"
	case SWITCH:
		return "SWITCH"
	default:
		return "UNKNOWN"
	}
	return ""
}

var Led PiPin        // Setup: GPIO -> <1k Resistor -> LED -> GND
var TestRelay *Relay // Setup GPIO -> 4.7k Resistor -> Relay Board
var Cap4700 PiPin    // Setup: +3.3v -> 4.7k Resistor -> GPIO -> 10uF capacitor -> GND
var Cap10000 PiPin   // Setup: +3.3v -> 10k Resistor -> GPIO -> 10uF capacitor -> GND
var Switch PiPin     // Setup: GPIO -> Button Switch -> GND

func ExpectedState(t *testing.T, gpio PiPin, exp GpioState) {
	if val := gpio.Read(); val != exp {
		t.Errorf("%s: Expected %s but found %s", GpioStr(gpio), exp, val)
	}
}

func TestInitilization(t *testing.T) {
	err := GpioInit()
	t.Run("Init Host", func(t *testing.T) {
		if err != nil {
			t.Errorf("Problem initializing gpio: %s", err.Error())
		}
	})

	// Initialized GPIOs
	Led = NewGpio(LED)
	ExpectedState(t, Led, Low)
}

func TestBlinkLed(t *testing.T) {
	Info("Running %s", t.Name())
	for i := 0; i < 6; i++ {
		time.Sleep(time.Second / 5)
		Led.Output(High)
		ExpectedState(t, Led, High)
		time.Sleep(time.Second / 5)
		Led.Output(Low)
		ExpectedState(t, Led, Low)
	}
}

func doStop(button *Button, b *bool, t time.Time) {
	*b = false
	button.Stop()
	*b = true
	Info("doStop - Stopped after %d ms", time.Now().Sub(t)/time.Millisecond)
}

func runRelayTestOn(t *testing.T, relay *Relay) {
	relay.TurnOn()
	Info("Testing Relay On: %s is %s", relay.Name(), relay.Status())
	if !relay.isOn() {
		t.Errorf("Relay(%s) is %s", relay.Name(), relay.Status())
	}
}

func runRelayTestOff(t *testing.T, relay *Relay) {
	relay.TurnOff()
	Info("Testing Relay Off: %s is %s", relay.Name(), relay.Status())
	if relay.isOn() {
		t.Errorf("Relay(%s) is %s", relay.Name(), relay.Status())
	}
}

func runRelayTest(t *testing.T, r *Relay, sleep time.Duration) {
	t.Run(fmt.Sprintf("%s.Test", r.Name()), func(t *testing.T) {
		Info("Running %s", t.Name())
		runRelayTestOn(t, r)
		time.Sleep(sleep)
		runRelayTestOff(t, r)
	})
}

func TestRelays(t *testing.T) {
	Info("Running %s", t.Name())
	TestRelay = NewRelay(RELAY, "Relay", "Testing")
	runRelayTest(t, TestRelay, time.Second)
}

func discharge_us(t *GpioThermometer, e Edge, p Pull) time.Duration {
	t.mutex.Lock()
	defer t.mutex.Unlock()

	//Discharge the capacitor (low temps could make this really long)
	t.pin.Output(Low)
	time.Sleep(300 * time.Millisecond)

	// Start polling
	start := time.Now()
	t.pin.InputEdge(p, e)
	if !t.pin.WaitForEdge(time.Second / 2) {
		Trace("Thermometer %s, Rising read timed out", t.Name())
		return 0.0
	}
	stop := time.Now()
	t.pin.Output(Low)
	return stop.Sub(start)
}

func TestDischargeStrategies(t *testing.T) {
	Info("Running %s", t.Name())
	therm := NewGpioThermometer("Fixed 4.7kOhm ResistorTest", "TestManufacturer", CAP4700)
	pulls := []Pull{PullDown, PullUp, Float}
	edges := []Edge{RisingEdge, FallingEdge, BothEdges}
	expected := 4700 * therm.microfarads
	for _, p := range pulls {
		for _, e := range edges {
			h := NewHistory(10)
			for i := 0; i < 10; i++ {
				dt := discharge_us(therm, e, p)
				//Info("DischargeTime %f us,  %f k-ohms", us(dt), therm.getOhms(dt))
				h.Push(us(dt))
			}
			Info("Strategy(%s, %s): Expected %0.3fus %0.3fus stddev=%0.4f pct=%0.2f",
				p, e, expected, h.Average(), h.Stddev(), 100.0*h.Stddev()/h.Average())
		}
	}
}

func TestThermometer(t *testing.T) {
	t.Skip("Skipping TestThermometer until it is fixed")
	Info("Running %s", t.Name())
	therm := NewGpioThermometer("Fixed 4.7kOhm ResistorTest", "TestManufacturer", CAP4700)

	t.Run("Calibrate Cap4700", func(t *testing.T) {
		Info("Running %s", t.Name())
		c, err := therm.Calibrate(4700)
		if err != nil {
			t.Errorf("Failure to Calibrate successfully: %s", err.Error())
		}
		Debug("Setting calibration for %0.3f", c)
		therm.SetAdjustment(c)
	})
	t.Run("Temperature Cap4700", func(t *testing.T) {
		Info("Running %s", t.Name())
		err := therm.Update()
		if err != nil {
			t.Errorf("Thermometer update failed: %s", err.Error())
		}
		if therm.Temperature() > 44.1 || therm.Temperature() < 43.1 {
			t.Errorf("Thermometer value off: %0.1f, expected 43.6",
				therm.Temperature())
		}
	})

	therm = NewGpioThermometer("Fixed 10kOhm ResistorTest", "TestManufacturer", CAP10000)
	t.Run("Calibrate Cap10000", func(t *testing.T) {
		Info("Running %s", t.Name())
		c, err := therm.Calibrate(10000)
		if err != nil {
			t.Errorf("Failure to Calibrate successfully: %s", err.Error())
		}
		Debug("Setting calibration for %0.3f", c)
		therm.SetAdjustment(c)
	})
	t.Run("Temperature Cap4700", func(t *testing.T) {
		Info("Running %s", t.Name())
		err := therm.Update()
		if err != nil {
			t.Errorf("Thermometer update failed: %s", err.Error())
		}
		if therm.Temperature() > 25.4 || therm.Temperature() < 24.4 {
			t.Errorf("Thermometer value off: %0.1f, expected 24.9",
				therm.Temperature())
		}
	})
}

func TestPushButton(t *testing.T) {
	Info("Running %s", t.Name())
	wasRun := 0
	button := NewGpioButton(SWITCH, func() {
		wasRun++
		Info("Button Pushed %d!!!", wasRun)
	})

	Info("Starting button test, push it 3 times!")
	button.Start()
	for i := 0; i < 3; i++ {
		TestRelay.TurnOn()
		time.Sleep(time.Second / 3)
		TestRelay.TurnOff()
		time.Sleep(2 * time.Second)
	}
	if wasRun < 3 {
		t.Errorf("Expected 3 button pushes")
	}
	Info("Stopping button job")
	exited := false
	go doStop(button, &exited, time.Now())
	time.Sleep(time.Second)
	if !exited {
		t.Errorf("Button loop should have stopped within time allotted")
	}
	Info("Button job stopped")
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"testing"
	"time"
)

const (
	LED      = 5  // Pin 29
	RELAY    = 13 // Pin 33
	CAP4700  = 19 // Pin 35: Also PCM capable
	CAP10000 = 6  // Pin 31
	SWITCH   = 26 // Pin 37
)

func GpioStr(g PiPin) string {
	switch g.Pin() {
	case LED:
		return "LED"
	case RELAY:
		return "RELAY"
	case CAP4700:
		return "CAP4700"
	case CAP10000:
		return "CAP10000"
	case SWITCH:
		return "SWITCH"
	default:
		return "UNKNOWN"
	}
	return ""
}

var Led PiPin        // Setup: GPIO -> <1k Resistor -> LED -> GND
var TestRelay *Relay // Setup GPIO -> 4.7k Resistor -> Relay Board
var Cap4700 PiPin    // Setup: +3.3v -> 4.7k Resistor -> GPIO -> 10uF capacitor -> GND
var Cap10000 PiPin   // Setup: +3.3v -> 10k Resistor -> GPIO -> 10uF capacitor -> GND
var Switch PiPin     // Setup: GPIO -> Button Switch -> GND

func ExpectedState(t *testing.T, gpio PiPin, exp GpioState) {
	if val := gpio.Read(); val != exp {
		t.Errorf("%s: Expected %s but found %s", GpioStr(gpio), exp, val)
	}
}

func TestInitilization(t *testing.T) {
	err := GpioInit()
	t.Run("Init Host", func(t *testing.T) {
		if err != nil {
			t.Errorf("Problem initializing gpio: %s", err.Error())
		}
	})

	// Initialized GPIOs
	Led = NewGpio(LED)
	ExpectedState(t, Led, Low)
}

func TestBlinkLed(t *testing.T) {
	Info("Running %s", t.Name())
	for i := 0; i < 6; i++ {
		time.Sleep(time.Second / 5)
		Led.Output(High)
		ExpectedState(t, Led, High)
		time.Sleep(time.Second / 5)
		Led.Output(Low)
		ExpectedState(t, Led, Low)
	}
}

func doStop(button *Button, b *bool, t time.Time) {
	*b = false
	button.Stop()
	*b = true
	Info("doStop - Stopped after %d ms", time.Now().Sub(t)/time.Millisecond)
}

func runRelayTestOn(t *testing.T, relay *Relay) {
	relay.TurnOn()
	Info("Testing Relay On: %s is %s", relay.Name(), relay.Status())
	if !relay.isOn() {
		t.Errorf("Relay(%s) is %s", relay.Name(), relay.Status())
	}
}

func runRelayTestOff(t *testing.T, relay *Relay) {
	relay.TurnOff()
	Info("Testing Relay Off: %s is %s", relay.Name(), relay.Status())
	if relay.isOn() {
		t.Errorf("Relay(%s) is %s", relay.Name(), relay.Status())
	}
}

func runRelayTest(t *testing.T, r *Relay, sleep time.Duration) {
	t.Run(fmt.Sprintf("%s.Test", r.Name()), func(t *testing.T) {
		Info("Running %s", t.Name())
		runRelayTestOn(t, r)
		time.Sleep(sleep)
		runRelayTestOff(t, r)
	})
}

func TestRelays(t *testing.T) {
	Info("Running %s", t.Name())
	TestRelay = NewRelay(RELAY, "Relay", "Testing")
	runRelayTest(t, TestRelay, time.Second)
}

func discharge_us(t *GpioThermometer, e Edge, p Pull) time.Duration {
	t.mutex.Lock()
	defer t.mutex.Unlock()

	//Discharge the capacitor (low temps could make this really long)
	t.pin.Output(Low)
	time.Sleep(300 * time.Millisecond)

	// Start polling
	start := time.Now()
	t.pin.InputEdge(p, e)
	if !t.pin.WaitForEdge(time.Second / 2) {
		Trace("Thermometer %s, Rising read timed out", t.Name())
		return 0.0
	}
	stop := time.Now()
	t.pin.Output(Low)
	return stop.Sub(start)
}

func TestDischargeStrategies(t *testing.T) {
	Info("Running %s", t.Name())
	therm := NewGpioThermometer("Fixed 4.7kOhm ResistorTest", "TestManufacturer", CAP4700)
	pulls := []Pull{PullDown, PullUp, Float}
	edges := []Edge{RisingEdge, FallingEdge, BothEdges}
	expected := 4700 * therm.microfarads
	Info("Strategy: Pull, Edge, Expected, Average, Stddev, PctVar")
	for _, p := range pulls {
		for _, e := range edges {
			h := NewHistory(10)
			for i := 0; i < 10; i++ {
				dt := discharge_us(therm, e, p)
				//Info("DischargeTime %f us,  %f k-ohms", us(dt), therm.getOhms(dt))
				h.Push(us(dt))
			}
			Info("Strategy: %s, %s, %0.3f, %0.3f, %0.4f, %0.2f",
				p, e, expected, h.Average(), h.Stddev(), 100.0*h.Stddev()/h.Average())
		}
	}
}

func TestThermometer(t *testing.T) {
	t.Skip("Skipping TestThermometer until it is fixed")
	Info("Running %s", t.Name())
	therm := NewGpioThermometer("Fixed 4.7kOhm ResistorTest", "TestManufacturer", CAP4700)

	t.Run("Calibrate Cap4700", func(t *testing.T) {
		Info("Running %s", t.Name())
		c, err := therm.Calibrate(4700)
		if err != nil {
			t.Errorf("Failure to Calibrate successfully: %s", err.Error())
		}
		Debug("Setting calibration for %0.3f", c)
		therm.SetAdjustment(c)
	})
	t.Run("Temperature Cap4700", func(t *testing.T) {
		Info("Running %s", t.Name())
		err := therm.Update()
		if err != nil {
			t.Errorf("Thermometer update failed: %s", err.Error())
		}
		if therm.Temperature() > 44.1 || therm.Temperature() < 43.1 {
			t.Errorf("Thermometer value off: %0.1f, expected 43.6",
				therm.Temperature())
		}
	})

	therm = NewGpioThermometer("Fixed 10kOhm ResistorTest", "TestManufacturer", CAP10000)
	t.Run("Calibrate Cap10000", func(t *testing.T) {
		Info("Running %s", t.Name())
		c, err := therm.Calibrate(10000)
		if err != nil {
			t.Errorf("Failure to Calibrate successfully: %s", err.Error())
		}
		Debug("Setting calibration for %0.3f", c)
		therm.SetAdjustment(c)
	})
	t.Run("Temperature Cap4700", func(t *testing.T) {
		Info("Running %s", t.Name())
		err := therm.Update()
		if err != nil {
			t.Errorf("Thermometer update failed: %s", err.Error())
		}
		if therm.Temperature() > 25.4 || therm.Temperature() < 24.4 {
			t.Errorf("Thermometer value off: %0.1f, expected 24.9",
				therm.Temperature())
		}
	})
}

func TestPushButton(t *testing.T) {
	Info("Running %s", t.Name())
	wasRun := 0
	button := NewGpioButton(SWITCH, func() {
		wasRun++
		Led.Output(High)
		Info("Button Pushed %d!!!", wasRun)
	})

	Info("Starting button test, push it 3 times!")
	button.Start()
	time.Sleep(time.Second / 2) // let it start TODO Channel?
	for i := 0; i < 3; i++ {
		TestRelay.TurnOn()
		time.Sleep(time.Second / 3)
		TestRelay.TurnOff()
		Led.Output(Low)
		time.Sleep(2 * time.Second)
	}
	if wasRun < 3 {
		t.Errorf("Expected 3 button pushes")
	}
	Info("Stopping button job")
	exited := false
	go doStop(button, &exited, time.Now())
	time.Sleep(time.Second)
	if !exited {
		t.Errorf("Button loop should have stopped within time allotted")
	}
	Info("Button job stopped")
}
<commit_msg>test sync<commit_after>package main

import (
	"fmt"
	"testing"
	"time"
)

const (
	LED      = 5  // Pin 29
	RELAY    = 13 // Pin 33
	CAP4700  = 19 // Pin 35: Also PCM capable
	CAP10000 = 6  // Pin 31
	SWITCH   = 26 // Pin 37
)

func GpioStr(g PiPin) string {
	switch g.Pin() {
	case LED:
		return "LED"
	case RELAY:
		return "RELAY"
	case CAP4700:
		return "CAP4700"
	case CAP10000:
		return "CAP10000"
	case SWITCH:
		return "SWITCH"
	default:
		return "UNKNOWN"
	}
	return ""
}

var Led PiPin        // Setup: GPIO -> <1k Resistor -> LED -> GND
var TestRelay *Relay // Setup GPIO -> 4.7k Resistor -> Relay Board
var Cap4700 PiPin    // Setup: +3.3v -> 4.7k Resistor -> GPIO -> 10uF capacitor -> GND
var Cap10000 PiPin   // Setup: +3.3v -> 10k Resistor -> GPIO -> 10uF capacitor -> GND
var Switch PiPin     // Setup: GPIO -> Button Switch -> GND

func ExpectedState(t *testing.T, gpio PiPin, exp GpioState) {
	if val := gpio.Read(); val != exp {
		t.Errorf("%s: Expected %s but found %s", GpioStr(gpio), exp, val)
	}
}

func TestInitilization(t *testing.T) {
	err := GpioInit()
	t.Run("Init Host", func(t *testing.T) {
		if err != nil {
			t.Errorf("Problem initializing gpio: %s", err.Error())
		}
	})

	// Initialized GPIOs
	Led = NewGpio(LED)
	ExpectedState(t, Led, Low)
}

func TestBlinkLed(t *testing.T) {
	Info("Running %s", t.Name())
	for i := 0; i < 6; i++ {
		time.Sleep(time.Second / 5)
		Led.Output(High)
		ExpectedState(t, Led, High)
		time.Sleep(time.Second / 5)
		Led.Output(Low)
		ExpectedState(t, Led, Low)
	}
}

func doStop(button *Button, b *bool, t time.Time) {
	*b = false
	button.Stop()
	*b = true
	Info("doStop - Stopped after %d ms", time.Now().Sub(t)/time.Millisecond)
}

func runRelayTestOn(t *testing.T, relay *Relay) {
	relay.TurnOn()
	Info("Testing Relay On: %s is %s", relay.Name(), relay.Status())
	if !relay.isOn() {
		t.Errorf("Relay(%s) is %s", relay.Name(), relay.Status())
	}
}

func runRelayTestOff(t *testing.T, relay *Relay) {
	relay.TurnOff()
	Info("Testing Relay Off: %s is %s", relay.Name(), relay.Status())
	if relay.isOn() {
		t.Errorf("Relay(%s) is %s", relay.Name(), relay.Status())
	}
}

func runRelayTest(t *testing.T, r *Relay, sleep time.Duration) {
	t.Run(fmt.Sprintf("%s.Test", r.Name()), func(t *testing.T) {
		Info("Running %s", t.Name())
		runRelayTestOn(t, r)
		time.Sleep(sleep)
		runRelayTestOff(t, r)
	})
}

func TestRelays(t *testing.T) {
	Info("Running %s", t.Name())
	TestRelay = NewRelay(RELAY, "Relay", "Testing")
	runRelayTest(t, TestRelay, time.Second)
}

func discharge_us(t *GpioThermometer, e Edge, p Pull) time.Duration {
	t.mutex.Lock()
	defer t.mutex.Unlock()

	//Discharge the capacitor (low temps could make this really long)
	t.pin.Output(Low)
	time.Sleep(300 * time.Millisecond)

	// Start polling
	start := time.Now()
	t.pin.InputEdge(p, e)
	if !t.pin.WaitForEdge(time.Second / 2) {
		Trace("Thermometer %s, Rising read timed out", t.Name())
		return 0.0
	}
	stop := time.Now()
	t.pin.Output(Low)
	return stop.Sub(start)
}

func TestDischargeStrategies(t *testing.T) {
	Info("Running %s", t.Name())
	therm := NewGpioThermometer("Fixed 4.7kOhm ResistorTest", "TestManufacturer", CAP4700)
	pulls := []Pull{PullDown, PullUp, Float}
	edges := []Edge{RisingEdge, FallingEdge, BothEdges}
	expected := 4700 * therm.microfarads
	Info("Strategy: Pull, Edge, Expected, Average, Stddev, PctVar")
	for _, p := range pulls {
		for _, e := range edges {
			h := NewHistory(10)
			for i := 0; i < 10; i++ {
				dt := discharge_us(therm, e, p)
				//Info("DischargeTime %f us,  %f k-ohms", us(dt), therm.getOhms(dt))
				h.Push(us(dt))
			}
			Info("Strategy: %s, %s, %0.3f, %0.3f, %0.4f, %0.2f",
				p, e, expected, h.Average(), h.Stddev(), 100.0*h.Stddev()/h.Average())
		}
	}
}

func TestBestDischargeStrategy(t *testing.T) {
	Info("Running %s", t.Name())
	therm := NewGpioThermometer("Fixed 4.7kOhm ResistorTest", "TestManufacturer", CAP4700)
	pulls := []Pull{PullDown, PullUp, Float}
	edges := []Edge{RisingEdge, FallingEdge, BothEdges}
	expected := 4.700 * therm.microfarads
	Info("Strategy: Pull, Edge, Expected, Average, Stddev, PctVar")
	h := NewHistory(10)
	for i := 0; i < 10; i++ {
		dt1 := discharge_us(therm, RisingEdge, PullDown)
		dt2 := discharge_us(therm, FallingEdge, PullDown)
		dt := dt1 + dt2
		Info("DischargeTime dt1(%f ms),  dt2(%f ms), dt(%fms), %f k-ohms",
			ms(dt1), ms(dt2), ms(dt), therm.getOhms(dt))
		h.Push(ms(dt1 + dt2))
	}
	Info("Strategy: %0.3f, %0.3f, %0.4f, %0.2f",
		expected, h.Average(), h.Stddev(), 100.0*h.Stddev()/h.Average())
}

func TestThermometer(t *testing.T) {
	t.Skip("Skipping TestThermometer until it is fixed")
	Info("Running %s", t.Name())
	therm := NewGpioThermometer("Fixed 4.7kOhm ResistorTest", "TestManufacturer", CAP4700)

	t.Run("Calibrate Cap4700", func(t *testing.T) {
		Info("Running %s", t.Name())
		c, err := therm.Calibrate(4700)
		if err != nil {
			t.Errorf("Failure to Calibrate successfully: %s", err.Error())
		}
		Debug("Setting calibration for %0.3f", c)
		therm.SetAdjustment(c)
	})
	t.Run("Temperature Cap4700", func(t *testing.T) {
		Info("Running %s", t.Name())
		err := therm.Update()
		if err != nil {
			t.Errorf("Thermometer update failed: %s", err.Error())
		}
		if therm.Temperature() > 44.1 || therm.Temperature() < 43.1 {
			t.Errorf("Thermometer value off: %0.1f, expected 43.6",
				therm.Temperature())
		}
	})

	therm = NewGpioThermometer("Fixed 10kOhm ResistorTest", "TestManufacturer", CAP10000)
	t.Run("Calibrate Cap10000", func(t *testing.T) {
		Info("Running %s", t.Name())
		c, err := therm.Calibrate(10000)
		if err != nil {
			t.Errorf("Failure to Calibrate successfully: %s", err.Error())
		}
		Debug("Setting calibration for %0.3f", c)
		therm.SetAdjustment(c)
	})
	t.Run("Temperature Cap4700", func(t *testing.T) {
		Info("Running %s", t.Name())
		err := therm.Update()
		if err != nil {
			t.Errorf("Thermometer update failed: %s", err.Error())
		}
		if therm.Temperature() > 25.4 || therm.Temperature() < 24.4 {
			t.Errorf("Thermometer value off: %0.1f, expected 24.9",
				therm.Temperature())
		}
	})
}

func TestPushButton(t *testing.T) {
	Info("Running %s", t.Name())
	wasRun := 0
	button := NewGpioButton(SWITCH, func() {
		wasRun++
		Led.Output(High)
		Info("Button Pushed %d!!!", wasRun)
	})

	Info("Starting button test, push it 3 times!")
	button.Start()
	time.Sleep(time.Second / 2) // let it start TODO Channel?
	for i := 0; i < 3; i++ {
		TestRelay.TurnOn()
		time.Sleep(time.Second / 3)
		TestRelay.TurnOff()
		Led.Output(Low)
		time.Sleep(2 * time.Second)
	}
	if wasRun < 3 {
		t.Errorf("Expected 3 button pushes")
	}
	Info("Stopping button job")
	exited := false
	go doStop(button, &exited, time.Now())
	time.Sleep(time.Second)
	if !exited {
		t.Errorf("Button loop should have stopped within time allotted")
	}
	Info("Button job stopped")
}
<|endoftext|>


<commit_before>// Copyright 2015 CoreOS, Inc.
//
// 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 main

import (
	"os"
	"strings"
	"testing"

	"github.com/coreos/rkt/Godeps/_workspace/src/github.com/ThomasRooney/gexpect"
)

func TestSuccess(t *testing.T) {
	patchTestACI("rkt-inspect-exit0.aci", "--exec=/inspect --print-msg=Hello --exit-code=0")
	defer os.Remove("rkt-inspect-exit0.aci")

	child, err := gexpect.Spawn("../bin/rkt --debug --insecure-skip-verify run ./rkt-inspect-exit0.aci")
	if err != nil {
		t.Fatalf("Cannot exec rkt")
	}
	err = child.Expect("Hello")
	if err != nil {
		t.Fatalf("Missing hello")
	}
	forbidden := "main process exited, code=exited, status="
	_, receiver := child.AsyncInteractChannels()
	for {
		msg, open := <-receiver
		if !open {
			break
		}
		if strings.Contains(msg, forbidden) {
			t.Fatalf("Forbidden text received")
		}
	}

	err = child.Wait()
	if err != nil {
		t.Fatalf("rkt didn't terminate correctly: %v", err)
	}
}

func TestFailure(t *testing.T) {
	patchTestACI("rkt-inspect-exit20.aci", "--exec=/inspect --print-msg=Hello --exit-code=20")
	defer os.Remove("rkt-inspect-exit20.aci")

	child, err := gexpect.Spawn("../bin/rkt --debug --insecure-skip-verify run ./rkt-inspect-exit20.aci")
	if err != nil {
		t.Fatalf("Cannot exec rkt")
	}
	err = child.Expect("Hello")
	if err != nil {
		t.Fatalf("Missing hello")
	}
	err = child.Expect("main process exited, code=exited, status=20")
	if err != nil {
		t.Fatalf("Missing hello")
	}

	err = child.Wait()
	if err != nil {
		t.Fatalf("rkt didn't terminate correctly: %v", err)
	}
}
<commit_msg>functional tests: Port exit tests to rkt run context<commit_after>// Copyright 2015 CoreOS, Inc.
//
// 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 main

import (
	"fmt"
	"os"
	"strings"
	"testing"

	"github.com/coreos/rkt/Godeps/_workspace/src/github.com/ThomasRooney/gexpect"
)

func TestSuccess(t *testing.T) {
	patchTestACI("rkt-inspect-exit0.aci", "--exec=/inspect --print-msg=Hello --exit-code=0")
	defer os.Remove("rkt-inspect-exit0.aci")
	ctx := newRktRunCtx()
	defer ctx.cleanup()

	child, err := gexpect.Spawn(fmt.Sprintf("%s --debug --insecure-skip-verify run ./rkt-inspect-exit0.aci", ctx.cmd()))
	if err != nil {
		t.Fatalf("Cannot exec rkt")
	}
	err = child.Expect("Hello")
	if err != nil {
		t.Fatalf("Missing hello")
	}
	forbidden := "main process exited, code=exited, status="
	_, receiver := child.AsyncInteractChannels()
	for {
		msg, open := <-receiver
		if !open {
			break
		}
		if strings.Contains(msg, forbidden) {
			t.Fatalf("Forbidden text received")
		}
	}

	err = child.Wait()
	if err != nil {
		t.Fatalf("rkt didn't terminate correctly: %v", err)
	}
}

func TestFailure(t *testing.T) {
	patchTestACI("rkt-inspect-exit20.aci", "--exec=/inspect --print-msg=Hello --exit-code=20")
	defer os.Remove("rkt-inspect-exit20.aci")
	ctx := newRktRunCtx()
	defer ctx.cleanup()

	child, err := gexpect.Spawn(fmt.Sprintf("%s --debug --insecure-skip-verify run ./rkt-inspect-exit20.aci", ctx.cmd()))
	if err != nil {
		t.Fatalf("Cannot exec rkt")
	}
	err = child.Expect("Hello")
	if err != nil {
		t.Fatalf("Missing hello")
	}
	err = child.Expect("main process exited, code=exited, status=20")
	if err != nil {
		t.Fatalf("Missing hello")
	}

	err = child.Wait()
	if err != nil {
		t.Fatalf("rkt didn't terminate correctly: %v", err)
	}
}
<|endoftext|>


<commit_before>// +build graphite

package connector

import (
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"strings"
	"time"

	"github.com/facette/facette/pkg/catalog"
	"github.com/facette/facette/pkg/config"
	"github.com/facette/facette/pkg/types"
	"github.com/facette/facette/pkg/utils"
)

const (
	graphiteURLMetrics     string  = "/metrics/index.json"
	graphiteURLRender      string  = "/render"
	graphiteDefaultTimeout float64 = 10
)

type graphitePlot struct {
	Target     string
	Datapoints [][2]float64
}

// GraphiteConnector represents the main structure of the Graphite connector.
type GraphiteConnector struct {
	URL         string
	insecureTLS bool
	timeout     float64
}

func init() {
	Connectors["graphite"] = func(settings map[string]interface{}) (Connector, error) {
		var err error

		connector := &GraphiteConnector{
			insecureTLS: false,
		}

		if connector.URL, err = config.GetString(settings, "url", true); err != nil {
			return nil, err
		}

		if connector.insecureTLS, err = config.GetBool(settings, "allow_insecure_tls", false); err != nil {
			return nil, err
		}

		if connector.timeout, err = config.GetFloat(settings, "timeout", false); err != nil {
			return nil, err
		}

		if connector.timeout <= 0 {
			connector.timeout = graphiteDefaultTimeout
		}

		return connector, nil
	}
}

// GetPlots retrieves time series data from provider based on a query and a time interval.
func (connector *GraphiteConnector) GetPlots(query *types.PlotQuery) ([]*types.PlotResult, error) {
	var result []*types.PlotResult

	if len(query.Group.Series) == 0 {
		return nil, fmt.Errorf("group has no series")
	} else if query.Group.Type != OperGroupTypeNone && len(query.Group.Series) == 1 {
		query.Group.Type = OperGroupTypeNone
	}

	queryURL, err := graphiteBuildQueryURL(query.Group, query.StartTime, query.EndTime, query.Sample)
	if err != nil {
		return nil, fmt.Errorf("unable to build Graphite query URL: %s", err)
	}

	httpTransport := &http.Transport{
		Dial: (&net.Dialer{
			// Enable dual IPv4/IPv6 stack connectivity:
			DualStack: true,
			// Enforce HTTP connection timeout:
			Timeout: time.Duration(connector.timeout) * time.Second,
		}).Dial,
	}

	if connector.insecureTLS {
		httpTransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
	}

	httpClient := http.Client{Transport: httpTransport}

	request, err := http.NewRequest("GET", strings.TrimSuffix(connector.URL, "/")+queryURL, nil)
	if err != nil {
		return nil, fmt.Errorf("unable to set up HTTP request: %s", err)
	}

	request.Header.Add("User-Agent", "Facette")
	request.Header.Add("X-Requested-With", "GraphiteConnector")

	response, err := httpClient.Do(request)
	if err != nil {
		return nil, fmt.Errorf("unable to perform HTTP request: %s", err)
	}

	if err = graphiteCheckBackendResponse(response); err != nil {
		return nil, fmt.Errorf("invalid HTTP backend response: %s", err)
	}

	data, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return nil, fmt.Errorf("unable to read HTTP response body: %s", err)
	}

	graphitePlots := make([]graphitePlot, 0)
	if err = json.Unmarshal(data, &graphitePlots); err != nil {
		return nil, fmt.Errorf("unable to unmarshal JSON data: %s", err)
	}

	if result, err = graphiteExtractPlotResult(graphitePlots); err != nil {
		return nil, fmt.Errorf("unable to extract plot values from backend response: %s", err)
	}

	return result, nil
}

// Refresh triggers a full connector data update.
func (connector *GraphiteConnector) Refresh(originName string, outputChan chan *catalog.CatalogRecord) error {
	httpTransport := &http.Transport{
		Dial: (&net.Dialer{
			// Enable dual IPv4/IPv6 stack connectivity:
			DualStack: true,
			// Enforce HTTP connection timeout:
			Timeout: time.Duration(connector.timeout) * time.Second,
		}).Dial,
	}

	if connector.insecureTLS {
		httpTransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
	}

	httpClient := http.Client{Transport: httpTransport}

	request, err := http.NewRequest("GET", strings.TrimSuffix(connector.URL, "/")+graphiteURLMetrics, nil)
	if err != nil {
		return fmt.Errorf("unable to set up HTTP request: %s", err)
	}

	request.Header.Add("User-Agent", "Facette")
	request.Header.Add("X-Requested-With", "GraphiteConnector")

	response, err := httpClient.Do(request)
	if err != nil {
		return fmt.Errorf("unable to perform HTTP request: %s", err)
	}

	if err = graphiteCheckBackendResponse(response); err != nil {
		return fmt.Errorf("invalid HTTP backend response: %s", err)
	}

	data, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return fmt.Errorf("unable to read HTTP response body: %s", err)
	}

	metrics := make([]string, 0)
	if err = json.Unmarshal(data, &metrics); err != nil {
		return fmt.Errorf("unable to unmarshal JSON data: %s", err)
	}

	for _, metric := range metrics {
		var sourceName, metricName string

		index := strings.Index(metric, ".")

		if index == -1 {
			sourceName = "unknown"
			metricName = metric
		} else {
			sourceName = metric[0:index]
			metricName = metric[index+1:]
		}

		outputChan <- &catalog.CatalogRecord{
			Origin:    originName,
			Source:    sourceName,
			Metric:    metricName,
			Connector: connector,
		}
	}

	return nil
}

func graphiteCheckBackendResponse(response *http.Response) error {
	if response.StatusCode != 200 {
		return fmt.Errorf("got HTTP status code %d, expected 200", response.StatusCode)
	}

	if utils.HTTPGetContentType(response) != "application/json" {
		return fmt.Errorf("got HTTP content type `%s', expected `application/json'", response.Header["Content-Type"])
	}

	return nil
}

func graphiteBuildQueryURL(queryGroup *types.PlotQueryGroup, startTime, endTime time.Time, sample int) (string, error) {
	now := time.Now()

	fromTime := 0

	interval := fmt.Sprintf("%.0fseconds", (endTime.Sub(startTime) / time.Duration(sample)).Seconds())

	queryURL := fmt.Sprintf("%s?format=json", graphiteURLRender)

	count := 0

	if queryGroup.Type == OperGroupTypeNone {
		for _, serie := range queryGroup.Series {
			count += 1

			target := fmt.Sprintf("%s.%s", serie.Metric.Source, serie.Metric.Name)

			if scale, _ := config.GetFloat(serie.Options, "scale", false); scale != 0 {
				target = fmt.Sprintf("scale(%s, %g)", target, scale)
			}

			queryURL += fmt.Sprintf("&target=legendValue(%s, 'min', 'max', 'avg', 'last')", target)
		}
	} else {
		count += 1

		targets := make([]string, 0)

		for _, serie := range queryGroup.Series {
			targets = append(targets, fmt.Sprintf("%s.%s", serie.Metric.Source, serie.Metric.Name))
		}

		target := fmt.Sprintf("group(%s)", strings.Join(targets, ","))

		if scale, _ := config.GetFloat(queryGroup.Series[0].Options, "scale", false); scale != 0 {
			target = fmt.Sprintf("scale(%s, %g)", target, scale)
		}

		switch queryGroup.Type {
		case OperGroupTypeAvg:
			target = fmt.Sprintf("averageSeries(%s)", target)
		case OperGroupTypeSum:
			target = fmt.Sprintf("sumSeries(%s)", target)
		}

		target = fmt.Sprintf("legendValue(%s, 'min', 'max', 'avg', 'last')", target)

		queryURL += fmt.Sprintf("&target=summarize(%s, \"%s\", \"avg\")", target, interval)
	}

	if startTime.Before(now) {
		fromTime = int(now.Sub(startTime).Seconds())
	}

	queryURL += fmt.Sprintf("&from=-%ds", fromTime)

	// Only specify `until' parameter if endTime is still in the past
	if endTime.Before(now) {
		untilTime := int(time.Now().Sub(endTime).Seconds())
		queryURL += fmt.Sprintf("&until=-%ds", untilTime)
	}

	return queryURL, nil
}

func graphiteExtractPlotResult(plots []graphitePlot) ([]*types.PlotResult, error) {
	var min, max, avg, last float64

	result := make([]*types.PlotResult, 0)

	for _, plot := range plots {
		plotResult := &types.PlotResult{Info: make(map[string]types.PlotValue)}

		for _, plotPoint := range plot.Datapoints {
			plotResult.Plots = append(plotResult.Plots, types.PlotValue(plotPoint[0]))
		}

		// Scan the target legend for serie name and plot min/max/avg/last info
		if index := strings.Index(plots[0].Target, "(min"); index > 0 {
			fmt.Sscanf(plot.Target[0:index], "%s ", &plotResult.Name)
			fmt.Sscanf(plot.Target[index:], "(min: %f) (max: %f) (avg: %f) (last: %f)", &min, &max, &avg, &last)
		}

		plotResult.Info["min"] = types.PlotValue(min)
		plotResult.Info["max"] = types.PlotValue(max)
		plotResult.Info["avg"] = types.PlotValue(avg)
		plotResult.Info["last"] = types.PlotValue(last)

		fmt.Printf("graphite: serie %s: %#v\n", plotResult.Name, plotResult.Info)

		result = append(result, plotResult)
	}

	return result, nil
}
<commit_msg>Remove call to legendValue() in Graphite connector<commit_after>// +build graphite

package connector

import (
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"strings"
	"time"

	"github.com/facette/facette/pkg/catalog"
	"github.com/facette/facette/pkg/config"
	"github.com/facette/facette/pkg/types"
	"github.com/facette/facette/pkg/utils"
)

const (
	graphiteURLMetrics     string  = "/metrics/index.json"
	graphiteURLRender      string  = "/render"
	graphiteDefaultTimeout float64 = 10
)

type graphitePlot struct {
	Target     string
	Datapoints [][2]float64
}

// GraphiteConnector represents the main structure of the Graphite connector.
type GraphiteConnector struct {
	URL         string
	insecureTLS bool
	timeout     float64
}

func init() {
	Connectors["graphite"] = func(settings map[string]interface{}) (Connector, error) {
		var err error

		connector := &GraphiteConnector{
			insecureTLS: false,
		}

		if connector.URL, err = config.GetString(settings, "url", true); err != nil {
			return nil, err
		}

		if connector.insecureTLS, err = config.GetBool(settings, "allow_insecure_tls", false); err != nil {
			return nil, err
		}

		if connector.timeout, err = config.GetFloat(settings, "timeout", false); err != nil {
			return nil, err
		}

		if connector.timeout <= 0 {
			connector.timeout = graphiteDefaultTimeout
		}

		return connector, nil
	}
}

// GetPlots retrieves time series data from provider based on a query and a time interval.
func (connector *GraphiteConnector) GetPlots(query *types.PlotQuery) ([]*types.PlotResult, error) {
	var result []*types.PlotResult

	if len(query.Group.Series) == 0 {
		return nil, fmt.Errorf("group has no series")
	} else if query.Group.Type != OperGroupTypeNone && len(query.Group.Series) == 1 {
		query.Group.Type = OperGroupTypeNone
	}

	queryURL, err := graphiteBuildQueryURL(query.Group, query.StartTime, query.EndTime, query.Sample)
	if err != nil {
		return nil, fmt.Errorf("unable to build Graphite query URL: %s", err)
	}

	httpTransport := &http.Transport{
		Dial: (&net.Dialer{
			// Enable dual IPv4/IPv6 stack connectivity:
			DualStack: true,
			// Enforce HTTP connection timeout:
			Timeout: time.Duration(connector.timeout) * time.Second,
		}).Dial,
	}

	if connector.insecureTLS {
		httpTransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
	}

	httpClient := http.Client{Transport: httpTransport}

	request, err := http.NewRequest("GET", strings.TrimSuffix(connector.URL, "/")+queryURL, nil)
	if err != nil {
		return nil, fmt.Errorf("unable to set up HTTP request: %s", err)
	}

	request.Header.Add("User-Agent", "Facette")
	request.Header.Add("X-Requested-With", "GraphiteConnector")

	response, err := httpClient.Do(request)
	if err != nil {
		return nil, fmt.Errorf("unable to perform HTTP request: %s", err)
	}

	if err = graphiteCheckBackendResponse(response); err != nil {
		return nil, fmt.Errorf("invalid HTTP backend response: %s", err)
	}

	data, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return nil, fmt.Errorf("unable to read HTTP response body: %s", err)
	}

	graphitePlots := make([]graphitePlot, 0)
	if err = json.Unmarshal(data, &graphitePlots); err != nil {
		return nil, fmt.Errorf("unable to unmarshal JSON data: %s", err)
	}

	if result, err = graphiteExtractPlotResult(graphitePlots); err != nil {
		return nil, fmt.Errorf("unable to extract plot values from backend response: %s", err)
	}

	return result, nil
}

// Refresh triggers a full connector data update.
func (connector *GraphiteConnector) Refresh(originName string, outputChan chan *catalog.CatalogRecord) error {
	httpTransport := &http.Transport{
		Dial: (&net.Dialer{
			// Enable dual IPv4/IPv6 stack connectivity:
			DualStack: true,
			// Enforce HTTP connection timeout:
			Timeout: time.Duration(connector.timeout) * time.Second,
		}).Dial,
	}

	if connector.insecureTLS {
		httpTransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
	}

	httpClient := http.Client{Transport: httpTransport}

	request, err := http.NewRequest("GET", strings.TrimSuffix(connector.URL, "/")+graphiteURLMetrics, nil)
	if err != nil {
		return fmt.Errorf("unable to set up HTTP request: %s", err)
	}

	request.Header.Add("User-Agent", "Facette")
	request.Header.Add("X-Requested-With", "GraphiteConnector")

	response, err := httpClient.Do(request)
	if err != nil {
		return fmt.Errorf("unable to perform HTTP request: %s", err)
	}

	if err = graphiteCheckBackendResponse(response); err != nil {
		return fmt.Errorf("invalid HTTP backend response: %s", err)
	}

	data, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return fmt.Errorf("unable to read HTTP response body: %s", err)
	}

	metrics := make([]string, 0)
	if err = json.Unmarshal(data, &metrics); err != nil {
		return fmt.Errorf("unable to unmarshal JSON data: %s", err)
	}

	for _, metric := range metrics {
		var sourceName, metricName string

		index := strings.Index(metric, ".")

		if index == -1 {
			sourceName = "unknown"
			metricName = metric
		} else {
			sourceName = metric[0:index]
			metricName = metric[index+1:]
		}

		outputChan <- &catalog.CatalogRecord{
			Origin:    originName,
			Source:    sourceName,
			Metric:    metricName,
			Connector: connector,
		}
	}

	return nil
}

func graphiteCheckBackendResponse(response *http.Response) error {
	if response.StatusCode != 200 {
		return fmt.Errorf("got HTTP status code %d, expected 200", response.StatusCode)
	}

	if utils.HTTPGetContentType(response) != "application/json" {
		return fmt.Errorf("got HTTP content type `%s', expected `application/json'", response.Header["Content-Type"])
	}

	return nil
}

func graphiteBuildQueryURL(queryGroup *types.PlotQueryGroup, startTime, endTime time.Time, sample int) (string, error) {
	now := time.Now()

	fromTime := 0

	interval := fmt.Sprintf("%.0fseconds", (endTime.Sub(startTime) / time.Duration(sample)).Seconds())

	queryURL := fmt.Sprintf("%s?format=json", graphiteURLRender)

	count := 0

	if queryGroup.Type == OperGroupTypeNone {
		for _, serie := range queryGroup.Series {
			count += 1

			target := fmt.Sprintf("%s.%s", serie.Metric.Source, serie.Metric.Name)

			if scale, _ := config.GetFloat(serie.Options, "scale", false); scale != 0 {
				target = fmt.Sprintf("scale(%s, %g)", target, scale)
			}

			queryURL += fmt.Sprintf("&target=%s", target)
		}
	} else {
		count += 1

		targets := make([]string, 0)

		for _, serie := range queryGroup.Series {
			targets = append(targets, fmt.Sprintf("%s.%s", serie.Metric.Source, serie.Metric.Name))
		}

		target := fmt.Sprintf("group(%s)", strings.Join(targets, ","))

		if scale, _ := config.GetFloat(queryGroup.Series[0].Options, "scale", false); scale != 0 {
			target = fmt.Sprintf("scale(%s, %g)", target, scale)
		}

		switch queryGroup.Type {
		case OperGroupTypeAvg:
			target = fmt.Sprintf("averageSeries(%s)", target)
		case OperGroupTypeSum:
			target = fmt.Sprintf("sumSeries(%s)", target)
		}

		queryURL += fmt.Sprintf("&target=summarize(%s, \"%s\", \"avg\")", target, interval)
	}

	if startTime.Before(now) {
		fromTime = int(now.Sub(startTime).Seconds())
	}

	queryURL += fmt.Sprintf("&from=-%ds", fromTime)

	// Only specify `until' parameter if endTime is still in the past
	if endTime.Before(now) {
		untilTime := int(time.Now().Sub(endTime).Seconds())
		queryURL += fmt.Sprintf("&until=-%ds", untilTime)
	}

	return queryURL, nil
}

func graphiteExtractPlotResult(plots []graphitePlot) ([]*types.PlotResult, error) {
	result := make([]*types.PlotResult, 0)

	for _, plot := range plots {
		plotResult := &types.PlotResult{Info: make(map[string]types.PlotValue)}

		for _, plotPoint := range plot.Datapoints {
			plotResult.Plots = append(plotResult.Plots, types.PlotValue(plotPoint[0]))
		}

		result = append(result, plotResult)
	}

	return result, nil
}
<|endoftext|>


<commit_before>// +build selenium

/*
 * Copyright (C) 2017 Red Hat, Inc.
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 tests

import (
	"fmt"
	"net"
	"os"
	"testing"
	"time"

	"github.com/tebeka/selenium"

	gclient "github.com/skydive-project/skydive/cmd/client"
	shttp "github.com/skydive-project/skydive/http"
	"github.com/skydive-project/skydive/tests/helper"
)

func TestSelenium(t *testing.T) {
	gopath := os.Getenv("GOPATH")
	topology := gopath + "/src/github.com/skydive-project/skydive/scripts/simple.sh"

	setupCmds := []helper.Cmd{
		{fmt.Sprintf("%s start 124.65.54.42/24 124.65.54.43/24", topology), true},
		{"sudo docker pull elgalu/selenium", true},
		{"sudo docker run -d --name=grid -p 4444:24444 -p 5900:25900 -e --shm-size=1g elgalu/selenium", true},
		{"docker exec grid wait_all_done 30s", true},
	}

	tearDownCmds := []helper.Cmd{
		{fmt.Sprintf("%s stop", topology), true},
		{"sudo docker exec grid stop", true},
		{"sudo docker stop grid", true},
		{"sudo docker rm grid", true},
	}

	helper.ExecCmds(t, setupCmds...)
	defer helper.ExecCmds(t, tearDownCmds...)

	caps := selenium.Capabilities{"browserName": "chrome"}
	webdriver, err := selenium.NewRemote(caps, "http://127.0.0.1:4444/wd/hub")
	if err != nil {
		t.Fatal(err)
	}
	defer webdriver.Quit()

	ipaddr, err := getIPv4Addr()
	if err != nil {
		t.Fatal("Not able to find Analayzer addr: %v", err)
	}

	if err := webdriver.Get("http://" + ipaddr + ":8082"); err != nil {
		t.Fatal(err)
	}
	time.Sleep(5 * time.Second)

	startCapture := func(wd selenium.WebDriver) error {
		captureTab, err := wd.FindElement(selenium.ByXPATH, ".//*[@id='Captures']")
		if err != nil || captureTab == nil {
			return fmt.Errorf("Not found capture tab: %v", err)
		}
		if err := captureTab.Click(); err != nil {
			return fmt.Errorf("%v", err)
		}
		createBtn, err := wd.FindElement(selenium.ByXPATH, ".//*[@id='create-capture']")
		if err != nil || createBtn == nil {
			return fmt.Errorf("Not found create button : %v", err)
		}
		if err := createBtn.Click(); err != nil {
			return fmt.Errorf("%v", err)
		}
		time.Sleep(2 * time.Second)

		gremlinRdoBtn, err := wd.FindElement(selenium.ByXPATH, ".//*[@id='by-gremlin']")
		if err != nil || gremlinRdoBtn == nil {
			return fmt.Errorf("Not found gremlin expression radio button: %v", err)
		}
		if err := gremlinRdoBtn.Click(); err != nil {
			return err
		}

		queryTxtBox, err := wd.FindElement(selenium.ByXPATH, ".//*[@id='capture-query']")
		if err != nil || queryTxtBox == nil {
			return fmt.Errorf("Not found Query text box: %v", err)
		}
		if err := queryTxtBox.Clear(); err != nil {
			return err
		}
		if err := queryTxtBox.SendKeys("G.V().Has('Name', 'br-int', 'Type', 'ovsbridge')"); err != nil {
			return err
		}

		startBtn, err := wd.FindElement(selenium.ByXPATH, ".//*[@id='start-capture']")
		if err != nil || startBtn == nil {
			return fmt.Errorf("Not found start button: %v", err)
		}
		if err := startBtn.Click(); err != nil {
			return err
		}
		time.Sleep(3 * time.Second)

		//check capture created with the given query
		captures, err := wd.FindElements(selenium.ByClassName, "query")
		if err != nil {
			return err
		}
		var foundCapture bool
		for _, capture := range captures {
			if txt, _ := capture.Text(); txt == "G.V().Has('Name', 'br-int', 'Type', 'ovsbridge')" {
				foundCapture = true
				break
			}

		}
		if !foundCapture {
			return fmt.Errorf("Capture not found in the list")
		}
		return nil

	}

	injectPacket := func(wd selenium.WebDriver) error {
		generatorTab, err := wd.FindElement(selenium.ByXPATH, ".//*[@id='Generator']")
		if err != nil || generatorTab == nil {
			return fmt.Errorf("Generator tab not found: %v", err)
		}
		if err := generatorTab.Click(); err != nil {
			return err
		}

		injectSrc, err := wd.FindElement(selenium.ByXPATH, ".//*[@id='inject-src']/input")
		if err != nil || injectSrc == nil {
			return err
		}
		if err := injectSrc.Click(); err != nil {
			return err
		}

		authOptions := &shttp.AuthenticationOpts{}
		gh := gclient.NewGremlinQueryHelper(authOptions)

		node1, err := gh.GetNode("G.V().Has('Name', 'eth0', 'IPV4', Contains('124.65.54.42/24')).HasKey('TID')")
		if err != nil {
			return err
		}

		node2, err := gh.GetNode("G.V().Has('Name', 'eth0', 'IPV4', Contains('124.65.54.43/24')).HasKey('TID')")
		if err != nil {
			return err
		}

		tid1, _ := node1.GetFieldString("TID")
		tid2, _ := node2.GetFieldString("TID")

		srcNode, err := wd.FindElement(selenium.ByXPATH, ".//*[@tid='"+tid1+"']")
		if err != nil || srcNode == nil {
			return err
		}
		if err := srcNode.Click(); err != nil {
			return err
		}

		injectDst, err := wd.FindElement(selenium.ByXPATH, ".//*[@id='inject-dst']/input")
		if err != nil || injectDst == nil {
			return err
		}
		if err := injectDst.Click(); err != nil {
			return err
		}
		dstNode, err := wd.FindElement(selenium.ByXPATH, ".//*[@tid='"+tid2+"']")
		if err != nil || dstNode == nil {
			return err
		}
		if err := dstNode.Click(); err != nil {
			return err
		}

		injectBtn, err := wd.FindElement(selenium.ByXPATH, ".//*[@id='inject']")
		if err != nil || injectBtn == nil {
			return nil
		}
		if err := injectBtn.Click(); err != nil {
			return err
		}

		var alertMsg selenium.WebElement
		for i := 1; i <= 10; i++ {
			alertMsg, err = wd.FindElement(selenium.ByClassName, "alert-success")
			if err != nil {
				time.Sleep(500 * time.Millisecond)
				continue
			}
			break
		}
		if alertMsg != nil {
			closeBtn, _ := alertMsg.FindElement(selenium.ByClassName, "close")
			if closeBtn != nil {
				closeBtn.Click()
			}
		} else {
			return fmt.Errorf("No success alert msg.")
		}
		return nil
	}

	verifyFlows := func(wd selenium.WebDriver) error {
		time.Sleep(3 * time.Second)

		flowsTab, err := wd.FindElement(selenium.ByXPATH, ".//*[@id='Flows']")
		if err != nil || flowsTab == nil {
			return fmt.Errorf("Flows tab not found: %v", err)
		}
		if err := flowsTab.Click(); err != nil {
			return err
		}

		flowQuery, err := wd.FindElement(selenium.ByXPATH, ".//*[@id='flow-table-query']")
		if err != nil || flowQuery == nil {
			return err
		}
		if err := flowQuery.Clear(); err != nil {
			return err
		}
		query := "G.Flows().Has('Network.A', '124.65.54.42', 'Network.B', '124.65.54.43')"
		if err := flowQuery.SendKeys(query); err != nil {
			return err
		}

		time.Sleep(2 * time.Second)

		flowRow, err := wd.FindElement(selenium.ByClassName, "flow-row")
		if err != nil || flowRow == nil {
			return err
		}
		rowData, err := flowRow.FindElements(selenium.ByTagName, "td")
		if err != nil {
			return err
		}
		if len(rowData) != 7 {
			return fmt.Errorf("By default 7 rows should be return")
		}
		txt, err := rowData[1].Text()
		if err != nil {
			return err
		}
		if txt != "124.65.54.42" {
			fmt.Errorf("Network.A should be '124.65.54.42' but got: %s", txt)
		}
		return nil
	}

	if err := startCapture(webdriver); err != nil {
		t.Fatal(err)
	}

	if err := injectPacket(webdriver); err != nil {
		t.Fatal(err)
	}

	if err := verifyFlows(webdriver); err != nil {
		t.Fatal(err)
	}
}

func getIPv4Addr() (string, error) {
	ifaces, err := net.Interfaces()
	if err != nil {
		return "", err
	}

	for _, iface := range ifaces {
		//neglect interfaces which are down
		if iface.Flags&net.FlagUp == 0 {
			continue
		}
		//neglect loopback interface
		if iface.Flags&net.FlagLoopback != 0 {
			continue
		}
		addrs, err := iface.Addrs()
		if err != nil {
			return "", err
		}
		for _, addr := range addrs {
			var ip net.IP
			switch t := addr.(type) {
			case *net.IPNet:
				ip = t.IP
			case *net.IPAddr:
				ip = t.IP
			}
			if ip == nil || ip.IsLoopback() {
				continue
			}
			ip = ip.To4()
			if ip != nil {
				return ip.String(), nil
			}
		}
	}
	return "", fmt.Errorf("No IP found")
}
<commit_msg>selenium: add helper to retry when an element is not found<commit_after>// +build selenium

/*
 * Copyright (C) 2017 Red Hat, Inc.
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 tests

import (
	"fmt"
	"net"
	"os"
	"testing"
	"time"

	"github.com/tebeka/selenium"

	gclient "github.com/skydive-project/skydive/cmd/client"
	"github.com/skydive-project/skydive/common"
	shttp "github.com/skydive-project/skydive/http"
	"github.com/skydive-project/skydive/tests/helper"
)

func TestSelenium(t *testing.T) {
	gopath := os.Getenv("GOPATH")
	topology := gopath + "/src/github.com/skydive-project/skydive/scripts/simple.sh"

	setupCmds := []helper.Cmd{
		{fmt.Sprintf("%s start 124.65.54.42/24 124.65.54.43/24", topology), true},
		{"docker pull elgalu/selenium", true},
		{"docker run -d --name=grid -p 4444:24444 -p 5900:25900 -e --shm-size=1g elgalu/selenium", true},
		{"docker exec grid wait_all_done 30s", true},
	}

	tearDownCmds := []helper.Cmd{
		{fmt.Sprintf("%s stop", topology), true},
		{"docker stop grid", true},
		{"docker rm -f grid", true},
	}

	helper.ExecCmds(t, setupCmds...)
	defer helper.ExecCmds(t, tearDownCmds...)

	caps := selenium.Capabilities{"browserName": "chrome"}
	webdriver, err := selenium.NewRemote(caps, "http://127.0.0.1:4444/wd/hub")
	if err != nil {
		t.Fatal(err)
	}
	defer webdriver.Quit()

	ipaddr, err := getIPv4Addr()
	if err != nil {
		t.Fatalf("Not able to find Analayzer addr: %v", err)
	}

	if err := webdriver.Get("http://" + ipaddr + ":8082"); err != nil {
		t.Fatal(err)
	}
	time.Sleep(5 * time.Second)

	startCapture := func(wd selenium.WebDriver) error {
		captureTab, err := wd.FindElement(selenium.ByXPATH, ".//*[@id='Captures']")
		if err != nil || captureTab == nil {
			return fmt.Errorf("Not found capture tab: %v", err)
		}
		if err := captureTab.Click(); err != nil {
			return fmt.Errorf("%v", err)
		}
		createBtn, err := wd.FindElement(selenium.ByXPATH, ".//*[@id='create-capture']")
		if err != nil || createBtn == nil {
			return fmt.Errorf("Not found create button : %v", err)
		}
		if err := createBtn.Click(); err != nil {
			return fmt.Errorf("%v", err)
		}
		time.Sleep(2 * time.Second)

		gremlinRdoBtn, err := wd.FindElement(selenium.ByXPATH, ".//*[@id='by-gremlin']")
		if err != nil || gremlinRdoBtn == nil {
			return fmt.Errorf("Not found gremlin expression radio button: %v", err)
		}
		if err := gremlinRdoBtn.Click(); err != nil {
			return err
		}

		queryTxtBox, err := wd.FindElement(selenium.ByXPATH, ".//*[@id='capture-query']")
		if err != nil || queryTxtBox == nil {
			return fmt.Errorf("Not found Query text box: %v", err)
		}
		if err := queryTxtBox.Clear(); err != nil {
			return err
		}
		if err := queryTxtBox.SendKeys("G.V().Has('Name', 'br-int', 'Type', 'ovsbridge')"); err != nil {
			return err
		}

		startBtn, err := wd.FindElement(selenium.ByXPATH, ".//*[@id='start-capture']")
		if err != nil || startBtn == nil {
			return fmt.Errorf("Not found start button: %v", err)
		}
		if err := startBtn.Click(); err != nil {
			return err
		}
		time.Sleep(3 * time.Second)

		//check capture created with the given query
		captures, err := wd.FindElements(selenium.ByClassName, "query")
		if err != nil {
			return err
		}
		var foundCapture bool
		for _, capture := range captures {
			if txt, _ := capture.Text(); txt == "G.V().Has('Name', 'br-int', 'Type', 'ovsbridge')" {
				foundCapture = true
				break
			}

		}
		if !foundCapture {
			return fmt.Errorf("Capture not found in the list")
		}
		return nil
	}

	findElement := func(wd selenium.WebDriver, selection, xpath string) (el selenium.WebElement, err error) {
		common.Retry(func() error {
			el, err = wd.FindElement(selection, xpath)
			if err != nil || el == nil {
				return fmt.Errorf("Failed to find element for %s (error: %+v)", xpath, err)
			}
			return nil
		}, 10, time.Second)
		return
	}

	injectPacket := func(wd selenium.WebDriver) error {
		generatorTab, err := findElement(wd, selenium.ByXPATH, ".//*[@id='Generator']")
		if err != nil {
			return err
		}

		err = common.Retry(func() error {
			return generatorTab.Click()
		}, 10, time.Second)
		if err != nil {
			return fmt.Errorf("Could not click on generator tab: %s", err.Error())
		}

		injectSrc, err := findElement(wd, selenium.ByXPATH, ".//*[@id='inject-src']/input")
		if err != nil {
			return err
		}

		if err := injectSrc.Click(); err != nil {
			return fmt.Errorf("Failed to click on inject input: %s", err.Error())
		}

		authOptions := &shttp.AuthenticationOpts{}
		gh := gclient.NewGremlinQueryHelper(authOptions)

		node1, err := gh.GetNode("G.V().Has('Name', 'eth0', 'IPV4', Contains('124.65.54.42/24')).HasKey('TID')")
		if err != nil {
			return err
		}

		node2, err := gh.GetNode("G.V().Has('Name', 'eth0', 'IPV4', Contains('124.65.54.43/24')).HasKey('TID')")
		if err != nil {
			return err
		}

		tid1, _ := node1.GetFieldString("TID")
		tid2, _ := node2.GetFieldString("TID")

		srcNode, err := findElement(wd, selenium.ByXPATH, ".//*[@tid='"+tid1+"']")
		if err != nil {
			return err
		}

		if err := srcNode.Click(); err != nil {
			return fmt.Errorf("Failed to click on source node: %s", err.Error())
		}

		injectDst, err := findElement(wd, selenium.ByXPATH, ".//*[@id='inject-dst']/input")
		if err != nil {
			return err
		}
		if err := injectDst.Click(); err != nil {
			return fmt.Errorf("Failed to click on destination input: %s", err.Error())
		}

		dstNode, err := findElement(wd, selenium.ByXPATH, ".//*[@tid='"+tid2+"']")
		if err != nil {
			return err
		}
		if err := dstNode.Click(); err != nil {
			return fmt.Errorf("Failed to click on destination node: %s", err.Error())
		}

		injectBtn, err := findElement(wd, selenium.ByXPATH, ".//*[@id='inject']")
		if err != nil {
			return err
		}
		if err := injectBtn.Click(); err != nil {
			return fmt.Errorf("Failed to click on inject button: %s", err.Error())
		}

		var alertMsg selenium.WebElement
		err = common.Retry(func() error {
			alertMsg, err = findElement(wd, selenium.ByClassName, "alert-success")
			return err
		}, 10, time.Second)
		if err != nil {
			return err
		}

		closeBtn, _ := alertMsg.FindElement(selenium.ByClassName, "close")
		if closeBtn != nil {
			closeBtn.Click()
		}

		return nil
	}

	verifyFlows := func(wd selenium.WebDriver) error {
		time.Sleep(3 * time.Second)

		flowsTab, err := wd.FindElement(selenium.ByXPATH, ".//*[@id='Flows']")
		if err != nil || flowsTab == nil {
			return fmt.Errorf("Flows tab not found: %v", err)
		}
		if err := flowsTab.Click(); err != nil {
			return err
		}

		flowQuery, err := wd.FindElement(selenium.ByXPATH, ".//*[@id='flow-table-query']")
		if err != nil || flowQuery == nil {
			return err
		}
		if err := flowQuery.Clear(); err != nil {
			return err
		}
		query := "G.Flows().Has('Network.A', '124.65.54.42', 'Network.B', '124.65.54.43')"
		if err := flowQuery.SendKeys(query); err != nil {
			return err
		}

		time.Sleep(2 * time.Second)

		flowRow, err := wd.FindElement(selenium.ByClassName, "flow-row")
		if err != nil || flowRow == nil {
			return err
		}
		rowData, err := flowRow.FindElements(selenium.ByTagName, "td")
		if err != nil {
			return err
		}
		if len(rowData) != 7 {
			return fmt.Errorf("By default 7 rows should be return")
		}
		txt, err := rowData[1].Text()
		if err != nil {
			return err
		}
		if txt != "124.65.54.42" {
			return fmt.Errorf("Network.A should be '124.65.54.42' but got: %s", txt)
		}
		return nil
	}

	if err := startCapture(webdriver); err != nil {
		t.Fatal(err)
	}

	if err := injectPacket(webdriver); err != nil {
		t.Fatal(err)
	}

	if err := verifyFlows(webdriver); err != nil {
		t.Fatal(err)
	}
}

func getIPv4Addr() (string, error) {
	ifaces, err := net.Interfaces()
	if err != nil {
		return "", err
	}

	for _, iface := range ifaces {
		//neglect interfaces which are down
		if iface.Flags&net.FlagUp == 0 {
			continue
		}
		//neglect loopback interface
		if iface.Flags&net.FlagLoopback != 0 {
			continue
		}
		addrs, err := iface.Addrs()
		if err != nil {
			return "", err
		}
		for _, addr := range addrs {
			var ip net.IP
			switch t := addr.(type) {
			case *net.IPNet:
				ip = t.IP
			case *net.IPAddr:
				ip = t.IP
			}
			if ip == nil || ip.IsLoopback() {
				continue
			}
			ip = ip.To4()
			if ip != nil {
				return ip.String(), nil
			}
		}
	}
	return "", fmt.Errorf("No IP found")
}
<|endoftext|>


<commit_before>package mocks

import "github.com/materials-commons/testify/mock"

import (
	"github.com/materials-commons/mcstore/pkg/db/schema"
	"fmt"
)

type Files struct {
	mock.Mock
}

func NewMFiles() *Files {
	return &Files{}
}

func (m *Files) ByID(id string) (*schema.File, error) {
	ret := m.Called(id)

	r0 := ret.Get(0).(*schema.File)
	r1 := ret.Error(1)

	return r0, r1
}

func (m *Files) ByChecksum(checksum string) (*schema.File, error) {
	ret := m.Called(checksum)

	r0 := ret.Get(0).(*schema.File)
	r1 := ret.Error(1)

	return r0, r1
}

func (m *Files) ByPath(name, dirID string) (*schema.File, error) {
	ret := m.Called(name, dirID)
	r0 := ret.Get(0).(*schema.File)
	r1 := ret.Error(1)
	return r0, r1
}

func (m *Files) Insert(file *schema.File, dirID string, projectID string) (*schema.File, error) {
	ret := m.Called()
	r0 := ret.Get(0).(*schema.File)
	r1 := ret.Error(1)
	return r0, r1
}

func (m *Files) Update(file *schema.File) error {
	ret := m.Called()
	r0 := ret.Error(0)
	return r0
}

func (m *Files) UpdateFields(fileID string, fields map[string]interface{}) error {
	ret := m.Called(fileID)
	r0 := ret.Error(0)
	return r0
}

func (m *Files) Delete(fileID, directoryID, projectID string) (*schema.File, error) {
	ret := m.Called(fileID, directoryID, projectID)
	r0 := ret.Get(0).(*schema.File)
	r1 := ret.Error(1)
	return r0, r1
}

func (m *Files) GetProject(fileID string) (*schema.Project, error) {
	ret := m.Called(fileID)
	r0 := ret.Get(0).(*schema.Project)
	r1 := ret.Error(1)
	return r0, r1
}

type fentry struct {
	file *schema.File
	err error
	project *schema.Project
}

type Files2 struct {
	method map[string]*fentry
	currentMethod string
}

func NewMFiles2() *Files2 {
	return &Files2{
		method: make(map[string]*fentry),
	}
}

func (m *Files2) lookup(method string) *fentry {
	if e, ok := m.method[method]; ok {
		return e
	}
	panic(fmt.Sprintf("Unable to find method: %s", method))
}

func (m *Files2) ByID(id string) (*schema.File, error) {
	e := m.lookup("ByID")
	return e.file, e.err
}

func (m *Files2) ByChecksum(checksum string) (*schema.File, error) {
	e := m.lookup("ByChecksum")
	return e.file, e.err
}

func (m *Files2) ByPath(name, dirID string) (*schema.File, error) {
	e := m.lookup("ByPath")
	return e.file, e.err
}

func (m *Files2) Insert(file *schema.File, dirID string, projectID string) (*schema.File, error) {
	e := m.lookup("Insert")
	return e.file, e.err
}

func (m *Files2) Update(file *schema.File) error {
	e := m.lookup("Update")
	return e.err
}

func (m *Files2) UpdateFields(fileID string, fields map[string]interface{}) error {
	e := m.lookup("UpdateFields")
	return e.err
}

func (m *Files2) Delete(fileID, directoryID, projectID string) (*schema.File, error) {
	e := m.lookup("Delete")
	return e.file, e.err
}

func (m *Files2) GetProject(fileID string) (*schema.Project, error) {
	e := m.lookup("GetProject")
	return e.project, e.err
}

func (m *Files2) On(method string) *Files2 {
	m.currentMethod = method
	m.method[method] = &fentry{}
	return m
}

func (m *Files2) SetError(err error) *Files2 {
	m.method[m.currentMethod].err = err
	return m
}

func (m *Files2) SetFile(file *schema.File) *Files2 {
	m.method[m.currentMethod].file = file
	return m
}

func (m *Files2) SetProject(project *schema.Project) *Files2 {
	m.method[m.currentMethod].project = project
	return m
}<commit_msg>gofmt<commit_after>package mocks

import "github.com/materials-commons/testify/mock"

import (
	"fmt"
	"github.com/materials-commons/mcstore/pkg/db/schema"
)

type Files struct {
	mock.Mock
}

func NewMFiles() *Files {
	return &Files{}
}

func (m *Files) ByID(id string) (*schema.File, error) {
	ret := m.Called(id)

	r0 := ret.Get(0).(*schema.File)
	r1 := ret.Error(1)

	return r0, r1
}

func (m *Files) ByChecksum(checksum string) (*schema.File, error) {
	ret := m.Called(checksum)

	r0 := ret.Get(0).(*schema.File)
	r1 := ret.Error(1)

	return r0, r1
}

func (m *Files) ByPath(name, dirID string) (*schema.File, error) {
	ret := m.Called(name, dirID)
	r0 := ret.Get(0).(*schema.File)
	r1 := ret.Error(1)
	return r0, r1
}

func (m *Files) Insert(file *schema.File, dirID string, projectID string) (*schema.File, error) {
	ret := m.Called()
	r0 := ret.Get(0).(*schema.File)
	r1 := ret.Error(1)
	return r0, r1
}

func (m *Files) Update(file *schema.File) error {
	ret := m.Called()
	r0 := ret.Error(0)
	return r0
}

func (m *Files) UpdateFields(fileID string, fields map[string]interface{}) error {
	ret := m.Called(fileID)
	r0 := ret.Error(0)
	return r0
}

func (m *Files) Delete(fileID, directoryID, projectID string) (*schema.File, error) {
	ret := m.Called(fileID, directoryID, projectID)
	r0 := ret.Get(0).(*schema.File)
	r1 := ret.Error(1)
	return r0, r1
}

func (m *Files) GetProject(fileID string) (*schema.Project, error) {
	ret := m.Called(fileID)
	r0 := ret.Get(0).(*schema.Project)
	r1 := ret.Error(1)
	return r0, r1
}

type fentry struct {
	file    *schema.File
	err     error
	project *schema.Project
}

type Files2 struct {
	method        map[string]*fentry
	currentMethod string
}

func NewMFiles2() *Files2 {
	return &Files2{
		method: make(map[string]*fentry),
	}
}

func (m *Files2) lookup(method string) *fentry {
	if e, ok := m.method[method]; ok {
		return e
	}
	panic(fmt.Sprintf("Unable to find method: %s", method))
}

func (m *Files2) ByID(id string) (*schema.File, error) {
	e := m.lookup("ByID")
	return e.file, e.err
}

func (m *Files2) ByChecksum(checksum string) (*schema.File, error) {
	e := m.lookup("ByChecksum")
	return e.file, e.err
}

func (m *Files2) ByPath(name, dirID string) (*schema.File, error) {
	e := m.lookup("ByPath")
	return e.file, e.err
}

func (m *Files2) Insert(file *schema.File, dirID string, projectID string) (*schema.File, error) {
	e := m.lookup("Insert")
	return e.file, e.err
}

func (m *Files2) Update(file *schema.File) error {
	e := m.lookup("Update")
	return e.err
}

func (m *Files2) UpdateFields(fileID string, fields map[string]interface{}) error {
	e := m.lookup("UpdateFields")
	return e.err
}

func (m *Files2) Delete(fileID, directoryID, projectID string) (*schema.File, error) {
	e := m.lookup("Delete")
	return e.file, e.err
}

func (m *Files2) GetProject(fileID string) (*schema.Project, error) {
	e := m.lookup("GetProject")
	return e.project, e.err
}

func (m *Files2) On(method string) *Files2 {
	m.currentMethod = method
	m.method[method] = &fentry{}
	return m
}

func (m *Files2) SetError(err error) *Files2 {
	m.method[m.currentMethod].err = err
	return m
}

func (m *Files2) SetFile(file *schema.File) *Files2 {
	m.method[m.currentMethod].file = file
	return m
}

func (m *Files2) SetProject(project *schema.Project) *Files2 {
	m.method[m.currentMethod].project = project
	return m
}
<|endoftext|>