<commit_before>// Copyright 2015 Matthew Collins
//
// 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 steven

import (
	"fmt"
	"math"
	"math/rand"
	"runtime"
	"strings"
	"time"

	"github.com/thinkofdeath/steven/native"
	"github.com/thinkofdeath/steven/render"
	"github.com/thinkofdeath/steven/ui"
	"github.com/thinkofdeath/steven/ui/scene"
)

type uiLogo struct {
	scene *scene.Type

	text          *ui.Text
	origX         float64
	textBaseScale float64
}

var (
	logoTextures = []string{
		"blocks/cobblestone",
		"blocks/netherrack",
		"blocks/dirt",
		"blocks/planks_oak",
		"blocks/brick",
		"blocks/snow",
		"blocks/sand",
		"blocks/gravel",
		"blocks/hardened_clay",
		"blocks/clay",
		"blocks/bedrock",
		"blocks/obsidian",
		"blocks/end_stone",
		"blocks/stone_andesite",
		"blocks/dirt_podzol_top",
		"blocks/portal",
		"blocks/prismarine_rough",
		"blocks/soul_sand",
		"blocks/lava_still",
		"blocks/hay_block_top",
		"blocks/log_acacia",
		"blocks/red_sandstone_carved",
	}
	r             = rand.New(rand.NewSource(time.Now().UnixNano()))
	logoTexture   = logoTextures[r.Intn(len(logoTextures))]
	logoText      = stevenLogoLines[r.Intn(len(stevenLogoLines))]
	logoTextTimer float64
)

func (u *uiLogo) init(scene *scene.Type) {
	u.scene = scene
	row := 0
	tex := render.GetTexture(logoTexture)
	titleBox := (&ui.Container{
		Y: 8,
	}).Attach(ui.Top, ui.Center)
	for _, line := range strings.Split(stevenLogo, "\n") {
		if line == "" {
			continue
		}
		for i, r := range line {
			if r == ' ' {
				continue
			}
			x, y := i*4, row*8
			rr, gg, bb := 255, 255, 255
			if r != ':' {
				rr, gg, bb = 170, 170, 170
			}
			shadow := ui.NewImage(
				render.GetTexture("solid"),
				float64(x+2), float64(y+4), 4, 8,
				float64(x%16)/16.0, float64(y%16)/16.0, 4/16.0, 8/16.0,
				0, 0, 0,
			)
			shadow.A = 100
			shadow.Parent = titleBox
			u.scene.AddDrawable(shadow)
			img := ui.NewImage(
				tex,
				float64(x), float64(y), 4, 8,
				float64(x%16)/16.0, float64(y%16)/16.0, 4/16.0, 8/16.0,
				rr, gg, bb,
			)
			img.Parent = titleBox
			u.scene.AddDrawable(img)
			if titleBox.W < float64(x+4) {
				titleBox.W = float64(x + 4)
			}
		}
		row++
	}
	titleBox.H = float64(row) * 8.0

	txt := ui.NewText(logoText, 0, -8, 255, 255, 0).Attach(ui.Bottom, ui.Right)
	txt.Parent = titleBox
	txt.Rotation = -math.Pi / 8
	u.scene.AddDrawable(txt)
	u.text = txt
	width, _ := txt.Size()
	u.textBaseScale = 300 / width
	if u.textBaseScale > 1 {
		u.textBaseScale = 1
	}
	txt.X = (-txt.Width / 2) * u.textBaseScale
	u.origX = txt.X
}

func (u *uiLogo) tick(delta float64) {
	logoTextTimer += delta
	if logoTextTimer > 60 {
		logoTextTimer -= 60
	}
	off := (logoTextTimer / 30)
	if off > 1.0 {
		off = 2.0 - off
	}
	off = (math.Cos(off*math.Pi) + 1) / 2
	u.text.ScaleX = (0.7 + (off / 3)) * u.textBaseScale
	u.text.ScaleY = (0.7 + (off / 3)) * u.textBaseScale
	u.text.X = u.origX
	u.text.X *= u.text.ScaleX * u.textBaseScale
}

var stevenLogoLines = []string{
	"I blame Xor",
	"Its not a bug its a feature!",
	"Don't go to #think, tis a silly place",
	"Tested! (In production)",
	"Not in scala!",
	"Its steven not phteven!",
	"Now webscale!",
	"Meow",
	"I bet one of cindy's cats broke it!",
	"=^.^=",
	"ಠ_ಠ",
	"Commit reverted in 5..4..3...",
	"Latest is greatest!",
	"[This space is intentionally left blank]",
	"ThinkBot: .... *Thinkofdeath damn it",
	"Now with more bugs!",
	"I blame Mojang",
	"The logo is totally not ascii art rendered as textures",
	"Look, it works on my machine.",
	"Open Source! https://github.com/thinkofdeath/steven",
	"Built with Go!",
	"Your machine uses " + native.Order.String() + " byte order!",
	fmt.Sprintf("You have %d CPUs!", runtime.NumCPU()),
	fmt.Sprintf("Compiled for %s with a %s CPU!", runtime.GOOS, runtime.GOARCH),
	"Compiled with " + runtime.Version() + "!",
	"try { } catch (Exception e) { }",
	"panic(recover())",
	"// Abandon hope all ye who enter here",
	"Its like I'm racing vanilla to see who can have the most bugs",
	"Using ascii art for the logo seemed like a bad idea at first",
	"... and still does.",
	"Help! I'm trapped in the splash text!",
	"Linux support!",
	"Windows support!",
	"Mac support! (in theory)",
	"Could have used vanilla's splash text!",
	"Come chat on IRC!",
	"Knowing Murphy's Law doesn't help",
	"Minecraft Multi-processing: breaking three things at once",
	"Silly Mortal...",
	"Software isn't released. It's allowed to escape.",
	"General System Error: Please sacrifice a cow and two chickens to continue",
	"Do you want to build a client?",
	"sudo rm -rf --no-preserve-root /",
	fmt.Sprintf("Splash generated at %d", time.Now().Unix()),
	"Thinkofdeath.getClass().getField(\"sanity\").set(Thinkofdeath, null);",
	"There is no God, only Zuul",
	"Now with potatoes!",
	"ask :: String -> Int; ask x = 42",
	"And then you cleanse them in a ball of atomic fire!",
	"I'm a little matrix, square and stout,",
	"this is my transpose, this is my count.",
	"<?php if(\"6 geese\" + \"4 chickens\" == \"10 birds\") echo(\"lolphp\");",
	"All hail the Cat Godess!",
	"var f = function() { return f; };",
	"unsafe.allocateObject(Unsafe.class);",
	":(){ :|:& };:",
	"You must pay to view this content.",
	"No touchy the topic",
	"Ceci n'est pas un splash.",
	"Xor is not actually a cat.",
	"The MD5 of md_5 is e14cfacdd442a953343ebd8529138680",
	"Gas powered stick! It never runs out of gas!",
}

const stevenLogo = `
   SSSSSSSSSSSSSSS          tttt
 SS:::::::::::::::S      ttt:::t
S:::::SSSSSS::::::S      t:::::t
S:::::S     SSSSSSS      t:::::t
S:::::S            ttttttt:::::ttttttt        eeeeeeeeeeee    vvvvvvv           vvvvvvv    eeeeeeeeeeee    nnnn  nnnnnnnn
S:::::S            t:::::::::::::::::t      ee::::::::::::ee   v:::::v         v:::::v   ee::::::::::::ee  n:::nn::::::::nn
 S::::SSSS         t:::::::::::::::::t     e::::::eeeee:::::ee  v:::::v       v:::::v   e::::::eeeee:::::een::::::::::::::nn
  SS::::::SSSSS    tttttt:::::::tttttt    e::::::e     e:::::e   v:::::v     v:::::v   e::::::e     e:::::enn:::::::::::::::n
    SSS::::::::SS        t:::::t          e:::::::eeeee::::::e    v:::::v   v:::::v    e:::::::eeeee::::::e  n:::::nnnn:::::n
       SSSSSS::::S       t:::::t          e:::::::::::::::::e      v:::::v v:::::v     e:::::::::::::::::e   n::::n    n::::n
            S:::::S      t:::::t          e::::::eeeeeeeeeee        v:::::v:::::v      e::::::eeeeeeeeeee    n::::n    n::::n
            S:::::S      t:::::t    tttttte:::::::e                  v:::::::::v       e:::::::e             n::::n    n::::n
SSSSSSS     S:::::S      t::::::tttt:::::te::::::::e                  v:::::::v        e::::::::e            n::::n    n::::n
S::::::SSSSSS:::::S      tt::::::::::::::t e::::::::eeeeeeee           v:::::v          e::::::::eeeeeeee    n::::n    n::::n
S:::::::::::::::SS         tt:::::::::::tt  ee:::::::::::::e            v:::v            ee:::::::::::::e    n::::n    n::::n
 SSSSSSSSSSSSSSS             ttttttttttt      eeeeeeeeeeeeee             vvv               eeeeeeeeeeeeee    nnnnnn    nnnnnn
`
<commit_msg>steven: randomly cycle the logo text and textures<commit_after>// Copyright 2015 Matthew Collins
//
// 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 steven

import (
	"fmt"
	"math"
	"math/rand"
	"runtime"
	"strings"
	"time"

	"github.com/thinkofdeath/steven/native"
	"github.com/thinkofdeath/steven/render"
	"github.com/thinkofdeath/steven/ui"
	"github.com/thinkofdeath/steven/ui/scene"
)

type uiLogo struct {
	scene *scene.Type

	text          *ui.Text
	origX         float64
	textBaseScale float64
}

var (
	logoTextures = []string{
		"blocks/cobblestone",
		"blocks/netherrack",
		"blocks/dirt",
		"blocks/planks_oak",
		"blocks/brick",
		"blocks/snow",
		"blocks/sand",
		"blocks/gravel",
		"blocks/hardened_clay",
		"blocks/clay",
		"blocks/bedrock",
		"blocks/obsidian",
		"blocks/end_stone",
		"blocks/stone_andesite",
		"blocks/dirt_podzol_top",
		"blocks/portal",
		"blocks/prismarine_rough",
		"blocks/soul_sand",
		"blocks/lava_still",
		"blocks/hay_block_top",
		"blocks/log_acacia",
		"blocks/red_sandstone_carved",
	}
	r                         = rand.New(rand.NewSource(time.Now().UnixNano()))
	logoTexture               = logoTextures[r.Intn(len(logoTextures))]
	logoTargetTexture         = logoTextures[r.Intn(len(logoTextures))]
	logoText                  = stevenLogoLines[r.Intn(len(stevenLogoLines))]
	logoTextTimer             float64
	logoLayers                [2][]*ui.Image
	logoTimer, logoTransTimer float64
)

func (u *uiLogo) init(scene *scene.Type) {
	u.scene = scene
	row := 0
	tex, tex2 := render.GetTexture(logoTexture), render.GetTexture(logoTargetTexture)
	titleBox := (&ui.Container{
		Y: 8,
	}).Attach(ui.Top, ui.Center)
	logoTimer = r.Float64() * 60 * 30
	logoTransTimer = 120
	for _, line := range strings.Split(stevenLogo, "\n") {
		if line == "" {
			continue
		}
		for i, r := range line {
			if r == ' ' {
				continue
			}
			x, y := i*4, row*8
			rr, gg, bb := 255, 255, 255
			if r != ':' {
				rr, gg, bb = 170, 170, 170
			}
			shadow := ui.NewImage(
				render.GetTexture("solid"),
				float64(x+2), float64(y+4), 4, 8,
				float64(x%16)/16.0, float64(y%16)/16.0, 4/16.0, 8/16.0,
				0, 0, 0,
			)
			shadow.A = 100
			shadow.Parent = titleBox
			u.scene.AddDrawable(shadow)

			img := ui.NewImage(
				tex,
				float64(x), float64(y), 4, 8,
				float64(x%16)/16.0, float64(y%16)/16.0, 4/16.0, 8/16.0,
				rr, gg, bb,
			)
			img.Parent = titleBox
			u.scene.AddDrawable(img)
			logoLayers[0] = append(logoLayers[0], img)

			img = ui.NewImage(
				tex2,
				float64(x), float64(y), 4, 8,
				float64(x%16)/16.0, float64(y%16)/16.0, 4/16.0, 8/16.0,
				rr, gg, bb,
			)
			img.Parent = titleBox
			img.A = 0
			u.scene.AddDrawable(img)
			logoLayers[1] = append(logoLayers[1], img)
			if titleBox.W < float64(x+4) {
				titleBox.W = float64(x + 4)
			}
		}
		row++
	}
	titleBox.H = float64(row) * 8.0

	txt := ui.NewText(logoText, 0, -8, 255, 255, 0).Attach(ui.Bottom, ui.Right)
	txt.Parent = titleBox
	txt.Rotation = -math.Pi / 8
	u.scene.AddDrawable(txt)
	u.text = txt
	width, _ := txt.Size()
	u.textBaseScale = 300 / width
	if u.textBaseScale > 1 {
		u.textBaseScale = 1
	}
	txt.X = (-txt.Width / 2) * u.textBaseScale
	u.origX = txt.X
}

func (u *uiLogo) tick(delta float64) {
	if logoTimer > 0 {
		logoTimer -= delta
	} else if logoTransTimer < 0 {
		logoTransTimer = 120
		logoTimer = r.Float64() * 60 * 30
		logoTexture = logoTargetTexture
		logoTargetTexture = logoTextures[r.Intn(len(logoTextures))]
		logoText = stevenLogoLines[r.Intn(len(stevenLogoLines))]
		u.text.Update(logoText)
		width, _ := u.text.Size()
		u.textBaseScale = 300 / width
		if u.textBaseScale > 1 {
			u.textBaseScale = 1
		}
		u.text.X = (-u.text.Width / 2) * u.textBaseScale
		u.origX = u.text.X
	} else {
		logoTransTimer -= delta
	}

	tex, tex2 := render.GetTexture(logoTexture), render.GetTexture(logoTargetTexture)
	for i := range logoLayers[0] {
		logoLayers[0][i].Texture = tex
		logoLayers[1][i].Texture = tex2

		logoLayers[0][i].A = int(255 * (logoTransTimer / 120))
		logoLayers[1][i].A = int(255 * (1 - (logoTransTimer / 120)))
	}

	logoTextTimer += delta
	if logoTextTimer > 60 {
		logoTextTimer -= 60
	}
	off := (logoTextTimer / 30)
	if off > 1.0 {
		off = 2.0 - off
	}
	off = (math.Cos(off*math.Pi) + 1) / 2
	u.text.ScaleX = (0.7 + (off / 3)) * u.textBaseScale
	u.text.ScaleY = (0.7 + (off / 3)) * u.textBaseScale
	u.text.X = u.origX
	u.text.X *= u.text.ScaleX * u.textBaseScale
}

