<commit_before>package atlas

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/url"
	"testing"

	"github.com/h2non/gock"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

var (
	TesCfg = Config{
		APIKey:       "foobar",
		DefaultProbe: 666,
		IsOneOff:     true,
		PoolSize:     10,
		AreaType:     "country",
		AreaValue:    "fr",
		Tags:         "",
		Verbose:      true,
		Log:          nil,
	}
)

func Before(t *testing.T) *Client {

	testc, err := NewClient(TesCfg)

	assert.NoError(t, err)
	assert.NotNil(t, testc)
	assert.IsType(t, (*Client)(nil), testc)

	return testc
}

func TestClient_NewMeasurement(t *testing.T) {
	c := Before(t)

	m := c.NewMeasurement()

	assert.NotNil(t, c)
	assert.NotNil(t, m)
	assert.IsType(t, (*MeasurementRequest)(nil), m)
	assert.IsType(t, ([]Definition)(nil), m.Definitions)
	assert.IsType(t, ([]ProbeSet)(nil), m.Probes)
	assert.True(t, m.IsOneoff)
}

func TestMeasurementRequest_AddDefinition(t *testing.T) {
	c := Before(t)
	require.NotNil(t, c)
	require.NotEmpty(t, c)

	mr := c.NewMeasurement()
	require.NotNil(t, mr)
	assert.IsType(t, (*MeasurementRequest)(nil), mr)

	mrlen := len(mr.Definitions)

	opts := map[string]string{"AF": "6"}

	mrr := mr.AddDefinition(opts)
	require.NotNil(t, mrr)
	assert.IsType(t, (*MeasurementRequest)(nil), mrr)

	assert.Equal(t, mrlen+1, len(mrr.Definitions))
}

func TestIsPositive(t *testing.T) {
	a := ""
	b, y := isPositive(a)
	assert.True(t, y)
	assert.Equal(t, "", b)

	a = "foo"
	b, y = isPositive(a)
	assert.True(t, y)
	assert.Equal(t, "foo", b)

	a = "+foo"
	b, y = isPositive(a)
	assert.True(t, y)
	assert.Equal(t, "foo", b)

	a = "-foo"
	b, y = isPositive(a)
	assert.False(t, y)
	assert.Equal(t, "foo", b)

	a = "!foo"
	b, y = isPositive(a)
	assert.False(t, y)
	assert.Equal(t, "foo", b)
}

var TestSplitTagsData = []struct {
	tags    string
	in, out string
}{
	{"", "", ""},
	{"foo", "foo", ""},
	{"foo,bar", "foo,bar", ""},
	{"!foo", "", "foo"},
	{"foo,!bar", "foo", "bar"},
	{"+foo,bar", "foo,bar", ""},
	{"+foo,-bar", "foo", "bar"},
	{"+foo,-bar,!baz", "foo", "bar,baz"},
}

func TestSplitTags(t *testing.T) {
	for _, d := range TestSplitTagsData {
		in, out := splitTags(d.tags)
		assert.Equal(t, d.in, in)
		assert.Equal(t, d.out, out)
	}
}

func TestNewProbeSet(t *testing.T) {
	bmps := ProbeSet{Requested: 10, Type: "country", Value: "fr", TagsInclude: "system-ipv6-stable-1d", TagsExclude: ""}
	ps := NewProbeSet(10, "country", "fr", "system-ipv6-stable-1d")

	assert.NotEmpty(t, ps)
	assert.EqualValues(t, bmps, ps)
}

func TestNewProbeSet_2(t *testing.T) {
	bmps := ProbeSet{Requested: 10, Type: "area", Value: "WW", TagsInclude: "system-ipv6-stable-1d", TagsExclude: ""}
	ps := NewProbeSet(0, "", "", "system-ipv6-stable-1d")

	assert.NotEmpty(t, ps)
	assert.EqualValues(t, bmps, ps)
}

func TestDNS(t *testing.T) {
	//BeforeAPI(t)
	defer gock.Off()

	d := []Definition{{Type: "foo"}}
	r := &MeasurementRequest{Definitions: d}
	jr, _ := json.Marshal(r)
	myrp := MeasurementResp{}

	t.Logf("jr=%v", string(jr))

	myurl, _ := url.Parse(apiEndpoint)

	buf := bytes.NewReader(jr)
	gock.New(apiEndpoint).
		Post("measurements/dns").
		MatchParam("key", "foobar").
		MatchHeaders(map[string]string{
			"content-type": "application/json",
			"accept":       "application/json",
			"host":         myurl.Host,
			"user-agent":   fmt.Sprintf("ripe-atlas/%s", ourVersion),
		}).
		Body(buf).
		Reply(403).
		BodyString(`{"error":{"status":403,"code":104,"detail":"The provided API key does not exist","title":"Forbidden"}}`)

	c := Before(t)

	gock.InterceptClient(c.client)
	defer gock.RestoreClient(c.client)

	rp, err := c.DNS(r)
	t.Logf("rp=%#v", rp)
	assert.Error(t, err, "should be in error")
	assert.EqualValues(t, myrp, rp, "should be equal")
	assert.EqualValues(t, ErrInvalidMeasurementType, err, "should be equal")
}

func TestClient_Call(t *testing.T) {
	defer gock.Off()

	d := []Definition{{Type: "foo"}}
	r := &MeasurementRequest{Definitions: d}
	jr, _ := json.Marshal(r)
	//myrp := MeasurementResp{}

	t.Logf("jr=%v", string(jr))

	myurl, _ := url.Parse(apiEndpoint)

	gock.EnableNetworking()
	gock.New(apiEndpoint).
		Post("measurements/dns").
		MatchParam("key", "foobar").
		MatchHeaders(map[string]string{
			"content-type": "application/json",
			"accept":       "application/json",
			"host":         myurl.Host,
			"user-agent":   fmt.Sprintf("ripe-atlas/%s", ourVersion),
		}).
		JSON(r).
		Reply(403).
		BodyString(`{"error":{"status":403,"code":104,"detail":"The provided API key does not exist","title":"Forbidden"}}`)

	c := Before(t)

	gock.InterceptClient(c.client)
	defer gock.RestoreClient(c.client)
	defer gock.DisableNetworking()

	opts := map[string]string{"key": "foobar"}
	req := c.prepareRequest("POST", "/measurements/dns/", opts)
	require.NotNil(t, req)

	resp, err := c.call(req)
	assert.NoError(t, err)
	assert.NotNil(t, resp)
}

/*
func (c *Client) call(req *http.Request) (*http.Response, error) {
	c.verbose("Full URL:\n%v", req.URL)

	myurl, _ := url.Parse(apiEndpoint)
	req.Header.Set("Host", myurl.Host)
	req.Header.Set("User-Agent", fmt.Sprintf("ripe-atlas/%s", ourVersion))

	return c.client.Do(req)
}

func TestNTP(t *testing.T) {
	d := []Definition{{Type: "foo"}}
	r := &MeasurementRequest{Definitions: d}

	_, err := NTP(r)
	assert.Error(t, err, "should be an error")
	assert.EqualValues(t, ErrInvalidMeasurementType, err, "should be equal")
}

func TestPing(t *testing.T) {
	d := []Definition{{Type: "foo"}}
	r := &MeasurementRequest{Definitions: d}

	_, err := Ping(r)
	assert.Error(t, err, "should be an error")
	assert.EqualValues(t, ErrInvalidMeasurementType, err, "should be equal")
}

func TestSSLCert(t *testing.T) {
	d := []Definition{{Type: "foo"}}
	r := &MeasurementRequest{Definitions: d}

	_, err := SSLCert(r)
	assert.Error(t, err, "should be an error")
	assert.EqualValues(t, ErrInvalidMeasurementType, err, "should be equal")
}

func TestTraceroute(t *testing.T) {
	d := []Definition{{Type: "foo"}}
	r := &MeasurementRequest{Definitions: d}

	_, err := Traceroute(r)
	assert.Error(t, err, "should be an error")
	assert.EqualValues(t, ErrInvalidMeasurementType, err, "should be equal")
}
*/
<commit_msg>Partial tests for DNS().<commit_after>package atlas

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/url"
	"testing"

	"github.com/h2non/gock"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

var (
	TesCfg = Config{
		APIKey:       "foobar",
		DefaultProbe: 666,
		IsOneOff:     true,
		PoolSize:     10,
		AreaType:     "country",
		AreaValue:    "fr",
		Tags:         "",
		Verbose:      true,
		Log:          nil,
	}
)

func Before(t *testing.T) *Client {

	testc, err := NewClient(TesCfg)

	assert.NoError(t, err)
	assert.NotNil(t, testc)
	assert.IsType(t, (*Client)(nil), testc)
	require.NotNil(t, testc.client)

	return testc
}

func TestClient_NewMeasurement(t *testing.T) {
	c := Before(t)

	m := c.NewMeasurement()

	assert.NotNil(t, c)
	assert.NotNil(t, m)
	assert.IsType(t, (*MeasurementRequest)(nil), m)
	assert.IsType(t, ([]Definition)(nil), m.Definitions)
	assert.IsType(t, ([]ProbeSet)(nil), m.Probes)
	assert.True(t, m.IsOneoff)
}

func TestMeasurementRequest_AddDefinition(t *testing.T) {
	c := Before(t)
	require.NotNil(t, c)
	require.NotEmpty(t, c)

	mr := c.NewMeasurement()
	require.NotNil(t, mr)
	assert.IsType(t, (*MeasurementRequest)(nil), mr)

	mrlen := len(mr.Definitions)

	opts := map[string]string{"AF": "6"}

	mrr := mr.AddDefinition(opts)
	require.NotNil(t, mrr)
	assert.IsType(t, (*MeasurementRequest)(nil), mrr)

	assert.Equal(t, mrlen+1, len(mrr.Definitions))
}

func TestIsPositive(t *testing.T) {
	a := ""
	b, y := isPositive(a)
	assert.True(t, y)
	assert.Equal(t, "", b)

	a = "foo"
	b, y = isPositive(a)
	assert.True(t, y)
	assert.Equal(t, "foo", b)

	a = "+foo"
	b, y = isPositive(a)
	assert.True(t, y)
	assert.Equal(t, "foo", b)

	a = "-foo"
	b, y = isPositive(a)
	assert.False(t, y)
	assert.Equal(t, "foo", b)

	a = "!foo"
	b, y = isPositive(a)
	assert.False(t, y)
	assert.Equal(t, "foo", b)
}

var TestSplitTagsData = []struct {
	tags    string
	in, out string
}{
	{"", "", ""},
	{"foo", "foo", ""},
	{"foo,bar", "foo,bar", ""},
	{"!foo", "", "foo"},
	{"foo,!bar", "foo", "bar"},
	{"+foo,bar", "foo,bar", ""},
	{"+foo,-bar", "foo", "bar"},
	{"+foo,-bar,!baz", "foo", "bar,baz"},
}

func TestSplitTags(t *testing.T) {
	for _, d := range TestSplitTagsData {
		in, out := splitTags(d.tags)
		assert.Equal(t, d.in, in)
		assert.Equal(t, d.out, out)
	}
}

func TestNewProbeSet(t *testing.T) {
	bmps := ProbeSet{Requested: 10, Type: "country", Value: "fr", TagsInclude: "system-ipv6-stable-1d", TagsExclude: ""}
	ps := NewProbeSet(10, "country", "fr", "system-ipv6-stable-1d")

	assert.NotEmpty(t, ps)
	assert.EqualValues(t, bmps, ps)
}

