<commit_before>package http

import (
	"database/sql"
	"database/sql/driver"
	"encoding/json"
	"strconv"
	"strings"

	"github.com/pkg/errors"

	"github.com/amsokol/go-ignite-client/sql/http/v1"
)

type connectionInfo struct {
	Version    float64  `json:"version"`
	Servers    []string `json:"servers"`
	Username   string   `json:"username"`
	Password   string   `json:"password"`
	Cache      string   `json:"cache"`
	PageSize   int64    `json:"pageSize"`
	Quarantine float64  `json:"quarantine"`
}

// Driver is exported to allow it to be used directly.
type Driver struct{}

// Open a Connection to the server.
func (a *Driver) Open(name string) (driver.Conn, error) {
	ci := connectionInfo{}

	err := json.Unmarshal([]byte(name), &ci)
	if err != nil {
		return nil, errors.Wrap(err, "Invalid format of connection information")
	}

	if len(ci.Servers) == 0 {
		return nil, errors.New("You need to provide at least one server")
	}

	if len(ci.Cache) == 0 {
		return nil, errors.New("You need to provide cache name")
	}

	if ci.PageSize == 0 {
		// set default value 1000
		ci.PageSize = 1000
	}

	if ci.Quarantine == 0 {
		// set default value 30 min
		ci.Quarantine = 30
	}

	if ci.Version == 0 {
		// set default version is 1.0
		ci.Version = 1.0
	}

	var conn driver.Conn
	switch ci.Version {
	case 1:
		conn = v1.Open(ci.Servers, ci.Quarantine, ci.Username, ci.Password, ci.Cache, ci.PageSize)
	case 2:
		conn = v1.Open(ci.Servers, ci.Quarantine, ci.Username, ci.Password, ci.Cache, ci.PageSize)
	default:
		return nil, errors.New(strings.Join([]string{"Unsupported HTTP REST API version v",
			strconv.FormatFloat(ci.Version, 'f', -1, 64), ". Supported versions are \"1\" and \"2\""}, ""))
	}

	return conn, nil
}

// Init Initializes driver
func init() {
	sql.Register("ignite-sql-http", &Driver{})
}
<commit_msg>fixed BUG: connection v1 is used for API v2<commit_after>package http

import (
	"database/sql"
	"database/sql/driver"
	"encoding/json"
	"strconv"
	"strings"

	"github.com/pkg/errors"

	"github.com/amsokol/go-ignite-client/sql/http/v1"
	"github.com/amsokol/go-ignite-client/sql/http/v2"
)

type connectionInfo struct {
	Version    float64  `json:"version"`
	Servers    []string `json:"servers"`
	Username   string   `json:"username"`
	Password   string   `json:"password"`
	Cache      string   `json:"cache"`
	PageSize   int64    `json:"pageSize"`
	Quarantine float64  `json:"quarantine"`
}

// Driver is exported to allow it to be used directly.
type Driver struct{}

// Open a Connection to the server.
func (a *Driver) Open(name string) (driver.Conn, error) {
	ci := connectionInfo{}

	err := json.Unmarshal([]byte(name), &ci)
	if err != nil {
		return nil, errors.Wrap(err, "Invalid format of connection information")
	}

	if len(ci.Servers) == 0 {
		return nil, errors.New("You need to provide at least one server")
	}

	if len(ci.Cache) == 0 {
		return nil, errors.New("You need to provide cache name")
	}

	if ci.PageSize == 0 {
		// set default value 1000
		ci.PageSize = 1000
	}

	if ci.Quarantine == 0 {
		// set default value 30 min
		ci.Quarantine = 30
	}

	if ci.Version == 0 {
		// set default version is 1.0
		ci.Version = 1.0
	}

	var conn driver.Conn
	switch ci.Version {
	case 1:
		conn = v1.Open(ci.Servers, ci.Quarantine, ci.Username, ci.Password, ci.Cache, ci.PageSize)
	case 2:
		conn = v2.Open(ci.Servers, ci.Quarantine, ci.Username, ci.Password, ci.Cache, ci.PageSize)
	default:
		return nil, errors.New(strings.Join([]string{"Unsupported HTTP REST API version v",
			strconv.FormatFloat(ci.Version, 'f', -1, 64), ". Supported versions are \"1\" and \"2\""}, ""))
	}

	return conn, nil
}

// Init Initializes driver
func init() {
	sql.Register("ignite-sql-http", &Driver{})
}
<|endoftext|>