var stevenLogoLines = []string{
	"I blame Xor",
	"Its not a bug its a feature!",
	"Don't go to #think, tis a silly place",
	"Tested! (In production)",
	"Not in scala!",
	"Its steven not phteven!",
	"Now webscale!",
	"Meow",
	"I bet one of cindy's cats broke it!",
	"=^.^=",
	"ಠ_ಠ",
	"Commit reverted in 5..4..3...",
	"Latest is greatest!",
	"[This space is intentionally left blank]",
	"ThinkBot: .... *Thinkofdeath damn it",
	"Now with more bugs!",
	"I blame Mojang",
	"The logo is totally not ascii art rendered as textures",
	"Look, it works on my machine.",
	"Open Source! https://github.com/thinkofdeath/steven",
	"Built with Go!",
	"Your machine uses " + native.Order.String() + " byte order!",
	fmt.Sprintf("You have %d CPUs!", runtime.NumCPU()),
	fmt.Sprintf("Compiled for %s with a %s CPU!", runtime.GOOS, runtime.GOARCH),
	"Compiled with " + runtime.Version() + "!",
	"try { } catch (Exception e) { }",
	"panic(recover())",
	"// Abandon hope all ye who enter here",
	"Its like I'm racing vanilla to see who can have the most bugs",
	"Using ascii art for the logo seemed like a bad idea at first",
	"... and still does.",
	"Help! I'm trapped in the splash text!",
	"Linux support!",
	"Windows support!",
	"Mac support! (in theory)",
	"Could have used vanilla's splash text!",
	"Come chat on IRC!",
	"Knowing Murphy's Law doesn't help",
	"Minecraft Multi-processing: breaking three things at once",
	"Silly Mortal...",
	"Software isn't released. It's allowed to escape.",
	"General System Error: Please sacrifice a cow and two chickens to continue",
	"Do you want to build a client?",
	"sudo rm -rf --no-preserve-root /",
	fmt.Sprintf("Splash generated at %d", time.Now().Unix()),
	"Thinkofdeath.getClass().getField(\"sanity\").set(Thinkofdeath, null);",
	"There is no God, only Zuul",
	"Now with potatoes!",
	"ask :: String -> Int; ask x = 42",
	"And then you cleanse them in a ball of atomic fire!",
	"I'm a little matrix, square and stout,",
	"this is my transpose, this is my count.",
	"<?php if(\"6 geese\" + \"4 chickens\" == \"10 birds\") echo(\"lolphp\");",
	"All hail the Cat Godess!",
	"var f = function() { return f; };",
	"unsafe.allocateObject(Unsafe.class);",
	":(){ :|:& };:",
	"You must pay to view this content.",
	"No touchy the topic",
	"Ceci n'est pas un splash.",
	"Xor is not actually a cat.",
	"The MD5 of md_5 is e14cfacdd442a953343ebd8529138680",
	"Gas powered stick! It never runs out of gas!",
}

const stevenLogo = `
   SSSSSSSSSSSSSSS          tttt
 SS:::::::::::::::S      ttt:::t
S:::::SSSSSS::::::S      t:::::t
S:::::S     SSSSSSS      t:::::t
S:::::S            ttttttt:::::ttttttt        eeeeeeeeeeee    vvvvvvv           vvvvvvv    eeeeeeeeeeee    nnnn  nnnnnnnn
S:::::S            t:::::::::::::::::t      ee::::::::::::ee   v:::::v         v:::::v   ee::::::::::::ee  n:::nn::::::::nn
 S::::SSSS         t:::::::::::::::::t     e::::::eeeee:::::ee  v:::::v       v:::::v   e::::::eeeee:::::een::::::::::::::nn
  SS::::::SSSSS    tttttt:::::::tttttt    e::::::e     e:::::e   v:::::v     v:::::v   e::::::e     e:::::enn:::::::::::::::n
    SSS::::::::SS        t:::::t          e:::::::eeeee::::::e    v:::::v   v:::::v    e:::::::eeeee::::::e  n:::::nnnn:::::n
       SSSSSS::::S       t:::::t          e:::::::::::::::::e      v:::::v v:::::v     e:::::::::::::::::e   n::::n    n::::n
            S:::::S      t:::::t          e::::::eeeeeeeeeee        v:::::v:::::v      e::::::eeeeeeeeeee    n::::n    n::::n
            S:::::S      t:::::t    tttttte:::::::e                  v:::::::::v       e:::::::e             n::::n    n::::n
SSSSSSS     S:::::S      t::::::tttt:::::te::::::::e                  v:::::::v        e::::::::e            n::::n    n::::n
S::::::SSSSSS:::::S      tt::::::::::::::t e::::::::eeeeeeee           v:::::v          e::::::::eeeeeeee    n::::n    n::::n
S:::::::::::::::SS         tt:::::::::::tt  ee:::::::::::::e            v:::v            ee:::::::::::::e    n::::n    n::::n
 SSSSSSSSSSSSSSS             ttttttttttt      eeeeeeeeeeeeee             vvv               eeeeeeeeeeeeee    nnnnnn    nnnnnn
`
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"net/http"
	"strings"
	"testing"

	"github.com/jroimartin/gocui"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func newTestUI(t *testing.T) (*gocui.Gui, *UI) {
	g, err := gocui.NewGui(gocui.Output256)
	require.NoError(t, err)

	ui := NewUI("")
	ui.Layout(g)

	return g, ui
}

func TestUIAddRequestSavesInOrder(t *testing.T) {
	g, ui := newTestUI(t)
	defer g.Close()

	for i := 0; i < 10; i++ {
		req, _ := http.NewRequest("GET", fmt.Sprintf("/%d", i), &bytes.Buffer{})
		require.NoError(t, ui.AddRequest(g, req))
	}

	assert.Len(t, ui.requests, 10)
	for i := 0; i < 10; i++ {
		req := ui.requests[i]
		split := strings.Split(string(req), " ")
		path := split[1]
		assert.Equal(t, fmt.Sprintf("/%d", i), path)
	}

	assert.Equal(t, 9, ui.currentRequest)
}

func TestUIScrollRequests(t *testing.T) {
	g, ui := newTestUI(t)
	defer g.Close()

	for i := 0; i < 10; i++ {
		req, _ := http.NewRequest("GET", fmt.Sprintf("/%d", i), &bytes.Buffer{})
		require.NoError(t, ui.AddRequest(g, req))
	}

	cur := ui.currentRequest
	ui.prevRequest(g, nil)
	assert.Equal(t, ui.currentRequest, cur-1)

	ui.nextRequest(g, nil)
	assert.Equal(t, ui.currentRequest, cur)

	t.Run("Doesn't autoscroll", func(t *testing.T) {
		req, _ := http.NewRequest("GET", "/", &bytes.Buffer{})
		ui.prevRequest(g, nil)
		cur := ui.currentRequest

		ui.AddRequest(g, req)
		assert.Equal(t, cur, ui.currentRequest)
	})
}
<commit_msg>Verify ui.Layout err on tests<commit_after>package main

import (
	"bytes"
	"fmt"
	"net/http"
	"strings"
	"testing"

	"github.com/jroimartin/gocui"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func newTestUI(t *testing.T) (*gocui.Gui, *UI) {
	g, err := gocui.NewGui(gocui.Output256)
	require.NoError(t, err)

	ui := NewUI("")
	require.NoError(t, ui.Layout(g))

	return g, ui
}

func TestUIAddRequestSavesInOrder(t *testing.T) {
	g, ui := newTestUI(t)
	defer g.Close()

	for i := 0; i < 10; i++ {
		req, _ := http.NewRequest("GET", fmt.Sprintf("/%d", i), &bytes.Buffer{})
		require.NoError(t, ui.AddRequest(g, req))
	}

	assert.Len(t, ui.requests, 10)
	for i := 0; i < 10; i++ {
		req := ui.requests[i]
		split := strings.Split(string(req), " ")
		path := split[1]
		assert.Equal(t, fmt.Sprintf("/%d", i), path)
	}

	assert.Equal(t, 9, ui.currentRequest)
}

func TestUIScrollRequests(t *testing.T) {
	g, ui := newTestUI(t)
	defer g.Close()

	for i := 0; i < 10; i++ {
		req, _ := http.NewRequest("GET", fmt.Sprintf("/%d", i), &bytes.Buffer{})
		require.NoError(t, ui.AddRequest(g, req))
	}

	cur := ui.currentRequest
	ui.prevRequest(g, nil)
	assert.Equal(t, ui.currentRequest, cur-1)

	ui.nextRequest(g, nil)
	assert.Equal(t, ui.currentRequest, cur)

	t.Run("Doesn't autoscroll", func(t *testing.T) {
		req, _ := http.NewRequest("GET", "/", &bytes.Buffer{})
		ui.prevRequest(g, nil)
		cur := ui.currentRequest

		ui.AddRequest(g, req)
		assert.Equal(t, cur, ui.currentRequest)
	})
}
<|endoftext|>


<commit_before>package vagrantutil

import (
	"bufio"
	"bytes"
	"encoding/csv"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"os/user"
	"path/filepath"
	"strings"
	"sync"
)

//go:generate stringer -type=BoxSubcommand,Status  -output=stringer.go

type (
	BoxSubcommand int
	Status        int
)

const (
	Add BoxSubcommand = iota
	List
	Outdated
	Remove
	Repackage
	Update
)

const (
	// Some possible states:
	// https://github.com/mitchellh/vagrant/blob/master/templates/locales/en.yml#L1504
	Unknown Status = iota
	NotCreated
	Running
	Saved
	PowerOff
)

type CommandOutput struct {
	Line  string
	Error error
}

type Vagrant struct {
	// VagrantfilePath is the directory with specifies the directory where
	// Vagrantfile is being stored.
	VagrantfilePath string
}

// NewVagrant returns a new Vagrant instance for the given name. The name
// should be unique. If the name already exists in the system it'll be used, if
// not a new setup will be createad.
func NewVagrant(name string) (*Vagrant, error) {
	u, err := user.Current()
	if err != nil {
		return nil, err
	}

	if name == "" {
		return nil, err
	}

	vagrantHome := filepath.Join(u.HomeDir, ".koding-boxes", name)
	if err := os.MkdirAll(vagrantHome, 0755); err != nil {
		return nil, err
	}

	return &Vagrant{
		VagrantfilePath: vagrantHome,
	}, nil
}

func (v *Vagrant) Version() (string, error) {
	out, err := v.runCommand("version")
	if err != nil {
		return "", err
	}

	records, err := parseRecords(out)
	if err != nil {
		return "", err
	}

	versionInstalled, err := parseData(records, "version-installed")
	if err != nil {
		return "", err
	}

	return versionInstalled, nil
}

func (v *Vagrant) Box(subcommand BoxSubcommand) (string, error) {
	out, err := v.runCommand("box", subcommand.String())
	if err != nil {
		return "", err
	}

	return strings.TrimSpace(out), nil
}

func (v *Vagrant) Status() (Status, error) {
	if err := v.vagrantfileExists(); err != nil {
		return Unknown, err
	}

	out, err := v.runCommand("status")
	if err != nil {
		return Unknown, err
	}

	records, err := parseRecords(out)
	if err != nil {
		return Unknown, err
	}

	status, err := parseData(records, "state")
	if err != nil {
		return Unknown, err
	}

	return toStatus(status)
}

// Up executes "vagrant up" for the given vagrantfile. The returned channel
// contains the output stream. At the end of the output, the error is put into
// the Error field if there is any.
func (v *Vagrant) Up(vagrantfile string) (<-chan *CommandOutput, error) {
	if vagrantfile == "" {
		return nil, errors.New("Vagrantfile content is empty")
	}

	// if it's exists, don't overwrite anything and use the existing one
	if err := v.vagrantfileExists(); err != nil {
		err := ioutil.WriteFile(v.vagrantfile(), []byte(vagrantfile), 0644)
		if err != nil {
			return nil, err
		}
	} else {
		// TODO(arslan): replace logging with koding/logging
		log.Printf("Using existing Vagrantfile at %s", v.VagrantfilePath)
	}

	cmd := v.createCommand("up")
	return startCommand(cmd)
}

// Destroy executes "vagrant destroy". The returned reader contains the output
// stream. The client is responsible of calling the Close method of the
// returned reader.
func (v *Vagrant) Destroy() (<-chan *CommandOutput, error) {
	if err := v.vagrantfileExists(); err != nil {
		return nil, err
	}

	cmd := v.createCommand("destroy", "--force")
	return startCommand(cmd)
}

// vagrantfile returns the Vagrantfile path
func (v *Vagrant) vagrantfile() string {
	return filepath.Join(v.VagrantfilePath, "Vagrantfile")
}

// vagrantfileExists checks if a Vagrantfile exists in the given path. It
// returns a nil error if exists.
func (v *Vagrant) vagrantfileExists() error {
	if _, err := os.Stat(v.vagrantfile()); os.IsNotExist(err) {
		return err
	}
	return nil
}

func (v *Vagrant) createCommand(args ...string) *exec.Cmd {
	cmd := exec.Command("vagrant", args...)
	cmd.Dir = v.VagrantfilePath
	return cmd
}

func (v *Vagrant) runCommand(args ...string) (string, error) {
	args = append(args, "--machine-readable")
	cmd := exec.Command("vagrant", args...)
	cmd.Dir = v.VagrantfilePath
	out, err := cmd.CombinedOutput()
	if err != nil {
		return "", err
	}

	return string(out), nil
}

// startCommand starts the command and sends back both the stdout and stderr to
// the returned channel. Any error happened during the streaming is passed to
// the Error field.
func startCommand(cmd *exec.Cmd) (<-chan *CommandOutput, error) {
	stdoutPipe, err := cmd.StdoutPipe()
	if err != nil {
		return nil, err
	}

	stderrPipe, err := cmd.StderrPipe()
	if err != nil {
		return nil, err
	}

	if err := cmd.Start(); err != nil {
		return nil, err
	}

	var wg sync.WaitGroup
	out := make(chan *CommandOutput)

	output := func(r io.Reader) {
		wg.Add(1)
		scanner := bufio.NewScanner(r)
		for scanner.Scan() {
			out <- &CommandOutput{Line: scanner.Text(), Error: nil}
		}

		if err := scanner.Err(); err != nil {
			out <- &CommandOutput{Line: "", Error: err}
		}
		wg.Done()
	}

	go output(stdoutPipe)
	go output(stderrPipe)

	go func() {
		wg.Wait()
		if err := cmd.Wait(); err != nil {
			out <- &CommandOutput{Line: "", Error: err}
		}

		close(out)
	}()

	return out, nil
}

func parseData(records [][]string, typeName string) (string, error) {
	data := ""
	for _, record := range records {
		// first three are defined, after that data is variadic, it contains
		// zero or more information. We should have a data, otherwise it's
		// useless.
		if len(record) < 4 {
			continue
		}

		if typeName == record[2] {
			data = record[3]
		}
	}

	if data == "" {
		return "", fmt.Errorf("couldn't parse data for vagrant type: '%s'", typeName)
	}

	return data, nil
}

func parseRecords(out string) ([][]string, error) {
	buf := bytes.NewBufferString(out)
	c := csv.NewReader(buf)
	return c.ReadAll()
}

// toStatus convers the given state string to Status type
func toStatus(state string) (Status, error) {
	switch state {
	case "running":
		return Running, nil
	case "not_created":
		return NotCreated, nil
	case "saved":
		return Saved, nil
	case "poweroff":
		return PowerOff, nil
	default:
		return Unknown, fmt.Errorf("Unknown state: %s", state)
	}

}
<commit_msg>vagrant: rename name to path<commit_after>package vagrantutil

import (
	"bufio"
	"bytes"
	"encoding/csv"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"os/user"
	"path/filepath"
	"strings"
	"sync"
)

//go:generate stringer -type=BoxSubcommand,Status  -output=stringer.go

type (
	BoxSubcommand int
	Status        int
)

const (
	Add BoxSubcommand = iota
	List
	Outdated
	Remove
	Repackage
	Update
)

const (
	// Some possible states:
	// https://github.com/mitchellh/vagrant/blob/master/templates/locales/en.yml#L1504
	Unknown Status = iota
	NotCreated
	Running
	Saved
	PowerOff
)

type CommandOutput struct {
	Line  string
	Error error
}

type Vagrant struct {
	// VagrantfilePath is the directory with specifies the directory where
	// Vagrantfile is being stored.
	VagrantfilePath string
}

// NewVagrant returns a new Vagrant instance for the given path. The path
// should be unique. If the path already exists in the system it'll be used, if
// not a new setup will be createad.
func NewVagrant(path string) (*Vagrant, error) {
	u, err := user.Current()
	if err != nil {
		return nil, err
	}

	if path == "" {
		return nil, err
	}

	vagrantHome := filepath.Join(u.HomeDir, ".koding-boxes", path)
	if err := os.MkdirAll(vagrantHome, 0755); err != nil {
		return nil, err
	}

	return &Vagrant{
		VagrantfilePath: vagrantHome,
	}, nil
}

func (v *Vagrant) Version() (string, error) {
	out, err := v.runCommand("version")
	if err != nil {
		return "", err
	}

	records, err := parseRecords(out)
	if err != nil {
		return "", err
	}

	versionInstalled, err := parseData(records, "version-installed")
	if err != nil {
		return "", err
	}

	return versionInstalled, nil
}

func (v *Vagrant) Box(subcommand BoxSubcommand) (string, error) {
	out, err := v.runCommand("box", subcommand.String())
	if err != nil {
		return "", err
	}

	return strings.TrimSpace(out), nil
}

func (v *Vagrant) Status() (Status, error) {
	if err := v.vagrantfileExists(); err != nil {
		return Unknown, err
	}

	out, err := v.runCommand("status")
	if err != nil {
		return Unknown, err
	}

	records, err := parseRecords(out)
	if err != nil {
		return Unknown, err
	}

	status, err := parseData(records, "state")
	if err != nil {
		return Unknown, err
	}

	return toStatus(status)
}

// Up executes "vagrant up" for the given vagrantfile. The returned channel
// contains the output stream. At the end of the output, the error is put into
// the Error field if there is any.
func (v *Vagrant) Up(vagrantfile string) (<-chan *CommandOutput, error) {
	if vagrantfile == "" {
		return nil, errors.New("Vagrantfile content is empty")
	}

	// if it's exists, don't overwrite anything and use the existing one
	if err := v.vagrantfileExists(); err != nil {
		err := ioutil.WriteFile(v.vagrantfile(), []byte(vagrantfile), 0644)
		if err != nil {
			return nil, err
		}
	} else {
		// TODO(arslan): replace logging with koding/logging
		log.Printf("Using existing Vagrantfile at %s", v.VagrantfilePath)
	}

	cmd := v.createCommand("up")
	return startCommand(cmd)
}

// Destroy executes "vagrant destroy". The returned reader contains the output
// stream. The client is responsible of calling the Close method of the
// returned reader.
func (v *Vagrant) Destroy() (<-chan *CommandOutput, error) {
	if err := v.vagrantfileExists(); err != nil {
		return nil, err
	}

	cmd := v.createCommand("destroy", "--force")
	return startCommand(cmd)
}

// vagrantfile returns the Vagrantfile path
func (v *Vagrant) vagrantfile() string {
	return filepath.Join(v.VagrantfilePath, "Vagrantfile")
}

// vagrantfileExists checks if a Vagrantfile exists in the given path. It
// returns a nil error if exists.
func (v *Vagrant) vagrantfileExists() error {
	if _, err := os.Stat(v.vagrantfile()); os.IsNotExist(err) {
		return err
	}
	return nil
}

func (v *Vagrant) createCommand(args ...string) *exec.Cmd {
	cmd := exec.Command("vagrant", args...)
	cmd.Dir = v.VagrantfilePath
	return cmd
}

func (v *Vagrant) runCommand(args ...string) (string, error) {
	args = append(args, "--machine-readable")
	cmd := exec.Command("vagrant", args...)
	cmd.Dir = v.VagrantfilePath
	out, err := cmd.CombinedOutput()
	if err != nil {
		return "", err
	}

	return string(out), nil
}

// startCommand starts the command and sends back both the stdout and stderr to
// the returned channel. Any error happened during the streaming is passed to
// the Error field.
func startCommand(cmd *exec.Cmd) (<-chan *CommandOutput, error) {
	stdoutPipe, err := cmd.StdoutPipe()
	if err != nil {
		return nil, err
	}

	stderrPipe, err := cmd.StderrPipe()
	if err != nil {
		return nil, err
	}

	if err := cmd.Start(); err != nil {
		return nil, err
	}

	var wg sync.WaitGroup
	out := make(chan *CommandOutput)

	output := func(r io.Reader) {
		wg.Add(1)
		scanner := bufio.NewScanner(r)
		for scanner.Scan() {
			out <- &CommandOutput{Line: scanner.Text(), Error: nil}
		}

		if err := scanner.Err(); err != nil {
			out <- &CommandOutput{Line: "", Error: err}
		}
		wg.Done()
	}

	go output(stdoutPipe)
	go output(stderrPipe)

	go func() {
		wg.Wait()
		if err := cmd.Wait(); err != nil {
			out <- &CommandOutput{Line: "", Error: err}
		}

		close(out)
	}()

	return out, nil
}

func parseData(records [][]string, typeName string) (string, error) {
	data := ""
	for _, record := range records {
		// first three are defined, after that data is variadic, it contains
		// zero or more information. We should have a data, otherwise it's
		// useless.
		if len(record) < 4 {
			continue
		}

		if typeName == record[2] {
			data = record[3]
		}
	}

	if data == "" {
		return "", fmt.Errorf("couldn't parse data for vagrant type: '%s'", typeName)
	}

	return data, nil
}

func parseRecords(out string) ([][]string, error) {
	buf := bytes.NewBufferString(out)
	c := csv.NewReader(buf)
	return c.ReadAll()
}

// toStatus convers the given state string to Status type
func toStatus(state string) (Status, error) {
	switch state {
	case "running":
		return Running, nil
	case "not_created":
		return NotCreated, nil
	case "saved":
		return Saved, nil
	case "poweroff":
		return PowerOff, nil
	default:
		return Unknown, fmt.Errorf("Unknown state: %s", state)
	}

}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"runtime"
)