func TestNewProbeSet_2(t *testing.T) {
	bmps := ProbeSet{Requested: 10, Type: "area", Value: "WW", TagsInclude: "system-ipv6-stable-1d", TagsExclude: ""}
	ps := NewProbeSet(0, "", "", "system-ipv6-stable-1d")

	assert.NotEmpty(t, ps)
	assert.EqualValues(t, bmps, ps)
}

func TestClient_DNS_InvalidKey(t *testing.T) {
	//BeforeAPI(t)
	defer gock.Off()

	d := []Definition{{Type: "foo"}}
	r := &MeasurementRequest{Definitions: d}
	jr, _ := json.Marshal(r)

	myrp := `{"error":{"status":403,"code":104,"detail":"The provided API key does not exist","title":"Forbidden"}}`

	t.Logf("jr=%v", string(jr))

	myurl, _ := url.Parse(apiEndpoint)

	buf := bytes.NewReader(jr)
	gock.New(apiEndpoint).
		Post("measurements/dns").
		MatchParam("key", "foobar").
		MatchHeaders(map[string]string{
			"content-type": "application/json",
			"accept":       "application/json",
			"host":         myurl.Host,
			"user-agent":   fmt.Sprintf("ripe-atlas/%s", ourVersion),
		}).
		Body(buf).
		Reply(403).
		BodyString(myrp)

	c := Before(t)

	gock.InterceptClient(c.client)
	defer gock.RestoreClient(c.client)

	rp, err := c.DNS(r)
	t.Logf("rp=%#v", rp)
	assert.Error(t, err)
	assert.Empty(t, rp)
	assert.EqualValues(t, "createMeasurement: The provided API key does not exist", err.Error())
}

func TestClient_DNS(t *testing.T) {
	defer gock.Off()

	d := []Definition{{Type: "foo"}}
	r := &MeasurementRequest{Definitions: d}
	jr, _ := json.Marshal(r)
	jrq, _ := json.Marshal(MeasurementResp{})

	myurl, _ := url.Parse(apiEndpoint)

	buf := bytes.NewReader(jr)
	gock.New(apiEndpoint).
		Post("measurements/dns").
		MatchParam("key", "foobar").
		MatchHeaders(map[string]string{
			"content-type": "application/json",
			"accept":       "application/json",
			"host":         myurl.Host,
			"user-agent":   fmt.Sprintf("ripe-atlas/%s", ourVersion),
		}).
		Body(buf).
		Reply(200).
		BodyString(string(jrq))

	c := Before(t)

	gock.InterceptClient(c.client)
	defer gock.RestoreClient(c.client)

	rp, err := c.DNS(r)
	t.Logf("rp=%#v", rp)
	assert.NoError(t, err)
	assert.Empty(t, rp)
}

func TestClient_Call(t *testing.T) {
	defer gock.Off()

	d := []Definition{{Type: "foo"}}
	r := &MeasurementRequest{Definitions: d}
	jr, _ := json.Marshal(r)
	//myrp := MeasurementResp{}

	t.Logf("jr=%v", string(jr))

	myurl, _ := url.Parse(apiEndpoint)

	gock.New(apiEndpoint).
		Post("measurements/dns").
		MatchParam("key", "foobar").
		MatchHeaders(map[string]string{
			"content-type": "application/json",
			"accept":       "application/json",
			"host":         myurl.Host,
			"user-agent":   fmt.Sprintf("ripe-atlas/%s", ourVersion),
		}).
		MatchType("json").
		JSON(r).
		Reply(403).
		BodyString(`{"error":{"status":403,"code":104,"detail":"The provided API key does not exist","title":"Forbidden"}}`)

	c := Before(t)

	gock.InterceptClient(c.client)
	defer gock.RestoreClient(c.client)

	opts := map[string]string{"key": "foobar"}
	req := c.prepareRequest("POST", "/measurements/dns", opts)
	require.NotNil(t, req)

	buf := bytes.NewReader(jr)
	req.Body = ioutil.NopCloser(buf)
	req.ContentLength = int64(buf.Len())

	require.NotNil(t, req.Body)

	resp, err := c.call(req)
	assert.NoError(t, err)
	assert.NotNil(t, resp)
}

/*
func (c *Client) call(req *http.Request) (*http.Response, error) {
	c.verbose("Full URL:\n%v", req.URL)

	myurl, _ := url.Parse(apiEndpoint)
	req.Header.Set("Host", myurl.Host)
	req.Header.Set("User-Agent", fmt.Sprintf("ripe-atlas/%s", ourVersion))

	return c.client.Do(req)
}

func TestNTP(t *testing.T) {
	d := []Definition{{Type: "foo"}}
	r := &MeasurementRequest{Definitions: d}

	_, err := NTP(r)
	assert.Error(t, err, "should be an error")
	assert.EqualValues(t, ErrInvalidMeasurementType, err, "should be equal")
}

func TestPing(t *testing.T) {
	d := []Definition{{Type: "foo"}}
	r := &MeasurementRequest{Definitions: d}

	_, err := Ping(r)
	assert.Error(t, err, "should be an error")
	assert.EqualValues(t, ErrInvalidMeasurementType, err, "should be equal")
}

func TestSSLCert(t *testing.T) {
	d := []Definition{{Type: "foo"}}
	r := &MeasurementRequest{Definitions: d}

	_, err := SSLCert(r)
	assert.Error(t, err, "should be an error")
	assert.EqualValues(t, ErrInvalidMeasurementType, err, "should be equal")
}

func TestTraceroute(t *testing.T) {
	d := []Definition{{Type: "foo"}}
	r := &MeasurementRequest{Definitions: d}

	_, err := Traceroute(r)
	assert.Error(t, err, "should be an error")
	assert.EqualValues(t, ErrInvalidMeasurementType, err, "should be equal")
}
*/
<|endoftext|>


<commit_before>package media

import (
	"bytes"
	"encoding/gob"
	"errors"
	"fmt"

	"github.com/boltdb/bolt"
	datautils "github.com/sgeisbacher/goutils/datautils"
)

var (
	BUCKET_GALLERIES = []byte("galleries")
)

type Gallery struct {
	Id     string
	Name   string
	Year   int
	Photos []string
}

type GalleryService struct {
	Db *bolt.DB
}

func (srv *GalleryService) FindGalleryById(id string) (*Gallery, error) {
	var gallery *Gallery
	err := srv.Db.View(func(tx *bolt.Tx) error {
		bucket, err := tx.CreateBucketIfNotExists(BUCKET_GALLERIES)
		if err != nil {
			return err
		}

		gallery = getGalleryFromBucket(bucket, id)

		return err
	})

	return gallery, err
}

func (srv *GalleryService) Add(galleryName string) (*Gallery, error) {
	galleryId := datautils.ToID(galleryName)
	gallery, _ := srv.FindGalleryById(galleryId)
	if gallery != nil {
		return gallery, nil
	}

	err := srv.Db.Update(func(tx *bolt.Tx) error {
		bucket, err := tx.CreateBucketIfNotExists(BUCKET_GALLERIES)
		if err != nil {
			fmt.Println("error while creating/getting bucket:", err)
			return err
		}

		gallery = &Gallery{}
		gallery.Id = galleryId
		gallery.Name = galleryName

		galleryEncoded, err := gallery.gobEncode()
		return bucket.Put([]byte(gallery.Id), galleryEncoded)
	})

	return gallery, err
}

func (srv *GalleryService) AddMediaToGallery(galleryName string, media Media) error {
	srv.Add(galleryName)
	return srv.Db.Update(func(tx *bolt.Tx) error {
		bucket, err := tx.CreateBucketIfNotExists(BUCKET_GALLERIES)
		if err != nil {
			fmt.Println("error while creating/getting bucket:", err)
			return err
		}

		galleryId := datautils.ToID(galleryName)
		gallery := getGalleryFromBucket(bucket, galleryId)
		if gallery == nil {
			return errors.New(fmt.Sprintf("could not find gallery '%v'", galleryId))
		}

		gallery.Photos = append(gallery.Photos, media.Hash)

		galleryEncoded, err := gallery.gobEncode()
		return bucket.Put([]byte(gallery.Id), galleryEncoded)
	})
}

func (srv *GalleryService) FindAll() ([]*Gallery, error) {
	var galleries []*Gallery
	err := srv.Db.View(func(tx *bolt.Tx) error {
		bucket := tx.Bucket(BUCKET_GALLERIES)
		if bucket == nil {
			return errors.New(fmt.Sprintf("bucket '%v' not found", string(BUCKET_GALLERIES)))
		}
		cursor := bucket.Cursor()
		for key, data := cursor.First(); data != nil; key, data = cursor.Next() {
			gallery, err := gobDecodeGallery(data)
			if err != nil {
				fmt.Printf("could not decode '%v': %v\n", key, err)
				continue
			}
			galleries = append(galleries, gallery)
		}
		return nil
	})
	return galleries, err
}

func getGalleryFromBucket(bucket *bolt.Bucket, id string) *Gallery {
	data := bucket.Get([]byte(id))
	if data == nil {
		return nil
	}
	gallery, err := gobDecodeGallery(data)
	if err != nil {
		return nil
	}
	return gallery
}