<commit_before>/*
Copyright 2021 The TestGrid Authors.

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

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

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

package prometheus

import (
	"net/http"
	"strings"

	"github.com/GoogleCloudPlatform/testgrid/util/metrics"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	dto "github.com/prometheus/client_model/go"
)

// Valuer extends a metric to include a report on its values.
type Valuer interface {
	metrics.Metric
	Values() map[string]float64
}

type int64Metric struct {
	name   string
	fields map[string]bool
	met    *prometheus.GaugeVec
}

// init sets up the Prometheus endpoint at this port and URL when the package is imported
func init() {
	go func() {
		http.Handle("/metrics", promhttp.Handler())
		http.ListenAndServe(":2112", nil)
	}()
}

// NewInt64 creates and registers an Int64 metric with Prometheus.
func NewInt64(name, desc string, fields ...string) metrics.Int64 {
	m := prometheus.NewGaugeVec(prometheus.GaugeOpts{
		Name: name,
		Help: desc,
	}, fields)
	prometheus.MustRegister(m)
	return &int64Metric{
		name:   name,
		fields: make(map[string]bool),
		met:    m,
	}
}

// Name returns the metric's name.
func (m *int64Metric) Name() string {
	return m.name
}

// Set the metric's value to the given number.
func (m *int64Metric) Set(n int64, fields ...string) {
	m.met.WithLabelValues(fields...).Set(float64(n))
	m.fields[strings.Join(fields, "|")] = true
}

func gaugeValue(metric *prometheus.GaugeVec, labels ...string) float64 {
	var m = &dto.Metric{}
	if err := metric.WithLabelValues(labels...).Write(m); err != nil {
		return 0
	}
	return m.Gauge.GetValue()
}

// Values returns each field and its current value.
func (m *int64Metric) Values() map[string]float64 {
	values := make(map[string]float64)
	for fieldStr := range m.fields {
		fields := strings.Split(fieldStr, "|")
		values[fieldStr] = gaugeValue(m.met, fields...)
	}
	return values
}

type counterMetric struct {
	name   string
	fields map[string]bool
	met    *prometheus.CounterVec
}

// NewCounter creates and registers a strictly-increasing counter metric with Prometheus.
func NewCounter(name, desc string, fields ...string) metrics.Counter {
	m := prometheus.NewCounterVec(prometheus.CounterOpts{
		Name: name,
		Help: desc,
	}, fields)
	prometheus.MustRegister(m)
	return &counterMetric{
		name:   name,
		fields: make(map[string]bool),
		met:    m,
	}
}

// Name returns the metric's name.
func (m *counterMetric) Name() string {
	return m.name
}

// Add the given number to the Counter.
func (m *counterMetric) Add(n int64, fields ...string) {
	m.met.WithLabelValues(fields...).Add(float64(n))
	m.fields[strings.Join(fields, "|")] = true
}

func counterValue(metric *prometheus.CounterVec, labels ...string) float64 {
	var m = &dto.Metric{}
	if err := metric.WithLabelValues(labels...).Write(m); err != nil {
		return 0
	}
	return m.Counter.GetValue()
}

// Values returns each field and its current value.
func (m *counterMetric) Values() map[string]float64 {
	values := make(map[string]float64)
	for fieldStr := range m.fields {
		fields := strings.Split(fieldStr, "|")
		values[fieldStr] = counterValue(m.met, fields...)
	}
	return values
}
<commit_msg>Make prometheus metrics safe for concurrency<commit_after>/*
Copyright 2021 The TestGrid Authors.

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

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

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

package prometheus

import (
	"net/http"
	"strings"
	"sync"

	"github.com/GoogleCloudPlatform/testgrid/util/metrics"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	dto "github.com/prometheus/client_model/go"
)

// Valuer extends a metric to include a report on its values.
type Valuer interface {
	metrics.Metric
	Values() map[string]float64
}

type int64Metric struct {
	name   string
	fields map[string]bool
	met    *prometheus.GaugeVec
	lock   sync.RWMutex
}

// init sets up the Prometheus endpoint at this port and URL when the package is imported
func init() {
	go func() {
		http.Handle("/metrics", promhttp.Handler())
		http.ListenAndServe(":2112", nil)
	}()
}

// NewInt64 creates and registers an Int64 metric with Prometheus.
func NewInt64(name, desc string, fields ...string) metrics.Int64 {
	m := prometheus.NewGaugeVec(prometheus.GaugeOpts{
		Name: name,
		Help: desc,
	}, fields)
	prometheus.MustRegister(m)
	return &int64Metric{
		name:   name,
		fields: map[string]bool{},
		met:    m,
	}
}

// Name returns the metric's name.
func (m *int64Metric) Name() string {
	return m.name
}

// Set the metric's value to the given number.
func (m *int64Metric) Set(n int64, fields ...string) {
	m.lock.Lock()
	defer m.lock.Unlock()
	m.met.WithLabelValues(fields...).Set(float64(n))
	m.fields[strings.Join(fields, "|")] = true
}

func gaugeValue(metric *prometheus.GaugeVec, labels ...string) float64 {
	var m = &dto.Metric{}
	if err := metric.WithLabelValues(labels...).Write(m); err != nil {
		return 0
	}
	return m.Gauge.GetValue()
}

// Values returns each field and its current value.
func (m *int64Metric) Values() map[string]float64 {
	values := map[string]float64{}
	m.lock.RLock()
	defer m.lock.RUnlock()
	for fieldStr := range m.fields {
		fields := strings.Split(fieldStr, "|")
		values[fieldStr] = gaugeValue(m.met, fields...)
	}
	return values
}

type counterMetric struct {
	name   string
	fields map[string]bool
	met    *prometheus.CounterVec
	lock   sync.RWMutex
}

// NewCounter creates and registers a strictly-increasing counter metric with Prometheus.
func NewCounter(name, desc string, fields ...string) metrics.Counter {
	m := prometheus.NewCounterVec(prometheus.CounterOpts{
		Name: name,
		Help: desc,
	}, fields)
	prometheus.MustRegister(m)
	return &counterMetric{
		name:   name,
		fields: map[string]bool{},
		met:    m,
	}
}

// Name returns the metric's name.
func (m *counterMetric) Name() string {
	return m.name
}

// Add the given number to the Counter.
func (m *counterMetric) Add(n int64, fields ...string) {
	m.met.WithLabelValues(fields...).Add(float64(n))
	m.lock.Lock()
	defer m.lock.Unlock()
	m.fields[strings.Join(fields, "|")] = true
}

func counterValue(metric *prometheus.CounterVec, labels ...string) float64 {
	var m = &dto.Metric{}
	if err := metric.WithLabelValues(labels...).Write(m); err != nil {
		return 0
	}
	return m.Counter.GetValue()
}

// Values returns each field and its current value.
func (m *counterMetric) Values() map[string]float64 {
	values := map[string]float64{}
	m.lock.RLock()
	defer m.lock.RUnlock()
	for fieldStr := range m.fields {
		fields := strings.Split(fieldStr, "|")
		values[fieldStr] = counterValue(m.met, fields...)
	}
	return values
}
<|endoftext|>


<commit_before>package limio

import (
	"io"
	"log"
	"strings"
	"sync"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"

	_ "net/http/pprof"
)

func verifyIsManager(m Manager) {}

func TestManager(t *testing.T) {
	asrt := assert.New(t)
	lmr := NewSimpleManager()

	asrt.Implements((*Manager)(nil), lmr)

	ch := make(chan int, 1)
	lmr.Limit(ch)

	l1 := lmr.NewReader(strings.NewReader(testText))
	l2 := lmr.NewReader(strings.NewReader(testText))

	p := make([]byte, len(testText))

	ch <- 20

	n, err := l1.Read(p)

	asrt.NoError(err)
	asrt.Equal(10, n)

	n, err = l2.Read(p)

	asrt.NoError(err)
	asrt.Equal(10, n)

	l3 := lmr.NewReader(strings.NewReader(testText))
	asrt.NoError(lmr.Manage(l3))

	ch <- 30

	n, err = l3.Read(p)
	assert.NoError(t, err)
	asrt.Equal(n, 10)

	l1.Read(p)
	l2.Read(p)
	lmr.Unmanage(l3)

	log.Println("unmanage done")

	lmr.SimpleLimit(KB, 10*time.Millisecond)

	//Drain channel
	n, err = l1.Read(p)
	m, err := l2.Read(p)

	if n+m != 1024 {
		t.Errorf("Wrong number of bytes read: %d, should be 1024", n+m)
	}
	if err != nil {
		t.Errorf("Error reading: %v", err)
	}

	lmr.Unlimit()

	n, err = l1.Read(p)

	if n != len(testText)-20-m {
		t.Errorf("Wrong number read after unlimit: %d", n)
	}

	if err != nil && err != io.EOF {
		t.Errorf("Error reading unlimited: %v", err)
	}

	n, err = l2.Read(p)

	if n != len(testText)-20-m {
		t.Errorf("Wrong number read after unlimit: %d", n)
	}

	if err != nil && err != io.EOF {
		t.Errorf("Error reading unlimited: %v", err)
	}

	_, err = l2.Read(p)

	if err != io.EOF {
		t.Errorf("Should have thrown EOF after reached EOF.")
	}

	done := lmr.SimpleLimit(KB, time.Second)
	lmr.Manage(l3)

	w := &sync.WaitGroup{}
	w.Add(1)

	go func() {
		if cls := <-done; !cls {
			t.Errorf("Did not close \"done\" and pass true. Done: %t", cls)
		}
		w.Done()
	}()

	err = lmr.Close()

	if err != nil {
		t.Errorf("Error closing lmr: %v", err)
	}

	n, err = l3.Read(p)

	if n != len(testText)-10 {
		t.Errorf("Wrong number of bytes read: %d, should be %d", n, len(testText)-10)
	}
	w.Wait()
}
<commit_msg>More updates to limit manager test<commit_after>package limio

import (
	"io"
	"strings"
	"sync"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"

	_ "net/http/pprof"
)

func verifyIsManager(m Manager) {}

func TestManager(t *testing.T) {
	asrt := assert.New(t)
	lmr := NewSimpleManager()

	asrt.Implements((*Manager)(nil), lmr)

	ch := make(chan int, 1)
	lmr.Limit(ch)

	l1 := lmr.NewReader(strings.NewReader(testText))
	l2 := lmr.NewReader(strings.NewReader(testText))

	p := make([]byte, len(testText))

	ch <- 20

	t.Log("Reading 1")

	n, err := l1.Read(p)

	t.Logf("Read 1: %d", n)

	asrt.NoError(err)
	asrt.Equal(10, n)

	t.Log("Reading 2")

	n, err = l2.Read(p)

	t.Logf("Read 2: %d", n)

	asrt.NoError(err)
	asrt.Equal(10, n)

	l3 := lmr.NewReader(strings.NewReader(testText))
	asrt.NoError(lmr.Manage(l3))

	ch <- 30

	t.Log("Reading 3")

	n, err = l3.Read(p)
	assert.NoError(t, err)
	asrt.Equal(n, 10)

	t.Logf("Read 3: %d", n)

	_, err = l1.Read(p)
	asrt.NoError(err)
	_, err = l2.Read(p)
	asrt.NoError(err)
	lmr.Unmanage(l3)

	t.Log("unmanage done")

	lmr.SimpleLimit(KB, 10*time.Millisecond)

	//Drain channel
	n, err = l1.Read(p)
	asrt.NoError(err)
	m, err := l2.Read(p)

	asrt.NoError(err)
	asrt.Equal(1024, n+m, "Wrong number of total bytes read")
	if err != nil {
		t.Errorf("Error reading: %v", err)
	}

	lmr.Unlimit()

	n, err = l1.Read(p)

	if n != len(testText)-20-m {
		t.Errorf("Wrong number read after unlimit: %d", n)
	}

	if err != nil && err != io.EOF {
		t.Errorf("Error reading unlimited: %v", err)
	}

	n, err = l2.Read(p)

	if n != len(testText)-20-m {
		t.Errorf("Wrong number read after unlimit: %d", n)
	}

	if err != nil && err != io.EOF {
		t.Errorf("Error reading unlimited: %v", err)
	}

	_, err = l2.Read(p)

	if err != io.EOF {
		t.Errorf("Should have thrown EOF after reached EOF.")
	}

	done := lmr.SimpleLimit(KB, time.Second)
	lmr.Manage(l3)

	w := &sync.WaitGroup{}
	w.Add(1)

	go func() {
		if cls := <-done; !cls {
			t.Errorf("Did not close \"done\" and pass true. Done: %t", cls)
		}
		w.Done()
	}()

	err = lmr.Close()

	if err != nil {
		t.Errorf("Error closing lmr: %v", err)
	}

	n, err = l3.Read(p)

	if n != len(testText)-10 {
		t.Errorf("Wrong number of bytes read: %d, should be %d", n, len(testText)-10)
	}
	w.Wait()
}
<|endoftext|>


<commit_before>// Copyright (c) 2013 The Go Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd.

// Package lintutil provides helpers for writing linter command lines.
package lintutil // import "honnef.co/go/lint/lintutil"

import (
	"errors"
	"flag"
	"fmt"
	"go/build"
	"go/parser"
	"log"
	"os"
	"strings"

	"honnef.co/go/lint"

	"github.com/kisielk/gotool"
	"golang.org/x/tools/go/loader"
)

func usage(name string, flags *flag.FlagSet) func() {
	return func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", name)
		fmt.Fprintf(os.Stderr, "\t%s [flags] # runs on package in current directory\n", name)
		fmt.Fprintf(os.Stderr, "\t%s [flags] packages\n", name)
		fmt.Fprintf(os.Stderr, "\t%s [flags] directory\n", name)
		fmt.Fprintf(os.Stderr, "\t%s [flags] files... # must be a single package\n", name)
		fmt.Fprintf(os.Stderr, "Flags:\n")
		flags.PrintDefaults()
	}
}

type runner struct {
	checker lint.Checker
	tags    []string
	ignores []lint.Ignore

	unclean bool
}

func (runner runner) resolveRelative(importPaths []string) (goFiles bool, err error) {
	if len(importPaths) == 0 {
		return false, nil
	}
	if strings.HasSuffix(importPaths[0], ".go") {
		// User is specifying a package in terms of .go files, don't resolve
		return true, nil
	}
	wd, err := os.Getwd()
	if err != nil {
		return false, err
	}
	ctx := build.Default
	ctx.BuildTags = runner.tags
	for i, path := range importPaths {
		bpkg, err := ctx.Import(path, wd, build.FindOnly)
		if err != nil {
			return false, fmt.Errorf("can't load package %q: %v", path, err)
		}
		importPaths[i] = bpkg.ImportPath
	}
	return false, nil
}

func parseIgnore(s string) ([]lint.Ignore, error) {
	var out []lint.Ignore
	if len(s) == 0 {
		return nil, nil
	}
	for _, part := range strings.Fields(s) {
		p := strings.Split(part, ":")
		if len(p) != 2 {
			return nil, errors.New("malformed ignore string")
		}
		path := p[0]
		checks := strings.Split(p[1], ",")
		out = append(out, lint.Ignore{Pattern: path, Checks: checks})
	}
	return out, nil
}

func ProcessArgs(name string, c lint.Checker, args []string) {
	flags := flag.NewFlagSet("", flag.ExitOnError)
	flags.Usage = usage(name, flags)
	flags.Float64("min_confidence", 0, "Deprecated; use -ignore instead")
	tags := flags.String("tags", "", "List of `build tags`")
	ignore := flags.String("ignore", "", "Space separated list of checks to ignore, in the following format: 'import/path/file.go:Check1,Check2,...' Both the import path and file name sections support globbing, e.g. 'os/exec/*_test.go'")
	flags.Parse(args)

	ignores, err := parseIgnore(*ignore)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	runner := &runner{
		checker: c,
		tags:    strings.Fields(*tags),
		ignores: ignores,
	}
	paths := gotool.ImportPaths(flags.Args())
	goFiles, err := runner.resolveRelative(paths)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		runner.unclean = true
	}
	ctx := build.Default
	ctx.BuildTags = runner.tags
	conf := &loader.Config{
		Build:      &ctx,
		ParserMode: parser.ParseComments,
	}
	if goFiles {
		conf.CreateFromFilenames("adhoc", paths...)
		lprog, err := conf.Load()
		if err != nil {
			log.Fatal(err)
		}
		ps := runner.lint(lprog)
		for _, ps := range ps {
			for _, p := range ps {
				runner.unclean = true
				fmt.Printf("%v: %s\n", p.Position, p.Text)
			}
		}
	} else {
		conf.TypeCheckFuncBodies = func(s string) bool {
			for _, path := range paths {
				if s == path || s == path+"_test" {
					return true
				}
			}
			return false
		}
		for _, path := range paths {
			conf.ImportWithTests(path)
		}
		lprog, err := conf.Load()
		if err != nil {
			log.Fatal(err)
		}
		ps := runner.lint(lprog)
		for _, ps := range ps {
			for _, p := range ps {
				runner.unclean = true
				fmt.Printf("%v: %s\n", p.Position, p.Text)
			}

		}
	}
	if runner.unclean {
		os.Exit(1)
	}
}

func (runner *runner) lint(lprog *loader.Program) map[string][]lint.Problem {
	l := &lint.Linter{
		Checker: runner.checker,
		Ignores: runner.ignores,
	}
	return l.Lint(lprog)
}
<commit_msg>Add flag to control checking of tests<commit_after>// Copyright (c) 2013 The Go Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd.

// Package lintutil provides helpers for writing linter command lines.
package lintutil // import "honnef.co/go/lint/lintutil"

import (
	"errors"
	"flag"
	"fmt"
	"go/build"
	"go/parser"
	"log"
	"os"
	"strings"

	"honnef.co/go/lint"

	"github.com/kisielk/gotool"
	"golang.org/x/tools/go/loader"
)

func usage(name string, flags *flag.FlagSet) func() {
	return func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", name)
		fmt.Fprintf(os.Stderr, "\t%s [flags] # runs on package in current directory\n", name)
		fmt.Fprintf(os.Stderr, "\t%s [flags] packages\n", name)
		fmt.Fprintf(os.Stderr, "\t%s [flags] directory\n", name)
		fmt.Fprintf(os.Stderr, "\t%s [flags] files... # must be a single package\n", name)
		fmt.Fprintf(os.Stderr, "Flags:\n")
		flags.PrintDefaults()
	}
}

type runner struct {
	checker lint.Checker
	tags    []string
	ignores []lint.Ignore

	unclean bool
}

func (runner runner) resolveRelative(importPaths []string) (goFiles bool, err error) {
	if len(importPaths) == 0 {
		return false, nil
	}
	if strings.HasSuffix(importPaths[0], ".go") {
		// User is specifying a package in terms of .go files, don't resolve
		return true, nil
	}
	wd, err := os.Getwd()
	if err != nil {
		return false, err
	}
	ctx := build.Default
	ctx.BuildTags = runner.tags
	for i, path := range importPaths {
		bpkg, err := ctx.Import(path, wd, build.FindOnly)
		if err != nil {
			return false, fmt.Errorf("can't load package %q: %v", path, err)
		}
		importPaths[i] = bpkg.ImportPath
	}
	return false, nil
}

func parseIgnore(s string) ([]lint.Ignore, error) {
	var out []lint.Ignore
	if len(s) == 0 {
		return nil, nil
	}
	for _, part := range strings.Fields(s) {
		p := strings.Split(part, ":")
		if len(p) != 2 {
			return nil, errors.New("malformed ignore string")
		}
		path := p[0]
		checks := strings.Split(p[1], ",")
		out = append(out, lint.Ignore{Pattern: path, Checks: checks})
	}
	return out, nil
}

func ProcessArgs(name string, c lint.Checker, args []string) {
	flags := flag.NewFlagSet("", flag.ExitOnError)
	flags.Usage = usage(name, flags)
	flags.Float64("min_confidence", 0, "Deprecated; use -ignore instead")
	tags := flags.String("tags", "", "List of `build tags`")
	ignore := flags.String("ignore", "", "Space separated list of checks to ignore, in the following format: 'import/path/file.go:Check1,Check2,...' Both the import path and file name sections support globbing, e.g. 'os/exec/*_test.go'")
	tests := flags.Bool("tests", true, "Include tests")
	flags.Parse(args)

	ignores, err := parseIgnore(*ignore)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	runner := &runner{
		checker: c,
		tags:    strings.Fields(*tags),
		ignores: ignores,
	}
	paths := gotool.ImportPaths(flags.Args())
	goFiles, err := runner.resolveRelative(paths)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		runner.unclean = true
	}
	ctx := build.Default
	ctx.BuildTags = runner.tags
	conf := &loader.Config{
		Build:      &ctx,
		ParserMode: parser.ParseComments,
		ImportPkgs: map[string]bool{},
	}
	if goFiles {
		conf.CreateFromFilenames("adhoc", paths...)
		lprog, err := conf.Load()
		if err != nil {
			log.Fatal(err)
		}
		ps := runner.lint(lprog)
		for _, ps := range ps {
			for _, p := range ps {
				runner.unclean = true
				fmt.Printf("%v: %s\n", p.Position, p.Text)
			}
		}
	} else {
		conf.TypeCheckFuncBodies = func(s string) bool {
			for _, path := range paths {
				if s == path || s == path+"_test" {
					return true
				}
			}
			return false
		}
		for _, path := range paths {
			conf.ImportPkgs[path] = *tests
		}
		lprog, err := conf.Load()
		if err != nil {
			log.Fatal(err)
		}
		ps := runner.lint(lprog)
		for _, ps := range ps {
			for _, p := range ps {
				runner.unclean = true
				fmt.Printf("%v: %s\n", p.Position, p.Text)
			}

		}
	}
	if runner.unclean {
		os.Exit(1)
	}
}

func (runner *runner) lint(lprog *loader.Program) map[string][]lint.Problem {
	l := &lint.Linter{
		Checker: runner.checker,
		Ignores: runner.ignores,
	}
	return l.Lint(lprog)
}
<|endoftext|>


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

package batchprocessor

import (
	"go.opentelemetry.io/collector/model/pdata"
)

// splitMetrics removes metrics from the input data and returns a new data of the specified size.
func splitMetrics(size int, src pdata.Metrics) pdata.Metrics {
	dataPoints := src.DataPointCount()
	if dataPoints <= size {
		return src
	}
	totalCopiedDataPoints := 0
	dest := pdata.NewMetrics()

	src.ResourceMetrics().RemoveIf(func(srcRs pdata.ResourceMetrics) bool {
		// If we are done skip everything else.
		if totalCopiedDataPoints == size {
			return false
		}

		destRs := dest.ResourceMetrics().AppendEmpty()
		srcRs.Resource().CopyTo(destRs.Resource())

		srcRs.InstrumentationLibraryMetrics().RemoveIf(func(srcIlm pdata.InstrumentationLibraryMetrics) bool {
			// If we are done skip everything else.
			if totalCopiedDataPoints == size {
				return false
			}

			destIlm := destRs.InstrumentationLibraryMetrics().AppendEmpty()
			srcIlm.InstrumentationLibrary().CopyTo(destIlm.InstrumentationLibrary())

			// If possible to move all metrics do that.
			srcDataPointCount := metricSliceDataPointCount(srcIlm.Metrics())
			if size-totalCopiedDataPoints >= srcDataPointCount {
				totalCopiedDataPoints += srcDataPointCount
				srcIlm.Metrics().MoveAndAppendTo(destIlm.Metrics())
				return true
			}

			srcIlm.Metrics().RemoveIf(func(srcMetric pdata.Metric) bool {
				// If we are done skip everything else.
				if totalCopiedDataPoints == size {
					return false
				}
				// If the metric has more data points than free slots we should split it.
				copiedDataPoints, remove := splitMetric(srcMetric, destIlm.Metrics().AppendEmpty(), size-totalCopiedDataPoints)
				totalCopiedDataPoints += copiedDataPoints
				return remove
			})
			return false
		})
		return srcRs.InstrumentationLibraryMetrics().Len() == 0
	})

	return dest
}

// metricSliceDataPointCount calculates the total number of  data points.
func metricSliceDataPointCount(ms pdata.MetricSlice) (dataPointCount int) {
	for k := 0; k < ms.Len(); k++ {
		dataPointCount += metricDataPointCount(ms.At(k))
	}
	return
}

// metricDataPointCount calculates the total number of  data points.
func metricDataPointCount(ms pdata.Metric) (dataPointCount int) {
	switch ms.DataType() {
	case pdata.MetricDataTypeIntGauge:
		dataPointCount = ms.IntGauge().DataPoints().Len()
	case pdata.MetricDataTypeGauge:
		dataPointCount = ms.Gauge().DataPoints().Len()
	case pdata.MetricDataTypeIntSum:
		dataPointCount = ms.IntSum().DataPoints().Len()
	case pdata.MetricDataTypeSum:
		dataPointCount = ms.Sum().DataPoints().Len()
	case pdata.MetricDataTypeHistogram:
		dataPointCount = ms.Histogram().DataPoints().Len()
	case pdata.MetricDataTypeSummary:
		dataPointCount = ms.Summary().DataPoints().Len()
	}
	return
}

// splitMetric removes metric points from the input data and moves data of the specified size to destination.
// Returns size of moved data and boolean describing, whether the metric should be removed from original slice.
func splitMetric(ms, dest pdata.Metric, size int) (int, bool) {
	if metricDataPointCount(ms) <= size {
		ms.CopyTo(dest)
		return metricDataPointCount(ms), true
	}

	msSize, i := metricDataPointCount(ms)-size, 0
	filterDataPoints := func() bool { i++; return i <= msSize }

	dest.SetDataType(ms.DataType())
	dest.SetName(ms.Name())
	dest.SetDescription(ms.Description())
	dest.SetUnit(ms.Unit())

	switch ms.DataType() {
	case pdata.MetricDataTypeIntGauge:
		src := ms.IntGauge().DataPoints()
		dst := dest.IntGauge().DataPoints()
		dst.EnsureCapacity(size)
		for j := 0; j < size; j++ {
			src.At(j).CopyTo(dst.AppendEmpty())
		}
		src.RemoveIf(func(_ pdata.IntDataPoint) bool {
			return filterDataPoints()
		})
	case pdata.MetricDataTypeGauge:
		src := ms.Gauge().DataPoints()
		dst := dest.Gauge().DataPoints()
		dst.EnsureCapacity(size)
		for j := 0; j < size; j++ {
			src.At(j).CopyTo(dst.AppendEmpty())
		}
		src.RemoveIf(func(_ pdata.NumberDataPoint) bool {
			return filterDataPoints()
		})
	case pdata.MetricDataTypeIntSum:
		src := ms.IntSum().DataPoints()
		dst := dest.IntSum().DataPoints()
		dst.EnsureCapacity(size)
		for j := 0; j < size; j++ {
			src.At(j).CopyTo(dst.AppendEmpty())
		}
		src.RemoveIf(func(_ pdata.IntDataPoint) bool {
			return filterDataPoints()
		})
	case pdata.MetricDataTypeSum:
		src := ms.Sum().DataPoints()
		dst := dest.Sum().DataPoints()
		dst.EnsureCapacity(size)
		for j := 0; j < size; j++ {
			src.At(j).CopyTo(dst.AppendEmpty())
		}
		src.RemoveIf(func(_ pdata.NumberDataPoint) bool {
			return filterDataPoints()
		})
	case pdata.MetricDataTypeHistogram:
		src := ms.Histogram().DataPoints()
		dst := dest.Histogram().DataPoints()
		dst.EnsureCapacity(size)
		for j := 0; j < size; j++ {
			src.At(j).CopyTo(dst.AppendEmpty())
		}
		src.RemoveIf(func(_ pdata.HistogramDataPoint) bool {
			return filterDataPoints()
		})
	case pdata.MetricDataTypeSummary:
		src := ms.Summary().DataPoints()
		dst := dest.Summary().DataPoints()
		dst.EnsureCapacity(size)
		for j := 0; j < size; j++ {
			src.At(j).CopyTo(dst.AppendEmpty())
		}
		src.RemoveIf(func(_ pdata.SummaryDataPoint) bool {
			return filterDataPoints()
		})
	}
	return size, false
}
<commit_msg>update initSumIntMetric and initGaugeIntMetric (#3718)<commit_after>// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package batchprocessor

import (
	"go.opentelemetry.io/collector/model/pdata"
)

// splitMetrics removes metrics from the input data and returns a new data of the specified size.
func splitMetrics(size int, src pdata.Metrics) pdata.Metrics {
	dataPoints := src.DataPointCount()
	if dataPoints <= size {
		return src
	}
	totalCopiedDataPoints := 0
	dest := pdata.NewMetrics()

	src.ResourceMetrics().RemoveIf(func(srcRs pdata.ResourceMetrics) bool {
		// If we are done skip everything else.
		if totalCopiedDataPoints == size {
			return false
		}

		destRs := dest.ResourceMetrics().AppendEmpty()
		srcRs.Resource().CopyTo(destRs.Resource())

		srcRs.InstrumentationLibraryMetrics().RemoveIf(func(srcIlm pdata.InstrumentationLibraryMetrics) bool {
			// If we are done skip everything else.
			if totalCopiedDataPoints == size {
				return false
			}

			destIlm := destRs.InstrumentationLibraryMetrics().AppendEmpty()
			srcIlm.InstrumentationLibrary().CopyTo(destIlm.InstrumentationLibrary())

			// If possible to move all metrics do that.
			srcDataPointCount := metricSliceDataPointCount(srcIlm.Metrics())
			if size-totalCopiedDataPoints >= srcDataPointCount {
				totalCopiedDataPoints += srcDataPointCount
				srcIlm.Metrics().MoveAndAppendTo(destIlm.Metrics())
				return true
			}

			srcIlm.Metrics().RemoveIf(func(srcMetric pdata.Metric) bool {
				// If we are done skip everything else.
				if totalCopiedDataPoints == size {
					return false
				}
				// If the metric has more data points than free slots we should split it.
				copiedDataPoints, remove := splitMetric(srcMetric, destIlm.Metrics().AppendEmpty(), size-totalCopiedDataPoints)
				totalCopiedDataPoints += copiedDataPoints
				return remove
			})
			return false
		})
		return srcRs.InstrumentationLibraryMetrics().Len() == 0
	})

	return dest
}

// metricSliceDataPointCount calculates the total number of  data points.
func metricSliceDataPointCount(ms pdata.MetricSlice) (dataPointCount int) {
	for k := 0; k < ms.Len(); k++ {
		dataPointCount += metricDataPointCount(ms.At(k))
	}
	return
}

// metricDataPointCount calculates the total number of  data points.
func metricDataPointCount(ms pdata.Metric) (dataPointCount int) {
	switch ms.DataType() {
	case pdata.MetricDataTypeGauge:
		dataPointCount = ms.Gauge().DataPoints().Len()
	case pdata.MetricDataTypeSum:
		dataPointCount = ms.Sum().DataPoints().Len()
	case pdata.MetricDataTypeHistogram:
		dataPointCount = ms.Histogram().DataPoints().Len()
	case pdata.MetricDataTypeSummary:
		dataPointCount = ms.Summary().DataPoints().Len()
	}
	return
}

// splitMetric removes metric points from the input data and moves data of the specified size to destination.
// Returns size of moved data and boolean describing, whether the metric should be removed from original slice.
func splitMetric(ms, dest pdata.Metric, size int) (int, bool) {
	if metricDataPointCount(ms) <= size {
		ms.CopyTo(dest)
		return metricDataPointCount(ms), true
	}

	msSize, i := metricDataPointCount(ms)-size, 0
	filterDataPoints := func() bool { i++; return i <= msSize }

	dest.SetDataType(ms.DataType())
	dest.SetName(ms.Name())
	dest.SetDescription(ms.Description())
	dest.SetUnit(ms.Unit())

	switch ms.DataType() {
	case pdata.MetricDataTypeGauge:
		src := ms.Gauge().DataPoints()
		dst := dest.Gauge().DataPoints()
		dst.EnsureCapacity(size)
		for j := 0; j < size; j++ {
			src.At(j).CopyTo(dst.AppendEmpty())
		}
		src.RemoveIf(func(_ pdata.NumberDataPoint) bool {
			return filterDataPoints()
		})
	case pdata.MetricDataTypeSum:
		src := ms.Sum().DataPoints()
		dst := dest.Sum().DataPoints()
		dst.EnsureCapacity(size)
		for j := 0; j < size; j++ {
			src.At(j).CopyTo(dst.AppendEmpty())
		}
		src.RemoveIf(func(_ pdata.NumberDataPoint) bool {
			return filterDataPoints()
		})
	case pdata.MetricDataTypeHistogram:
		src := ms.Histogram().DataPoints()
		dst := dest.Histogram().DataPoints()
		dst.EnsureCapacity(size)
		for j := 0; j < size; j++ {
			src.At(j).CopyTo(dst.AppendEmpty())
		}
		src.RemoveIf(func(_ pdata.HistogramDataPoint) bool {
			return filterDataPoints()
		})
	case pdata.MetricDataTypeSummary:
		src := ms.Summary().DataPoints()
		dst := dest.Summary().DataPoints()
		dst.EnsureCapacity(size)
		for j := 0; j < size; j++ {
			src.At(j).CopyTo(dst.AppendEmpty())
		}
		src.RemoveIf(func(_ pdata.SummaryDataPoint) bool {
			return filterDataPoints()
		})
	}
	return size, false
}
<|endoftext|>


<commit_before>//  Copyright (c) 2014 Couchbase, 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"
	"io/ioutil"
	"net/http"

	log "github.com/couchbaselabs/clog"
)

func docIDLookup(req *http.Request) string {
	return muxVariableLookup(req, "docID")
}

func indexNameLookup(req *http.Request) string {
	return muxVariableLookup(req, "indexName")
}

func pindexNameLookup(req *http.Request) string {
	return muxVariableLookup(req, "pindexName")
}

// ------------------------------------------------------------------

type ListIndexHandler struct {
	mgr *Manager
}

func NewListIndexHandler(mgr *Manager) *ListIndexHandler {
	return &ListIndexHandler{mgr: mgr}
}

func (h *ListIndexHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	indexDefs, _, err := h.mgr.GetIndexDefs(false)
	if err != nil {
		showError(w, req, "could not retrieve index defs", 500)
		return
	}

	rv := struct {
		Status    string     `json:"status"`
		IndexDefs *IndexDefs `json:"indexDefs"`
	}{
		Status:    "ok",
		IndexDefs: indexDefs,
	}
	mustEncode(w, rv)
}

// ---------------------------------------------------

type GetIndexHandler struct {
	mgr *Manager
}

func NewGetIndexHandler(mgr *Manager) *GetIndexHandler {
	return &GetIndexHandler{mgr: mgr}
}

func (h *GetIndexHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	indexName := indexNameLookup(req)
	if indexName == "" {
		showError(w, req, "index name is required", 400)
		return
	}

	_, indexDefsByName, err := h.mgr.GetIndexDefs(false)
	if err != nil {
		showError(w, req, "could not retrieve index defs", 500)
		return
	}

	indexDef, exists := indexDefsByName[indexName]
	if !exists || indexDef == nil {
		showError(w, req, "not an index", 400)
		return
	}

	indexUUID := req.FormValue("indexUUID")
	if indexUUID != "" && indexUUID != indexDef.UUID {
		showError(w, req, "wrong index UUID", 400)
		return
	}

	mustEncode(w, struct {
		Status   string    `json:"status"`
		IndexDef *IndexDef `json:"indexDef"`
	}{
		Status:   "ok",
		IndexDef: indexDef,
	})
}

// ---------------------------------------------------

type CountHandler struct {
	mgr *Manager
}

func NewCountHandler(mgr *Manager) *CountHandler {
	return &CountHandler{mgr: mgr}
}

func (h *CountHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	indexName := indexNameLookup(req)
	if indexName == "" {
		showError(w, req, "index name is required", 400)
		return
	}

	indexUUID := req.FormValue("indexUUID")

	pindexImplType, err := PIndexImplTypeForIndex(h.mgr.Cfg(), indexName)
	if err != nil || pindexImplType.Count == nil {
		showError(w, req, fmt.Sprintf("rest.Count,"+
			" no pindexImplType, indexName: %s, err: %v", indexName, err), 400)
		return
	}

	count, err := pindexImplType.Count(h.mgr, indexName, indexUUID)
	if err != nil {
		showError(w, req, fmt.Sprintf("rest.Count,"+
			" indexName: %s, err: %v", indexName, err), 500)
		return
	}

	rv := struct {
		Status string `json:"status"`
		Count  uint64 `json:"count"`
	}{
		Status: "ok",
		Count:  count,
	}
	mustEncode(w, rv)
}

// ---------------------------------------------------

type QueryHandler struct {
	mgr *Manager
}

func NewQueryHandler(mgr *Manager) *QueryHandler {
	return &QueryHandler{mgr: mgr}
}

func (h *QueryHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	indexName := indexNameLookup(req)
	if indexName == "" {
		showError(w, req, "index name is required", 400)
		return
	}

	indexUUID := req.FormValue("indexUUID")

	requestBody, err := ioutil.ReadAll(req.Body)
	if err != nil {
		showError(w, req, fmt.Sprintf("rest.Query,"+
			" could not read request body, indexName: %s", indexName), 400)
		return
	}

	pindexImplType, err := PIndexImplTypeForIndex(h.mgr.Cfg(), indexName)
	if err != nil || pindexImplType.Query == nil {
		showError(w, req, fmt.Sprintf("rest.Query,"+
			" no pindexImplType, indexName: %s, err: %v", indexName, err), 400)
		return
	}

	log.Printf("rest.Query indexName: %s, requestBody: %s", indexName, requestBody)

	err = pindexImplType.Query(h.mgr, indexName, indexUUID, requestBody, w)
	if err != nil {
		showError(w, req, fmt.Sprintf("rest.Query,"+
			" indexName: %s, requestBody: %s, req: %#v, err: %v",
			indexName, requestBody, req, err), 400)
		return
	}

	log.Printf("rest.Query indexName: %s, DONE, requestBody: %s", indexName, requestBody)
}

// ---------------------------------------------------

type QueryPIndexHandler struct {
	mgr *Manager
}

func NewQueryPIndexHandler(mgr *Manager) *QueryPIndexHandler {
	return &QueryPIndexHandler{mgr: mgr}
}

func (h *QueryPIndexHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	pindexName := pindexNameLookup(req)
	if pindexName == "" {
		showError(w, req, "pindex name is required", 400)
		return
	}

	pindexUUID := req.FormValue("pindexUUID")

	requestBody, err := ioutil.ReadAll(req.Body)
	if err != nil {
		showError(w, req, fmt.Sprintf("rest.QueryPIndex,"+
			" could not read request body, pindexName: %s", pindexName), 400)
		return
	}

	pindex := h.mgr.GetPIndex(pindexName)
	if pindex == nil {
		showError(w, req, fmt.Sprintf("rest.QueryPIndex,"+
			" no pindex, pindexName: %s", pindexName), 400)
		return
	}
	if pindexUUID != "" && pindex.UUID != pindexUUID {
		showError(w, req, fmt.Sprintf("rest.QueryPIndex,"+
			" wrong pindexUUID: %s, pindex.UUID: %s, pindexName: %s",
			pindexUUID, pindex.UUID, pindexName), 400)
		return
	}
	if pindex.Dest == nil {
		showError(w, req, fmt.Sprintf("rest.QueryPIndex,"+
			" no pindex.Dest, pindexName: %s", pindexName), 400)
		return
	}

	var cancelCh chan struct{} // TODO: Support request timeout and cancellation.

	log.Printf("rest.QueryPIndex pindexName: %s, requestBody: %s",
		pindexName, requestBody)

	err = pindex.Dest.Query(pindex, requestBody, w, cancelCh)
	if err != nil {
		showError(w, req, fmt.Sprintf("rest.QueryPIndex,"+
			" pindexName: %s, requestBody: %s, req: %#v, err: %v",
			pindexName, requestBody, req, err), 400)
		return
	}

	log.Printf("rest.QueryPIndex pindexName: %s, DONE, requestBody: %s",
		pindexName, requestBody)
}
<commit_msg>more straightforward QueryPIndexHandler<commit_after>//  Copyright (c) 2014 Couchbase, 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"
	"io/ioutil"
	"net/http"

	log "github.com/couchbaselabs/clog"
)

func docIDLookup(req *http.Request) string {
	return muxVariableLookup(req, "docID")
}

func indexNameLookup(req *http.Request) string {
	return muxVariableLookup(req, "indexName")
}

func pindexNameLookup(req *http.Request) string {
	return muxVariableLookup(req, "pindexName")
}

// ------------------------------------------------------------------

type ListIndexHandler struct {
	mgr *Manager
}

func NewListIndexHandler(mgr *Manager) *ListIndexHandler {
	return &ListIndexHandler{mgr: mgr}
}

func (h *ListIndexHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	indexDefs, _, err := h.mgr.GetIndexDefs(false)
	if err != nil {
		showError(w, req, "could not retrieve index defs", 500)
		return
	}

	rv := struct {
		Status    string     `json:"status"`
		IndexDefs *IndexDefs `json:"indexDefs"`
	}{
		Status:    "ok",
		IndexDefs: indexDefs,
	}
	mustEncode(w, rv)
}

// ---------------------------------------------------

type GetIndexHandler struct {
	mgr *Manager
}

func NewGetIndexHandler(mgr *Manager) *GetIndexHandler {
	return &GetIndexHandler{mgr: mgr}
}

func (h *GetIndexHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	indexName := indexNameLookup(req)
	if indexName == "" {
		showError(w, req, "index name is required", 400)
		return
	}

	_, indexDefsByName, err := h.mgr.GetIndexDefs(false)
	if err != nil {
		showError(w, req, "could not retrieve index defs", 500)
		return
	}

	indexDef, exists := indexDefsByName[indexName]
	if !exists || indexDef == nil {
		showError(w, req, "not an index", 400)
		return
	}

	indexUUID := req.FormValue("indexUUID")
	if indexUUID != "" && indexUUID != indexDef.UUID {
		showError(w, req, "wrong index UUID", 400)
		return
	}

	mustEncode(w, struct {
		Status   string    `json:"status"`
		IndexDef *IndexDef `json:"indexDef"`
	}{
		Status:   "ok",
		IndexDef: indexDef,
	})
}

// ---------------------------------------------------

type CountHandler struct {
	mgr *Manager
}

func NewCountHandler(mgr *Manager) *CountHandler {
	return &CountHandler{mgr: mgr}
}

func (h *CountHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	indexName := indexNameLookup(req)
	if indexName == "" {
		showError(w, req, "index name is required", 400)
		return
	}

	indexUUID := req.FormValue("indexUUID")

	pindexImplType, err := PIndexImplTypeForIndex(h.mgr.Cfg(), indexName)
	if err != nil || pindexImplType.Count == nil {
		showError(w, req, fmt.Sprintf("rest.Count,"+
			" no pindexImplType, indexName: %s, err: %v", indexName, err), 400)
		return
	}

	count, err := pindexImplType.Count(h.mgr, indexName, indexUUID)
	if err != nil {
		showError(w, req, fmt.Sprintf("rest.Count,"+
			" indexName: %s, err: %v", indexName, err), 500)
		return
	}

	rv := struct {
		Status string `json:"status"`
		Count  uint64 `json:"count"`
	}{
		Status: "ok",
		Count:  count,
	}
	mustEncode(w, rv)
}

// ---------------------------------------------------

type QueryHandler struct {
	mgr *Manager
}

func NewQueryHandler(mgr *Manager) *QueryHandler {
	return &QueryHandler{mgr: mgr}
}

func (h *QueryHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	indexName := indexNameLookup(req)
	if indexName == "" {
		showError(w, req, "index name is required", 400)
		return
	}

	indexUUID := req.FormValue("indexUUID")

	requestBody, err := ioutil.ReadAll(req.Body)
	if err != nil {
		showError(w, req, fmt.Sprintf("rest.Query,"+
			" could not read request body, indexName: %s", indexName), 400)
		return
	}

	pindexImplType, err := PIndexImplTypeForIndex(h.mgr.Cfg(), indexName)
	if err != nil || pindexImplType.Query == nil {
		showError(w, req, fmt.Sprintf("rest.Query,"+
			" no pindexImplType, indexName: %s, err: %v", indexName, err), 400)
		return
	}

	log.Printf("rest.Query indexName: %s, requestBody: %s", indexName, requestBody)

	err = pindexImplType.Query(h.mgr, indexName, indexUUID, requestBody, w)
	if err != nil {
		showError(w, req, fmt.Sprintf("rest.Query,"+
			" indexName: %s, requestBody: %s, req: %#v, err: %v",
			indexName, requestBody, req, err), 400)
		return
	}

	log.Printf("rest.Query indexName: %s, DONE, requestBody: %s", indexName, requestBody)
}

// ---------------------------------------------------

type QueryPIndexHandler struct {
	mgr *Manager
}

func NewQueryPIndexHandler(mgr *Manager) *QueryPIndexHandler {
	return &QueryPIndexHandler{mgr: mgr}
}

func (h *QueryPIndexHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	pindexName := pindexNameLookup(req)
	if pindexName == "" {
		showError(w, req, "pindex name is required", 400)
		return
	}

	pindex := h.mgr.GetPIndex(pindexName)
	if pindex == nil {
		showError(w, req, fmt.Sprintf("rest.QueryPIndex,"+
			" no pindex, pindexName: %s", pindexName), 400)
		return
	}
	if pindex.Dest == nil {
		showError(w, req, fmt.Sprintf("rest.QueryPIndex,"+
			" no pindex.Dest, pindexName: %s", pindexName), 400)
		return
	}

	pindexUUID := req.FormValue("pindexUUID")
	if pindexUUID != "" && pindex.UUID != pindexUUID {
		showError(w, req, fmt.Sprintf("rest.QueryPIndex,"+
			" wrong pindexUUID: %s, pindex.UUID: %s, pindexName: %s",
			pindexUUID, pindex.UUID, pindexName), 400)
		return
	}

	requestBody, err := ioutil.ReadAll(req.Body)
	if err != nil {
		showError(w, req, fmt.Sprintf("rest.QueryPIndex,"+
			" could not read request body, pindexName: %s", pindexName), 400)
		return
	}

	var cancelCh chan struct{} // TODO: Support request timeout and cancellation.

	log.Printf("rest.QueryPIndex pindexName: %s, requestBody: %s",
		pindexName, requestBody)

	err = pindex.Dest.Query(pindex, requestBody, w, cancelCh)
	if err != nil {
		showError(w, req, fmt.Sprintf("rest.QueryPIndex,"+
			" pindexName: %s, requestBody: %s, req: %#v, err: %v",
			pindexName, requestBody, req, err), 400)
		return
	}

	log.Printf("rest.QueryPIndex pindexName: %s, DONE, requestBody: %s",
		pindexName, requestBody)
}
<|endoftext|>


<commit_before>package main

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

func TestLink(t *testing.T) {

	pomProject := PomProject{ArtifactId:PomArtifactId{Value:"myartifact"}}

	pomProjects := PomProjects{}
	pomProjects = append(pomProjects, pomProject)
	output := link(pomProjects)

	assert.Equal(t, "myartifact", output[0].ArtifactId)
}

func TestLinkParentChild(t *testing.T) {

	parent := PomProject{ArtifactId:PomArtifactId{Value:"parent"}}
	child := PomProject{
		ArtifactId:PomArtifactId{
			Value:"child",
		},
		Parent:PomParent{
			ArtifactId:PomArtifactId{
				Value:"parent",
			},
		},
	}
	pomProjects := PomProjects{}
	pomProjects = append(pomProjects, parent)
	pomProjects = append(pomProjects, child)
	output := link(pomProjects)

	assert.Equal(t, "parent", output[0].ArtifactId)
	assert.Equal(t, 1, len(output[0].Children))
	if len(output[0].Children) > 0 {
		assert.Equal(t, "child", output[0].Children[0].ArtifactId)
	}
}

func TestLinkParentChildOutOfOrder(t *testing.T) {

	parent := PomProject{ArtifactId:PomArtifactId{Value:"parent"}}
	child := PomProject{
		ArtifactId:PomArtifactId{
			Value:"child",
		},
		Parent:PomParent{
			ArtifactId:PomArtifactId{
				Value:"parent",
			},
		},
	}
	pomProjects := PomProjects{}
	pomProjects = append(pomProjects, child)
	pomProjects = append(pomProjects, parent)
	output := link(pomProjects)

	assert.Equal(t, "parent", output[0].ArtifactId)
//	assert.Equal(t, 1, len(output[0].Children))
//	if len(output[0].Children) > 0 {
//		assert.Equal(t, "child", output[0].Children[0].ArtifactId)
//	}
}
<commit_msg>Additional tests<commit_after>package main

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

func TestLink(t *testing.T) {

	pomProject := PomProject{ArtifactId:PomArtifactId{Value:"myartifact"}}

	pomProjects := PomProjects{}
	pomProjects = append(pomProjects, pomProject)
	output := link(pomProjects)

	assert.Equal(t, "myartifact", output[0].ArtifactId)
}

func TestLinkParentChild(t *testing.T) {

	parent := PomProject{ArtifactId:PomArtifactId{Value:"parent"}}
	child := PomProject{
		ArtifactId:PomArtifactId{
			Value:"child",
		},
		Parent:PomParent{
			ArtifactId:PomArtifactId{
				Value:"parent",
			},
		},
	}
	pomProjects := PomProjects{}
	pomProjects = append(pomProjects, parent)
	pomProjects = append(pomProjects, child)
	output := link(pomProjects)

	assert.Equal(t, "parent", output[0].ArtifactId)
	assert.Equal(t, 1, len(output[0].Children))
	if len(output[0].Children) > 0 {
		assert.Equal(t, "child", output[0].Children[0].ArtifactId)
	}
}

func TestLinkParentChildOutOfOrder(t *testing.T) {

	parent := PomProject{ArtifactId:PomArtifactId{Value:"parent"}}
	child := PomProject{
		ArtifactId:PomArtifactId{
			Value:"child",
		},
		Parent:PomParent{
			ArtifactId:PomArtifactId{
				Value:"parent",
			},
		},
	}
	pomProjects := PomProjects{}
	pomProjects = append(pomProjects, child)
	pomProjects = append(pomProjects, parent)
	output := link(pomProjects)

	assert.Equal(t, "parent", output[0].ArtifactId)
	assert.Equal(t, 1, len(output[0].Children))
	if len(output[0].Children) > 0 {
		assert.Equal(t, "child", output[0].Children[0].ArtifactId)
	}
}
<|endoftext|>


<commit_before>package wirelesstag

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"testing"
	"time"

	. "github.com/smartystreets/goconvey/convey"
	"golang.org/x/oauth2"
)

func TestExchangeToken(t *testing.T) {
	Convey("Exchange", t, func() {
		ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			fmt.Fprint(w, `{"access_token": "foo", "token_type": "Bearer", "expiry": "1970-01-01T00:00:00Z"}`)
		}))
		defer ts.Close()

		config := &oauth2.Config{
			Endpoint: oauth2.Endpoint{
				TokenURL: ts.URL,
			},
		}
		token, err := exchangeToken(config, "foobar")
		So(err, ShouldBeNil)
		So(token.AccessToken, ShouldEqual, "foo")
		So(token.TokenType, ShouldEqual, "Bearer")
		So(token.Expiry, ShouldEqual, time.Unix(0, 0))
	})
}

func TestCacheDir(t *testing.T) {
	Convey("Cache file path", t, func() {
		path, err := tokenCacheFile()
		So(err, ShouldBeNil)
		So(path, ShouldEndWith, ".credentials/mytaglist.json")
	})
}
<commit_msg>Fix test<commit_after>package wirelesstag

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"testing"
	"time"

	. "github.com/smartystreets/goconvey/convey"
	"golang.org/x/oauth2"
)

func TestExchangeToken(t *testing.T) {
	Convey("Exchange", t, func() {
		ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			fmt.Fprint(w, `{"access_token": "foo", "token_type": "Bearer", "expiry": "1970-01-01T00:00:00Z"}`)
		}))
		defer ts.Close()

		config := &oauth2.Config{
			Endpoint: oauth2.Endpoint{
				TokenURL: ts.URL,
			},
		}
		token, err := exchangeToken(config, "foobar")
		So(err, ShouldBeNil)
		So(token.AccessToken, ShouldEqual, "foo")
		So(token.TokenType, ShouldEqual, "Bearer")
		So(token.Expiry, ShouldHappenOnOrBefore, time.Unix(0, 0))
	})
}

func TestCacheDir(t *testing.T) {
	Convey("Cache file path", t, func() {
		path, err := tokenCacheFile()
		So(err, ShouldBeNil)
		So(path, ShouldEndWith, ".credentials/mytaglist.json")
	})
}
<|endoftext|>


<commit_before>package rio

import (
	"go.polydawn.net/meep"

	"go.polydawn.net/repeatr/api/def"
)

/*
	Raised to indicate a serious internal error with a transmat's functioning.

	Typically these indicate a need for the whole program to stop; examples are
	the repeatr daemon hitting permissions problems in the main work area,
	or running out of disk space, or something equally severe.

	Errors relating to communicating with a warehouse, data integrity checks,
	absense of data, etc, are all recoverable errors, and are expressed with
	error types exported in the `api/def` package.
*/
type ErrInternal struct {
	Msg string
	meep.TraitAutodescribing
	meep.TraitCausable
	meep.TraitTraceable
}