func init() {
	Topics = append(Topics, &Topic{
		Name:   "version",
		Hidden: true,
		Commands: CommandSet{
			{
				Topic:            "version",
				Description:      "print the version",
				DisableAnalytics: true,
				Help: `Shows the Heroku CLI version.

Example:

  $ heroku version
	heroku-cli/1.2.3 (x86_64-darwin11.2.0) ruby/1.9.3`,
				Run: func(ctx *Context) {
					ShowVersion()
				},
			},
		},
	})
}

func version() string {
	return fmt.Sprintf("heroku-cli/%s (%s-%s) %s", Version, runtime.GOARCH, runtime.GOOS, runtime.Version())
}

// ShowVersion shows the version and exits
func ShowVersion() {
	Printf(version())
	if Channel != "stable" {
		Printf(" %s", Channel)
	}
	Println()
	Exit(0)
}
<commit_msg>fix version exit in tests<commit_after>package main

import (
	"fmt"
	"runtime"
)

func init() {
	Topics = append(Topics, &Topic{
		Name:   "version",
		Hidden: true,
		Commands: CommandSet{
			{
				Topic:            "version",
				Description:      "print the version",
				DisableAnalytics: true,
				Help: `Shows the Heroku CLI version.

Example:

  $ heroku version
	heroku-cli/1.2.3 (x86_64-darwin11.2.0) ruby/1.9.3`,
				Run: func(ctx *Context) {
					ShowVersion()
				},
			},
		},
	})
}

func version() string {
	return fmt.Sprintf("heroku-cli/%s (%s-%s) %s", Version, runtime.GOARCH, runtime.GOOS, runtime.Version())
}

// ShowVersion shows the version and exits
func ShowVersion() {
	Printf(version())
	if Channel != "stable" {
		Printf(" %s", Channel)
	}
	Println()
}
<|endoftext|>


<commit_before>package db

import (
	"bytes"
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"sync"

	"github.com/etcd-io/bbolt"
)

var bucket = []byte("tm")

func init() {
	registerDBCreator(BoltDBBackend, func(name, dir string) (DB, error) {
		return NewBoltDB(name, dir)
	}, false)
}

// BoltDB is a wrapper around etcd's fork of bolt
// (https://github.com/etcd-io/bbolt).
//
// NOTE: All operations (including Set, Delete) are synchronous by default. One
// can globally turn it off by using NoSync config option (not recommended).
//
// A single bucket ([]byte("tm")) is used per a database instance. This could
// lead to performance issues when/if there will be lots of keys.
type BoltDB struct {
	db *bbolt.DB
}

// NewBoltDB returns a BoltDB with default options.
func NewBoltDB(name, dir string) (DB, error) {
	return NewBoltDBWithOpts(name, dir, bbolt.DefaultOptions)
}

// NewBoltDBWithOpts allows you to supply *bbolt.Options. ReadOnly: true is not
// supported because NewBoltDBWithOpts creates a global bucket.
func NewBoltDBWithOpts(name string, dir string, opts *bbolt.Options) (DB, error) {
	if opts.ReadOnly {
		return nil, errors.New("ReadOnly: true is not supported")
	}

	dbPath := filepath.Join(dir, name+".db")
	db, err := bbolt.Open(dbPath, os.ModePerm, opts)
	if err != nil {
		return nil, err
	}

	// create a global bucket
	err = db.Update(func(tx *bbolt.Tx) error {
		_, err := tx.CreateBucketIfNotExists(bucket)
		return err
	})
	if err != nil {
		return nil, err
	}

	return &BoltDB{db: db}, nil
}

func (bdb *BoltDB) Get(key []byte) (value []byte) {
	key = nonEmptyKey(nonNilBytes(key))
	err := bdb.db.View(func(tx *bbolt.Tx) error {
		b := tx.Bucket(bucket)
		value = b.Get(key)
		return nil
	})
	if err != nil {
		panic(err)
	}
	return
}

func (bdb *BoltDB) Has(key []byte) bool {
	return bdb.Get(key) != nil
}

func (bdb *BoltDB) Set(key, value []byte) {
	key = nonEmptyKey(nonNilBytes(key))
	value = nonNilBytes(value)
	err := bdb.db.Update(func(tx *bbolt.Tx) error {
		b := tx.Bucket(bucket)
		return b.Put(key, value)
	})
	if err != nil {
		panic(err)
	}
}

func (bdb *BoltDB) SetSync(key, value []byte) {
	bdb.Set(key, value)
}

func (bdb *BoltDB) Delete(key []byte) {
	key = nonEmptyKey(nonNilBytes(key))
	err := bdb.db.Update(func(tx *bbolt.Tx) error {
		return tx.Bucket(bucket).Delete(key)
	})
	if err != nil {
		panic(err)
	}
}

func (bdb *BoltDB) DeleteSync(key []byte) {
	bdb.Delete(key)
}

func (bdb *BoltDB) Close() {
	bdb.db.Close()
}

func (bdb *BoltDB) Print() {
	stats := bdb.db.Stats()
	fmt.Printf("%v\n", stats)

	err := bdb.db.View(func(tx *bbolt.Tx) error {
		tx.Bucket(bucket).ForEach(func(k, v []byte) error {
			fmt.Printf("[%X]:\t[%X]\n", k, v)
			return nil
		})
		return nil
	})
	if err != nil {
		panic(err)
	}
}

func (bdb *BoltDB) Stats() map[string]string {
	stats := bdb.db.Stats()
	m := make(map[string]string)

	// Freelist stats
	m["FreePageN"] = fmt.Sprintf("%v", stats.FreePageN)
	m["PendingPageN"] = fmt.Sprintf("%v", stats.PendingPageN)
	m["FreeAlloc"] = fmt.Sprintf("%v", stats.FreeAlloc)
	m["FreelistInuse"] = fmt.Sprintf("%v", stats.FreelistInuse)

	// Transaction stats
	m["TxN"] = fmt.Sprintf("%v", stats.TxN)
	m["OpenTxN"] = fmt.Sprintf("%v", stats.OpenTxN)

	return m
}

// boltDBBatch stores key values in sync.Map and dumps them to the underlying
// DB upon Write call.
type boltDBBatch struct {
	buffer *sync.Map
	db     *BoltDB
}

// NewBatch returns a new batch.
func (bdb *BoltDB) NewBatch() Batch {
	return &boltDBBatch{
		buffer: &sync.Map{},
		db:     bdb,
	}
}

func (bdb *boltDBBatch) Set(key, value []byte) {
	bdb.buffer.Store(key, value)
}

func (bdb *boltDBBatch) Delete(key []byte) {
	bdb.buffer.Delete(key)
}

// NOTE: the operation is synchronous (see BoltDB for reasons)
func (bdb *boltDBBatch) Write() {
	err := bdb.db.db.Batch(func(tx *bbolt.Tx) error {
		b := tx.Bucket(bucket)
		var putErr error
		bdb.buffer.Range(func(key, value interface{}) bool {
			putErr = b.Put(key.([]byte), value.([]byte))
			return putErr == nil // stop if putErr is not nil
		})
		return putErr
	})
	if err != nil {
		panic(err)
	}
}

func (bdb *boltDBBatch) WriteSync() {
	bdb.Write()
}

func (bdb *boltDBBatch) Close() {}

// WARNING: Any concurrent writes (Set, SetSync) will block until the Iterator
// is closed.
func (bdb *BoltDB) Iterator(start, end []byte) Iterator {
	tx, err := bdb.db.Begin(false)
	if err != nil {
		panic(err)
	}
	c := tx.Bucket(bucket).Cursor()
	return newBoltDBIterator(c, start, end, false)
}