func (gallery Gallery) gobEncode() ([]byte, error) {
	buf := new(bytes.Buffer)
	enc := gob.NewEncoder(buf)
	err := enc.Encode(gallery)
	if err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

func gobDecodeGallery(data []byte) (*Gallery, error) {
	var g *Gallery
	buf := bytes.NewBuffer(data)
	dec := gob.NewDecoder(buf)
	err := dec.Decode(&g)
	if err != nil {
		return nil, err
	}
	return g, nil
}
<commit_msg>fixed reader's opening read-write-transaction<commit_after>package media

import (
	"bytes"
	"encoding/gob"
	"errors"
	"fmt"

	"github.com/boltdb/bolt"
	datautils "github.com/sgeisbacher/goutils/datautils"
)

var (
	BUCKET_GALLERIES = []byte("galleries")
)

type Gallery struct {
	Id     string
	Name   string
	Year   int
	Photos []string
}

type GalleryService struct {
	Db *bolt.DB
}

func (srv *GalleryService) FindGalleryById(id string) (*Gallery, error) {
	var gallery *Gallery
	err := srv.Db.View(func(tx *bolt.Tx) error {
		bucket := tx.Bucket(BUCKET_GALLERIES)
		if bucket == nil {
			return errors.New(fmt.Sprintf("bucket '%v' not found", BUCKET_GALLERIES))
		}

		gallery = getGalleryFromBucket(bucket, id)

		return nil
	})

	return gallery, err
}

func (srv *GalleryService) Add(galleryName string) (*Gallery, error) {
	galleryId := datautils.ToID(galleryName)
	gallery, _ := srv.FindGalleryById(galleryId)
	if gallery != nil {
		return gallery, nil
	}

	err := srv.Db.Update(func(tx *bolt.Tx) error {
		bucket, err := tx.CreateBucketIfNotExists(BUCKET_GALLERIES)
		if err != nil {
			fmt.Println("error while creating/getting bucket:", err)
			return err
		}

		gallery = &Gallery{}
		gallery.Id = galleryId
		gallery.Name = galleryName

		galleryEncoded, err := gallery.gobEncode()
		return bucket.Put([]byte(gallery.Id), galleryEncoded)
	})

	return gallery, err
}

func (srv *GalleryService) AddMediaToGallery(galleryName string, media Media) error {
	srv.Add(galleryName)
	return srv.Db.Update(func(tx *bolt.Tx) error {
		bucket, err := tx.CreateBucketIfNotExists(BUCKET_GALLERIES)
		if err != nil {
			fmt.Println("error while creating/getting bucket:", err)
			return err
		}

		galleryId := datautils.ToID(galleryName)
		gallery := getGalleryFromBucket(bucket, galleryId)
		if gallery == nil {
			return errors.New(fmt.Sprintf("could not find gallery '%v'", galleryId))
		}

		gallery.Photos = append(gallery.Photos, media.Hash)

		galleryEncoded, err := gallery.gobEncode()
		return bucket.Put([]byte(gallery.Id), galleryEncoded)
	})
}

func (srv *GalleryService) FindAll() ([]*Gallery, error) {
	var galleries []*Gallery
	err := srv.Db.View(func(tx *bolt.Tx) error {
		bucket := tx.Bucket(BUCKET_GALLERIES)
		if bucket == nil {
			return errors.New(fmt.Sprintf("bucket '%v' not found", string(BUCKET_GALLERIES)))
		}
		cursor := bucket.Cursor()
		for key, data := cursor.First(); data != nil; key, data = cursor.Next() {
			gallery, err := gobDecodeGallery(data)
			if err != nil {
				fmt.Printf("could not decode '%v': %v\n", key, err)
				continue
			}
			galleries = append(galleries, gallery)
		}
		return nil
	})
	return galleries, err
}

func getGalleryFromBucket(bucket *bolt.Bucket, id string) *Gallery {
	data := bucket.Get([]byte(id))
	if data == nil {
		return nil
	}
	gallery, err := gobDecodeGallery(data)
	if err != nil {
		return nil
	}
	return gallery
}

func (gallery Gallery) gobEncode() ([]byte, error) {
	buf := new(bytes.Buffer)
	enc := gob.NewEncoder(buf)
	err := enc.Encode(gallery)
	if err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

func gobDecodeGallery(data []byte) (*Gallery, error) {
	var g *Gallery
	buf := bytes.NewBuffer(data)
	dec := gob.NewDecoder(buf)
	err := dec.Decode(&g)
	if err != nil {
		return nil, err
	}
	return g, nil
}
<|endoftext|>


<commit_before>// Copyright 2017-2018 Authors of Cilium
//
// 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 cmd

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"github.com/cilium/cilium/daemon/defaults"
	"github.com/cilium/cilium/pkg/logging/logfields"

	"github.com/sirupsen/logrus"
)

// BugtoolConfiguration creates and loads the configuration file used to run
// the commands. The only commands not managed by the configuration is initial
// setup, for ex. searching for Cilium daemonset pods or running uname.
type BugtoolConfiguration struct {
	// Commands is the exact commands that will be run by the bugtool
	Commands []string `json:"commands"`
}

func setupDefaultConfig(path string, k8sPods []string, confDir, cmdDir string) (*BugtoolConfiguration, error) {
	c := BugtoolConfiguration{defaultCommands(confDir, cmdDir, k8sPods)}
	return &c, save(&c, path)
}

func defaultCommands(confDir string, cmdDir string, k8sPods []string) []string {
	var commands []string
	// Not expecting all of the commands to be available
	commands = []string{
		// Host and misc
		"ps",
		"hostname",
		"ip a",
		"ip r",
		"ip link",
		"uname -a",
		"dig",
		"netstat",
		"pidstat",
		"arp",
		"top -b -n 1",
		"uptime",
		"dmesg",
		"bpftool map show",
		"bpftool prog show",
		// Versions
		"docker version",
		// Docker and Kubernetes logs from systemd
		"journalctl -u cilium*",
		"journalctl -u kubelet",
		// iptables
		"iptables-save",
		"iptables -S",
		"ip6tables -S",
		"iptables -L -v",
	}

	// Commands that require variables and / or more configuration are added
	// separately below
	commands = append(commands, catCommands()...)
	commands = append(commands, ethoolCommands()...)
	commands = append(commands, copyConfigCommands(confDir, k8sPods)...)
	commands = append(commands, copyCiliumInfoCommands(cmdDir, k8sPods)...)

	return k8sCommands(commands, k8sPods)
}

func save(c *BugtoolConfiguration, path string) error {
	f, err := os.Create(path)
	if err != nil {
		return fmt.Errorf("Failed to open file %s for writing: %s", path, err)
	}
	defer f.Close()

	data, err := json.MarshalIndent(c, "", "\t")
	if err != nil {
		return fmt.Errorf("Cannot marshal config %s", err)
	}
	err = ioutil.WriteFile(path, data, 0644)
	if err != nil {
		return fmt.Errorf("Cannot write config %s", err)
	}
	return nil
}

func loadConfigFile(path string) (*BugtoolConfiguration, error) {
	var content []byte
	var err error
	logrus.WithField(logfields.Path, path).Debug("Loading file")

	content, err = ioutil.ReadFile(path)

	if err != nil {
		return nil, err
	}

	var c BugtoolConfiguration
	err = json.Unmarshal(content, &c)
	return &c, err
}

func catCommands() []string {
	files := []string{
		"/proc/sys/net/core/bpf_jit_enable",
		"/proc/kallsyms",
		"/etc/resolv.conf",
		"/var/log/upstart/docker.log",
		"/var/log/docker.log",
		"/var/log/daemon.log",
		"/var/log/messages",
	}
	// Only print the files that do exist to reduce number of errors in
	// archive
	commands := []string{}
	for _, f := range files {
		if _, err := os.Stat(f); os.IsNotExist(err) {
			continue
		}
		commands = append(commands, fmt.Sprintf("cat %s", f))
	}
	// TODO: handle K8s case as well.
	return commands
}

func copyConfigCommands(confDir string, k8sPods []string) []string {
	commands := []string{}
	// Location is a convenince structure to avoid too many long lines
	type Location struct {
		Src string
		Dst string
	}

	// These locations don't depend on the kernel version for running so we
	// can add them in this scope.
	locations := []Location{
		{"/proc/config", fmt.Sprintf("%s/kernel-config", confDir)},
		{"/proc/config.gz", fmt.Sprintf("%s/kernel-config.gz", confDir)},
	}

	// The following lines copy the kernel configuration. This code is
	// duplicated for the non Kubernetes case. The variables preventing
	// them to be one block is the pod prefix and namespace used in the
	// path. This should be refactored.
	if len(k8sPods) == 0 {
		kernel, _ := execCommand("uname", "-r")
		kernel = strings.TrimSpace(kernel)
		// Append the boot config for the current kernel
		l := Location{fmt.Sprintf("/boot/config-%s", kernel),
			fmt.Sprintf("%s/kernel-config-%s", confDir, kernel)}
		locations = append(locations, l)

		// Use the locations to create command strings
		for _, location := range locations {
			if _, err := os.Stat(location.Src); os.IsNotExist(err) {
				continue
			}
			commands = append(commands, fmt.Sprintf("cp %s %s", location.Src, location.Dst))
		}
	} else {
		// If there are multiple pods, we want to get all of the kernel
		// configs. Therefore we need copy commands for all the pods.
		for _, pod := range k8sPods {
			prompt := podPrefix(pod, "uname -r")
			cmd, args := split(prompt)
			kernel, _ := execCommand(cmd, args...)
			kernel = strings.TrimSpace(kernel)
			l := Location{fmt.Sprintf("/boot/config-%s", kernel),
				fmt.Sprintf("%s/kernel-config-%s", confDir, kernel)}
			locations = append(locations, l)

			// The location is mostly the same but the command is
			// prepended with 'kubectl` and the path contains the
			// namespace and pod. For ex:
			// kubectl cp kube-system/cilium-kg8lv:/tmp/cilium-bugtool-243785589.tar /tmp/cilium-bugtool-243785589.tar
			for _, location := range locations {
				kubectlArg := fmt.Sprintf("%s/%s:%s", k8sNamespace, pod, location.Src)
				cmd := fmt.Sprintf("%s %s %s %s", "kubectl", "cp", kubectlArg, location.Dst)
				commands = append(commands, cmd)
			}
		}
	}
	return commands
}

func copyCiliumInfoCommands(cmdDir string, k8sPods []string) []string {
	// Most of the output should come via debuginfo but also adding
	// these ones for skimming purposes
	ciliumCommands := []string{
		"cilium debuginfo",
		"cilium config",
		"cilium bpf tunnel list",
		"cilium bpf lb list",
		"cilium bpf endpoint list",
		"cilium bpf ct list global",
		"cilium bpf proxy list",
		"cilium bpf ipcache list",
		"cilium status --verbose",
	}
	var commands []string

	stateDir := filepath.Join(defaults.RuntimePath, defaults.StateDir)
	if len(k8sPods) == 0 { // Assuming this is a non k8s deployment
		dst := filepath.Join(cmdDir, defaults.StateDir)
		commands = append(commands, fmt.Sprintf("cp -r %s %s", stateDir, dst))
		for _, cmd := range ciliumCommands {
			// Add the host flag if set
			if len(host) > 0 {
				cmd = fmt.Sprintf("%s -H %s", cmd, host)
			}
			commands = append(commands, cmd)
		}
	} else { // Found k8s pods
		for _, pod := range k8sPods {
			dst := filepath.Join(cmdDir, fmt.Sprintf("%s-%s", pod, defaults.StateDir))
			kubectlArg := fmt.Sprintf("%s/%s:%s", k8sNamespace, pod, stateDir)
			// kubectl cp kube-system/cilium-xrzwr:/var/run/cilium/state cilium-xrzwr-state
			commands = append(commands, fmt.Sprintf("kubectl cp %s %s", kubectlArg, dst))
			for _, cmd := range ciliumCommands {
				// Add the host flag if set
				if len(host) > 0 {
					cmd = fmt.Sprintf("%s -H %s", cmd, host)
				}
				commands = append(commands, podPrefix(pod, cmd))
			}
		}
	}

	return commands
}

func k8sCommands(allCommands []string, pods []string) []string {
	// These commands do not require a pod argument
	var commands = []string{
		"kubectl get nodes -o wide",
		"kubectl describe nodes",
		"kubectl get pods,svc --all-namespaces",
		"kubectl version",
	}

	// Prepare to run all the commands inside of the pod(s)
	for _, pod := range pods {
		for _, cmd := range allCommands {
			// Add the host flag if set
			if strings.HasPrefix(cmd, "cilium") &&
				!strings.Contains(cmd, "-H") && len(host) > 0 {
				cmd = fmt.Sprintf("%s -H %s", cmd, host)
			}

			if !strings.Contains(cmd, "kubectl exec") {
				cmd = podPrefix(pod, cmd)
			}
			commands = append(commands, cmd)
		}

		// Retrieve current version of pod logs
		cmd := fmt.Sprintf("kubectl -n %s logs --timestamps %s", k8sNamespace, pod)
		commands = append(commands, cmd)

		// Retrieve previous version of pod logs
		cmd = fmt.Sprintf("kubectl -n %s logs --timestamps -p %s", k8sNamespace, pod)
		commands = append(commands, cmd)

		cmd = fmt.Sprintf("kubectl -n %s describe pod %s", k8sNamespace, pod)
		commands = append(commands, cmd)
	}

	if len(pods) == 0 {
		allCommands = append(allCommands, commands...)
		return allCommands
	}

	return commands
}
<commit_msg>bugtool: run `ip rule`<commit_after>// Copyright 2017-2018 Authors of Cilium
//
// 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 cmd

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"github.com/cilium/cilium/daemon/defaults"
	"github.com/cilium/cilium/pkg/logging/logfields"

	"github.com/sirupsen/logrus"
)

// BugtoolConfiguration creates and loads the configuration file used to run
// the commands. The only commands not managed by the configuration is initial
// setup, for ex. searching for Cilium daemonset pods or running uname.
type BugtoolConfiguration struct {
	// Commands is the exact commands that will be run by the bugtool
	Commands []string `json:"commands"`
}