/*
	Raised to indicat a serious error while assembling filesystems together.

	Typically these indicate a need for the whole program to stop; examples are
	the repeatr daemon hitting permissions problems in the main work area,
	or running out of disk space, or something equally severe.

	(This is not significantly different than `ErrInternal`,
	but indicates which phase of work the error came from.
	Placer and assembler functions will raise this error; transmats won't.)
*/
type ErrAssembly struct {
	meep.TraitAutodescribing
	meep.TraitCausable
	meep.TraitTraceable
	System string // e.g. "copyingplacer" or etc.
	Path   string // often just "srcPath" or "destPath"
	// "op" is usually covered in the io error string, if that's a cause
}

/*
	Wraps any other unknown errors just to emphasize the system that raised them;
	any well known errors should use a different type.

	If an error of this type is exposed to the user, it should be
	considered a bug, and specific error detection added to the site.
*/
type ErrUnknown struct {
	meep.TraitAutodescribing
	meep.TraitCausable
	meep.TraitTraceable
}

/*
	A standard TryPlan snippet for passing up any well-known error types
	which are reasonable for a transmat to raise during operation,
	and swaddling anything else in an ErrUnknown, so it gets a stack from here.
*/
var TryPlanWhitelist = meep.TryPlan{
	{ByType: &ErrInternal{}, Handler: func(e error) { panic(e) }},
	{ByType: &ErrAssembly{}, Handler: func(e error) { panic(e) }},
	{ByType: &ErrUnknown{}, Handler: func(e error) { panic(e) }},
	{ByType: &def.ErrWarehouseUnavailable{}, Handler: func(e error) { panic(e) }},
	{ByType: &def.ErrWarehouseProblem{}, Handler: func(e error) { panic(e) }},
	{ByType: &def.ErrWareDNE{}, Handler: func(e error) { panic(e) }},
	{ByType: &def.ErrHashMismatch{}, Handler: func(e error) { panic(e) }},
	{CatchAny: true, Handler: meep.TryHandlerMapto(&ErrUnknown{})},
}
<commit_msg>rio: add ErrWareCorrupt to the returnable set.<commit_after>package rio