// WARNING: Any concurrent writes (Set, SetSync) will block until the Iterator
// is closed.
func (bdb *BoltDB) ReverseIterator(start, end []byte) Iterator {
	tx, err := bdb.db.Begin(false)
	if err != nil {
		panic(err)
	}
	c := tx.Bucket(bucket).Cursor()
	return newBoltDBIterator(c, start, end, true)
}

// boltDBIterator allows you to iterate on range of keys/values given some
// start / end keys (nil & nil will result in doing full scan).
type boltDBIterator struct {
	itr   *bbolt.Cursor
	start []byte
	end   []byte

	currentKey   []byte
	currentValue []byte

	isInvalid bool
	isReverse bool
}

func newBoltDBIterator(itr *bbolt.Cursor, start, end []byte, isReverse bool) *boltDBIterator {
	var ck, cv []byte
	if isReverse {
		if end == nil {
			ck, cv = itr.Last()
		} else {
			_, _ = itr.Seek(end) // after key
			ck, cv = itr.Prev()  // return to end key
		}
	} else {
		if start == nil {
			ck, cv = itr.First()
		} else {
			ck, cv = itr.Seek(start)
		}
	}

	return &boltDBIterator{
		itr:          itr,
		start:        start,
		end:          end,
		currentKey:   ck,
		currentValue: cv,
		isReverse:    isReverse,
		isInvalid:    false,
	}
}

func (itr *boltDBIterator) Domain() ([]byte, []byte) {
	return itr.start, itr.end
}

func (itr *boltDBIterator) Valid() bool {
	if itr.isInvalid {
		return false
	}

	// iterated to the end of the cursor
	if len(itr.currentKey) == 0 {
		itr.isInvalid = true
		return false
	}

	if itr.isReverse {
		if itr.start != nil && bytes.Compare(itr.currentKey, itr.start) < 0 {
			itr.isInvalid = true
			return false
		}
	} else {
		if itr.end != nil && bytes.Compare(itr.end, itr.currentKey) <= 0 {
			itr.isInvalid = true
			return false
		}
	}

	// Valid
	return true
}

func (itr *boltDBIterator) Next() {
	itr.assertIsValid()
	if itr.isReverse {
		itr.currentKey, itr.currentValue = itr.itr.Prev()
	} else {
		itr.currentKey, itr.currentValue = itr.itr.Next()
	}
}

func (itr *boltDBIterator) Key() []byte {
	itr.assertIsValid()
	return itr.currentKey
}

func (itr *boltDBIterator) Value() []byte {
	itr.assertIsValid()
	return itr.currentValue
}

// boltdb cursor has no close op.
func (itr *boltDBIterator) Close() {}

func (itr *boltDBIterator) assertIsValid() {
	if !itr.Valid() {
		panic("Boltdb-iterator is invalid")
	}
}