func setupDefaultConfig(path string, k8sPods []string, confDir, cmdDir string) (*BugtoolConfiguration, error) {
	c := BugtoolConfiguration{defaultCommands(confDir, cmdDir, k8sPods)}
	return &c, save(&c, path)
}

func defaultCommands(confDir string, cmdDir string, k8sPods []string) []string {
	var commands []string
	// Not expecting all of the commands to be available
	commands = []string{
		// Host and misc
		"ps",
		"hostname",
		"ip a",
		"ip r",
		"ip link",
		"uname -a",
		"dig",
		"netstat",
		"pidstat",
		"arp",
		"top -b -n 1",
		"uptime",
		"dmesg",
		"bpftool map show",
		"bpftool prog show",
		// Versions
		"docker version",
		// Docker and Kubernetes logs from systemd
		"journalctl -u cilium*",
		"journalctl -u kubelet",
		// iptables
		"iptables-save",
		"iptables -S",
		"ip6tables -S",
		"iptables -L -v",
		"ip rule",
	}

	// Commands that require variables and / or more configuration are added
	// separately below
	commands = append(commands, catCommands()...)
	commands = append(commands, ethoolCommands()...)
	commands = append(commands, copyConfigCommands(confDir, k8sPods)...)
	commands = append(commands, copyCiliumInfoCommands(cmdDir, k8sPods)...)

	return k8sCommands(commands, k8sPods)
}

func save(c *BugtoolConfiguration, path string) error {
	f, err := os.Create(path)
	if err != nil {
		return fmt.Errorf("Failed to open file %s for writing: %s", path, err)
	}
	defer f.Close()

	data, err := json.MarshalIndent(c, "", "\t")
	if err != nil {
		return fmt.Errorf("Cannot marshal config %s", err)
	}
	err = ioutil.WriteFile(path, data, 0644)
	if err != nil {
		return fmt.Errorf("Cannot write config %s", err)
	}
	return nil
}

func loadConfigFile(path string) (*BugtoolConfiguration, error) {
	var content []byte
	var err error
	logrus.WithField(logfields.Path, path).Debug("Loading file")

	content, err = ioutil.ReadFile(path)

	if err != nil {
		return nil, err
	}

	var c BugtoolConfiguration
	err = json.Unmarshal(content, &c)
	return &c, err
}

func catCommands() []string {
	files := []string{
		"/proc/sys/net/core/bpf_jit_enable",
		"/proc/kallsyms",
		"/etc/resolv.conf",
		"/var/log/upstart/docker.log",
		"/var/log/docker.log",
		"/var/log/daemon.log",
		"/var/log/messages",
	}
	// Only print the files that do exist to reduce number of errors in
	// archive
	commands := []string{}
	for _, f := range files {
		if _, err := os.Stat(f); os.IsNotExist(err) {
			continue
		}
		commands = append(commands, fmt.Sprintf("cat %s", f))
	}
	// TODO: handle K8s case as well.
	return commands
}

func copyConfigCommands(confDir string, k8sPods []string) []string {
	commands := []string{}
	// Location is a convenince structure to avoid too many long lines
	type Location struct {
		Src string
		Dst string
	}

	// These locations don't depend on the kernel version for running so we
	// can add them in this scope.
	locations := []Location{
		{"/proc/config", fmt.Sprintf("%s/kernel-config", confDir)},
		{"/proc/config.gz", fmt.Sprintf("%s/kernel-config.gz", confDir)},
	}

	// The following lines copy the kernel configuration. This code is
	// duplicated for the non Kubernetes case. The variables preventing
	// them to be one block is the pod prefix and namespace used in the
	// path. This should be refactored.
	if len(k8sPods) == 0 {
		kernel, _ := execCommand("uname", "-r")
		kernel = strings.TrimSpace(kernel)
		// Append the boot config for the current kernel
		l := Location{fmt.Sprintf("/boot/config-%s", kernel),
			fmt.Sprintf("%s/kernel-config-%s", confDir, kernel)}
		locations = append(locations, l)

		// Use the locations to create command strings
		for _, location := range locations {
			if _, err := os.Stat(location.Src); os.IsNotExist(err) {
				continue
			}
			commands = append(commands, fmt.Sprintf("cp %s %s", location.Src, location.Dst))
		}
	} else {
		// If there are multiple pods, we want to get all of the kernel
		// configs. Therefore we need copy commands for all the pods.
		for _, pod := range k8sPods {
			prompt := podPrefix(pod, "uname -r")
			cmd, args := split(prompt)
			kernel, _ := execCommand(cmd, args...)
			kernel = strings.TrimSpace(kernel)
			l := Location{fmt.Sprintf("/boot/config-%s", kernel),
				fmt.Sprintf("%s/kernel-config-%s", confDir, kernel)}
			locations = append(locations, l)

			// The location is mostly the same but the command is
			// prepended with 'kubectl` and the path contains the
			// namespace and pod. For ex:
			// kubectl cp kube-system/cilium-kg8lv:/tmp/cilium-bugtool-243785589.tar /tmp/cilium-bugtool-243785589.tar
			for _, location := range locations {
				kubectlArg := fmt.Sprintf("%s/%s:%s", k8sNamespace, pod, location.Src)
				cmd := fmt.Sprintf("%s %s %s %s", "kubectl", "cp", kubectlArg, location.Dst)
				commands = append(commands, cmd)
			}
		}
	}
	return commands
}

func copyCiliumInfoCommands(cmdDir string, k8sPods []string) []string {
	// Most of the output should come via debuginfo but also adding
	// these ones for skimming purposes
	ciliumCommands := []string{
		"cilium debuginfo",
		"cilium config",
		"cilium bpf tunnel list",
		"cilium bpf lb list",
		"cilium bpf endpoint list",
		"cilium bpf ct list global",
		"cilium bpf proxy list",
		"cilium bpf ipcache list",
		"cilium status --verbose",
	}
	var commands []string

	stateDir := filepath.Join(defaults.RuntimePath, defaults.StateDir)
	if len(k8sPods) == 0 { // Assuming this is a non k8s deployment
		dst := filepath.Join(cmdDir, defaults.StateDir)
		commands = append(commands, fmt.Sprintf("cp -r %s %s", stateDir, dst))
		for _, cmd := range ciliumCommands {
			// Add the host flag if set
			if len(host) > 0 {
				cmd = fmt.Sprintf("%s -H %s", cmd, host)
			}
			commands = append(commands, cmd)
		}
	} else { // Found k8s pods
		for _, pod := range k8sPods {
			dst := filepath.Join(cmdDir, fmt.Sprintf("%s-%s", pod, defaults.StateDir))
			kubectlArg := fmt.Sprintf("%s/%s:%s", k8sNamespace, pod, stateDir)
			// kubectl cp kube-system/cilium-xrzwr:/var/run/cilium/state cilium-xrzwr-state
			commands = append(commands, fmt.Sprintf("kubectl cp %s %s", kubectlArg, dst))
			for _, cmd := range ciliumCommands {
				// Add the host flag if set
				if len(host) > 0 {
					cmd = fmt.Sprintf("%s -H %s", cmd, host)
				}
				commands = append(commands, podPrefix(pod, cmd))
			}
		}
	}

	return commands
}

func k8sCommands(allCommands []string, pods []string) []string {
	// These commands do not require a pod argument
	var commands = []string{
		"kubectl get nodes -o wide",
		"kubectl describe nodes",
		"kubectl get pods,svc --all-namespaces",
		"kubectl version",
	}

	// Prepare to run all the commands inside of the pod(s)
	for _, pod := range pods {
		for _, cmd := range allCommands {
			// Add the host flag if set
			if strings.HasPrefix(cmd, "cilium") &&
				!strings.Contains(cmd, "-H") && len(host) > 0 {
				cmd = fmt.Sprintf("%s -H %s", cmd, host)
			}

			if !strings.Contains(cmd, "kubectl exec") {
				cmd = podPrefix(pod, cmd)
			}
			commands = append(commands, cmd)
		}

		// Retrieve current version of pod logs
		cmd := fmt.Sprintf("kubectl -n %s logs --timestamps %s", k8sNamespace, pod)
		commands = append(commands, cmd)

		// Retrieve previous version of pod logs
		cmd = fmt.Sprintf("kubectl -n %s logs --timestamps -p %s", k8sNamespace, pod)
		commands = append(commands, cmd)

		cmd = fmt.Sprintf("kubectl -n %s describe pod %s", k8sNamespace, pod)
		commands = append(commands, cmd)
	}

	if len(pods) == 0 {
		allCommands = append(allCommands, commands...)
		return allCommands
	}

	return commands
}
<|endoftext|>


<commit_before>package integration

import (
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/zorkian/go-datadog-api"
)

func TestMonitorCreateAndDelete(t *testing.T) {
	expected := getTestMonitor()
	// create the monitor and compare it
	actual := createTestMonitor(t)
	defer cleanUpMonitor(t, actual.GetId())

	// Set ID of our original struct to zero so we can easily compare the results
	expected.SetId(actual.GetId())
	// Set Creator to the original struct as we can't predict details of the creator
	expected.SetCreator(actual.GetCreator())

	assert.Equal(t, expected, actual)

	actual, err := client.GetMonitor(*actual.Id)
	if err != nil {
		t.Fatalf("Retrieving a monitor failed when it shouldn't: (%s)", err)
	}
	assert.Equal(t, expected, actual)
}

func TestMonitorUpdate(t *testing.T) {

	monitor := createTestMonitor(t)
	defer cleanUpMonitor(t, *monitor.Id)

	monitor.SetName("___New-Test-Monitor___")
	if err := client.UpdateMonitor(monitor); err != nil {
		t.Fatalf("Updating a monitor failed when it shouldn't: %s", err)
	}

	actual, err := client.GetMonitor(*monitor.Id)
	if err != nil {
		t.Fatalf("Retrieving a monitor failed when it shouldn't: %s", err)
	}

	assert.Equal(t, monitor, actual)

}

func TestMonitorUpdateRemovingTags(t *testing.T) {

	monitor := createTestMonitorWithTags(t)
	defer cleanUpMonitor(t, *monitor.Id)

	monitor.Tags = make([]string, 0)
	if err := client.UpdateMonitor(monitor); err != nil {
		t.Fatalf("Updating a monitor failed when it shouldn't: %s", err)
	}

	actual, err := client.GetMonitor(*monitor.Id)
	if err != nil {
		t.Fatalf("Retrieving a monitor failed when it shouldn't: %s", err)
	}

	assert.Equal(t, monitor, actual)

}

func TestMonitorGet(t *testing.T) {
	monitors, err := client.GetMonitors()
	if err != nil {
		t.Fatalf("Retrieving monitors failed when it shouldn't: %s", err)
	}
	num := len(monitors)

	monitor := createTestMonitor(t)
	defer cleanUpMonitor(t, *monitor.Id)

	monitors, err = client.GetMonitors()
	if err != nil {
		t.Fatalf("Retrieving monitors failed when it shouldn't: %s", err)
	}

	if num+1 != len(monitors) {
		t.Fatalf("Number of monitors didn't match expected: %d != %d", len(monitors), num+1)
	}
}

func TestMonitorGetWithoutNoDataTimeframe(t *testing.T) {
	monitors, err := client.GetMonitors()
	if err != nil {
		t.Fatalf("Retrieving monitors failed when it shouldn't: %s", err)
	}
	num := len(monitors)

	monitor := createTestMonitorWithoutNoDataTimeframe(t)
	defer cleanUpMonitor(t, *monitor.Id)

	monitors, err = client.GetMonitors()
	if err != nil {
		t.Fatalf("Retrieving monitors failed when it shouldn't: %s", err)
	}

	if num+1 != len(monitors) {
		t.Fatalf("Number of monitors didn't match expected: %d != %d", len(monitors), num+1)
	}
}