import (
	"go.polydawn.net/meep"

	"go.polydawn.net/repeatr/api/def"
)

/*
	Raised to indicate a serious internal error with a transmat's functioning.

	Typically these indicate a need for the whole program to stop; examples are
	the repeatr daemon hitting permissions problems in the main work area,
	or running out of disk space, or something equally severe.

	Errors relating to communicating with a warehouse, data integrity checks,
	absense of data, etc, are all recoverable errors, and are expressed with
	error types exported in the `api/def` package.
*/
type ErrInternal struct {
	Msg string
	meep.TraitAutodescribing
	meep.TraitCausable
	meep.TraitTraceable
}

/*
	Raised to indicat a serious error while assembling filesystems together.

	Typically these indicate a need for the whole program to stop; examples are
	the repeatr daemon hitting permissions problems in the main work area,
	or running out of disk space, or something equally severe.

	(This is not significantly different than `ErrInternal`,
	but indicates which phase of work the error came from.
	Placer and assembler functions will raise this error; transmats won't.)
*/
type ErrAssembly struct {
	meep.TraitAutodescribing
	meep.TraitCausable
	meep.TraitTraceable
	System string // e.g. "copyingplacer" or etc.
	Path   string // often just "srcPath" or "destPath"
	// "op" is usually covered in the io error string, if that's a cause
}