// nonEmptyKey returns a []byte("nil") if key is empty.
// WARNING: this may collude with "nil" user key!
func nonEmptyKey(key []byte) []byte {
	if len(key) == 0 {
		return []byte("nil")
	}
	return key
}
<commit_msg>libs/db: close boltDBIterator (#3627)<commit_after>package db

import (
	"bytes"
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"sync"

	"github.com/etcd-io/bbolt"
)

var bucket = []byte("tm")

func init() {
	registerDBCreator(BoltDBBackend, func(name, dir string) (DB, error) {
		return NewBoltDB(name, dir)
	}, false)
}

// BoltDB is a wrapper around etcd's fork of bolt
// (https://github.com/etcd-io/bbolt).
//
// NOTE: All operations (including Set, Delete) are synchronous by default. One
// can globally turn it off by using NoSync config option (not recommended).
//
// A single bucket ([]byte("tm")) is used per a database instance. This could
// lead to performance issues when/if there will be lots of keys.
type BoltDB struct {
	db *bbolt.DB
}

// NewBoltDB returns a BoltDB with default options.
func NewBoltDB(name, dir string) (DB, error) {
	return NewBoltDBWithOpts(name, dir, bbolt.DefaultOptions)
}

// NewBoltDBWithOpts allows you to supply *bbolt.Options. ReadOnly: true is not
// supported because NewBoltDBWithOpts creates a global bucket.
func NewBoltDBWithOpts(name string, dir string, opts *bbolt.Options) (DB, error) {
	if opts.ReadOnly {
		return nil, errors.New("ReadOnly: true is not supported")
	}

	dbPath := filepath.Join(dir, name+".db")
	db, err := bbolt.Open(dbPath, os.ModePerm, opts)
	if err != nil {
		return nil, err
	}

	// create a global bucket
	err = db.Update(func(tx *bbolt.Tx) error {
		_, err := tx.CreateBucketIfNotExists(bucket)
		return err
	})
	if err != nil {
		return nil, err
	}

	return &BoltDB{db: db}, nil
}

func (bdb *BoltDB) Get(key []byte) (value []byte) {
	key = nonEmptyKey(nonNilBytes(key))
	err := bdb.db.View(func(tx *bbolt.Tx) error {
		b := tx.Bucket(bucket)
		value = b.Get(key)
		return nil
	})
	if err != nil {
		panic(err)
	}
	return
}

func (bdb *BoltDB) Has(key []byte) bool {
	return bdb.Get(key) != nil
}

func (bdb *BoltDB) Set(key, value []byte) {
	key = nonEmptyKey(nonNilBytes(key))
	value = nonNilBytes(value)
	err := bdb.db.Update(func(tx *bbolt.Tx) error {
		b := tx.Bucket(bucket)
		return b.Put(key, value)
	})
	if err != nil {
		panic(err)
	}
}

func (bdb *BoltDB) SetSync(key, value []byte) {
	bdb.Set(key, value)
}

func (bdb *BoltDB) Delete(key []byte) {
	key = nonEmptyKey(nonNilBytes(key))
	err := bdb.db.Update(func(tx *bbolt.Tx) error {
		return tx.Bucket(bucket).Delete(key)
	})
	if err != nil {
		panic(err)
	}
}

func (bdb *BoltDB) DeleteSync(key []byte) {
	bdb.Delete(key)
}

func (bdb *BoltDB) Close() {
	bdb.db.Close()
}

func (bdb *BoltDB) Print() {
	stats := bdb.db.Stats()
	fmt.Printf("%v\n", stats)

	err := bdb.db.View(func(tx *bbolt.Tx) error {
		tx.Bucket(bucket).ForEach(func(k, v []byte) error {
			fmt.Printf("[%X]:\t[%X]\n", k, v)
			return nil
		})
		return nil
	})
	if err != nil {
		panic(err)
	}
}

func (bdb *BoltDB) Stats() map[string]string {
	stats := bdb.db.Stats()
	m := make(map[string]string)

	// Freelist stats
	m["FreePageN"] = fmt.Sprintf("%v", stats.FreePageN)
	m["PendingPageN"] = fmt.Sprintf("%v", stats.PendingPageN)
	m["FreeAlloc"] = fmt.Sprintf("%v", stats.FreeAlloc)
	m["FreelistInuse"] = fmt.Sprintf("%v", stats.FreelistInuse)

	// Transaction stats
	m["TxN"] = fmt.Sprintf("%v", stats.TxN)
	m["OpenTxN"] = fmt.Sprintf("%v", stats.OpenTxN)

	return m
}

// boltDBBatch stores key values in sync.Map and dumps them to the underlying
// DB upon Write call.
type boltDBBatch struct {
	buffer *sync.Map
	db     *BoltDB
}

// NewBatch returns a new batch.
func (bdb *BoltDB) NewBatch() Batch {
	return &boltDBBatch{
		buffer: &sync.Map{},
		db:     bdb,
	}
}

func (bdb *boltDBBatch) Set(key, value []byte) {
	bdb.buffer.Store(key, value)
}

func (bdb *boltDBBatch) Delete(key []byte) {
	bdb.buffer.Delete(key)
}

// NOTE: the operation is synchronous (see BoltDB for reasons)
func (bdb *boltDBBatch) Write() {
	err := bdb.db.db.Batch(func(tx *bbolt.Tx) error {
		b := tx.Bucket(bucket)
		var putErr error
		bdb.buffer.Range(func(key, value interface{}) bool {
			putErr = b.Put(key.([]byte), value.([]byte))
			return putErr == nil // stop if putErr is not nil
		})
		return putErr
	})
	if err != nil {
		panic(err)
	}
}

func (bdb *boltDBBatch) WriteSync() {
	bdb.Write()
}

func (bdb *boltDBBatch) Close() {}

// WARNING: Any concurrent writes or reads will block until the iterator is
// closed.
func (bdb *BoltDB) Iterator(start, end []byte) Iterator {
	tx, err := bdb.db.Begin(false)
	if err != nil {
		panic(err)
	}
	return newBoltDBIterator(tx, start, end, false)
}

// WARNING: Any concurrent writes or reads will block until the iterator is
// closed.
func (bdb *BoltDB) ReverseIterator(start, end []byte) Iterator {
	tx, err := bdb.db.Begin(false)
	if err != nil {
		panic(err)
	}
	return newBoltDBIterator(tx, start, end, true)
}

// boltDBIterator allows you to iterate on range of keys/values given some
// start / end keys (nil & nil will result in doing full scan).
type boltDBIterator struct {
	tx *bbolt.Tx

	itr   *bbolt.Cursor
	start []byte
	end   []byte

	currentKey   []byte
	currentValue []byte

	isInvalid bool
	isReverse bool
}

func newBoltDBIterator(tx *bbolt.Tx, start, end []byte, isReverse bool) *boltDBIterator {
	itr := tx.Bucket(bucket).Cursor()

	var ck, cv []byte
	if isReverse {
		if end == nil {
			ck, cv = itr.Last()
		} else {
			_, _ = itr.Seek(end) // after key
			ck, cv = itr.Prev()  // return to end key
		}
	} else {
		if start == nil {
			ck, cv = itr.First()
		} else {
			ck, cv = itr.Seek(start)
		}
	}

	return &boltDBIterator{
		tx:           tx,
		itr:          itr,
		start:        start,
		end:          end,
		currentKey:   ck,
		currentValue: cv,
		isReverse:    isReverse,
		isInvalid:    false,
	}
}

func (itr *boltDBIterator) Domain() ([]byte, []byte) {
	return itr.start, itr.end
}

func (itr *boltDBIterator) Valid() bool {
	if itr.isInvalid {
		return false
	}

	// iterated to the end of the cursor
	if len(itr.currentKey) == 0 {
		itr.isInvalid = true
		return false
	}

	if itr.isReverse {
		if itr.start != nil && bytes.Compare(itr.currentKey, itr.start) < 0 {
			itr.isInvalid = true
			return false
		}
	} else {
		if itr.end != nil && bytes.Compare(itr.end, itr.currentKey) <= 0 {
			itr.isInvalid = true
			return false
		}
	}

	// Valid
	return true
}

func (itr *boltDBIterator) Next() {
	itr.assertIsValid()
	if itr.isReverse {
		itr.currentKey, itr.currentValue = itr.itr.Prev()
	} else {
		itr.currentKey, itr.currentValue = itr.itr.Next()
	}
}

func (itr *boltDBIterator) Key() []byte {
	itr.assertIsValid()
	return itr.currentKey
}

func (itr *boltDBIterator) Value() []byte {
	itr.assertIsValid()
	return itr.currentValue
}

func (itr *boltDBIterator) Close() {
	err := itr.tx.Rollback()
	if err != nil {
		panic(err)
	}
}

func (itr *boltDBIterator) assertIsValid() {
	if !itr.Valid() {
		panic("Boltdb-iterator is invalid")
	}
}

// nonEmptyKey returns a []byte("nil") if key is empty.
// WARNING: this may collude with "nil" user key!
func nonEmptyKey(key []byte) []byte {
	if len(key) == 0 {
		return []byte("nil")
	}
	return key
}
<|endoftext|>


<commit_before>package web

import (
	"fmt"
	"net/http"

	"github.com/cozy/cozy-stack/pkg/workers/mails"
	"github.com/cozy/cozy-stack/web/statik"
	"github.com/cozy/echo"
)

// devMailHandler allow to easily render a mail from a route of the stack. The
// query parameters are used as data input for the mail template. The
// ContentType query parameter allow to render the mail in "text/html" or
// "text/plain".
func devMailsHandler(c echo.Context) error {
	name := c.Param("name")
	locale := c.QueryParam("locale")
	if locale == "" {
		locale = statik.GetLanguageFromHeader(c.Request().Header)
	}

	recipientName := c.QueryParam("RecipientName")
	if recipientName == "" {
		recipientName = "Jean Dupont"
	}

	_, parts, err := mails.RenderMail(name, locale, recipientName, devData(c))
	if err != nil {
		return err
	}

	contentType := c.QueryParam("ContentType")
	if contentType == "" {
		contentType = "text/html"
	}

	var part *mails.Part
	for _, p := range parts {
		if p.Type == contentType {
			part = p
		}
	}
	if part == nil {
		return echo.NewHTTPError(http.StatusNotFound,
			fmt.Errorf("Could not find template %q with content-type %q", name, contentType))
	}

	// Remove all CSP policies to display HTML email. this is a dev-only
	// handler, no need to worry.
	c.Response().Header().Set(echo.HeaderContentSecurityPolicy, "")
	if part.Type == "text/html" {
		return c.HTML(http.StatusOK, part.Body)
	}
	return c.String(http.StatusOK, part.Body)
}

// devTemplatesHandler allow to easily render a given template from a route of
// the stack. The query parameters are used as data input for the template.
func devTemplatesHandler(c echo.Context) error {
	name := c.Param("name")
	return c.Render(http.StatusOK, name, devData(c))
}

func devData(c echo.Context) echo.Map {
	data := make(echo.Map)
	for k, v := range c.QueryParams() {
		if len(v) > 0 {
			data[k] = v[0]
		}
	}
	if _, ok := data["Domain"]; !ok {
		data["Domain"] = c.Request().Host
	}
	return data
}
<commit_msg>Fix default context for /dev/templates/:template (#1789)<commit_after>package web

import (
	"fmt"
	"net/http"

	"github.com/cozy/cozy-stack/pkg/config"
	"github.com/cozy/cozy-stack/pkg/workers/mails"
	"github.com/cozy/cozy-stack/web/statik"
	"github.com/cozy/echo"
)

// devMailHandler allow to easily render a mail from a route of the stack. The
// query parameters are used as data input for the mail template. The
// ContentType query parameter allow to render the mail in "text/html" or
// "text/plain".
func devMailsHandler(c echo.Context) error {
	name := c.Param("name")
	locale := c.QueryParam("locale")
	if locale == "" {
		locale = statik.GetLanguageFromHeader(c.Request().Header)
	}

	recipientName := c.QueryParam("RecipientName")
	if recipientName == "" {
		recipientName = "Jean Dupont"
	}

	_, parts, err := mails.RenderMail(name, locale, recipientName, devData(c))
	if err != nil {
		return err
	}

	contentType := c.QueryParam("ContentType")
	if contentType == "" {
		contentType = "text/html"
	}

	var part *mails.Part
	for _, p := range parts {
		if p.Type == contentType {
			part = p
		}
	}
	if part == nil {
		return echo.NewHTTPError(http.StatusNotFound,
			fmt.Errorf("Could not find template %q with content-type %q", name, contentType))
	}

	// Remove all CSP policies to display HTML email. this is a dev-only
	// handler, no need to worry.
	c.Response().Header().Set(echo.HeaderContentSecurityPolicy, "")
	if part.Type == "text/html" {
		return c.HTML(http.StatusOK, part.Body)
	}
	return c.String(http.StatusOK, part.Body)
}

// devTemplatesHandler allow to easily render a given template from a route of
// the stack. The query parameters are used as data input for the template.
func devTemplatesHandler(c echo.Context) error {
	name := c.Param("name")
	return c.Render(http.StatusOK, name, devData(c))
}

func devData(c echo.Context) echo.Map {
	data := make(echo.Map)
	for k, v := range c.QueryParams() {
		if len(v) > 0 {
			data[k] = v[0]
		}
	}
	if _, ok := data["Domain"]; !ok {
		data["Domain"] = c.Request().Host
	}
	if _, ok := data["ContextName"]; !ok {
		data["ContextName"] = config.DefaultInstanceContext
	}
	return data
}
<|endoftext|>


<commit_before>package pq_types

import (
	"bytes"
	"database/sql"
	"database/sql/driver"
	"encoding/binary"
	"encoding/hex"
	"fmt"
	"strings"
)

// PostGISPoint is wrapper for PostGIS POINT type.
type PostGISPoint struct {
	Lon, Lat float64
}

// Value implements database/sql/driver Valuer interface.
// It returns point as WKT with SRID 4326 (WGS 84).
func (p PostGISPoint) Value() (driver.Value, error) {
	return []byte(fmt.Sprintf("SRID=4326;POINT(%.7f %.7f)", p.Lon, p.Lat)), nil
}

type ewkbPoint struct {
	ByteOrder byte   // 1 (LittleEndian)
	WkbType   uint32 // 0x20000001 (PointS)
	SRID      uint32 // 4326
	Point     PostGISPoint
}

// Scan implements database/sql Scanner interface.
// It expectes EWKB with SRID 4326 (WGS 84).
func (p *PostGISPoint) Scan(value interface{}) error {
	if value == nil {
		*p = PostGISPoint{}
		return nil
	}

	v, ok := value.([]byte)
	if !ok {
		return fmt.Errorf("pq_types: expected []byte, got %T (%v)", value, value)
	}

	ewkb := make([]byte, hex.DecodedLen(len(v)))
	n, err := hex.Decode(ewkb, v)
	if err != nil {
		return err
	}

	var ewkbP ewkbPoint
	err = binary.Read(bytes.NewReader(ewkb[:n]), binary.LittleEndian, &ewkbP)
	if err != nil {
		return err
	}

	if ewkbP.ByteOrder != 1 || ewkbP.WkbType != 0x20000001 || ewkbP.SRID != 4326 {
		return fmt.Errorf("pq_types: unexpected ewkb %#v", ewkbP)
	}
	*p = ewkbP.Point
	return nil
}

// check interfaces
var (
	_ driver.Valuer = PostGISPoint{}
	_ sql.Scanner   = &PostGISPoint{}
)

// PostGISBox2D is wrapper for PostGIS Box2D type.
type PostGISBox2D struct {
	Min, Max PostGISPoint
}

// Value implements database/sql/driver Valuer interface.
func (b PostGISBox2D) Value() (driver.Value, error) {
	return []byte(fmt.Sprintf("BOX(%.7f %.7f,%.7f %.7f)", b.Min.Lon, b.Min.Lat, b.Max.Lon, b.Max.Lat)), nil
}

// Scan implements database/sql Scanner interface.
func (b *PostGISBox2D) Scan(value interface{}) error {
	if value == nil {
		*b = PostGISBox2D{}
		return nil
	}

	v, ok := value.([]byte)
	if !ok {
		return fmt.Errorf("pq_types: expected []byte, got %T (%v)", value, value)
	}

	n, err := fmt.Sscanf(string(v), "BOX(%f %f,%f %f)", &b.Min.Lon, &b.Min.Lat, &b.Max.Lon, &b.Max.Lat)
	if err != nil {
		return err
	}
	if n != 4 {
		return fmt.Errorf("not enough params in the string: %v, %v != 4", v, n)
	}

	return nil
}

// check interfaces
var (
	_ driver.Valuer = PostGISBox2D{}
	_ sql.Scanner   = &PostGISBox2D{}
)

// Polygon type compatible with PostGIS POLYGON type
// PostGISBox2D is wrapper for PostGIS Box2D type.
type PostGISPolygon struct {
	Points []PostGISPoint
}

// MakeEnvelope returns rectangular (min, max) polygon
func MakeEnvelope(min, max PostGISPoint) PostGISPolygon {
	return PostGISPolygon{
		Points: []PostGISPoint{min, {Lon: min.Lon, Lat: max.Lat}, max, {Lon: max.Lon, Lat: min.Lat}, min},
	}
}

// Min returns min side of rectangular polygon
func (p *PostGISPolygon) Min() PostGISPoint {
	if len(p.Points) != 5 || p.Points[0] != p.Points[4] ||
		p.Points[0].Lon != p.Points[1].Lon || p.Points[0].Lat != p.Points[3].Lat ||
		p.Points[1].Lat != p.Points[2].Lat || p.Points[2].Lon != p.Points[3].Lon {
		panic("Not an envelope polygon")
	}

	return p.Points[0]
}

// Max returns max side of rectangular polygon
func (p *PostGISPolygon) Max() PostGISPoint {
	if len(p.Points) != 5 || p.Points[0] != p.Points[4] ||
		p.Points[0].Lon != p.Points[1].Lon || p.Points[0].Lat != p.Points[3].Lat ||
		p.Points[1].Lat != p.Points[2].Lat || p.Points[2].Lon != p.Points[3].Lon {
		panic("Not an envelope polygon")
	}

	return p.Points[2]
}

// Value implements database/sql/driver Valuer interface.
func (p PostGISPolygon) Value() (driver.Value, error) {
	parts := make([]string, len(p.Points))
	for i, pt := range p.Points {
		parts[i] = fmt.Sprintf("%.7f %.7f", pt.Lon, pt.Lat)
	}
	return []byte(fmt.Sprintf("SRID=4326;POLYGON((%s))", strings.Join(parts, ","))), nil
}

type ewkbPolygon struct {
	ByteOrder byte   // 1 (LittleEndian)
	WkbType   uint32 // 0x20000003 (PolygonS)
	SRID      uint32 // 4326
	Rings     uint32
	Count     uint32
}

// Scan implements database/sql Scanner interface.
func (p *PostGISPolygon) Scan(value interface{}) error {
	if value == nil {
		*p = PostGISPolygon{}
		return nil
	}

	v, ok := value.([]byte)
	if !ok {
		return fmt.Errorf("pq_types: expected []byte, got %T (%v)", value, value)
	}

	ewkb := make([]byte, hex.DecodedLen(len(v)))
	_, err := hex.Decode(ewkb, v)
	if err != nil {
		return err
	}

	r := bytes.NewReader(ewkb)

	var ewkbP ewkbPolygon
	err = binary.Read(r, binary.LittleEndian, &ewkbP)
	if err != nil {
		return err
	}

	if ewkbP.ByteOrder != 1 || ewkbP.WkbType != 0x20000003 || ewkbP.SRID != 4326 || ewkbP.Rings != 1 {
		return fmt.Errorf("pq_types: unexpected ewkb %#v", ewkbP)
	}
	p.Points = make([]PostGISPoint, ewkbP.Count)

	err = binary.Read(r, binary.LittleEndian, p.Points)
	if err != nil {
		return err
	}

	return nil
}

// check interfaces
var (
	_ driver.Valuer = PostGISPolygon{}
	_ sql.Scanner   = &PostGISPolygon{}
)
<commit_msg>Add comments.<commit_after>package pq_types

import (
	"bytes"
	"database/sql"
	"database/sql/driver"
	"encoding/binary"
	"encoding/hex"
	"fmt"
	"strings"
)

// PostGISPoint is wrapper for PostGIS POINT type.
type PostGISPoint struct {
	Lon, Lat float64
}

// Value implements database/sql/driver Valuer interface.
// It returns point as WKT with SRID 4326 (WGS 84).
func (p PostGISPoint) Value() (driver.Value, error) {
	return []byte(fmt.Sprintf("SRID=4326;POINT(%.7f %.7f)", p.Lon, p.Lat)), nil
}

type ewkbPoint struct {
	ByteOrder byte   // 1 (LittleEndian)
	WkbType   uint32 // 0x20000001 (PointS)
	SRID      uint32 // 4326
	Point     PostGISPoint
}

// Scan implements database/sql Scanner interface.
// It expectes EWKB with SRID 4326 (WGS 84).
func (p *PostGISPoint) Scan(value interface{}) error {
	if value == nil {
		*p = PostGISPoint{}
		return nil
	}

	v, ok := value.([]byte)
	if !ok {
		return fmt.Errorf("pq_types: expected []byte, got %T (%v)", value, value)
	}

	ewkb := make([]byte, hex.DecodedLen(len(v)))
	n, err := hex.Decode(ewkb, v)
	if err != nil {
		return err
	}

	var ewkbP ewkbPoint
	err = binary.Read(bytes.NewReader(ewkb[:n]), binary.LittleEndian, &ewkbP)
	if err != nil {
		return err
	}

	if ewkbP.ByteOrder != 1 || ewkbP.WkbType != 0x20000001 || ewkbP.SRID != 4326 {
		return fmt.Errorf("pq_types: unexpected ewkb %#v", ewkbP)
	}
	*p = ewkbP.Point
	return nil
}

// check interfaces
var (
	_ driver.Valuer = PostGISPoint{}
	_ sql.Scanner   = &PostGISPoint{}
)

// PostGISBox2D is wrapper for PostGIS Box2D type.
type PostGISBox2D struct {
	Min, Max PostGISPoint
}

// Value implements database/sql/driver Valuer interface.
// It returns box as WKT.
func (b PostGISBox2D) Value() (driver.Value, error) {
	return []byte(fmt.Sprintf("BOX(%.7f %.7f,%.7f %.7f)", b.Min.Lon, b.Min.Lat, b.Max.Lon, b.Max.Lat)), nil
}

// Scan implements database/sql Scanner interface.
// It expectes WKT.
func (b *PostGISBox2D) Scan(value interface{}) error {
	if value == nil {
		*b = PostGISBox2D{}
		return nil
	}

	v, ok := value.([]byte)
	if !ok {
		return fmt.Errorf("pq_types: expected []byte, got %T (%v)", value, value)
	}

	n, err := fmt.Sscanf(string(v), "BOX(%f %f,%f %f)", &b.Min.Lon, &b.Min.Lat, &b.Max.Lon, &b.Max.Lat)
	if err != nil {
		return err
	}
	if n != 4 {
		return fmt.Errorf("not enough params in the string: %v, %v != 4", v, n)
	}

	return nil
}

// check interfaces
var (
	_ driver.Valuer = PostGISBox2D{}
	_ sql.Scanner   = &PostGISBox2D{}
)

// PostGISPolygon is wrapper for PostGIS Polygon type.
type PostGISPolygon struct {
	Points []PostGISPoint
}

// MakeEnvelope returns rectangular (min, max) polygon
func MakeEnvelope(min, max PostGISPoint) PostGISPolygon {
	return PostGISPolygon{
		Points: []PostGISPoint{min, {Lon: min.Lon, Lat: max.Lat}, max, {Lon: max.Lon, Lat: min.Lat}, min},
	}
}

// Min returns min side of rectangular polygon
func (p *PostGISPolygon) Min() PostGISPoint {
	if len(p.Points) != 5 || p.Points[0] != p.Points[4] ||
		p.Points[0].Lon != p.Points[1].Lon || p.Points[0].Lat != p.Points[3].Lat ||
		p.Points[1].Lat != p.Points[2].Lat || p.Points[2].Lon != p.Points[3].Lon {
		panic("Not an envelope polygon")
	}

	return p.Points[0]
}

// Max returns max side of rectangular polygon
func (p *PostGISPolygon) Max() PostGISPoint {
	if len(p.Points) != 5 || p.Points[0] != p.Points[4] ||
		p.Points[0].Lon != p.Points[1].Lon || p.Points[0].Lat != p.Points[3].Lat ||
		p.Points[1].Lat != p.Points[2].Lat || p.Points[2].Lon != p.Points[3].Lon {
		panic("Not an envelope polygon")
	}

	return p.Points[2]
}

// Value implements database/sql/driver Valuer interface.
// It returns polygon as WKT with SRID 4326 (WGS 84).
func (p PostGISPolygon) Value() (driver.Value, error) {
	parts := make([]string, len(p.Points))
	for i, pt := range p.Points {
		parts[i] = fmt.Sprintf("%.7f %.7f", pt.Lon, pt.Lat)
	}
	return []byte(fmt.Sprintf("SRID=4326;POLYGON((%s))", strings.Join(parts, ","))), nil
}

type ewkbPolygon struct {
	ByteOrder byte   // 1 (LittleEndian)
	WkbType   uint32 // 0x20000003 (PolygonS)
	SRID      uint32 // 4326
	Rings     uint32
	Count     uint32
}

// Scan implements database/sql Scanner interface.
// It expectes EWKB with SRID 4326 (WGS 84).
func (p *PostGISPolygon) Scan(value interface{}) error {
	if value == nil {
		*p = PostGISPolygon{}
		return nil
	}

	v, ok := value.([]byte)
	if !ok {
		return fmt.Errorf("pq_types: expected []byte, got %T (%v)", value, value)
	}

	ewkb := make([]byte, hex.DecodedLen(len(v)))
	_, err := hex.Decode(ewkb, v)
	if err != nil {
		return err
	}

	r := bytes.NewReader(ewkb)

	var ewkbP ewkbPolygon
	err = binary.Read(r, binary.LittleEndian, &ewkbP)
	if err != nil {
		return err
	}

	if ewkbP.ByteOrder != 1 || ewkbP.WkbType != 0x20000003 || ewkbP.SRID != 4326 || ewkbP.Rings != 1 {
		return fmt.Errorf("pq_types: unexpected ewkb %#v", ewkbP)
	}
	p.Points = make([]PostGISPoint, ewkbP.Count)

	err = binary.Read(r, binary.LittleEndian, p.Points)
	if err != nil {
		return err
	}

	return nil
}

// check interfaces
var (
	_ driver.Valuer = PostGISPolygon{}
	_ sql.Scanner   = &PostGISPolygon{}
)
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"

	"github.com/coopernurse/gorp"
	. "gopkg.in/check.v1"
)

func createTestDatabase() *gorp.DbMap {
	db, err := sql.Open("sqlite3", ":memory:")
	checkErr(err, "sql.Open failed")

	// construct a gorp DbMap
	dbmap := &gorp.DbMap{Db: db, Dialect: gorp.SqliteDialect{}}

	return dbmap
}

func Test(t *testing.T) { TestingT(t) }

type PRSuite struct {
	dbmap *gorp.DbMap
	app   Application
}

func (s *PRSuite) SetUpSuite(c *C) {
	s.dbmap = createTestDatabase()
}

func (s *PRSuite) SetUpTest(c *C) {
	err := s.dbmap.TruncateTables()
	if err != nil {
		c.Error(err)
	}
	s.app = CreateApplication(s.dbmap)
}

func (s *PRSuite) TearDownSuite(c *C) {
	s.dbmap.Db.Close()
}

func (s *PRSuite) PerformRequest(method string, relativePath string, body string) *httptest.ResponseRecorder {
	path := fmt.Sprintf("http://test.example.com%s", relativePath)
	w := httptest.NewRecorder()
	r, err := http.NewRequest(method, path, strings.NewReader(body))
	checkErr(err, "Request creation failed")

	s.app.handler.ServeHTTP(w, r)
	return w
}

type ElectionSuite struct {
	PRSuite
}

var _ = Suite(&ElectionSuite{})

func (s *ElectionSuite) TestAddElectionReturns201(c *C) {
	recorder := s.PerformRequest("POST", "/elections", `{"name": "Test Election"}`)

	c.Check(recorder.Code, Equals, 201)
}

func (s *ElectionSuite) TestAddElectionCreatesOneElection(c *C) {
	s.PerformRequest("POST", "/elections", `{"name": "Test Election"}`)

	count, err := s.dbmap.SelectInt("select count(*) from elections")
	checkErr(err, "Getting count failed")
	c.Assert(count, Equals, int64(1))
}

func (s *ElectionSuite) TestAddElectionCreatesElectionWithCorrectName(c *C) {
	s.PerformRequest("POST", "/elections", `{"name": "Test Election"}`)

	var createdElection Election
	err := s.dbmap.SelectOne(&createdElection, "select * from elections")
	if err != nil {
		c.Error(err)
	}
	c.Assert(createdElection.Name, Matches, "Test Election")
}

func (s *ElectionSuite) TestAddElectionRejectsZeroLengthName(c *C) {
	recorder := s.PerformRequest("POST", "/elections", `{"name": ""}`)

	c.Check(recorder.Code, Equals, 400)
	c.Check(recorder.Body.String(), Matches, "Empty name forbidden.\n?")

	count, err := s.dbmap.SelectInt("select count(*) from elections")
	checkErr(err, "Getting count failed")
	c.Check(count, Equals, int64(0))
}

func (s *ElectionSuite) TestAddElectionRejectsDuplicateNames(c *C) {
	s.PerformRequest("POST", "/elections", `{"name": "Duplicate"}`)
	recorder := s.PerformRequest("POST", "/elections", `{"name": "Duplicate"}`)

	c.Check(recorder.Code, Equals, 400)
	c.Check(recorder.Body.String(), Matches, "Name taken.\n?")

	count, err := s.dbmap.SelectInt("select count(*) from elections")
	checkErr(err, "Getting count failed")
	c.Check(count, Equals, int64(1))
}

func (s *ElectionSuite) TestGetElectionReturns200(c *C) {
	election := Election{Name: "my test name"}
	s.dbmap.Insert(&election)

	recorder := s.PerformRequest("GET", fmt.Sprintf("/elections/%d", election.Id), "")

	c.Check(recorder.Code, Equals, 200)
}

func (s *ElectionSuite) TestGetElectionReturnsElectionName(c *C) {
	election := Election{Name: "my test name"}
	s.dbmap.Insert(&election)

	recorder := s.PerformRequest("GET", fmt.Sprintf("/elections/%d", election.Id), "")
	returnedElection := Election{}
	json.Unmarshal(recorder.Body.Bytes(), &returnedElection)
	c.Assert(returnedElection.Name, Matches, "my test name")
}

func (s *ElectionSuite) TestGetElection404sForUnknownElection(c *C) {
	recorder := s.PerformRequest("GET", "/elections/1", "")

	c.Check(recorder.Code, Equals, 404)
}

func (s *ElectionSuite) TestListElectionsReturnsEmptyList(c *C) {
	recorder := s.PerformRequest("GET", "/elections", "")

	c.Check(recorder.Code, Equals, 200)
	c.Check(recorder.Body.String(), Equals, "[]")
}

func (s *ElectionSuite) TestListElectionsReturnsListOfCorrectLength(c *C) {
	election := Election{Name: "my test name"}
	other_election := Election{Name: "my other name"}
	third_election := Election{Name: "my third name"}
	s.dbmap.Insert(&election, &other_election, &third_election)

	recorder := s.PerformRequest("GET", "/elections", "")

	var electionList []Election
	json.Unmarshal(recorder.Body.Bytes(), &electionList)
	c.Check(len(electionList), Equals, 3)
}

func (s *ElectionSuite) TestListElectionReturnsExistingElections(c *C) {
	election := Election{Name: "my test name"}
	other_election := Election{Name: "my other name"}
	s.dbmap.Insert(&election, &other_election)

	recorder := s.PerformRequest("GET", "/elections", "")

	expectedElectionNames := map[string]int{
		"my test name":  0,
		"my other name": 0,
	}
	var electionList []Election
	json.Unmarshal(recorder.Body.Bytes(), &electionList)
	actualElectionNames := make(map[string]int)
	for _, election := range electionList {
		actualElectionNames[election.Name] = 0
	}
	c.Check(actualElectionNames, DeepEquals, expectedElectionNames)
}

type CandidatesSuite struct {
	PRSuite
}

var _ = Suite(&CandidatesSuite{})

func (s *CandidatesSuite) TestAddCandidateReturns404ForMissingElection(c *C) {
	recorder := s.PerformRequest("POST", "/elections/1/candidates", `{"name": "Test Candidate"}`)

	c.Check(recorder.Code, Equals, 404)
}

func (s *CandidatesSuite) TestAddCandidateReturns201(c *C) {
	election := Election{Name: "my test name"}
	err := s.dbmap.Insert(&election)
	if err != nil {
		c.Error(err)
	}

	recorder := s.PerformRequest("POST", "/elections/1/candidates", `{"name": "Test Candidate"}`)

	c.Check(recorder.Code, Equals, 201)
}
<commit_msg>Start sharing tests between suites.<commit_after>package main

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"

	"github.com/coopernurse/gorp"
	. "gopkg.in/check.v1"
)