func TestMonitorMuteUnmute(t *testing.T) {
	monitor := createTestMonitor(t)
	defer cleanUpMonitor(t, *monitor.Id)

	// Mute
	err := client.MuteMonitor(*monitor.Id)
	if err != nil {
		t.Fatalf("Failed to mute monitor")

	}

	monitor, err = client.GetMonitor(*monitor.Id)
	if err != nil {
		t.Fatalf("Retrieving monitors failed when it shouldn't: %s", err)
	}

	// Mute without options will result in monitor.Options.Silenced
	// to have a key of "*" with value 0
	assert.Equal(t, 0, monitor.Options.Silenced["*"])

	// Unmute
	err = client.UnmuteMonitor(*monitor.Id)
	if err != nil {
		t.Fatalf("Failed to unmute monitor")
	}

	// Update remote state
	monitor, err = client.GetMonitor(*monitor.Id)
	if err != nil {
		t.Fatalf("Retrieving monitors failed when it shouldn't: %s", err)
	}

	// Assert this map is empty
	assert.Equal(t, 0, len(monitor.Options.Silenced))
}

/*
	Testing of global mute and unmuting has not been added for following reasons:
	* Disabling and enabling of global monitoring does an @all mention which is noisy
	* It exposes risk to users that run integration tests in their main account
	* There is no endpoint to verify success
*/

func getTestMonitor() *datadog.Monitor {

	o := &datadog.Options{
		NotifyNoData:      datadog.Bool(true),
		NotifyAudit:       datadog.Bool(false),
		Locked:            datadog.Bool(false),
		NoDataTimeframe:   60,
		NewHostDelay:      datadog.Int(600),
		RequireFullWindow: datadog.Bool(true),
		Silenced:          map[string]int{},
	}

	return &datadog.Monitor{
		Message:      datadog.String("Test message"),
		Query:        datadog.String("avg(last_15m):avg:system.disk.in_use{*} by {host,device} > 0.8"),
		Name:         datadog.String("Test monitor"),
		Options:      o,
		Type:         datadog.String("metric alert"),
		Tags:         make([]string, 0),
		OverallState: datadog.String("No Data"),
	}
}

func getTestMonitorWithTags() *datadog.Monitor {

	o := &datadog.Options{
		NotifyNoData:      datadog.Bool(true),
		NotifyAudit:       datadog.Bool(false),
		Locked:            datadog.Bool(false),
		NoDataTimeframe:   60,
		NewHostDelay:      datadog.Int(600),
		RequireFullWindow: datadog.Bool(true),
		Silenced:          map[string]int{},
	}

	return &datadog.Monitor{
		Message: datadog.String("Test message"),
		Query:   datadog.String("avg(last_15m):avg:system.disk.in_use{*} by {host,device} > 0.8"),
		Name:    datadog.String("Test monitor"),
		Options: o,
		Type:    datadog.String("metric alert"),
		Tags:    []string{"foo:bar", "bar:baz"},
	}
}

func getTestMonitorWithoutNoDataTimeframe() *datadog.Monitor {

	o := &datadog.Options{
		NotifyNoData:      datadog.Bool(false),
		NotifyAudit:       datadog.Bool(false),
		Locked:            datadog.Bool(false),
		NewHostDelay:      datadog.Int(600),
		RequireFullWindow: datadog.Bool(true),
		Silenced:          map[string]int{},
	}

	return &datadog.Monitor{
		Message: datadog.String("Test message"),
		Query:   datadog.String("avg(last_15m):avg:system.disk.in_use{*} by {host,device} > 0.8"),
		Name:    datadog.String("Test monitor"),
		Options: o,
		Type:    datadog.String("metric alert"),
		Tags:    make([]string, 0),
	}
}

func createTestMonitor(t *testing.T) *datadog.Monitor {
	monitor := getTestMonitor()
	monitor, err := client.CreateMonitor(monitor)
	if err != nil {
		t.Fatalf("Creating a monitor failed when it shouldn't: %s", err)
	}

	return monitor
}

func createTestMonitorWithTags(t *testing.T) *datadog.Monitor {
	monitor := getTestMonitorWithTags()
	monitor, err := client.CreateMonitor(monitor)
	if err != nil {
		t.Fatalf("Creating a monitor failed when it shouldn't: %s", err)
	}

	return monitor
}

func createTestMonitorWithoutNoDataTimeframe(t *testing.T) *datadog.Monitor {
	monitor := getTestMonitorWithoutNoDataTimeframe()
	monitor, err := client.CreateMonitor(monitor)
	if err != nil {
		t.Fatalf("Creating a monitor failed when it shouldn't: %s", err)
	}

	return monitor
}

func cleanUpMonitor(t *testing.T, id int) {
	if err := client.DeleteMonitor(id); err != nil {
		t.Fatalf("Deleting a monitor failed when it shouldn't. Manual cleanup needed. (%s)", err)
	}

	deletedMonitor, err := client.GetMonitor(id)
	if deletedMonitor != nil {
		t.Fatal("Monitor hasn't been deleted when it should have been. Manual cleanup needed.")
	}

	if err == nil {
		t.Fatal("Fetching deleted monitor didn't lead to an error.")
	}
}
<commit_msg>add IncludeTags to test Monitor<commit_after>package integration

import (
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/zorkian/go-datadog-api"
)

func TestMonitorCreateAndDelete(t *testing.T) {
	expected := getTestMonitor()
	// create the monitor and compare it
	actual := createTestMonitor(t)
	defer cleanUpMonitor(t, actual.GetId())

	// Set ID of our original struct to zero so we can easily compare the results
	expected.SetId(actual.GetId())
	// Set Creator to the original struct as we can't predict details of the creator
	expected.SetCreator(actual.GetCreator())

	assert.Equal(t, expected, actual)

	actual, err := client.GetMonitor(*actual.Id)
	if err != nil {
		t.Fatalf("Retrieving a monitor failed when it shouldn't: (%s)", err)
	}
	assert.Equal(t, expected, actual)
}

func TestMonitorUpdate(t *testing.T) {

	monitor := createTestMonitor(t)
	defer cleanUpMonitor(t, *monitor.Id)

	monitor.SetName("___New-Test-Monitor___")
	if err := client.UpdateMonitor(monitor); err != nil {
		t.Fatalf("Updating a monitor failed when it shouldn't: %s", err)
	}

	actual, err := client.GetMonitor(*monitor.Id)
	if err != nil {
		t.Fatalf("Retrieving a monitor failed when it shouldn't: %s", err)
	}

	assert.Equal(t, monitor, actual)

}

func TestMonitorUpdateRemovingTags(t *testing.T) {

	monitor := createTestMonitorWithTags(t)
	defer cleanUpMonitor(t, *monitor.Id)

	monitor.Tags = make([]string, 0)
	if err := client.UpdateMonitor(monitor); err != nil {
		t.Fatalf("Updating a monitor failed when it shouldn't: %s", err)
	}

	actual, err := client.GetMonitor(*monitor.Id)
	if err != nil {
		t.Fatalf("Retrieving a monitor failed when it shouldn't: %s", err)
	}

	assert.Equal(t, monitor, actual)

}

func TestMonitorGet(t *testing.T) {
	monitors, err := client.GetMonitors()
	if err != nil {
		t.Fatalf("Retrieving monitors failed when it shouldn't: %s", err)
	}
	num := len(monitors)

	monitor := createTestMonitor(t)
	defer cleanUpMonitor(t, *monitor.Id)

	monitors, err = client.GetMonitors()
	if err != nil {
		t.Fatalf("Retrieving monitors failed when it shouldn't: %s", err)
	}

	if num+1 != len(monitors) {
		t.Fatalf("Number of monitors didn't match expected: %d != %d", len(monitors), num+1)
	}
}

func TestMonitorGetWithoutNoDataTimeframe(t *testing.T) {
	monitors, err := client.GetMonitors()
	if err != nil {
		t.Fatalf("Retrieving monitors failed when it shouldn't: %s", err)
	}
	num := len(monitors)

	monitor := createTestMonitorWithoutNoDataTimeframe(t)
	defer cleanUpMonitor(t, *monitor.Id)

	monitors, err = client.GetMonitors()
	if err != nil {
		t.Fatalf("Retrieving monitors failed when it shouldn't: %s", err)
	}

	if num+1 != len(monitors) {
		t.Fatalf("Number of monitors didn't match expected: %d != %d", len(monitors), num+1)
	}
}

func TestMonitorMuteUnmute(t *testing.T) {
	monitor := createTestMonitor(t)
	defer cleanUpMonitor(t, *monitor.Id)

	// Mute
	err := client.MuteMonitor(*monitor.Id)
	if err != nil {
		t.Fatalf("Failed to mute monitor")

	}

	monitor, err = client.GetMonitor(*monitor.Id)
	if err != nil {
		t.Fatalf("Retrieving monitors failed when it shouldn't: %s", err)
	}

	// Mute without options will result in monitor.Options.Silenced
	// to have a key of "*" with value 0
	assert.Equal(t, 0, monitor.Options.Silenced["*"])

	// Unmute
	err = client.UnmuteMonitor(*monitor.Id)
	if err != nil {
		t.Fatalf("Failed to unmute monitor")
	}

	// Update remote state
	monitor, err = client.GetMonitor(*monitor.Id)
	if err != nil {
		t.Fatalf("Retrieving monitors failed when it shouldn't: %s", err)
	}

	// Assert this map is empty
	assert.Equal(t, 0, len(monitor.Options.Silenced))
}

/*
	Testing of global mute and unmuting has not been added for following reasons:
	* Disabling and enabling of global monitoring does an @all mention which is noisy
	* It exposes risk to users that run integration tests in their main account
	* There is no endpoint to verify success
*/

func getTestMonitor() *datadog.Monitor {

	o := &datadog.Options{
		NotifyNoData:      datadog.Bool(true),
		NotifyAudit:       datadog.Bool(false),
		Locked:            datadog.Bool(false),
		NoDataTimeframe:   60,
		NewHostDelay:      datadog.Int(600),
		RequireFullWindow: datadog.Bool(true),
		Silenced:          map[string]int{},
		IncludeTags:       datadog.Bool(false),
	}

	return &datadog.Monitor{
		Message:      datadog.String("Test message"),
		Query:        datadog.String("avg(last_15m):avg:system.disk.in_use{*} by {host,device} > 0.8"),
		Name:         datadog.String("Test monitor"),
		Options:      o,
		Type:         datadog.String("metric alert"),
		Tags:         make([]string, 0),
		OverallState: datadog.String("No Data"),
	}
}

func getTestMonitorWithTags() *datadog.Monitor {

	o := &datadog.Options{
		NotifyNoData:      datadog.Bool(true),
		NotifyAudit:       datadog.Bool(false),
		Locked:            datadog.Bool(false),
		NoDataTimeframe:   60,
		NewHostDelay:      datadog.Int(600),
		RequireFullWindow: datadog.Bool(true),
		Silenced:          map[string]int{},
		IncludeTags:       datadog.Bool(true),
	}

	return &datadog.Monitor{
		Message: datadog.String("Test message"),
		Query:   datadog.String("avg(last_15m):avg:system.disk.in_use{*} by {host,device} > 0.8"),
		Name:    datadog.String("Test monitor"),
		Options: o,
		Type:    datadog.String("metric alert"),
		Tags:    []string{"foo:bar", "bar:baz"},
	}
}