/*
	Wraps any other unknown errors just to emphasize the system that raised them;
	any well known errors should use a different type.

	If an error of this type is exposed to the user, it should be
	considered a bug, and specific error detection added to the site.
*/
type ErrUnknown struct {
	meep.TraitAutodescribing
	meep.TraitCausable
	meep.TraitTraceable
}

/*
	A standard TryPlan snippet for passing up any well-known error types
	which are reasonable for a transmat to raise during operation,
	and swaddling anything else in an ErrUnknown, so it gets a stack from here.
*/
var TryPlanWhitelist = meep.TryPlan{
	{ByType: &ErrInternal{}, Handler: func(e error) { panic(e) }},
	{ByType: &ErrAssembly{}, Handler: func(e error) { panic(e) }},
	{ByType: &ErrUnknown{}, Handler: func(e error) { panic(e) }},
	{ByType: &def.ErrWarehouseUnavailable{}, Handler: func(e error) { panic(e) }},
	{ByType: &def.ErrWarehouseProblem{}, Handler: func(e error) { panic(e) }},
	{ByType: &def.ErrWareDNE{}, Handler: func(e error) { panic(e) }},
	{ByType: &def.ErrHashMismatch{}, Handler: func(e error) { panic(e) }},
	{ByType: &def.ErrWareCorrupt{}, Handler: func(e error) { panic(e) }},
	{CatchAny: true, Handler: meep.TryHandlerMapto(&ErrUnknown{})},
}
<|endoftext|>