func createTestDatabase() *gorp.DbMap {
	db, err := sql.Open("sqlite3", ":memory:")
	checkErr(err, "sql.Open failed")

	// construct a gorp DbMap
	dbmap := &gorp.DbMap{Db: db, Dialect: gorp.SqliteDialect{}}

	return dbmap
}

func Test(t *testing.T) { TestingT(t) }

type PRSuite struct {
	dbmap     *gorp.DbMap
	app       Application
	createURL string
}

func (s *PRSuite) SetUpSuite(c *C) {
	s.dbmap = createTestDatabase()
	s.app = CreateApplication(s.dbmap)
}

func (s *PRSuite) SetUpTest(c *C) {
	err := s.dbmap.TruncateTables()
	if err != nil {
		c.Error(err)
	}
}

func (s *PRSuite) TearDownSuite(c *C) {
	s.dbmap.Db.Close()
}

func (s *PRSuite) PerformRequest(method string, relativePath string, body string) *httptest.ResponseRecorder {
	path := fmt.Sprintf("http://test.example.com%s", relativePath)
	w := httptest.NewRecorder()
	r, err := http.NewRequest(method, path, strings.NewReader(body))
	checkErr(err, "Request creation failed")

	s.app.handler.ServeHTTP(w, r)
	return w
}

func (s *PRSuite) TestAddReturns201(c *C) {
	recorder := s.PerformRequest("POST", s.createURL, `{"name": "Test Name"}`)

	c.Check(recorder.Code, Equals, 201)
}

type ElectionSuite struct {
	PRSuite
}

func (s *ElectionSuite) SetUpSuite(c *C) {
	s.PRSuite.SetUpSuite(c)
	s.createURL = "/elections"
}

var _ = Suite(&ElectionSuite{})

func (s *ElectionSuite) TestAddElectionCreatesOneElection(c *C) {
	s.PerformRequest("POST", "/elections", `{"name": "Test Election"}`)

	count, err := s.dbmap.SelectInt("select count(*) from elections")
	checkErr(err, "Getting count failed")
	c.Assert(count, Equals, int64(1))
}

func (s *ElectionSuite) TestAddElectionCreatesElectionWithCorrectName(c *C) {
	s.PerformRequest("POST", "/elections", `{"name": "Test Election"}`)

	var createdElection Election
	err := s.dbmap.SelectOne(&createdElection, "select * from elections")
	if err != nil {
		c.Error(err)
	}
	c.Assert(createdElection.Name, Matches, "Test Election")
}

func (s *ElectionSuite) TestAddElectionRejectsZeroLengthName(c *C) {
	recorder := s.PerformRequest("POST", "/elections", `{"name": ""}`)

	c.Check(recorder.Code, Equals, 400)
	c.Check(recorder.Body.String(), Matches, "Empty name forbidden.\n?")

	count, err := s.dbmap.SelectInt("select count(*) from elections")
	checkErr(err, "Getting count failed")
	c.Check(count, Equals, int64(0))
}

func (s *ElectionSuite) TestAddElectionRejectsDuplicateNames(c *C) {
	s.PerformRequest("POST", "/elections", `{"name": "Duplicate"}`)
	recorder := s.PerformRequest("POST", "/elections", `{"name": "Duplicate"}`)

	c.Check(recorder.Code, Equals, 400)
	c.Check(recorder.Body.String(), Matches, "Name taken.\n?")

	count, err := s.dbmap.SelectInt("select count(*) from elections")
	checkErr(err, "Getting count failed")
	c.Check(count, Equals, int64(1))
}

func (s *ElectionSuite) TestGetElectionReturns200(c *C) {
	election := Election{Name: "my test name"}
	s.dbmap.Insert(&election)

	recorder := s.PerformRequest("GET", fmt.Sprintf("/elections/%d", election.Id), "")

	c.Check(recorder.Code, Equals, 200)
}

func (s *ElectionSuite) TestGetElectionReturnsElectionName(c *C) {
	election := Election{Name: "my test name"}
	s.dbmap.Insert(&election)

	recorder := s.PerformRequest("GET", fmt.Sprintf("/elections/%d", election.Id), "")
	returnedElection := Election{}
	json.Unmarshal(recorder.Body.Bytes(), &returnedElection)
	c.Assert(returnedElection.Name, Matches, "my test name")
}

func (s *ElectionSuite) TestGetElection404sForUnknownElection(c *C) {
	recorder := s.PerformRequest("GET", "/elections/1", "")

	c.Check(recorder.Code, Equals, 404)
}

func (s *ElectionSuite) TestListElectionsReturnsEmptyList(c *C) {
	recorder := s.PerformRequest("GET", "/elections", "")

	c.Check(recorder.Code, Equals, 200)
	c.Check(recorder.Body.String(), Equals, "[]")
}

func (s *ElectionSuite) TestListElectionsReturnsListOfCorrectLength(c *C) {
	election := Election{Name: "my test name"}
	other_election := Election{Name: "my other name"}
	third_election := Election{Name: "my third name"}
	s.dbmap.Insert(&election, &other_election, &third_election)

	recorder := s.PerformRequest("GET", "/elections", "")

	var electionList []Election
	json.Unmarshal(recorder.Body.Bytes(), &electionList)
	c.Check(len(electionList), Equals, 3)
}

func (s *ElectionSuite) TestListElectionReturnsExistingElections(c *C) {
	election := Election{Name: "my test name"}
	other_election := Election{Name: "my other name"}
	s.dbmap.Insert(&election, &other_election)

	recorder := s.PerformRequest("GET", "/elections", "")

	expectedElectionNames := map[string]int{
		"my test name":  0,
		"my other name": 0,
	}
	var electionList []Election
	json.Unmarshal(recorder.Body.Bytes(), &electionList)
	actualElectionNames := make(map[string]int)
	for _, election := range electionList {
		actualElectionNames[election.Name] = 0
	}
	c.Check(actualElectionNames, DeepEquals, expectedElectionNames)
}

type CandidatesSuite struct {
	PRSuite
}

func (s *CandidatesSuite) SetUpTest(c *C) {
	s.PRSuite.SetUpTest(c)

	// Set up test election
	election := Election{Name: "my test name"}
	err := s.dbmap.Insert(&election)
	if err != nil {
		c.Error(err)
	}

	s.createURL = fmt.Sprintf("/elections/%d/candidates", election.Id)
}

var _ = Suite(&CandidatesSuite{})

func (s *CandidatesSuite) TestAddCandidateReturns404ForMissingElection(c *C) {
	recorder := s.PerformRequest("POST", "/elections/1234/candidates", `{"name": "Test Candidate"}`)

	c.Check(recorder.Code, Equals, 404)
}
<|endoftext|>


<commit_before>package cli_test