func getTestMonitorWithoutNoDataTimeframe() *datadog.Monitor {

	o := &datadog.Options{
		NotifyNoData:      datadog.Bool(false),
		NotifyAudit:       datadog.Bool(false),
		Locked:            datadog.Bool(false),
		NewHostDelay:      datadog.Int(600),
		RequireFullWindow: datadog.Bool(true),
		Silenced:          map[string]int{},
		IncludeTags:       datadog.Bool(false),
	}

	return &datadog.Monitor{
		Message: datadog.String("Test message"),
		Query:   datadog.String("avg(last_15m):avg:system.disk.in_use{*} by {host,device} > 0.8"),
		Name:    datadog.String("Test monitor"),
		Options: o,
		Type:    datadog.String("metric alert"),
		Tags:    make([]string, 0),
	}
}

func createTestMonitor(t *testing.T) *datadog.Monitor {
	monitor := getTestMonitor()
	monitor, err := client.CreateMonitor(monitor)
	if err != nil {
		t.Fatalf("Creating a monitor failed when it shouldn't: %s", err)
	}

	return monitor
}

func createTestMonitorWithTags(t *testing.T) *datadog.Monitor {
	monitor := getTestMonitorWithTags()
	monitor, err := client.CreateMonitor(monitor)
	if err != nil {
		t.Fatalf("Creating a monitor failed when it shouldn't: %s", err)
	}

	return monitor
}

func createTestMonitorWithoutNoDataTimeframe(t *testing.T) *datadog.Monitor {
	monitor := getTestMonitorWithoutNoDataTimeframe()
	monitor, err := client.CreateMonitor(monitor)
	if err != nil {
		t.Fatalf("Creating a monitor failed when it shouldn't: %s", err)
	}

	return monitor
}

func cleanUpMonitor(t *testing.T, id int) {
	if err := client.DeleteMonitor(id); err != nil {
		t.Fatalf("Deleting a monitor failed when it shouldn't. Manual cleanup needed. (%s)", err)
	}

	deletedMonitor, err := client.GetMonitor(id)
	if deletedMonitor != nil {
		t.Fatal("Monitor hasn't been deleted when it should have been. Manual cleanup needed.")
	}

	if err == nil {
		t.Fatal("Fetching deleted monitor didn't lead to an error.")
	}
}
<|endoftext|>


<commit_before>package nomad

import (
	"testing"
	"time"

	"github.com/hashicorp/nomad/nomad/mock"
	"github.com/hashicorp/nomad/nomad/structs"
)

func testPlanQueue(t *testing.T) *PlanQueue {
	pq, err := NewPlanQueue()
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	return pq
}

func TestPlanQueue_Enqueue_Dequeue(t *testing.T) {
	t.Parallel()
	pq := testPlanQueue(t)
	if pq.Enabled() {
		t.Fatalf("should not be enabled")
	}
	pq.SetEnabled(true)
	if !pq.Enabled() {
		t.Fatalf("should be enabled")
	}

	plan := mock.Plan()
	future, err := pq.Enqueue(plan)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	stats := pq.Stats()
	if stats.Depth != 1 {
		t.Fatalf("bad: %#v", stats)
	}

	resCh := make(chan *structs.PlanResult, 1)
	go func() {
		res, err := future.Wait()
		if err != nil {
			t.Fatalf("err: %v", err)
		}
		resCh <- res
	}()

	pending, err := pq.Dequeue(time.Second)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	stats = pq.Stats()
	if stats.Depth != 0 {
		t.Fatalf("bad: %#v", stats)
	}

	if pending == nil || pending.plan != plan {
		t.Fatalf("bad: %#v", pending)
	}

	result := mock.PlanResult()
	pending.respond(result, nil)

	select {
	case r := <-resCh:
		if r != result {
			t.Fatalf("Bad: %#v", r)
		}
	case <-time.After(time.Second):
		t.Fatalf("timeout")
	}
}

func TestPlanQueue_Enqueue_Disable(t *testing.T) {
	t.Parallel()
	pq := testPlanQueue(t)

	// Enqueue
	plan := mock.Plan()
	pq.SetEnabled(true)
	future, err := pq.Enqueue(plan)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	// Flush via SetEnabled
	pq.SetEnabled(false)

	// Check the stats
	stats := pq.Stats()
	if stats.Depth != 0 {
		t.Fatalf("bad: %#v", stats)
	}

	// Future should be canceled
	res, err := future.Wait()
	if err != planQueueFlushed {
		t.Fatalf("err: %v", err)
	}
	if res != nil {
		t.Fatalf("bad: %#v", res)
	}
}

func TestPlanQueue_Dequeue_Timeout(t *testing.T) {
	t.Parallel()
	pq := testPlanQueue(t)
	pq.SetEnabled(true)

	start := time.Now()
	out, err := pq.Dequeue(5 * time.Millisecond)
	end := time.Now()

	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if out != nil {
		t.Fatalf("unexpected: %#v", out)
	}

	if diff := end.Sub(start); diff < 5*time.Millisecond {
		t.Fatalf("bad: %#v", diff)
	}
}

// Ensure higher priority dequeued first
func TestPlanQueue_Dequeue_Priority(t *testing.T) {
	t.Parallel()
	pq := testPlanQueue(t)
	pq.SetEnabled(true)

	plan1 := mock.Plan()
	plan1.Priority = 10
	pq.Enqueue(plan1)

	plan2 := mock.Plan()
	plan2.Priority = 30
	pq.Enqueue(plan2)

	plan3 := mock.Plan()
	plan3.Priority = 20
	pq.Enqueue(plan3)

	out1, _ := pq.Dequeue(time.Second)
	if out1.plan != plan2 {
		t.Fatalf("bad: %#v", out1)
	}

	out2, _ := pq.Dequeue(time.Second)
	if out2.plan != plan3 {
		t.Fatalf("bad: %#v", out2)
	}

	out3, _ := pq.Dequeue(time.Second)
	if out3.plan != plan1 {
		t.Fatalf("bad: %#v", out3)
	}
}