<commit_before>package database

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"time"

	_ "github.com/lib/pq"

	"github.com/mozilla/tls-observatory/connection"
)

type DB struct {
	*sql.DB
}

type Scan struct {
	ID               int64             `json:"id"`
	Timestamp        time.Time         `json:"timestamp"`
	Target           string            `json:"target"`
	Replay           int               `json:"replay"` //hours or days
	Has_tls          bool              `json:"has_tls"`
	Cert_id          int64             `json:"cert_id"`
	Trust_id         int64             `json:"trust_id"`
	Is_valid         bool              `json:"is_valid"`
	Validation_error string            `json:"validation_error,omitempty"`
	Complperc        int               `json:"completion_perc"`
	Conn_info        connection.Stored `json:"connection_info"`
	AnalysisResults  []Analysis        `json:"analysis,omitempty"`
	Ack              bool              `json:"ack"`
	Attempts         int               `json:"attempts"` //number of retries
}

type Analysis struct {
	ID       int64           `json:"id"`
	Analyzer string          `json:"analyzer"`
	Result   json.RawMessage `json:"result"`
}

func RegisterConnection(dbname, user, password, hostport, sslmode string) (*DB, error) {

	url := fmt.Sprintf("postgres://%s:%s@%s/%s?sslmode=%s",
		user, password, hostport, dbname, sslmode)

	db, err := sql.Open("postgres", url)

	if err != nil {
		db = nil
	}

	return &DB{db}, err
}

func (db *DB) NewScan(domain string, rplay int) (Scan, error) {

	timestamp := time.Now()

	var id int64

	err := db.QueryRow(`INSERT INTO scans
			(timestamp, target, replay, has_tls, is_valid, completion_perc, validation_error, conn_info, ack, attempts)
			VALUES($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
			RETURNING id`,
		timestamp, domain, rplay, false, false, 0, "", []byte("null"), false, 1).Scan(&id)

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

	return Scan{ID: id, Timestamp: timestamp, Replay: rplay}, nil
}

func (db *DB) GetScanByID(id int64) (Scan, error) {

	s := Scan{}
	s.ID = id

	var cID, tID sql.NullInt64

	var isvalid sql.NullBool

	var ci []byte

	row := db.QueryRow(`SELECT timestamp, target, replay, has_tls, cert_id, trust_id,
				   is_valid, completion_perc, validation_error, conn_info, ack, attempts
			    FROM scans
			    WHERE id=$1`, id)

	err := row.Scan(&s.Timestamp, &s.Target, &s.Replay, &s.Has_tls, &cID, &tID,
		&isvalid, &s.Complperc, &s.Validation_error, &ci, &s.Ack, &s.Attempts)

	if err != nil {
		if err == sql.ErrNoRows {
			s.ID = -1
			return s, nil
		} else {
			return s, err
		}
	}

	if cID.Valid {
		s.Cert_id = cID.Int64

	} else {
		s.Cert_id = -1
	}

	if tID.Valid {
		s.Trust_id = tID.Int64
	} else {
		s.Trust_id = -1
	}

	if isvalid.Valid {
		s.Is_valid = isvalid.Bool
	} else {
		s.Is_valid = false
	}

	err = json.Unmarshal(ci, &s.Conn_info)
	if err != nil {
		return s, err
	}

	if s.Complperc > 40 {
		s.AnalysisResults, err = db.GetAnalysisByScan(s.ID)
		return s, err
	}

	return s, nil
}

func (db *DB) GetAnalysisByScan(id int64) ([]Analysis, error) {

	var ana []Analysis
	rows, err := db.Query("SELECT id,worker_name,output FROM analysis WHERE scan_id=$1", id)
	if err != nil {
		return ana, err
	}
	defer rows.Close()
	for rows.Next() {
		a := Analysis{}
		if err := rows.Scan(&a.ID, &a.Analyzer, &a.Result); err != nil {
			return ana, err
		}
		ana = append(ana, a)
	}
	return ana, nil
}

func (db *DB) UpdateScanCompletionPercentage(id int64, p int) error {
	_, err := db.Exec("UPDATE scans SET completion_perc=$1 WHERE id=$2", p, id)

	return err
}

func (db *DB) InsertWorkerAnalysis(scanid int64, jsonRes []byte, workerName string) error {
	_, err := db.Exec("INSERT INTO analysis(scan_id,worker_name,output) VALUES($1,$2,$3)", scanid, workerName, jsonRes)

	return err
}
<commit_msg>added GetLastScanTimeForTarget<commit_after>package database

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"time"

	_ "github.com/lib/pq"

	"github.com/mozilla/tls-observatory/connection"
)

type DB struct {
	*sql.DB
}

type Scan struct {
	ID               int64             `json:"id"`
	Timestamp        time.Time         `json:"timestamp"`
	Target           string            `json:"target"`
	Replay           int               `json:"replay"` //hours or days
	Has_tls          bool              `json:"has_tls"`
	Cert_id          int64             `json:"cert_id"`
	Trust_id         int64             `json:"trust_id"`
	Is_valid         bool              `json:"is_valid"`
	Validation_error string            `json:"validation_error,omitempty"`
	Complperc        int               `json:"completion_perc"`
	Conn_info        connection.Stored `json:"connection_info"`
	AnalysisResults  []Analysis        `json:"analysis,omitempty"`
	Ack              bool              `json:"ack"`
	Attempts         int               `json:"attempts"` //number of retries
}

type Analysis struct {
	ID       int64           `json:"id"`
	Analyzer string          `json:"analyzer"`
	Result   json.RawMessage `json:"result"`
}

func RegisterConnection(dbname, user, password, hostport, sslmode string) (*DB, error) {

	url := fmt.Sprintf("postgres://%s:%s@%s/%s?sslmode=%s",
		user, password, hostport, dbname, sslmode)

	db, err := sql.Open("postgres", url)

	if err != nil {
		db = nil
	}

	return &DB{db}, err
}

func (db *DB) NewScan(domain string, rplay int) (Scan, error) {

	timestamp := time.Now().UTC()

	var id int64

	err := db.QueryRow(`INSERT INTO scans
			(timestamp, target, replay, has_tls, is_valid, completion_perc, validation_error, conn_info, ack, attempts)
			VALUES($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
			RETURNING id`,
		timestamp, domain, rplay, false, false, 0, "", []byte("null"), false, 1).Scan(&id)

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

	return Scan{ID: id, Timestamp: timestamp, Replay: rplay}, nil
}

// GetLastScanTimeForTarget searches the database for the latest scan for a specific target.
// It returns both the scan timestamp and the id of the scan to enable the api to
// respond to clients with just one db query.
func (db *DB) GetLastScanTimeForTarget(target string) (int64, time.Time, error) {

	var (
		id int64
		t  time.Time
	)

	row := db.QueryRow(`SELECT id, timestamp
			    FROM scans
			    WHERE target=$1 ORDER BY timestamp DESC LIMIT 1`, target)

	err := row.Scan(&id, &t)

	if err != nil {
		if err == sql.ErrNoRows {
			return -1, time.Now(), nil
		} else {
			return -1, time.Now(), err
		}
	}
	return id, t, nil
}

func (db *DB) GetScanByID(id int64) (Scan, error) {

	s := Scan{}
	s.ID = id

	var cID, tID sql.NullInt64

	var isvalid sql.NullBool

	var ci []byte

	row := db.QueryRow(`SELECT timestamp, target, replay, has_tls, cert_id, trust_id,
				   is_valid, completion_perc, validation_error, conn_info, ack, attempts
			    FROM scans
			    WHERE id=$1`, id)

	err := row.Scan(&s.Timestamp, &s.Target, &s.Replay, &s.Has_tls, &cID, &tID,
		&isvalid, &s.Complperc, &s.Validation_error, &ci, &s.Ack, &s.Attempts)

	if err != nil {
		if err == sql.ErrNoRows {
			s.ID = -1
			return s, nil
		} else {
			return s, err
		}
	}

	if cID.Valid {
		s.Cert_id = cID.Int64

	} else {
		s.Cert_id = -1
	}

	if tID.Valid {
		s.Trust_id = tID.Int64
	} else {
		s.Trust_id = -1
	}

	if isvalid.Valid {
		s.Is_valid = isvalid.Bool
	} else {
		s.Is_valid = false
	}

	err = json.Unmarshal(ci, &s.Conn_info)
	if err != nil {
		return s, err
	}

	if s.Complperc > 40 {
		s.AnalysisResults, err = db.GetAnalysisByScan(s.ID)
		return s, err
	}

	return s, nil
}

func (db *DB) GetAnalysisByScan(id int64) ([]Analysis, error) {

	var ana []Analysis
	rows, err := db.Query("SELECT id,worker_name,output FROM analysis WHERE scan_id=$1", id)
	if err != nil {
		return ana, err
	}
	defer rows.Close()
	for rows.Next() {
		a := Analysis{}
		if err := rows.Scan(&a.ID, &a.Analyzer, &a.Result); err != nil {
			return ana, err
		}
		ana = append(ana, a)
	}
	return ana, nil
}

func (db *DB) UpdateScanCompletionPercentage(id int64, p int) error {
	_, err := db.Exec("UPDATE scans SET completion_perc=$1 WHERE id=$2", p, id)

	return err
}

func (db *DB) InsertWorkerAnalysis(scanid int64, jsonRes []byte, workerName string) error {
	_, err := db.Exec("INSERT INTO analysis(scan_id,worker_name,output) VALUES($1,$2,$3)", scanid, workerName, jsonRes)

	return err
}
<|endoftext|>


<commit_before>package markdown

import (
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"sync"

	"github.com/mholt/caddy/middleware"
)

// GenerateStatic generate static files and link index from markdowns.
// It only generates static files if it is enabled (cfg.StaticDir
// must be set).
func GenerateStatic(md Markdown, cfg *Config) error {
	// Generate links since they may be needed, even without sitegen.
	generated, err := generateLinks(md, cfg)
	if err != nil {
		return err
	}

	// No new file changes, return.
	if !generated {
		return nil
	}

	// If static site generation is enabled, generate the site.
	if cfg.StaticDir != "" {
		if err := generateStaticHTML(md, cfg); err != nil {
			return err
		}
	}

	return nil
}

type linkGenerator struct {
	gens map[*Config]*linkGen
	sync.Mutex
}

var generator = linkGenerator{gens: make(map[*Config]*linkGen)}

// generateLinks generates links to all markdown files ordered by newest date.
// This blocks until link generation is done. When called by multiple goroutines,
// the first caller starts the generation and others only wait.
// It returns if generation is done and any error that occurred.
func generateLinks(md Markdown, cfg *Config) (bool, error) {
	generator.Lock()

	// if link generator exists for config and running, wait.
	if g, ok := generator.gens[cfg]; ok {
		if g.started() {
			g.addWaiter()
			generator.Unlock()
			g.Wait()
			// another goroutine has done the generation.
			return false, g.lastErr
		}
	}

	g := &linkGen{}
	generator.gens[cfg] = g
	generator.Unlock()

	generated := g.generateLinks(md, cfg)
	g.discardWaiters()
	return generated, g.lastErr
}

// generateStaticHTML generates static HTML files from markdowns.
func generateStaticHTML(md Markdown, cfg *Config) error {
	// If generated site already exists, clear it out
	_, err := os.Stat(cfg.StaticDir)
	if err == nil {
		err := os.RemoveAll(cfg.StaticDir)
		if err != nil {
			return err
		}
	}

	fp := filepath.Join(md.Root, cfg.PathScope)

	return filepath.Walk(fp, func(path string, info os.FileInfo, err error) error {
		for _, ext := range cfg.Extensions {
			if !info.IsDir() && strings.HasSuffix(info.Name(), ext) {
				// Load the file
				body, err := ioutil.ReadFile(path)
				if err != nil {
					return err
				}

				// Get the relative path as if it were a HTTP request,
				// then prepend with "/" (like a real HTTP request)
				reqPath, err := filepath.Rel(md.Root, path)
				if err != nil {
					return err
				}
				reqPath = filepath.ToSlash(reqPath)
				reqPath = "/" + reqPath

				// Generate the static file
				ctx := middleware.Context{Root: md.FileSys}
				_, err = md.Process(cfg, reqPath, body, ctx)
				if err != nil {
					return err
				}

				break // don't try other file extensions
			}
		}
		return nil
	})
}