import (
	"strings"

	. "github.com/jwaldrip/odin/cli"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("CLI Integration Test", func() {

	var cli *CLI
	var cmd Command
	var didRun bool

	BeforeEach(func() {
		didRun = false
		runFn := func(c Command) {
			cmd = c
			didRun = true
		}
		cli = New("v1.0.0", "sample description", runFn)
		cli.ErrorHandling = PanicOnError
		cli.Mute()
	})

	Describe("complex cli", func() {

		var subDidRun bool
		var subCmd *SubCommand

		BeforeEach(func() {
			cli.DefineParams("host", "path")
			cli.DefineBoolFlag("ssl", false, "do it over ssl")
			cli.AliasFlag('S', "ssl")
			cli.AliasFlag('s', "ssl")
			cli.DefineStringFlag("username", "", "the username")
			cli.AliasFlag('u', "username")
			cli.DefineStringFlag("password", "", "the password")
			cli.AliasFlag('p', "password")
			cli.DefineIntFlag("port", 80, "the port")
			cli.AliasFlag('P', "port")
			cli.DefineBoolFlag("keepopen", false, "keep the connection open")
			subCmd = cli.DefineSubCommand("do", "what action to do", func(c Command) { cmd = c; subDidRun = true }, "action")
		})

		It("should parse the main command properly", func() {
			cli.Start(strings.Split("cmd -Su=wally -p App1etw0 --port 3001 example.com /", " ")...)
			Expect(cmd.Param("host").Get()).To(Equal("example.com"))
			Expect(cmd.Param("path").Get()).To(Equal("/"))
			Expect(cmd.Flag("port").Get()).To(Equal(3001))
			Expect(cmd.Flag("username").Get()).To(Equal("wally"))
			Expect(cmd.Flag("password").Get()).To(Equal("App1etw0"))
			Expect(cmd.Flag("ssl").Get()).To(Equal(true))
			Expect(didRun).To(Equal(true))
		})

		It("should parse the sub command properly", func() {
			subCmd.DefineBoolFlag("power", false, "with power")
			cli.Start(strings.Split("cmd -Su=wally -p App1etw0 --port 3001 example.com / do --power something", " ")...)
			Expect(cmd.Parent().Param("host").Get()).To(Equal("example.com"))
			Expect(cmd.Parent().Param("path").Get()).To(Equal("/"))
			Expect(cmd.Parent().Flag("port").Get()).To(Equal(3001))
			Expect(cmd.Parent().Flag("username").Get()).To(Equal("wally"))
			Expect(cmd.Parent().Flag("password").Get()).To(Equal("App1etw0"))
			Expect(cmd.Parent().Flag("ssl").Get()).To(Equal(true))
			Expect(cmd.Flag("power").Get()).To(Equal(true))
			Expect(cmd.Param("action").Get()).To(Equal("something"))
			Expect(subDidRun).To(Equal(true))
		})

		Describe("version", func() {
			It("should not panic", func() {
				cli.Start("cmd", "--version")
			})
		})

		Describe("help", func() {
			It("should not panic", func() {
				cli.Start(strings.Split("cmd --help", " ")...)
				cli.Start(strings.Split("cmd host path do --help", " ")...)
			})
		})

		It("should parse flags that occur after positional params and without sub-command", func() {
			cli.Start(strings.Split("cmd example.com / --ssl", " ")...)
			Expect(cmd.Param("host").Get()).To(Equal("example.com"))
			Expect(cmd.Param("path").Get()).To(Equal("/"))
			Expect(cmd.Flag("ssl").Get()).To(Equal(true))
			Expect(cmd.Args()).To(BeZero())
			Expect(didRun).To(Equal(true))
		})

		It("should parse flags that occur after positional params and with sub-command", func() {
			subCmd.DefineBoolFlag("power", false, "with power")
			cli.Start(strings.Split("cmd example.com / do something --power", " ")...)
			Expect(cmd.Parent().Param("host").Get()).To(Equal("example.com"))
			Expect(cmd.Parent().Param("path").Get()).To(Equal("/"))
			Expect(cmd.Flag("power").Get()).To(Equal(true))
			Expect(cmd.Param("action").Get()).To(Equal("something"))
			Expect(cmd.Args()).To(BeZero())
			Expect(subDidRun).To(Equal(true))
		})

	})

})
<commit_msg>test that commands dont run on help and version<commit_after>package cli_test

import (
	"strings"

	. "github.com/jwaldrip/odin/cli"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("CLI Integration Test", func() {

	var cli *CLI
	var cmd Command
	var didRun bool

	BeforeEach(func() {
		didRun = false
		runFn := func(c Command) {
			cmd = c
			didRun = true
		}
		cli = New("v1.0.0", "sample description", runFn)
		cli.ErrorHandling = PanicOnError
		cli.Mute()
	})

	Describe("complex cli", func() {

		var subDidRun bool
		var subCmd *SubCommand

		BeforeEach(func() {
			subDidRun = false
			cli.DefineParams("host", "path")
			cli.DefineBoolFlag("ssl", false, "do it over ssl")
			cli.AliasFlag('S', "ssl")
			cli.AliasFlag('s', "ssl")
			cli.DefineStringFlag("username", "", "the username")
			cli.AliasFlag('u', "username")
			cli.DefineStringFlag("password", "", "the password")
			cli.AliasFlag('p', "password")
			cli.DefineIntFlag("port", 80, "the port")
			cli.AliasFlag('P', "port")
			cli.DefineBoolFlag("keepopen", false, "keep the connection open")
			subCmd = cli.DefineSubCommand("do", "what action to do", func(c Command) { cmd = c; subDidRun = true }, "action")
		})

		It("should parse the main command properly", func() {
			cli.Start(strings.Split("cmd -Su=wally -p App1etw0 --port 3001 example.com /", " ")...)
			Expect(cmd.Param("host").Get()).To(Equal("example.com"))
			Expect(cmd.Param("path").Get()).To(Equal("/"))
			Expect(cmd.Flag("port").Get()).To(Equal(3001))
			Expect(cmd.Flag("username").Get()).To(Equal("wally"))
			Expect(cmd.Flag("password").Get()).To(Equal("App1etw0"))
			Expect(cmd.Flag("ssl").Get()).To(Equal(true))
			Expect(didRun).To(Equal(true))
		})

		It("should parse the sub command properly", func() {
			subCmd.DefineBoolFlag("power", false, "with power")
			cli.Start(strings.Split("cmd -Su=wally -p App1etw0 --port 3001 example.com / do --power something", " ")...)
			Expect(cmd.Parent().Param("host").Get()).To(Equal("example.com"))
			Expect(cmd.Parent().Param("path").Get()).To(Equal("/"))
			Expect(cmd.Parent().Flag("port").Get()).To(Equal(3001))
			Expect(cmd.Parent().Flag("username").Get()).To(Equal("wally"))
			Expect(cmd.Parent().Flag("password").Get()).To(Equal("App1etw0"))
			Expect(cmd.Parent().Flag("ssl").Get()).To(Equal(true))
			Expect(cmd.Flag("power").Get()).To(Equal(true))
			Expect(cmd.Param("action").Get()).To(Equal("something"))
			Expect(subDidRun).To(Equal(true))
		})

		Describe("version", func() {
			It("should not run command or panic", func() {
				cli.Start("cmd", "--version")
				Expect(didRun).To(Equal(false))
			})
		})

		Describe("help", func() {
			It("should not run command or panic", func() {
				cli.Start(strings.Split("cmd --help", " ")...)
				Expect(didRun).To(Equal(false))
			})

			It("should not run sub-command or panic", func() {
				cli.Start(strings.Split("cmd host path do --help", " ")...)
				Expect(subDidRun).To(Equal(false))
			})
		})

		It("should parse flags that occur after positional params and without sub-command", func() {
			cli.Start(strings.Split("cmd example.com / --ssl", " ")...)
			Expect(cmd.Param("host").Get()).To(Equal("example.com"))
			Expect(cmd.Param("path").Get()).To(Equal("/"))
			Expect(cmd.Flag("ssl").Get()).To(Equal(true))
			Expect(cmd.Args()).To(BeZero())
			Expect(didRun).To(Equal(true))
		})

		It("should parse flags that occur after positional params and with sub-command", func() {
			subCmd.DefineBoolFlag("power", false, "with power")
			cli.Start(strings.Split("cmd example.com / do something --power", " ")...)
			Expect(cmd.Parent().Param("host").Get()).To(Equal("example.com"))
			Expect(cmd.Parent().Param("path").Get()).To(Equal("/"))
			Expect(cmd.Flag("power").Get()).To(Equal(true))
			Expect(cmd.Param("action").Get()).To(Equal("something"))
			Expect(cmd.Args()).To(BeZero())
			Expect(subDidRun).To(Equal(true))
		})

	})

})
<|endoftext|>


<commit_before>package suricata

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"math/rand"
	"net"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"testing"
	"time"

	"github.com/influxdata/telegraf/plugins/inputs"
	"github.com/influxdata/telegraf/testutil"
	"github.com/stretchr/testify/assert"
)

var ex2 = `{"timestamp":"2017-03-06T07:43:39.000397+0000","event_type":"stats","stats":{"capture":{"kernel_packets":905344474,"kernel_drops":78355440,"kernel_packets_delta":2376742,"kernel_drops_delta":82049}}}`
var ex3 = `{"timestamp":"2017-03-06T07:43:39.000397+0000","event_type":"stats","stats":{"threads": { "foo": { "capture":{"kernel_packets":905344474,"kernel_drops":78355440}}}}}`
var ex4 = `{"timestamp":"2017-03-06T07:43:39.000397+0000","event_type":"stats","stats":{"threads": { "W1#en..bar1": { "capture":{"kernel_packets":905344474,"kernel_drops":78355440}}}}}`
var brokenType1 = `{"timestamp":"2017-03-06T07:43:39.000397+0000","event_type":"stats","stats":{"threads": { "W1#en..bar1": { "capture":{"kernel_packets":905344474,"kernel_drops": true}}}}}`
var brokenType2 = `{"timestamp":"2017-03-06T07:43:39.000397+0000","event_type":"stats","stats":{"threads": { "W1#en..bar1": { "capture":{"kernel_packets":905344474,"kernel_drops": ["foo"]}}}}}`
var brokenType3 = `{"timestamp":"2017-03-06T07:43:39.000397+0000","event_type":"stats","stats":{"threads": { "W1#en..bar1": { "capture":{"kernel_packets":905344474,"kernel_drops":"none this time"}}}}}`
var brokenType4 = `{"timestamp":"2017-03-06T07:43:39.000397+0000","event_type":"stats","stats":{"threads": { "W1#en..bar1": { "capture":{"kernel_packets":905344474,"kernel_drops":null}}}}}`
var brokenType5 = `{"timestamp":"2017-03-06T07:43:39.000397+0000","event_type":"stats","stats":{"foo": null}}`
var brokenStruct1 = `{"timestamp":"2017-03-06T07:43:39.000397+0000","event_type":"stats","stats":{"threads": ["foo"]}}`
var brokenStruct2 = `{"timestamp":"2017-03-06T07:43:39.000397+0000","event_type":"stats"}`
var brokenStruct3 = `{"timestamp":"2017-03-06T07:43:39.000397+0000","event_type":"stats","stats": "foobar"}`
var brokenStruct4 = `{"timestamp":"2017-03-06T07:43:39.000397+0000","event_type":"stats","stats": null}`
var singleDotRegexp = regexp.MustCompilePOSIX(`[^.]\.[^.]`)

func TestSuricataLarge(t *testing.T) {
	dir, err := ioutil.TempDir("", "test")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(dir)
	tmpfn := filepath.Join(dir, fmt.Sprintf("t%d", rand.Int63()))

	s := Suricata{
		Source:    tmpfn,
		Delimiter: ".",
		Log: testutil.Logger{
			Name: "inputs.suricata",
		},
	}
	acc := testutil.Accumulator{}
	acc.SetDebug(true)
	assert.NoError(t, s.Start(&acc))

	data, err := ioutil.ReadFile("testdata/test1.json")
	if err != nil {
		t.Fatal(err)
	}

	c, err := net.Dial("unix", tmpfn)
	if err != nil {
		t.Fatal(err)
	}
	c.Write([]byte(data))
	c.Write([]byte("\n"))
	c.Close()

	acc.Wait(1)

	s.Stop()
}

func TestSuricata(t *testing.T) {
	dir, err := ioutil.TempDir("", "test")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(dir)
	tmpfn := filepath.Join(dir, fmt.Sprintf("t%d", rand.Int63()))

	s := Suricata{
		Source:    tmpfn,
		Delimiter: ".",
		Log: testutil.Logger{
			Name: "inputs.suricata",
		},
	}
	acc := testutil.Accumulator{}
	acc.SetDebug(true)
	assert.NoError(t, s.Start(&acc))

	c, err := net.Dial("unix", tmpfn)
	if err != nil {
		t.Fatalf("failed: %s", err.Error())
	}
	c.Write([]byte(ex2))
	c.Write([]byte("\n"))
	c.Close()

	acc.Wait(1)

	s.Stop()
	s = Suricata{
		Source:    tmpfn,
		Delimiter: ".",
		Log: testutil.Logger{
			Name: "inputs.suricata",
		},
	}

	acc.AssertContainsTaggedFields(t, "suricata",
		map[string]interface{}{
			"capture.kernel_packets":       float64(905344474),
			"capture.kernel_drops":         float64(78355440),
			"capture.kernel_packets_delta": float64(2376742),
			"capture.kernel_drops_delta":   float64(82049),
		},
		map[string]string{"thread": "total"})

	acc = testutil.Accumulator{}
	acc.SetDebug(true)
	assert.NoError(t, s.Start(&acc))

	c, err = net.Dial("unix", tmpfn)
	if err != nil {
		log.Println(err)
	}
	c.Write([]byte(""))
	c.Write([]byte("\n"))
	c.Write([]byte("foobard}\n"))
	c.Write([]byte(ex3))
	c.Write([]byte("\n"))
	c.Close()
	acc.Wait(1)

	s.Stop()

	acc.AssertContainsTaggedFields(t, "suricata",
		map[string]interface{}{
			"capture.kernel_packets": float64(905344474),
			"capture.kernel_drops":   float64(78355440),
		},
		map[string]string{"thread": "foo"})
}

func TestSuricataInvalid(t *testing.T) {
	dir, err := ioutil.TempDir("", "test")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(dir)
	tmpfn := filepath.Join(dir, fmt.Sprintf("t%d", rand.Int63()))

	s := Suricata{
		Source: tmpfn,
		Log: testutil.Logger{
			Name: "inputs.suricata",
		},
	}
	acc := testutil.Accumulator{}
	acc.SetDebug(true)

	assert.NoError(t, s.Start(&acc))

	c, err := net.Dial("unix", tmpfn)
	if err != nil {
		log.Println(err)
	}
	c.Write([]byte("sfjiowef"))
	c.Write([]byte("\n"))
	c.Close()

	acc.WaitError(1)
	s.Stop()
}

func splitAtSingleDot(in string) []string {
	res := singleDotRegexp.FindAllStringIndex(in, -1)
	if res == nil {
		return []string{in}
	}
	ret := make([]string, 0)
	startpos := 0
	for _, v := range res {
		ret = append(ret, in[startpos:v[0]+1])
		startpos = v[1] - 1
	}
	return append(ret, in[startpos:])
}

func TestSuricataSplitDots(t *testing.T) {
	dir, err := ioutil.TempDir("", "test")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(dir)
	tmpfn := filepath.Join(dir, fmt.Sprintf("t%d", rand.Int63()))

	out := splitAtSingleDot("foo")
	if len(out) != 1 {
		t.Fatalf("splitting 'foo' should yield one result")
	}
	if out[0] != "foo" {
		t.Fatalf("splitting 'foo' should yield one result, 'foo'")
	}

	s := Suricata{
		Source:    tmpfn,
		Delimiter: ".",
		Log: testutil.Logger{
			Name: "inputs.suricata",
		},
	}
	acc := testutil.Accumulator{}
	acc.SetDebug(true)

	assert.NoError(t, s.Start(&acc))

	c, err := net.Dial("unix", tmpfn)
	if err != nil {
		log.Println(err)
	}
	c.Write([]byte(ex4))
	c.Write([]byte("\n"))
	c.Close()

	acc.Wait(1)
	acc.AssertContainsTaggedFields(t, "suricata",
		map[string]interface{}{
			"capture.kernel_packets": float64(905344474),
			"capture.kernel_drops":   float64(78355440),
		},
		map[string]string{"thread": "W1#en..bar1"})

	s.Stop()
}

func TestSuricataInvalidPath(t *testing.T) {
	tmpfn := fmt.Sprintf("/t%d/X", rand.Int63())
	s := Suricata{
		Source: tmpfn,
		Log: testutil.Logger{
			Name: "inputs.suricata",
		},
	}

	acc := testutil.Accumulator{}
	acc.SetDebug(true)

	assert.Error(t, s.Start(&acc))
}

func TestSuricataTooLongLine(t *testing.T) {
	dir, err := ioutil.TempDir("", "test")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(dir)
	tmpfn := filepath.Join(dir, fmt.Sprintf("t%d", rand.Int63()))

	s := Suricata{
		Source: tmpfn,
		Log: testutil.Logger{
			Name: "inputs.suricata",
		},
	}
	acc := testutil.Accumulator{}
	acc.SetDebug(true)

	assert.NoError(t, s.Start(&acc))

	c, err := net.Dial("unix", tmpfn)
	if err != nil {
		log.Println(err)
	}
	c.Write([]byte(strings.Repeat("X", 20000000)))
	c.Write([]byte("\n"))
	c.Close()

	acc.WaitError(1)

	s.Stop()
}

func TestSuricataEmptyJSON(t *testing.T) {
	dir, err := ioutil.TempDir("", "test")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(dir)
	tmpfn := filepath.Join(dir, fmt.Sprintf("t%d", rand.Int63()))

	s := Suricata{
		Source: tmpfn,
		Log: testutil.Logger{
			Name: "inputs.suricata",
		},
	}
	acc := testutil.Accumulator{}
	acc.SetDebug(true)

	assert.NoError(t, s.Start(&acc))

	c, err := net.Dial("unix", tmpfn)
	if err != nil {
		log.Println(err)
	}
	c.Write([]byte("\n"))
	c.Close()

	acc.WaitError(1)

	s.Stop()
}

func TestSuricataInvalidInputs(t *testing.T) {
	dir, err := ioutil.TempDir("", "test")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(dir)
	defer func() {
		log.SetOutput(os.Stderr)
	}()
	tmpfn := filepath.Join(dir, fmt.Sprintf("t%d", rand.Int63()))

	for input, errmsg := range map[string]string{
		brokenType1:   `Unsupported type bool encountered`,
		brokenType2:   `Unsupported type []interface {} encountered`,
		brokenType3:   `Unsupported type string encountered`,
		brokenType4:   `Unsupported type <nil> encountered`,
		brokenType5:   `Unsupported type <nil> encountered`,
		brokenStruct1: `The 'threads' sub-object does not have required structure`,
		brokenStruct2: `Input does not contain necessary 'stats' sub-object`,
		brokenStruct3: `The 'stats' sub-object does not have required structure`,
		brokenStruct4: `The 'stats' sub-object does not have required structure`,
	} {
		var logBuf buffer
		logBuf.Reset()
		log.SetOutput(&logBuf)

		acc := testutil.Accumulator{}
		acc.SetDebug(true)

		s := Suricata{
			Source:    tmpfn,
			Delimiter: ".",
			Log: testutil.Logger{
				Name: "inputs.suricata",
			},
		}
		assert.NoError(t, s.Start(&acc))

		c, err := net.Dial("unix", tmpfn)
		if err != nil {
			t.Fatal(err)
		}
		c.Write([]byte(input))
		c.Write([]byte("\n"))
		c.Close()

		for {
			if bytes.Count(logBuf.Bytes(), []byte{'\n'}) > 0 {
				break
			}
			time.Sleep(50 * time.Millisecond)
		}

		assert.Contains(t, logBuf.String(), errmsg)
		s.Stop()
	}
}

func TestSuricataDisconnectSocket(t *testing.T) {
	dir, err := ioutil.TempDir("", "test")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(dir)
	tmpfn := filepath.Join(dir, fmt.Sprintf("t%d", rand.Int63()))

	s := Suricata{
		Source: tmpfn,
		Log: testutil.Logger{
			Name: "inputs.suricata",
		},
	}
	acc := testutil.Accumulator{}
	acc.SetDebug(true)

	assert.NoError(t, s.Start(&acc))

	c, err := net.Dial("unix", tmpfn)
	if err != nil {
		log.Println(err)
	}
	c.Write([]byte(ex2))
	c.Write([]byte("\n"))
	c.Close()

	c, err = net.Dial("unix", tmpfn)
	if err != nil {
		log.Println(err)
	}
	c.Write([]byte(ex3))
	c.Write([]byte("\n"))
	c.Close()

	acc.Wait(2)

	s.Stop()
}

func TestSuricataPluginDesc(t *testing.T) {
	v, ok := inputs.Inputs["suricata"]
	if !ok {
		t.Fatal("suricata plugin not registered")
	}
	desc := v().Description()
	if desc != "Suricata stats plugin" {
		t.Fatal("invalid description ", desc)
	}
}

func TestSuricataStartStop(t *testing.T) {
	dir, err := ioutil.TempDir("", "test")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(dir)
	tmpfn := filepath.Join(dir, fmt.Sprintf("t%d", rand.Int63()))

	s := Suricata{
		Source: tmpfn,
		Log: testutil.Logger{
			Name: "inputs.suricata",
		},
	}
	acc := testutil.Accumulator{}
	acc.SetDebug(true)
	assert.NoError(t, s.Start(&acc))
	s.Stop()
}

func TestSuricataGather(t *testing.T) {
	dir, err := ioutil.TempDir("", "test")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(dir)
	tmpfn := filepath.Join(dir, fmt.Sprintf("t%d", rand.Int63()))

	s := Suricata{
		Source: tmpfn,
		Log: testutil.Logger{
			Name: "inputs.suricata",
		},
	}
	acc := testutil.Accumulator{}
	acc.SetDebug(true)
	assert.NoError(t, s.Gather(&acc))
}

func TestSuricataSampleConfig(t *testing.T) {
	v, ok := inputs.Inputs["suricata"]
	if !ok {
		t.Fatal("suricata plugin not registered")
	}
	if v().SampleConfig() != sampleConfig {
		t.Fatal("wrong sampleconfig")
	}
}
<commit_msg>Improve suricata input unit test debugging (#6815)<commit_after>package suricata

import (
	"fmt"
	"io/ioutil"
	"log"
	"math/rand"
	"net"
	"os"
	"path/filepath"
	"strings"
	"testing"
	"time"

	"github.com/influxdata/telegraf"
	"github.com/influxdata/telegraf/testutil"
	"github.com/stretchr/testify/require"
)

var ex2 = `{"timestamp":"2017-03-06T07:43:39.000397+0000","event_type":"stats","stats":{"capture":{"kernel_packets":905344474,"kernel_drops":78355440,"kernel_packets_delta":2376742,"kernel_drops_delta":82049}}}`
var ex3 = `{"timestamp":"2017-03-06T07:43:39.000397+0000","event_type":"stats","stats":{"threads": { "W#05-wlp4s0": { "capture":{"kernel_packets":905344474,"kernel_drops":78355440}}}}}`

func TestSuricataLarge(t *testing.T) {
	dir, err := ioutil.TempDir("", "test")
	require.NoError(t, err)
	defer os.RemoveAll(dir)
	tmpfn := filepath.Join(dir, fmt.Sprintf("t%d", rand.Int63()))

	s := Suricata{
		Source:    tmpfn,
		Delimiter: ".",
		Log: testutil.Logger{
			Name: "inputs.suricata",
		},
	}
	acc := testutil.Accumulator{}
	require.NoError(t, s.Start(&acc))
	defer s.Stop()

	data, err := ioutil.ReadFile("testdata/test1.json")
	require.NoError(t, err)

	c, err := net.Dial("unix", tmpfn)
	require.NoError(t, err)
	c.Write([]byte(data))
	c.Write([]byte("\n"))
	c.Close()

	acc.Wait(1)
}

func TestSuricata(t *testing.T) {
	dir, err := ioutil.TempDir("", "test")
	require.NoError(t, err)
	defer os.RemoveAll(dir)
	tmpfn := filepath.Join(dir, fmt.Sprintf("t%d", rand.Int63()))

	s := Suricata{
		Source:    tmpfn,
		Delimiter: ".",
		Log: testutil.Logger{
			Name: "inputs.suricata",
		},
	}
	acc := testutil.Accumulator{}
	require.NoError(t, s.Start(&acc))
	defer s.Stop()

	c, err := net.Dial("unix", tmpfn)
	require.NoError(t, err)
	c.Write([]byte(ex2))
	c.Write([]byte("\n"))
	c.Close()

	acc.Wait(1)

	s = Suricata{
		Source:    tmpfn,
		Delimiter: ".",
		Log: testutil.Logger{
			Name: "inputs.suricata",
		},
	}

	expected := []telegraf.Metric{
		testutil.MustMetric(
			"suricata",
			map[string]string{
				"thread": "total",
			},
			map[string]interface{}{
				"capture.kernel_packets":       float64(905344474),
				"capture.kernel_drops":         float64(78355440),
				"capture.kernel_packets_delta": float64(2376742),
				"capture.kernel_drops_delta":   float64(82049),
			},
			time.Unix(0, 0),
		),
	}

	testutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())
}

func TestThreadStats(t *testing.T) {
	dir, err := ioutil.TempDir("", "test")
	require.NoError(t, err)
	defer os.RemoveAll(dir)
	tmpfn := filepath.Join(dir, fmt.Sprintf("t%d", rand.Int63()))

	s := Suricata{
		Source:    tmpfn,
		Delimiter: ".",
		Log: testutil.Logger{
			Name: "inputs.suricata",
		},
	}

	acc := testutil.Accumulator{}
	require.NoError(t, s.Start(&acc))
	defer s.Stop()

	c, err := net.Dial("unix", tmpfn)
	require.NoError(t, err)
	c.Write([]byte(""))
	c.Write([]byte("\n"))
	c.Write([]byte("foobard}\n"))
	c.Write([]byte(ex3))
	c.Write([]byte("\n"))
	c.Close()
	acc.Wait(1)

	expected := []telegraf.Metric{
		testutil.MustMetric(
			"suricata",
			map[string]string{
				"thread": "W#05-wlp4s0",
			},
			map[string]interface{}{
				"capture.kernel_packets": float64(905344474),
				"capture.kernel_drops":   float64(78355440),
			},
			time.Unix(0, 0),
		),
	}

	testutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())
}