// Ensure FIFO at fixed priority
func TestPlanQueue_Dequeue_FIFO(t *testing.T) {
	t.Parallel()
	pq := testPlanQueue(t)
	pq.SetEnabled(true)

	plans := make([]*structs.Plan, 100)
	for i := 0; i < len(plans); i++ {
		if i%5 == 0 {
			time.Sleep(10 * time.Millisecond)
		}
		plans[i] = mock.Plan()
		pq.Enqueue(plans[i])
	}

	var prev *pendingPlan
	for i := range plans {
		out, err := pq.Dequeue(time.Second)
		if err != nil {
			t.Fatalf("failed to dequeue plan %d: %v", i, err)
		}
		if prev != nil && out.enqueueTime.Before(prev.enqueueTime) {
			t.Fatalf("out of order dequeue at %d, prev=%v, got=%v", i, prev.enqueueTime, out.enqueueTime)
		}
		prev = out
	}
}
<commit_msg>nomad: fix test goroutine (#6593)<commit_after>package nomad

import (
	"testing"
	"time"

	"github.com/hashicorp/nomad/nomad/mock"
	"github.com/hashicorp/nomad/nomad/structs"
)

func testPlanQueue(t *testing.T) *PlanQueue {
	pq, err := NewPlanQueue()
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	return pq
}

func TestPlanQueue_Enqueue_Dequeue(t *testing.T) {
	t.Parallel()
	pq := testPlanQueue(t)
	if pq.Enabled() {
		t.Fatalf("should not be enabled")
	}
	pq.SetEnabled(true)
	if !pq.Enabled() {
		t.Fatalf("should be enabled")
	}

	plan := mock.Plan()
	future, err := pq.Enqueue(plan)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	stats := pq.Stats()
	if stats.Depth != 1 {
		t.Fatalf("bad: %#v", stats)
	}

	resCh := make(chan *structs.PlanResult, 1)
	errCh := make(chan error)
	go func() {
		defer close(errCh)
		defer close(resCh)

		res, err := future.Wait()
		if err != nil {
			errCh <- err
			return
		}
		resCh <- res
	}()

	pending, err := pq.Dequeue(time.Second)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	stats = pq.Stats()
	if stats.Depth != 0 {
		t.Fatalf("bad: %#v", stats)
	}

	if pending == nil || pending.plan != plan {
		t.Fatalf("bad: %#v", pending)
	}

	result := mock.PlanResult()
	pending.respond(result, nil)

	select {
	case err := <-errCh:
		if err != nil {
			t.Fatalf("error in anonymous goroutine: %s", err)
		}
	case r := <-resCh:
		if r != result {
			t.Fatalf("Bad: %#v", r)
		}
	case <-time.After(time.Second):
		t.Fatalf("timeout")
	}
}

func TestPlanQueue_Enqueue_Disable(t *testing.T) {
	t.Parallel()
	pq := testPlanQueue(t)

	// Enqueue
	plan := mock.Plan()
	pq.SetEnabled(true)
	future, err := pq.Enqueue(plan)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	// Flush via SetEnabled
	pq.SetEnabled(false)

	// Check the stats
	stats := pq.Stats()
	if stats.Depth != 0 {
		t.Fatalf("bad: %#v", stats)
	}

	// Future should be canceled
	res, err := future.Wait()
	if err != planQueueFlushed {
		t.Fatalf("err: %v", err)
	}
	if res != nil {
		t.Fatalf("bad: %#v", res)
	}
}

func TestPlanQueue_Dequeue_Timeout(t *testing.T) {
	t.Parallel()
	pq := testPlanQueue(t)
	pq.SetEnabled(true)

	start := time.Now()
	out, err := pq.Dequeue(5 * time.Millisecond)
	end := time.Now()

	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if out != nil {
		t.Fatalf("unexpected: %#v", out)
	}

	if diff := end.Sub(start); diff < 5*time.Millisecond {
		t.Fatalf("bad: %#v", diff)
	}
}

// Ensure higher priority dequeued first
func TestPlanQueue_Dequeue_Priority(t *testing.T) {
	t.Parallel()
	pq := testPlanQueue(t)
	pq.SetEnabled(true)

	plan1 := mock.Plan()
	plan1.Priority = 10
	pq.Enqueue(plan1)

	plan2 := mock.Plan()
	plan2.Priority = 30
	pq.Enqueue(plan2)

	plan3 := mock.Plan()
	plan3.Priority = 20
	pq.Enqueue(plan3)

	out1, _ := pq.Dequeue(time.Second)
	if out1.plan != plan2 {
		t.Fatalf("bad: %#v", out1)
	}

	out2, _ := pq.Dequeue(time.Second)
	if out2.plan != plan3 {
		t.Fatalf("bad: %#v", out2)
	}

	out3, _ := pq.Dequeue(time.Second)
	if out3.plan != plan1 {
		t.Fatalf("bad: %#v", out3)
	}
}

// Ensure FIFO at fixed priority
func TestPlanQueue_Dequeue_FIFO(t *testing.T) {
	t.Parallel()
	pq := testPlanQueue(t)
	pq.SetEnabled(true)

	plans := make([]*structs.Plan, 100)
	for i := 0; i < len(plans); i++ {
		if i%5 == 0 {
			time.Sleep(10 * time.Millisecond)
		}
		plans[i] = mock.Plan()
		pq.Enqueue(plans[i])
	}

	var prev *pendingPlan
	for i := range plans {
		out, err := pq.Dequeue(time.Second)
		if err != nil {
			t.Fatalf("failed to dequeue plan %d: %v", i, err)
		}
		if prev != nil && out.enqueueTime.Before(prev.enqueueTime) {
			t.Fatalf("out of order dequeue at %d, prev=%v, got=%v", i, prev.enqueueTime, out.enqueueTime)
		}
		prev = out
	}
}
<|endoftext|>


<commit_before>package color

import (
	"strings"
	"sync"
	"unicode"
)

// see doc.go for an explanation of these
const (
	errInvalid = "%%!h(INVALID)"
	errMissing = "%%!h(MISSING)"
	errBadAttr = "%%!h(BADATTR)"
)

// highlighter holds the state of the scanner.
type highlighter struct {
	s     string // string being scanned
	pos   int    // position in s
	buf   buffer // result
	attrs buffer // attributes of current verb
}

// Highlight replaces the highlight verbs in s with their appropriate
// control sequences and then returns the resulting string.
// This is a low-level function that only scans highlight verbs. The color.Printf functions
// are the intended user functions as they wrap around the fmt.Printf functions,
// which handle the rest. Only use this for performance reasons.
func Highlight(s string) string {
	hl := getHighlighter(s)
	hl.run()
	return string(hl.free())
}

// highlighterPool reuses highlighter objects to avoid an allocation per invocation.
var highlighterPool = sync.Pool{
	New: func() interface{} {
		hl := new(highlighter)
		// initial capacities avoid constant reallocation during growth.
		hl.buf = make([]byte, 0, 30)
		hl.attrs = make([]byte, 0, 10)
		return hl
	},
}

// getHighlighter returns a new initialized highlighter from the pool.
func getHighlighter(s string) (hl *highlighter) {
	hl = highlighterPool.Get().(*highlighter)
	hl.s = s
	return
}

// free resets the highlighter and returns the buffer.
func (hl *highlighter) free() (b []byte) {
	b = hl.buf
	hl.buf.reset()
	hl.pos = 0
	highlighterPool.Put(hl)
	return
}

// stateFn represents the state of the scanner as a function that returns the next state.
type stateFn func(*highlighter) stateFn

// run runs the state machine for the highlighter.
func (hl *highlighter) run() {
	for state := scanText; state != nil; {
		state = state(hl)
	}
}

const eof = -1

// get returns the current rune.
func (hl *highlighter) get() rune {
	if hl.pos >= len(hl.s) {
		return eof
	}
	return rune(hl.s[hl.pos])
}

// writeAttrs writes a control sequence derived from h.attrs[1:] to h.buf.
func (hl *highlighter) writeAttrs() {
	hl.buf.writeString(csi)
	hl.buf.write(hl.attrs[1:])
	hl.buf.writeByte('m')
}

// writePrev writes n previous characters to the buffer.
func (hl *highlighter) writePrev(n int) {
	hl.buf.writeString(hl.s[n:hl.pos])
}

// scanText scans until the next highlight or reset verb.
func scanText(hl *highlighter) stateFn {
	// previous position
	ppos := hl.pos
	for {
		if r := hl.get(); r == eof {
			if hl.pos > ppos {
				hl.writePrev(ppos)
			}
			return nil
		} else if r == '%' {
			if hl.pos > ppos {
				hl.writePrev(ppos)
			}
			break
		}
		hl.pos++
	}
	hl.pos++
	switch hl.get() {
	case 'r':
		hl.pos++
		return verbReset
	case 'h':
		hl.pos += 2
		return scanHighlight
	case eof:
		// no need to writePrev, we know it was '%
		hl.buf.writeByte('%')
		return nil
	}
	hl.pos++
	hl.writePrev(hl.pos - 2)
	return scanText
}

// verbReset writes the reset verb with the reset control sequence.
func verbReset(hl *highlighter) stateFn {
	hl.attrs.writeString(attrs["reset"])
	hl.writeAttrs()
	hl.attrs.reset()
	return scanText
}

// scanHighlight scans the highlight verb for attributes,
// then writes a control sequence derived from said attributes to the buffer.
func scanHighlight(hl *highlighter) stateFn {
	r := hl.get()
	switch {
	case r == 'f':
		return scanColor256(hl, preFg256)
	case r == 'b':
		return scanColor256(hl, preBg256)
	case unicode.IsLetter(r):
		return scanAttribute(hl, 0)
	case r == '+':
		hl.pos++
		return scanHighlight
	case r == ']':
		if len(hl.attrs) != 0 {
			hl.writeAttrs()
		} else {
			hl.buf.writeString(errMissing)
		}
		hl.attrs.reset()
		hl.pos++
		return scanText
	default:
		return abortHighlight(hl, errInvalid)
	}
}

// scanAttribute scans a named attribute
func scanAttribute(hl *highlighter, off int) stateFn {
	start := hl.pos - off
	for unicode.IsLetter(hl.get()) {
		hl.pos++
	}
	if a, ok := attrs[hl.s[start:hl.pos]]; ok {
		hl.attrs.writeString(a)
	} else {
		return abortHighlight(hl, errBadAttr)
	}
	return scanHighlight
}

// abortHighlight writes a error to the buffer and
// then skips to the end of the highlight verb.
func abortHighlight(hl *highlighter, msg string) stateFn {
	hl.buf.writeString(msg)
	hl.attrs.reset()
	for {
		switch hl.get() {
		case ']':
			hl.pos++
			return scanText
		case eof:
			return nil
		}
		hl.pos++
	}
}

// scanColor256 scans a 256 color attribute
func scanColor256(hl *highlighter, pre string) stateFn {
	hl.pos++
	if hl.get() != 'g' {
		return scanAttribute(hl, 1)
	}
	hl.pos++
	if !unicode.IsNumber(hl.get()) {
		return scanAttribute(hl, 2)
	}
	start := hl.pos
	hl.pos++
	for unicode.IsNumber(hl.get()) {
		hl.pos++
	}
	hl.attrs.writeString(pre)
	hl.attrs.writeString(hl.s[start:hl.pos])
	return scanHighlight
}

// bufferPool reuses buffers to avoid an allocation per invocation.
var bufferPool = sync.Pool{
	New: func() interface{} {
		// initial capacity avoids constant reallocation during growth.
		return buffer(make([]byte, 0, 30))
	},
}

// stripVerbs removes all highlight verbs in s.
func stripVerbs(s string) string {
	buf := bufferPool.Get().(buffer)
	// pi is the index after last verb
	var pi, i int
	for ; ; i++ {
		if i >= len(s) {
			if i > pi {
				buf.writeString(s[pi:i])
			}
			break
		} else if s[i] != '%' {
			continue
		}
		if i > pi {
			buf.writeString(s[pi:i])
		}
		i++
		if i >= len(s) {
			// let fmt handle this
			buf.writeByte('%')
			break
		}
		if c := s[i]; c == 'r' {
			// strip reset verb
			pi = i + 1
		} else if c == 'h' {
			// strip inside highlight verb
			j := strings.IndexByte(s[i+1:], ']')
			if j == -1 {
				buf.writeString(errInvalid)
				break
			}
			i += j + 1
			pi = i + 1
		} else {
			// include this verb
			pi = i - 1
		}
	}
	s = string(buf)
	buf.reset()
	bufferPool.Put(buf)
	return s
}
<commit_msg>faster stripVerbs<commit_after>package color

import (
	"strings"
	"sync"
	"unicode"
)

// see doc.go for an explanation of these
const (
	errInvalid = "%%!h(INVALID)"
	errMissing = "%%!h(MISSING)"
	errBadAttr = "%%!h(BADATTR)"
)

// highlighter holds the state of the scanner.
type highlighter struct {
	s     string // string being scanned
	pos   int    // position in s
	buf   buffer // result
	attrs buffer // attributes of current verb
}

// Highlight replaces the highlight verbs in s with their appropriate
// control sequences and then returns the resulting string.
// This is a low-level function that only scans highlight verbs. The color.Printf functions
// are the intended user functions as they wrap around the fmt.Printf functions,
// which handle the rest. Only use this for performance reasons.
func Highlight(s string) string {
	hl := getHighlighter(s)
	hl.run()
	return string(hl.free())
}

// highlighterPool reuses highlighter objects to avoid an allocation per invocation.
var highlighterPool = sync.Pool{
	New: func() interface{} {
		hl := new(highlighter)
		// initial capacities avoid constant reallocation during growth.
		hl.buf = make([]byte, 0, 30)
		hl.attrs = make([]byte, 0, 10)
		return hl
	},
}

// getHighlighter returns a new initialized highlighter from the pool.
func getHighlighter(s string) (hl *highlighter) {
	hl = highlighterPool.Get().(*highlighter)
	hl.s = s
	return
}

// free resets the highlighter and returns the buffer.
func (hl *highlighter) free() (b []byte) {
	b = hl.buf
	hl.buf.reset()
	hl.pos = 0
	highlighterPool.Put(hl)
	return
}

// stateFn represents the state of the scanner as a function that returns the next state.
type stateFn func(*highlighter) stateFn

// run runs the state machine for the highlighter.
func (hl *highlighter) run() {
	for state := scanText; state != nil; {
		state = state(hl)
	}
}

const eof = -1

// get returns the current rune.
func (hl *highlighter) get() rune {
	if hl.pos >= len(hl.s) {
		return eof
	}
	return rune(hl.s[hl.pos])
}

// writeAttrs writes a control sequence derived from h.attrs[1:] to h.buf.
func (hl *highlighter) writeAttrs() {
	hl.buf.writeString(csi)
	hl.buf.write(hl.attrs[1:])
	hl.buf.writeByte('m')
}

// writePrev writes n previous characters to the buffer.
func (hl *highlighter) writePrev(n int) {
	hl.buf.writeString(hl.s[n:hl.pos])
}

// scanText scans until the next highlight or reset verb.
func scanText(hl *highlighter) stateFn {
	// previous position
	ppos := hl.pos
	for {
		if r := hl.get(); r == eof {
			if hl.pos > ppos {
				hl.writePrev(ppos)
			}
			return nil
		} else if r == '%' {
			if hl.pos > ppos {
				hl.writePrev(ppos)
			}
			break
		}
		hl.pos++
	}
	hl.pos++
	switch hl.get() {
	case 'r':
		hl.pos++
		return verbReset
	case 'h':
		hl.pos += 2
		return scanHighlight
	case eof:
		// no need to writePrev, we know it was '%
		hl.buf.writeByte('%')
		return nil
	}
	hl.pos++
	hl.writePrev(hl.pos - 2)
	return scanText
}

// verbReset writes the reset verb with the reset control sequence.
func verbReset(hl *highlighter) stateFn {
	hl.attrs.writeString(attrs["reset"])
	hl.writeAttrs()
	hl.attrs.reset()
	return scanText
}

// scanHighlight scans the highlight verb for attributes,
// then writes a control sequence derived from said attributes to the buffer.
func scanHighlight(hl *highlighter) stateFn {
	r := hl.get()
	switch {
	case r == 'f':
		return scanColor256(hl, preFg256)
	case r == 'b':
		return scanColor256(hl, preBg256)
	case unicode.IsLetter(r):
		return scanAttribute(hl, 0)
	case r == '+':
		hl.pos++
		return scanHighlight
	case r == ']':
		if len(hl.attrs) != 0 {
			hl.writeAttrs()
		} else {
			hl.buf.writeString(errMissing)
		}
		hl.attrs.reset()
		hl.pos++
		return scanText
	default:
		return abortHighlight(hl, errInvalid)
	}
}

// scanAttribute scans a named attribute
func scanAttribute(hl *highlighter, off int) stateFn {
	start := hl.pos - off
	for unicode.IsLetter(hl.get()) {
		hl.pos++
	}
	if a, ok := attrs[hl.s[start:hl.pos]]; ok {
		hl.attrs.writeString(a)
	} else {
		return abortHighlight(hl, errBadAttr)
	}
	return scanHighlight
}

// abortHighlight writes a error to the buffer and
// then skips to the end of the highlight verb.
func abortHighlight(hl *highlighter, msg string) stateFn {
	hl.buf.writeString(msg)
	hl.attrs.reset()
	for {
		switch hl.get() {
		case ']':
			hl.pos++
			return scanText
		case eof:
			return nil
		}
		hl.pos++
	}
}

// scanColor256 scans a 256 color attribute
func scanColor256(hl *highlighter, pre string) stateFn {
	hl.pos++
	if hl.get() != 'g' {
		return scanAttribute(hl, 1)
	}
	hl.pos++
	if !unicode.IsNumber(hl.get()) {
		return scanAttribute(hl, 2)
	}
	start := hl.pos
	hl.pos++
	for unicode.IsNumber(hl.get()) {
		hl.pos++
	}
	hl.attrs.writeString(pre)
	hl.attrs.writeString(hl.s[start:hl.pos])
	return scanHighlight
}

// bufferPool reuses buffers to avoid an allocation per invocation.
var bufferPool = sync.Pool{
	New: func() interface{} {
		// initial capacity avoids constant reallocation during growth.
		return buffer(make([]byte, 0, 30))
	},
}

// stripVerbs removes all highlight verbs in s.
func stripVerbs(s string) string {
	buf := bufferPool.Get().(buffer)
	// pi is the index after last verb
	var pi, i int
P:
	for ; ; i++ {
		if i >= len(s) {
			if i > pi {
				buf.writeString(s[pi:i])
			}
			break
		} else if s[i] != '%' {
			continue
		}
		if i > pi {
			buf.writeString(s[pi:i])
		}
		i++
		if i >= len(s) {
			// let fmt handle this
			buf.writeByte('%')
			break
		}
		switch s[i] {
		case 'r':
			// strip reset verb
			pi = i + 1
		case 'h':
			// strip inside highlight verb
			j := strings.IndexByte(s[i+1:], ']')
			if j == -1 {
				buf.writeString(errInvalid)
				break P
			}
			i += j + 1
			pi = i + 1
		default:
			// include this verb
			pi = i - 1
		}
	}
	s = string(buf)
	buf.reset()
	bufferPool.Put(buf)
	return s
}
<|endoftext|>


<commit_before>package main

import (
	"data-structures/heap/heap"
	"fmt"
)

type IntNode int

// Implement heap.Node interface
func (n IntNode) Less(other heap.Node) bool {
	return n < other.(IntNode)
}

var testInts = [][]IntNode{
	{1},
	{2, 1},
	{5, 15, 95, 40, 21, 1},
}

type RuneNode rune

// Implement heap.Node interface
func (r RuneNode) Less(other heap.Node) bool {
	return r < other.(RuneNode)
}

var testRunes = [][]RuneNode{
	{'a'},
	{'z', 'x', 'y'},
	{'М', 'и', 'р', '!', 'М', 'М', 'М', '世', '界'},
}

type StringNode string

func (s StringNode) Less(other heap.Node) bool {
	return s < other.(StringNode)
}

var testStrings = [][]StringNode{
	{"Hello"},
	{"Hello", "world", "!"},
	{"Здравствуй", "strange", "世界", "!"},
}

func main() {

	// Test ints
	for N, nums := range testInts {
		h := heap.New()
		for _, n := range nums {
			h.Push(n)
		}

		// Check heap
		// fmt.Printf("Heap after test #%d: '%+v'\n", N, h)
		fmt.Printf("Test #%d sorted order: ", N+1)
		for n := h.Pop(); n != nil; n = h.Pop() {
			fmt.Printf("%d ", n)
		}
		fmt.Println()
	}

	// Test runes
	for N, runes := range testRunes {
		h := heap.New()
		for _, n := range runes {
			h.Push(n)
		}

		// Check heap
		// fmt.Printf("Heap after test #%d: '%+v'\n", N, h)
		fmt.Printf("Test #%d sorted order: ", N+1)
		for n := h.Pop(); n != nil; n = h.Pop() {
			fmt.Printf("%c ", n)
		}
		fmt.Println()
	}

	// Test strings
	for N, strings := range testStrings {
		h := heap.New()
		for _, n := range strings {
			h.Push(n)
		}

		// Check heap
		// fmt.Printf("Heap after test #%d: '%+v'\n", N, h)
		fmt.Printf("Test #%d sorted order: ", N+1)
		for n := h.Pop(); n != nil; n = h.Pop() {
			fmt.Printf("%q ", n)
		}
		fmt.Println()
	}
}
<commit_msg>- Fixed import path<commit_after>package main

import (
	"fmt"

	"github.com/caelifer/data-structures-in-go/heap/heap"
)

type IntNode int

// Implement heap.Node interface
func (n IntNode) Less(other heap.Node) bool {
	return n < other.(IntNode)
}

var testInts = [][]IntNode{
	{1},
	{2, 1},
	{5, 15, 95, 40, 21, 1},
}

type RuneNode rune

// Implement heap.Node interface
func (r RuneNode) Less(other heap.Node) bool {
	return r < other.(RuneNode)
}

var testRunes = [][]RuneNode{
	{'a'},
	{'z', 'x', 'y'},
	{'М', 'и', 'р', '!', 'М', 'М', 'М', '世', '界'},
}

type StringNode string

func (s StringNode) Less(other heap.Node) bool {
	return s < other.(StringNode)
}

var testStrings = [][]StringNode{
	{"Hello"},
	{"Hello", "world", "!"},
	{"Здравствуй", "strange", "世界", "!"},
}

func main() {

	// Test ints
	for N, nums := range testInts {
		h := heap.New()
		for _, n := range nums {
			h.Push(n)
		}

		// Check heap
		// fmt.Printf("Heap after test #%d: '%+v'\n", N, h)
		fmt.Printf("Test #%d sorted order: ", N+1)
		for n := h.Pop(); n != nil; n = h.Pop() {
			fmt.Printf("%d ", n)
		}
		fmt.Println()
	}

	// Test runes
	for N, runes := range testRunes {
		h := heap.New()
		for _, n := range runes {
			h.Push(n)
		}

		// Check heap
		// fmt.Printf("Heap after test #%d: '%+v'\n", N, h)
		fmt.Printf("Test #%d sorted order: ", N+1)
		for n := h.Pop(); n != nil; n = h.Pop() {
			fmt.Printf("%c ", n)
		}
		fmt.Println()
	}

	// Test strings
	for N, strings := range testStrings {
		h := heap.New()
		for _, n := range strings {
			h.Push(n)
		}

		// Check heap
		// fmt.Printf("Heap after test #%d: '%+v'\n", N, h)
		fmt.Printf("Test #%d sorted order: ", N+1)
		for n := h.Pop(); n != nil; n = h.Pop() {
			fmt.Printf("%q ", n)
		}
		fmt.Println()
	}
}
<|endoftext|>


<commit_before>package command

import (
	"net/url"
	"strings"
)

// EnvCommand is a Command Implementation that manipulates local state
// environments.
type EnvCommand struct {
	Meta
}

func (c *EnvCommand) Run(args []string) int {
	args = c.Meta.process(args, true)

	cmdFlags := c.Meta.flagSet("env")
	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }

	c.Ui.Output(c.Help())
	return 0
}