// computeDirHash computes an hash on static directory of c.
func computeDirHash(md Markdown, c *Config) (string, error) {
	dir := filepath.Join(md.Root, c.PathScope)
	if _, err := os.Stat(dir); err != nil {
		return "", err
	}

	hashString := ""
	err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		if !info.IsDir() && c.IsValidExt(filepath.Ext(path)) {
			hashString += fmt.Sprintf("%v%v%v%v", info.ModTime(), info.Name(), info.Size(), path)
		}
		return nil
	})
	if err != nil {
		return "", err
	}

	sum := md5.Sum([]byte(hashString))
	return hex.EncodeToString(sum[:]), nil
}
<commit_msg>Markdown: Fix panic on sitegen for request dependent template values.<commit_after>package markdown

import (
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"sync"

	"github.com/mholt/caddy/middleware"
)

// GenerateStatic generate static files and link index from markdowns.
// It only generates static files if it is enabled (cfg.StaticDir
// must be set).
func GenerateStatic(md Markdown, cfg *Config) error {
	// Generate links since they may be needed, even without sitegen.
	generated, err := generateLinks(md, cfg)
	if err != nil {
		return err
	}

	// No new file changes, return.
	if !generated {
		return nil
	}

	// If static site generation is enabled, generate the site.
	if cfg.StaticDir != "" {
		if err := generateStaticHTML(md, cfg); err != nil {
			return err
		}
	}

	return nil
}

type linkGenerator struct {
	gens map[*Config]*linkGen
	sync.Mutex
}

var generator = linkGenerator{gens: make(map[*Config]*linkGen)}

// generateLinks generates links to all markdown files ordered by newest date.
// This blocks until link generation is done. When called by multiple goroutines,
// the first caller starts the generation and others only wait.
// It returns if generation is done and any error that occurred.
func generateLinks(md Markdown, cfg *Config) (bool, error) {
	generator.Lock()

	// if link generator exists for config and running, wait.
	if g, ok := generator.gens[cfg]; ok {
		if g.started() {
			g.addWaiter()
			generator.Unlock()
			g.Wait()
			// another goroutine has done the generation.
			return false, g.lastErr
		}
	}

	g := &linkGen{}
	generator.gens[cfg] = g
	generator.Unlock()

	generated := g.generateLinks(md, cfg)
	g.discardWaiters()
	return generated, g.lastErr
}

// generateStaticHTML generates static HTML files from markdowns.
func generateStaticHTML(md Markdown, cfg *Config) error {
	// If generated site already exists, clear it out
	_, err := os.Stat(cfg.StaticDir)
	if err == nil {
		err := os.RemoveAll(cfg.StaticDir)
		if err != nil {
			return err
		}
	}

	fp := filepath.Join(md.Root, cfg.PathScope)

	return filepath.Walk(fp, func(path string, info os.FileInfo, err error) error {
		for _, ext := range cfg.Extensions {
			if !info.IsDir() && strings.HasSuffix(info.Name(), ext) {
				// Load the file
				body, err := ioutil.ReadFile(path)
				if err != nil {
					return err
				}

				// Get the relative path as if it were a HTTP request,
				// then prepend with "/" (like a real HTTP request)
				reqPath, err := filepath.Rel(md.Root, path)
				if err != nil {
					return err
				}
				reqPath = filepath.ToSlash(reqPath)
				reqPath = "/" + reqPath

				// Generate the static file
				ctx := middleware.Context{Root: md.FileSys, Req: new(http.Request), URL: new(url.URL)}
				_, err = md.Process(cfg, reqPath, body, ctx)
				if err != nil {
					return err
				}

				break // don't try other file extensions
			}
		}
		return nil
	})
}

// computeDirHash computes an hash on static directory of c.
func computeDirHash(md Markdown, c *Config) (string, error) {
	dir := filepath.Join(md.Root, c.PathScope)
	if _, err := os.Stat(dir); err != nil {
		return "", err
	}

	hashString := ""
	err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		if !info.IsDir() && c.IsValidExt(filepath.Ext(path)) {
			hashString += fmt.Sprintf("%v%v%v%v", info.ModTime(), info.Name(), info.Size(), path)
		}
		return nil
	})
	if err != nil {
		return "", err
	}

	sum := md5.Sum([]byte(hashString))
	return hex.EncodeToString(sum[:]), nil
}
<|endoftext|>