func TestSuricataInvalid(t *testing.T) {
	dir, err := ioutil.TempDir("", "test")
	require.NoError(t, err)
	defer os.RemoveAll(dir)
	tmpfn := filepath.Join(dir, fmt.Sprintf("t%d", rand.Int63()))

	s := Suricata{
		Source: tmpfn,
		Log: testutil.Logger{
			Name: "inputs.suricata",
		},
	}
	acc := testutil.Accumulator{}
	acc.SetDebug(true)

	require.NoError(t, s.Start(&acc))
	defer s.Stop()

	c, err := net.Dial("unix", tmpfn)
	require.NoError(t, err)
	c.Write([]byte("sfjiowef"))
	c.Write([]byte("\n"))
	c.Close()

	acc.WaitError(1)
}

func TestSuricataInvalidPath(t *testing.T) {
	tmpfn := fmt.Sprintf("/t%d/X", rand.Int63())
	s := Suricata{
		Source: tmpfn,
		Log: testutil.Logger{
			Name: "inputs.suricata",
		},
	}

	acc := testutil.Accumulator{}
	require.Error(t, s.Start(&acc))
}

func TestSuricataTooLongLine(t *testing.T) {
	dir, err := ioutil.TempDir("", "test")
	require.NoError(t, err)
	defer os.RemoveAll(dir)
	tmpfn := filepath.Join(dir, fmt.Sprintf("t%d", rand.Int63()))

	s := Suricata{
		Source: tmpfn,
		Log: testutil.Logger{
			Name: "inputs.suricata",
		},
	}
	acc := testutil.Accumulator{}

	require.NoError(t, s.Start(&acc))
	defer s.Stop()

	c, err := net.Dial("unix", tmpfn)
	require.NoError(t, err)
	c.Write([]byte(strings.Repeat("X", 20000000)))
	c.Write([]byte("\n"))
	c.Close()

	acc.WaitError(1)

}

func TestSuricataEmptyJSON(t *testing.T) {
	dir, err := ioutil.TempDir("", "test")
	require.NoError(t, err)
	defer os.RemoveAll(dir)
	tmpfn := filepath.Join(dir, fmt.Sprintf("t%d", rand.Int63()))

	s := Suricata{
		Source: tmpfn,
		Log: testutil.Logger{
			Name: "inputs.suricata",
		},
	}
	acc := testutil.Accumulator{}
	require.NoError(t, s.Start(&acc))
	defer s.Stop()

	c, err := net.Dial("unix", tmpfn)
	if err != nil {
		log.Println(err)

	}
	c.Write([]byte("\n"))
	c.Close()

	acc.WaitError(1)
}

func TestSuricataDisconnectSocket(t *testing.T) {
	dir, err := ioutil.TempDir("", "test")
	require.NoError(t, err)
	defer os.RemoveAll(dir)
	tmpfn := filepath.Join(dir, fmt.Sprintf("t%d", rand.Int63()))

	s := Suricata{
		Source: tmpfn,
		Log: testutil.Logger{
			Name: "inputs.suricata",
		},
	}
	acc := testutil.Accumulator{}

	require.NoError(t, s.Start(&acc))
	defer s.Stop()

	c, err := net.Dial("unix", tmpfn)
	require.NoError(t, err)
	c.Write([]byte(ex2))
	c.Write([]byte("\n"))
	c.Close()

	c, err = net.Dial("unix", tmpfn)
	require.NoError(t, err)
	c.Write([]byte(ex3))
	c.Write([]byte("\n"))
	c.Close()

	acc.Wait(2)
}

func TestSuricataStartStop(t *testing.T) {
	dir, err := ioutil.TempDir("", "test")
	require.NoError(t, err)
	defer os.RemoveAll(dir)
	tmpfn := filepath.Join(dir, fmt.Sprintf("t%d", rand.Int63()))

	s := Suricata{
		Source: tmpfn,
		Log: testutil.Logger{
			Name: "inputs.suricata",
		},
	}
	acc := testutil.Accumulator{}
	require.NoError(t, s.Start(&acc))
	s.Stop()
}
<|endoftext|>


<commit_before>// +build darwin linux solaris

package godirwalk

import "syscall"

func inoFromDirent(de *syscall.Dirent) uint64 {
	return de.Ino
}
<commit_msg>build flags for syscall.Dirent structs with Ino field<commit_after>// +build aix darwin linux nacl solaris

package godirwalk

import "syscall"

func inoFromDirent(de *syscall.Dirent) uint64 {
	return de.Ino
}
<|endoftext|>