func (c *EnvCommand) Help() string {
	helpText := `
Usage: terraform env

  Create, change and delete Terraform environments.

Subcommands:

    list      List environments.
    select    Select an environment.
    new       Create a new environment.
    delete    Delete an existing environment.
`
	return strings.TrimSpace(helpText)
}

func (c *EnvCommand) Synopsis() string {
	return "Environment management"
}

// validEnvName returns true is this name is valid to use as an environment name.
// Since most named states are accessed via a filesystem path or URL, check if
// escaping the name would be required.
func validEnvName(name string) bool {
	return name == url.PathEscape(name)
}

const (
	envNotSupported = `Backend does not support environments`

	envExists = `Environment %q already exists`

	envDoesNotExist = `
Environment %q doesn't exist!

You can create this environment with the "-new" option.`

	envChanged = `[reset][green]Switched to environment %q!`

	envCreated = `
[reset][green][bold]Created and switched to environment %q![reset][green]

You're now on a new, empty environment. Environments isolate their state,
so if you run "terraform plan" Terraform will not see any existing state
for this configuration.
`

	envDeleted = `[reset][green]Deleted environment %q!`

	envNotEmpty = `
Environment %[1]q is not empty!

Deleting %[1]q can result in dangling resources: resources that
exist but are no longer manageable by Terraform. Please destroy
these resources first.  If you want to delete this environment
anyways and risk dangling resources, use the '-force' flag.
`

	envWarnNotEmpty = `[reset][yellow]WARNING: %q was non-empty.
The resources managed by the deleted environment may still exist,
but are no longer manageable by Terraform since the state has
been deleted.
`

	envDelCurrent = `
Environment %[1]q is your active environment!

You cannot delete the currently active environment. Please switch
to another environment and try again.
`

	envInvalidName = `
The environment name %q is not allowed. The name must contain only URL safe
characters, and no path separators.
`
)
<commit_msg>update error response when env does not exist (#14009)<commit_after>package command

import (
	"net/url"
	"strings"
)

// EnvCommand is a Command Implementation that manipulates local state
// environments.
type EnvCommand struct {
	Meta
}

func (c *EnvCommand) Run(args []string) int {
	args = c.Meta.process(args, true)

	cmdFlags := c.Meta.flagSet("env")
	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }

	c.Ui.Output(c.Help())
	return 0
}

func (c *EnvCommand) Help() string {
	helpText := `
Usage: terraform env

  Create, change and delete Terraform environments.

Subcommands:

    list      List environments.
    select    Select an environment.
    new       Create a new environment.
    delete    Delete an existing environment.
`
	return strings.TrimSpace(helpText)
}

func (c *EnvCommand) Synopsis() string {
	return "Environment management"
}

// validEnvName returns true is this name is valid to use as an environment name.
// Since most named states are accessed via a filesystem path or URL, check if
// escaping the name would be required.
func validEnvName(name string) bool {
	return name == url.PathEscape(name)
}

const (
	envNotSupported = `Backend does not support environments`

	envExists = `Environment %q already exists`

	envDoesNotExist = `
Environment %q doesn't exist!

You can create this environment with the "new" option.`

	envChanged = `[reset][green]Switched to environment %q!`

	envCreated = `
[reset][green][bold]Created and switched to environment %q![reset][green]

You're now on a new, empty environment. Environments isolate their state,
so if you run "terraform plan" Terraform will not see any existing state
for this configuration.
`

	envDeleted = `[reset][green]Deleted environment %q!`

	envNotEmpty = `
Environment %[1]q is not empty!

Deleting %[1]q can result in dangling resources: resources that
exist but are no longer manageable by Terraform. Please destroy
these resources first.  If you want to delete this environment
anyways and risk dangling resources, use the '-force' flag.
`

	envWarnNotEmpty = `[reset][yellow]WARNING: %q was non-empty.
The resources managed by the deleted environment may still exist,
but are no longer manageable by Terraform since the state has
been deleted.
`

	envDelCurrent = `
Environment %[1]q is your active environment!

You cannot delete the currently active environment. Please switch
to another environment and try again.
`

	envInvalidName = `
The environment name %q is not allowed. The name must contain only URL safe
characters, and no path separators.
`
)
<|endoftext|>


<commit_before><commit_msg>Add function to calculate SHA256 from io.Reader<commit_after><|endoftext|>