<commit_before>/*

   Copyright 2016 Wenhui Shen <www.webx.top>

   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 session

import (
	"errors"

	"github.com/admpub/sessions"
	"github.com/webx-top/echo"
)

func Sessions(options *echo.SessionOptions, store sessions.Store) echo.MiddlewareFuncd {
	var newSession func(ctx echo.Context) echo.Sessioner
	if options == nil {
		newSession = func(ctx echo.Context) echo.Sessioner {
			return NewMySession(store, ctx.SessionOptions().Name, ctx)
		}
	} else {
		newSession = func(ctx echo.Context) echo.Sessioner {
			sessionOptions := options.Clone()
			ctx.SetSessionOptions(sessionOptions)
			return NewMySession(store, sessionOptions.Name, ctx)
		}
	}
	return func(h echo.Handler) echo.HandlerFunc {
		return func(c echo.Context) error {
			s := newSession(c)
			c.SetSessioner(s)
			c.AddPreResponseHook(s.Save)
			err := h.Handle(c)
			if e := s.Save(); e != nil {
				if err != nil {
					err = errors.New("Multiple errors:\n1. " + err.Error() + "\n2. " + e.Error())
				} else {
					err = e
				}
				c.Logger().Error(err)
			}
			return err
		}
	}
}

func Middleware(options *echo.SessionOptions) echo.MiddlewareFuncd {
	store := StoreEngine(options)
	return Sessions(options, store)
}
<commit_msg>update<commit_after>/*

   Copyright 2016 Wenhui Shen <www.webx.top>

   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 session

import (
	"errors"

	"github.com/admpub/sessions"
	"github.com/webx-top/echo"
)

const CookieMaxAgeKey = `CookieMaxAge`

func Sessions(options *echo.SessionOptions, store sessions.Store) echo.MiddlewareFuncd {
	var newSession func(ctx echo.Context) echo.Sessioner
	if options == nil {
		newSession = func(ctx echo.Context) echo.Sessioner {
			return NewMySession(store, ctx.SessionOptions().Name, ctx)
		}
	} else {
		newSession = func(ctx echo.Context) echo.Sessioner {
			sessionOptions := options.Clone()
			ctx.SetSessionOptions(sessionOptions)
			return NewMySession(store, sessionOptions.Name, ctx)
		}
	}
	return func(h echo.Handler) echo.HandlerFunc {
		return func(c echo.Context) error {
			s := newSession(c)
			c.SetSessioner(s)
			s.SetPreSaveHook(func(c echo.Context) error{
				if maxAge, ok := s.Get(CookieMaxAgeKey).(int); ok {
					c.CookieOptions().MaxAge = maxAge
				}
				return nil
			})
			c.AddPreResponseHook(s.Save)
			err := h.Handle(c)
			if e := s.Save(); e != nil {
				if err != nil {
					err = errors.New("Multiple errors:\n1. " + err.Error() + "\n2. " + e.Error())
				} else {
					err = e
				}
				c.Logger().Error(err)
			}
			return err
		}
	}
}

func Middleware(options *echo.SessionOptions) echo.MiddlewareFuncd {
	store := StoreEngine(options)
	return Sessions(options, store)
}
<|endoftext|>


<commit_before>package rsa

import (
	"math/big"
)

// AttackShortPlaintext exploits short plaintexts to compute the key.
func (k *PublicKey) AttackShortPlaintext(c *big.Int, bits int) (m *big.Int) {
	bm := make(bigMap)
	tmp := new(big.Int)

	// Find x and y such that c*(x^-e) = y^e (mod n)
	i := big.NewInt(1)
	var x, y *big.Int
	for i.BitLen() <= bits {
		ye := new(big.Int).Exp(i, k.E, k.N) // i^e      (mod n)
		tmp.ModInverse(ye, k.N)             // i^-e     (mod n)
		xe := new(big.Int).Mul(c, tmp)      // c*(i^-e) (mod n)
		xe.Mod(xe, k.N)

		// Check for match
		if v, ok := bm.GetOrPut(xe, i); ok {
			x, y = i, v
			break
		}
		if v, ok := bm.GetOrPut(ye, i); ok {
			x, y = v, i
			break
		}
		i = new(big.Int).Add(i, one)
	}

	// We now have c = (x*y)^e (mod n), thus m = x*y (mod n)
	xy := new(big.Int).Mul(x, y)
	xy.Mod(xy, k.N)
	return xy
}

// bigMap is a hash table for *big.Int keys. Keys are not copied and
// must not be modified after insertion.
type bigMap map[uint64][]mapPair
type mapPair struct{ K, V *big.Int }

// GetOrPut gets the value at the key, if it exists, or otherwise puts a
// value at the key.
func (m bigMap) GetOrPut(key, val *big.Int) (*big.Int, bool) {
	hash := key.Uint64()
	bucket := m[hash]
	for _, pair := range bucket {
		if pair.K.Cmp(key) == 0 {
			return pair.V, true
		}
	}
	m[hash] = append(bucket, mapPair{key, val})
	return nil, false
}
<commit_msg>Revise RSA short plaintext notes<commit_after>package rsa

import "math/big"

// AttackShortPlaintext exploits short plaintexts to compute the key.
func (k *PublicKey) AttackShortPlaintext(c *big.Int, bits int) (m *big.Int) {
	// Described in Introduction to Cryptography with Coding Theory by
	// Trappe and Washington, section 6.2.2.

	bm := make(bigMap)
	tmp := new(big.Int)

	// Find x and y such that c*(x^-e) = y^e (mod n)
	var x, y *big.Int
	for i := one; i.BitLen() <= bits; i = new(big.Int).Add(i, one) {
		yi := new(big.Int).Exp(i, k.E, k.N) // i^e      (mod n)
		tmp.ModInverse(yi, k.N)             // i^-e     (mod n)
		xi := new(big.Int).Mul(c, tmp)      // c*(i^-e) (mod n)
		xi.Mod(xi, k.N)

		// Check for match
		if v, ok := bm.GetOrPut(xi, i); ok {
			x, y = i, v
			break
		}
		if v, ok := bm.GetOrPut(yi, i); ok {
			x, y = v, i
			break
		}
	}

	// c*(x^-e) = y^e (mod n)
	// c = (x*y)^e    (mod n)
	// m = x*y        (mod n)
	m = tmp.Mod(tmp.Mul(x, y), k.N)
	return m
}

// bigMap is a hash table for *big.Int keys. Keys are not copied and
// must not be modified after insertion.
type bigMap map[uint64][]mapPair
type mapPair struct{ K, V *big.Int }

// GetOrPut gets the value at the key, if it exists, or otherwise puts a
// value at the key.
func (m bigMap) GetOrPut(key, val *big.Int) (*big.Int, bool) {
	hash := key.Uint64()
	bucket := m[hash]
	for _, pair := range bucket {
		if pair.K.Cmp(key) == 0 {
			return pair.V, true
		}
	}
	m[hash] = append(bucket, mapPair{key, val})
	return nil, false
}
<|endoftext|>


<commit_before>package ruler

import "testing"

func TestRules(t *testing.T) {

	cases := []struct {
		filters []*Filter
		o       map[string]interface{}
		name    string
	}{
		{
			[]*Filter{
				&Filter{
					"eq",
					"basic.property",
					"foobar",
				},
			},
			map[string]interface{}{
				"basic": map[string]interface{}{
					"property": "foobar",
				},
			},

			"testing basic property equality (string)",
		},
		{
			[]*Filter{
				&Filter{
					"eq",
					"basic.property",
					12,
				},
			},
			map[string]interface{}{
				"basic": map[string]interface{}{
					"property": 12,
				},
			},
			"testing basic property equality (int)",
		},
		{
			[]*Filter{
				&Filter{
					"gt",
					"basic.property",
					45,
				},
			},
			map[string]interface{}{
				"basic": map[string]interface{}{
					"property": 100,
				},
			},
			"testing greater than (int)",
		},
		{
			[]*Filter{
				&Filter{
					"gte",
					"basic.property",
					100,
				},
			},
			map[string]interface{}{
				"basic": map[string]interface{}{
					"property": 100,
				},
			},
			"testing greater than or equal to (int)",
		},
		{
			[]*Filter{
				&Filter{
					"lt",
					"basic.property",
					45,
				},
			},
			map[string]interface{}{
				"basic": map[string]interface{}{
					"property": 10,
				},
			},
			"testing less than (int)",
		},
		{
			[]*Filter{
				&Filter{
					"lte",
					"basic.property",
					45,
				},
			},
			map[string]interface{}{
				"basic": map[string]interface{}{
					"property": 45,
				},
			},
			"testing less than or equal to (int)",
		},

		{
			[]*Filter{
				&Filter{
					"regex",
					"basic.property",
					"a[0-9]*b",
				},
			},
			map[string]interface{}{
				"basic": map[string]interface{}{
					"property": "a9394b",
				},
			},
			"testing regexp",
		},
	}

	for _, c := range cases {
		r := &Ruler{
			filters: c.filters,
		}

		if !r.Test(c.o) {
			t.Errorf("rule test failed! %s\n filters: %s",
				c.name,
				c.filters,
			)
		}
	}
}

func TestPluck(t *testing.T) {
	exps := []struct {
		o       map[string]interface{}
		seeking string
		value   interface{}
		name    string
	}{

		{
			map[string]interface{}{
				"hey": map[string]interface{}{
					"hello": "bob",
				},
			},
			"hey.hello",
			"bob",
			`test extracting a simple property`,
		},

		{
			map[string]interface{}{
				"hey": map[string]interface{}{
					"hello": "bob",
				},
			},
			"hey.nope",
			nil,
			`test getting a nonexistent property
			on an existing object`,
		},
		{
			map[string]interface{}{
				"hey": map[string]interface{}{
					"hello": "bob",
				},
			},
			"hey.what.something.very.important",
			nil,
			`test getting a nonexistent property
			for a nonexistent object`,
		},
		{
			map[string]interface{}{
				"hey": map[string]interface{}{
					"hello": "bob",
				},
			},
			"hey.hello.something.very.important",
			nil,
			`test getting a property on a thing
			that isn't or doesn't assert to be a map`,
		},

		{
			map[string]interface{}{
				"hey": map[string]interface{}{
					"sup": 1,
				},
			},
			"hey.sup",
			1,
			`test plucking something that isn't
			a string`,
		},
		{
			map[string]interface{}{},
			"hey.lol",
			nil,
			`test plucking where the base obj doesn't exist`,
		},
		{
			map[string]interface{}{
				"test": map[string]interface{}{
					"thing": map[string]interface{}{
						"here": map[string]interface{}{
							"today": map[string]interface{}{
								"is": map[string]interface{}{
									"awesome": map[string]interface{}{
										"with": map[string]interface{}{
											"thestuff": "no dice",
										},
									},
								},
							},
						},
					},
				},
			},
			"test.thing.here.today.is.awesome.with.thestuff",
			"no dice",
			"testing deeply nested property",
		},
	}

	for _, e := range exps {
		res := pluck(e.o, e.seeking)
		if res != e.value {
			t.Errorf(
				"error with: %s\nfailed to pluck! %s != %s",
				e.name,
				res,
				e.value,
			)
		}
	}
}

func BenchmarkPluckShallow(b *testing.B) {
	o := map[string]interface{}{
		"hey": map[string]interface{}{
			"there": 4,
		},
	}

	for i := 0; i < b.N; i += 1 {
		r := pluck(o, "hey.there")
		if r != 4 {
			b.Errorf("fail bench, val was %s", r)
		}
	}
}

func BenchmarkPluckDeep(b *testing.B) {
	o := map[string]interface{}{
		"test": map[string]interface{}{
			"thing": map[string]interface{}{
				"here": map[string]interface{}{
					"today": map[string]interface{}{
						"is": map[string]interface{}{
							"awesome": map[string]interface{}{
								"with": map[string]interface{}{
									"thestuff": "no dice",
								},
							},
						},
					},
				},
			},
		},
	}

	for i := 0; i < b.N; i += 1 {
		r := pluck(o, "test.thing.here.today.is.awesome.with.thestuff")
		if r != "no dice" {
			b.Errorf("fail bench, val was %s", r)
		}
	}
}

func TestNewRulerWithJson(t *testing.T) {
	theJson := []byte(`[
			{"comparator": "eq", "path": "name", "value": "Thomas"}
		]
	`)

	r, err := NewRulerWithJson(theJson)
	if err != nil {
		t.Errorf("Error getting new ruler w/json: %s", err)
	}

	data := map[string]interface{}{
		"name": "Thomas",
	}

	if !r.Test(data) {
		t.Error("newRulerWithJson didn't do something properly!")
	}
}
<commit_msg>add some ruler benchmarks<commit_after>package ruler

import "testing"

func TestRules(t *testing.T) {

	cases := []struct {
		filters []*Filter
		o       map[string]interface{}
		name    string
	}{
		{
			[]*Filter{
				&Filter{
					"eq",
					"basic.property",
					"foobar",
				},
			},
			map[string]interface{}{
				"basic": map[string]interface{}{
					"property": "foobar",
				},
			},

			"testing basic property equality (string)",
		},
		{
			[]*Filter{
				&Filter{
					"eq",
					"basic.property",
					12,
				},
			},
			map[string]interface{}{
				"basic": map[string]interface{}{
					"property": 12,
				},
			},
			"testing basic property equality (int)",
		},
		{
			[]*Filter{
				&Filter{
					"gt",
					"basic.property",
					45,
				},
			},
			map[string]interface{}{
				"basic": map[string]interface{}{
					"property": 100,
				},
			},
			"testing greater than (int)",
		},
		{
			[]*Filter{
				&Filter{
					"gte",
					"basic.property",
					100,
				},
			},
			map[string]interface{}{
				"basic": map[string]interface{}{
					"property": 100,
				},
			},
			"testing greater than or equal to (int)",
		},
		{
			[]*Filter{
				&Filter{
					"lt",
					"basic.property",
					45,
				},
			},
			map[string]interface{}{
				"basic": map[string]interface{}{
					"property": 10,
				},
			},
			"testing less than (int)",
		},
		{
			[]*Filter{
				&Filter{
					"lte",
					"basic.property",
					45,
				},
			},
			map[string]interface{}{
				"basic": map[string]interface{}{
					"property": 45,
				},
			},
			"testing less than or equal to (int)",
		},

		{
			[]*Filter{
				&Filter{
					"regex",
					"basic.property",
					"a[0-9]*b",
				},
			},
			map[string]interface{}{
				"basic": map[string]interface{}{
					"property": "a9394b",
				},
			},
			"testing regexp",
		},
	}

	for _, c := range cases {
		r := &Ruler{
			filters: c.filters,
		}

		if !r.Test(c.o) {
			t.Errorf("rule test failed! %s\n filters: %s",
				c.name,
				c.filters,
			)
		}
	}
}

func TestPluck(t *testing.T) {
	exps := []struct {
		o       map[string]interface{}
		seeking string
		value   interface{}
		name    string
	}{

		{
			map[string]interface{}{
				"hey": map[string]interface{}{
					"hello": "bob",
				},
			},
			"hey.hello",
			"bob",
			`test extracting a simple property`,
		},

		{
			map[string]interface{}{
				"hey": map[string]interface{}{
					"hello": "bob",
				},
			},
			"hey.nope",
			nil,
			`test getting a nonexistent property
			on an existing object`,
		},
		{
			map[string]interface{}{
				"hey": map[string]interface{}{
					"hello": "bob",
				},
			},
			"hey.what.something.very.important",
			nil,
			`test getting a nonexistent property
			for a nonexistent object`,
		},
		{
			map[string]interface{}{
				"hey": map[string]interface{}{
					"hello": "bob",
				},
			},
			"hey.hello.something.very.important",
			nil,
			`test getting a property on a thing
			that isn't or doesn't assert to be a map`,
		},

		{
			map[string]interface{}{
				"hey": map[string]interface{}{
					"sup": 1,
				},
			},
			"hey.sup",
			1,
			`test plucking something that isn't
			a string`,
		},
		{
			map[string]interface{}{},
			"hey.lol",
			nil,
			`test plucking where the base obj doesn't exist`,
		},
		{
			map[string]interface{}{
				"test": map[string]interface{}{
					"thing": map[string]interface{}{
						"here": map[string]interface{}{
							"today": map[string]interface{}{
								"is": map[string]interface{}{
									"awesome": map[string]interface{}{
										"with": map[string]interface{}{
											"thestuff": "no dice",
										},
									},
								},
							},
						},
					},
				},
			},
			"test.thing.here.today.is.awesome.with.thestuff",
			"no dice",
			"testing deeply nested property",
		},
	}

	for _, e := range exps {
		res := pluck(e.o, e.seeking)
		if res != e.value {
			t.Errorf(
				"error with: %s\nfailed to pluck! %s != %s",
				e.name,
				res,
				e.value,
			)
		}
	}
}

func BenchmarkPluckShallow(b *testing.B) {
	o := map[string]interface{}{
		"hey": map[string]interface{}{
			"there": 4,
		},
	}

	for i := 0; i < b.N; i += 1 {
		r := pluck(o, "hey.there")
		if r != 4 {
			b.Errorf("fail bench, val was %s", r)
		}
	}
}

func BenchmarkPluckDeep(b *testing.B) {
	o := map[string]interface{}{
		"test": map[string]interface{}{
			"thing": map[string]interface{}{
				"here": map[string]interface{}{
					"today": map[string]interface{}{
						"is": map[string]interface{}{
							"awesome": map[string]interface{}{
								"with": map[string]interface{}{
									"thestuff": "no dice",
								},
							},
						},
					},
				},
			},
		},
	}

	for i := 0; i < b.N; i += 1 {
		r := pluck(o, "test.thing.here.today.is.awesome.with.thestuff")
		if r != "no dice" {
			b.Errorf("fail bench, val was %s", r)
		}
	}
}

func TestNewRulerWithJson(t *testing.T) {
	theJson := []byte(`[
			{"comparator": "eq", "path": "name", "value": "Thomas"}
		]
	`)

	r, err := NewRulerWithJson(theJson)
	if err != nil {
		t.Errorf("Error getting new ruler w/json: %s", err)
	}

	data := map[string]interface{}{
		"name": "Thomas",
	}

	if !r.Test(data) {
		t.Error("newRulerWithJson didn't do something properly!")
	}
}

func BenchmarkNewRulerWithJson(b *testing.B) {
	theJson := []byte(`[
			{"comparator": "eq", "path": "name", "value": "Thomas"}
		]
	`)
	data := map[string]interface{}{
		"name": "Thomas",
	}

	for i := 0; i < b.N; i += 1 {
		r, err := NewRulerWithJson(theJson)
		if err != nil {
			b.Errorf("Error getting new ruler w/json: %s", err)
		}

		if !r.Test(data) {
			b.Error("newRulerWithJson didn't do something properly!")
		}
	}
}

func BenchmarkNewRulerWithFiltersSimple(b *testing.B) {
	filters := []*Filter{
		&Filter{
			Comparator: "eq",
			Path:       "name",
			Value:      "Bob",
		},
	}

	data := map[string]interface{}{
		"name": "Bob",
	}

	for i := 0; i < b.N; i += 1 {
		r := NewRuler(&filters)

		if !r.Test(data) {
			b.Error("NewRuler didn't do something properly!")
		}
	}
}

func BenchmarkNewRulerWithFiltersTen(b *testing.B) {
	filters := []*Filter{
		&Filter{
			Comparator: "eq",
			Path:       "name",
			Value:      "Bob",
		},
		&Filter{
			Comparator: "ncontains",
			Path:       "name",
			Value:      "Jones",
		},
		&Filter{
			Comparator: "contains",
			Path:       "location.name",
			Value:      "Florida",
		},
		&Filter{
			Comparator: "gte",
			Path:       "location.x",
			Value:      45.63,
		},
		&Filter{
			Comparator: "lte",
			Path:       "location.y",
			Value:      35.10,
		},
		&Filter{
			Comparator: "gt",
			Path:       "location.pop",
			Value:      100000,
		},
		&Filter{
			Comparator: "lt",
			Path:       "location.elev",
			Value:      1000,
		},
		&Filter{
			Comparator: "eq",
			Path:       "location.extra.fips",
			Value:      "12-24000",
		},
		&Filter{
			Comparator: "eq",
			Path:       "location.extra.time.zone",
			Value:      "America/New_York",
		},
		&Filter{
			Comparator: "eq",
			Path:       "location.extra.time.speed.you-made-it-this-far.reward",
			Value:      "you",
		},
	}

	data := map[string]interface{}{
		"name": "Bob",
		"location": map[string]interface{}{
			"name": "Fort Lauderdale, Florida",
			"x":    93.23,
			"y":    22.32,
			"pop":  324234234,
			"elev": 72,
			"extra": map[string]interface{}{
				"fips": "12-24000",
				"time": map[string]interface{}{
					"zone":  "America/New_York",
					"isDst": "maybe",
					"speed": map[string]interface{}{
						"you-made-it-this-far": map[string]interface{}{
							"so":     "now",
							"we":     "will",
							"reward": "you",
						},
					},
				},
			},
		},
	}

	for i := 0; i < b.N; i += 1 {
		r := NewRuler(&filters)

		if !r.Test(data) {
			b.Error("NewRuler didn't do something properly!")
		}
	}
}
<|endoftext|>