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

package e2e

import (
	"os"
	"strings"
	"testing"
)

func TestCtlV3Alarm(t *testing.T) {
	// The boltdb minimum working set is six pages.
	testCtl(t, alarmTest, withQuota(int64(13*os.Getpagesize())))
}

func alarmTest(cx ctlCtx) {
	// test small put still works
	smallbuf := strings.Repeat("a", 64)
	if err := ctlV3Put(cx, "1st_test", smallbuf, ""); err != nil {
		cx.t.Fatal(err)
	}

	// write some chunks to fill up the database
	buf := strings.Repeat("b", int(os.Getpagesize()))
	var rev int64
	for ; ; rev++ {
		if err := ctlV3Put(cx, "2nd_test", buf, ""); err != nil {
			if !strings.Contains(err.Error(), "etcdserver: mvcc: database space exceeded") {
				cx.t.Fatal(err)
			}
			break
		}
	}

	// quota alarm should now be on
	if err := ctlV3Alarm(cx, "list", "alarm:NOSPACE"); err != nil {
		cx.t.Fatal(err)
	}

	// check that Put is rejected when alarm is on
	if err := ctlV3Put(cx, "3rd_test", smallbuf, ""); err != nil {
		if !strings.Contains(err.Error(), "etcdserver: mvcc: database space exceeded") {
			cx.t.Fatal(err)
		}
	}

	// make some space
	if err := ctlV3Compact(cx, rev, true); err != nil {
		cx.t.Fatal(err)
	}
	if err := ctlV3Defrag(cx); err != nil {
		cx.t.Fatal(err)
	}

	// turn off alarm
	if err := ctlV3Alarm(cx, "disarm", "alarm:NOSPACE"); err != nil {
		cx.t.Fatal(err)
	}

	// put one more key below quota
	if err := ctlV3Put(cx, "4th_test", smallbuf, ""); err != nil {
		cx.t.Fatal(err)
	}
}

func ctlV3Alarm(cx ctlCtx, cmd string, as ...string) error {
	cmdArgs := append(cx.PrefixArgs(), "alarm", cmd)
	return spawnWithExpects(cmdArgs, as...)
}
<commit_msg>e2e: compact with latest rev in alarm test<commit_after>// Copyright 2016 The etcd Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package e2e

import (
	"os"
	"strings"
	"testing"
	"time"

	"github.com/coreos/etcd/clientv3"
	"golang.org/x/net/context"
)

func TestCtlV3Alarm(t *testing.T) {
	// The boltdb minimum working set is six pages.
	testCtl(t, alarmTest, withQuota(int64(13*os.Getpagesize())))
}

func alarmTest(cx ctlCtx) {
	// test small put still works
	smallbuf := strings.Repeat("a", 64)
	if err := ctlV3Put(cx, "1st_test", smallbuf, ""); err != nil {
		cx.t.Fatal(err)
	}

	// write some chunks to fill up the database
	buf := strings.Repeat("b", int(os.Getpagesize()))
	for {
		if err := ctlV3Put(cx, "2nd_test", buf, ""); err != nil {
			if !strings.Contains(err.Error(), "etcdserver: mvcc: database space exceeded") {
				cx.t.Fatal(err)
			}
			break
		}
	}

	// quota alarm should now be on
	if err := ctlV3Alarm(cx, "list", "alarm:NOSPACE"); err != nil {
		cx.t.Fatal(err)
	}

	// check that Put is rejected when alarm is on
	if err := ctlV3Put(cx, "3rd_test", smallbuf, ""); err != nil {
		if !strings.Contains(err.Error(), "etcdserver: mvcc: database space exceeded") {
			cx.t.Fatal(err)
		}
	}

	eps := cx.epc.grpcEndpoints()

	// get latest revision to compact
	cli, err := clientv3.New(clientv3.Config{
		Endpoints:   eps,
		DialTimeout: 3 * time.Second,
	})
	if err != nil {
		cx.t.Fatal(err)
	}
	defer cli.Close()
	sresp, err := cli.Status(context.TODO(), eps[0])
	if err != nil {
		cx.t.Fatal(err)
	}

	// make some space
	if err := ctlV3Compact(cx, sresp.Header.Revision, true); err != nil {
		cx.t.Fatal(err)
	}
	if err := ctlV3Defrag(cx); err != nil {
		cx.t.Fatal(err)
	}

	// turn off alarm
	if err := ctlV3Alarm(cx, "disarm", "alarm:NOSPACE"); err != nil {
		cx.t.Fatal(err)
	}

	// put one more key below quota
	if err := ctlV3Put(cx, "4th_test", smallbuf, ""); err != nil {
		cx.t.Fatal(err)
	}
}

func ctlV3Alarm(cx ctlCtx, cmd string, as ...string) error {
	cmdArgs := append(cx.PrefixArgs(), "alarm", cmd)
	return spawnWithExpects(cmdArgs, as...)
}
<|endoftext|>


<commit_before>package encoding

import (
	"bytes"
	"encoding/json"
	"fmt"
	"image"
	"reflect"
	"testing"
)

type T struct {
	X string
	Y int
	Z int `gorethink:"-"`
}

type U struct {
	Alphabet string `gorethink:"alpha"`
}

type V struct {
	F1 interface{}
	F2 int32
	F3 string
}

type tx struct {
	x int
}

var txType = reflect.TypeOf((*tx)(nil)).Elem()

// Test data structures for anonymous fields.

type Point struct {
	Z int
}

type Top struct {
	Level0 int
	Embed0
	*Embed0a
	*Embed0b `gorethink:"e,omitempty"` // treated as named
	Embed0c  `gorethink:"-"`           // ignored
	Loop
	Embed0p // has Point with X, Y, used
	Embed0q // has Point with Z, used
}

type Embed0 struct {
	Level1a int // overridden by Embed0a's Level1a with tag
	Level1b int // used because Embed0a's Level1b is renamed
	Level1c int // used because Embed0a's Level1c is ignored
	Level1d int // annihilated by Embed0a's Level1d
	Level1e int `gorethink:"x"` // annihilated by Embed0a.Level1e
}

type Embed0a struct {
	Level1a int `gorethink:"Level1a,omitempty"`
	Level1b int `gorethink:"LEVEL1B,omitempty"`
	Level1c int `gorethink:"-"`
	Level1d int // annihilated by Embed0's Level1d
	Level1f int `gorethink:"x"` // annihilated by Embed0's Level1e
}

type Embed0b Embed0

type Embed0c Embed0

type Embed0p struct {
	image.Point
}

type Embed0q struct {
	Point
}

type Loop struct {
	Loop1 int `gorethink:",omitempty"`
	Loop2 int `gorethink:",omitempty"`
	*Loop
}

// From reflect test:
// The X in S6 and S7 annihilate, but they also block the X in S8.S9.
type S5 struct {
	S6
	S7
	S8
}

type S6 struct {
	X int
}

type S7 S6

type S8 struct {
	S9
}

type S9 struct {
	X int
	Y int
}

// From reflect test:
// The X in S11.S6 and S12.S6 annihilate, but they also block the X in S13.S8.S9.
type S10 struct {
	S11
	S12
	S13
}

type S11 struct {
	S6
}

type S12 struct {
	S6
}

type S13 struct {
	S8
}

type decodeTest struct {
	in  interface{}
	ptr interface{}
	out interface{}
	err error
}

type Ambig struct {
	// Given "hello", the first match should win.
	First  int `gorethink:"HELLO"`
	Second int `gorethink:"Hello"`
}

var decodeTests = []decodeTest{
	// basic types
	// {in: true, ptr: new(bool), out: true},
	// {in: 1, ptr: new(int), out: 1},
	// {in: 1.2, ptr: new(float64), out: 1.2},
	// {in: -5, ptr: new(int16), out: int16(-5)},
	// {in: 2, ptr: new(string), out: string("2")},
	// {in: float64(2.0), ptr: new(interface{}), out: float64(2.0)},
	// {in: string("2"), ptr: new(interface{}), out: string("2")},
	// {in: "a\u1234", ptr: new(string), out: "a\u1234"},
	// {in: []interface{}{}, ptr: new([]string), out: []string{}},
	// {in: map[string]interface{}{"X": []interface{}{1, 2, 3}, "Y": 4}, ptr: new(T), out: T{}, err: &DecodeTypeError{reflect.TypeOf([0]interface{}{}), reflect.TypeOf(""), ""}},
	// {in: map[string]interface{}{"x": 1}, ptr: new(tx), out: tx{}},
	// {in: map[string]interface{}{"F1": float64(1), "F2": 2, "F3": 3}, ptr: new(V), out: V{F1: float64(1), F2: int32(2), F3: string("3")}},
	// {in: map[string]interface{}{"F1": string("1"), "F2": 2, "F3": 3}, ptr: new(V), out: V{F1: string("1"), F2: int32(2), F3: string("3")}},
	// {
	// 	in:  map[string]interface{}{"k1": int64(1), "k2": "s", "k3": []interface{}{int64(1), 2.0, 3e-3}, "k4": map[string]interface{}{"kk1": "s", "kk2": int64(2)}},
	// 	out: map[string]interface{}{"k1": int64(1), "k2": "s", "k3": []interface{}{int64(1), 2.0, 3e-3}, "k4": map[string]interface{}{"kk1": "s", "kk2": int64(2)}},
	// 	ptr: new(interface{}),
	// },

	// // Z has a "-" tag.
	// {in: map[string]interface{}{"Y": 1, "Z": 2}, ptr: new(T), out: T{Y: 1}},

	// {in: map[string]interface{}{"alpha": "abc", "alphabet": "xyz"}, ptr: new(U), out: U{Alphabet: "abc"}},
	// {in: map[string]interface{}{"alpha": "abc"}, ptr: new(U), out: U{Alphabet: "abc"}},
	// {in: map[string]interface{}{"alphabet": "xyz"}, ptr: new(U), out: U{}},

	// // array tests
	// {in: []interface{}{1, 2, 3}, ptr: new([3]int), out: [3]int{1, 2, 3}},
	// {in: []interface{}{1, 2, 3}, ptr: new([1]int), out: [1]int{1}},
	// {in: []interface{}{1, 2, 3}, ptr: new([5]int), out: [5]int{1, 2, 3, 0, 0}},

	// // empty array to interface test
	// {in: map[string]interface{}{"T": []interface{}{}}, ptr: new(map[string]interface{}), out: map[string]interface{}{"T": []interface{}{}}},

	// {
	// 	in: map[string]interface{}{
	// 		"Level0":  1,
	// 		"Level1b": 2,
	// 		"Level1c": 3,
	// 		"level1d": 4,
	// 		"Level1a": 5,
	// 		"LEVEL1B": 6,
	// 		"e": map[string]interface{}{
	// 			"Level1a": 8,
	// 			"Level1b": 9,
	// 			"Level1c": 10,
	// 			"Level1d": 11,
	// 			"x":       12,
	// 		},
	// 		"Loop1": 13,
	// 		"Loop2": 14,
	// 		"X":     15,
	// 		"Y":     16,
	// 		"Z":     17,
	// 	},
	// 	ptr: new(Top),
	// 	out: Top{
	// 		Level0: 1,
	// 		Embed0: Embed0{
	// 			Level1b: 2,
	// 			Level1c: 3,
	// 		},
	// 		Embed0a: &Embed0a{
	// 			Level1a: 5,
	// 			Level1b: 6,
	// 		},
	// 		Embed0b: &Embed0b{
	// 			Level1a: 8,
	// 			Level1b: 9,
	// 			Level1c: 10,
	// 			Level1d: 11,
	// 		},
	// 		Loop: Loop{
	// 			Loop1: 13,
	// 			Loop2: 14,
	// 		},
	// 		Embed0p: Embed0p{
	// 			Point: image.Point{X: 15, Y: 16},
	// 		},
	// 		Embed0q: Embed0q{
	// 			Point: Point{Z: 17},
	// 		},
	// 	},
	// },
	{
		in:  map[string]interface{}{"hello": 1},
		ptr: new(Ambig),
		out: Ambig{First: 1},
	},
	// {
	// 	in:  map[string]interface{}{"X": 1, "Y": 2},
	// 	ptr: new(S5),
	// 	out: S5{S8: S8{S9: S9{Y: 2}}},
	// },
	// {
	// 	in:  map[string]interface{}{"X": 1, "Y": 2},
	// 	ptr: new(S10),
	// 	out: S10{S13: S13{S8: S8{S9: S9{Y: 2}}}},
	// },
}

func TestDecode(t *testing.T) {
	for i, tt := range decodeTests {
		if tt.ptr == nil {
			continue
		}

		// v = new(right-type)
		v := reflect.New(reflect.TypeOf(tt.ptr).Elem())

		err := Decode(v.Interface(), tt.in)
		if !jsonEqual(err, tt.err) {
			t.Errorf("#%d: got error %v want %v", i, err, tt.err)
			continue
		}

		if !jsonEqual(v.Elem().Interface(), tt.out) {
			fmt.Printf("%#v\n", v.Elem().Interface())
			fmt.Printf("%#v\n", tt.out)
			t.Errorf("#%d: mismatch\nhave: %+v\nwant: %+v", i, v.Elem().Interface(), tt.out)
			continue
		}

		// Check round trip.
		if tt.err == nil {
			enc, err := Encode(v.Interface())
			if err != nil {
				t.Errorf("#%d: error re-marshaling: %v", i, err)
				continue
			}
			vv := reflect.New(reflect.TypeOf(tt.ptr).Elem())

			if err := Decode(vv.Interface(), enc); err != nil {
				t.Errorf("#%d: error re-decodeing: %v", i, err)
				continue
			}
			if !jsonEqual(v.Elem().Interface(), vv.Elem().Interface()) {
				t.Errorf("#%d: mismatch\nhave: %#+v\nwant: %#+v", i, v.Elem().Interface(), vv.Elem().Interface())
				continue
			}
		}
	}
}

func TestStringKind(t *testing.T) {
	type aMap map[string]int

	var m1, m2 map[string]int
	m1 = map[string]int{
		"foo": 42,
	}

	data, err := Encode(m1)
	if err != nil {
		t.Errorf("Unexpected error encoding: %v", err)
	}

	err = Decode(&m2, data)
	if err != nil {
		t.Errorf("Unexpected error decoding: %v", err)
	}

	if !jsonEqual(m1, m2) {
		t.Error("Items should be equal after encoding and then decoding")
	}

}

// Test handling of unexported fields that should be ignored.
type unexportedFields struct {
	Name string
	m    map[string]interface{} `gorethink:"-"`
	m2   map[string]interface{} `gorethink:"abcd"`
}

func TestDecodeUnexported(t *testing.T) {
	input := map[string]interface{}{
		"Name": "Bob",
		"m": map[string]interface{}{
			"x": 123,
		},
		"m2": map[string]interface{}{
			"y": 123,
		},
		"abcd": map[string]interface{}{
			"z": 789,
		},
	}
	want := &unexportedFields{Name: "Bob"}

	out := &unexportedFields{}
	err := Decode(out, input)
	if err != nil {
		t.Errorf("got error %v, expected nil", err)
	}
	if !jsonEqual(out, want) {
		t.Errorf("got %q, want %q", out, want)
	}
}

type Foo struct {
	FooBar interface{} `gorethink:"foobar"`
}
type Bar struct {
	Baz int `gorethink:"baz"`
}

func jsonEqual(a, b interface{}) bool {
	ba, err := json.Marshal(a)
	if err != nil {
		panic(err)
	}
	bb, err := json.Marshal(b)
	if err != nil {
		panic(err)
	}

	return bytes.Compare(ba, bb) == 0
}
<commit_msg>Uncommented decoder tests<commit_after>package encoding

import (
	"bytes"
	"encoding/json"
	"fmt"
	"image"
	"reflect"
	"testing"
)

type T struct {
	X string
	Y int
	Z int `gorethink:"-"`
}

type U struct {
	Alphabet string `gorethink:"alpha"`
}

type V struct {
	F1 interface{}
	F2 int32
	F3 string
}

type tx struct {
	x int
}

var txType = reflect.TypeOf((*tx)(nil)).Elem()

// Test data structures for anonymous fields.

type Point struct {
	Z int
}

type Top struct {
	Level0 int
	Embed0
	*Embed0a
	*Embed0b `gorethink:"e,omitempty"` // treated as named
	Embed0c  `gorethink:"-"`           // ignored
	Loop
	Embed0p // has Point with X, Y, used
	Embed0q // has Point with Z, used
}

type Embed0 struct {
	Level1a int // overridden by Embed0a's Level1a with tag
	Level1b int // used because Embed0a's Level1b is renamed
	Level1c int // used because Embed0a's Level1c is ignored
	Level1d int // annihilated by Embed0a's Level1d
	Level1e int `gorethink:"x"` // annihilated by Embed0a.Level1e
}

type Embed0a struct {
	Level1a int `gorethink:"Level1a,omitempty"`
	Level1b int `gorethink:"LEVEL1B,omitempty"`
	Level1c int `gorethink:"-"`
	Level1d int // annihilated by Embed0's Level1d
	Level1f int `gorethink:"x"` // annihilated by Embed0's Level1e
}

type Embed0b Embed0

type Embed0c Embed0

type Embed0p struct {
	image.Point
}

type Embed0q struct {
	Point
}

type Loop struct {
	Loop1 int `gorethink:",omitempty"`
	Loop2 int `gorethink:",omitempty"`
	*Loop
}

// From reflect test:
// The X in S6 and S7 annihilate, but they also block the X in S8.S9.
type S5 struct {
	S6
	S7
	S8
}

type S6 struct {
	X int
}

type S7 S6

type S8 struct {
	S9
}

type S9 struct {
	X int
	Y int
}

// From reflect test:
// The X in S11.S6 and S12.S6 annihilate, but they also block the X in S13.S8.S9.
type S10 struct {
	S11
	S12
	S13
}

type S11 struct {
	S6
}

type S12 struct {
	S6
}

type S13 struct {
	S8
}

type decodeTest struct {
	in  interface{}
	ptr interface{}
	out interface{}
	err error
}

type Ambig struct {
	// Given "hello", the first match should win.
	First  int `gorethink:"HELLO"`
	Second int `gorethink:"Hello"`
}

var decodeTests = []decodeTest{
	// basic types
	{in: true, ptr: new(bool), out: true},
	{in: 1, ptr: new(int), out: 1},
	{in: 1.2, ptr: new(float64), out: 1.2},
	{in: -5, ptr: new(int16), out: int16(-5)},
	{in: 2, ptr: new(string), out: string("2")},
	{in: float64(2.0), ptr: new(interface{}), out: float64(2.0)},
	{in: string("2"), ptr: new(interface{}), out: string("2")},
	{in: "a\u1234", ptr: new(string), out: "a\u1234"},
	{in: []interface{}{}, ptr: new([]string), out: []string{}},
	{in: map[string]interface{}{"X": []interface{}{1, 2, 3}, "Y": 4}, ptr: new(T), out: T{}, err: &DecodeTypeError{reflect.TypeOf([0]interface{}{}), reflect.TypeOf(""), ""}},
	{in: map[string]interface{}{"x": 1}, ptr: new(tx), out: tx{}},
	{in: map[string]interface{}{"F1": float64(1), "F2": 2, "F3": 3}, ptr: new(V), out: V{F1: float64(1), F2: int32(2), F3: string("3")}},
	{in: map[string]interface{}{"F1": string("1"), "F2": 2, "F3": 3}, ptr: new(V), out: V{F1: string("1"), F2: int32(2), F3: string("3")}},
	{
		in:  map[string]interface{}{"k1": int64(1), "k2": "s", "k3": []interface{}{int64(1), 2.0, 3e-3}, "k4": map[string]interface{}{"kk1": "s", "kk2": int64(2)}},
		out: map[string]interface{}{"k1": int64(1), "k2": "s", "k3": []interface{}{int64(1), 2.0, 3e-3}, "k4": map[string]interface{}{"kk1": "s", "kk2": int64(2)}},
		ptr: new(interface{}),
	},

	// Z has a "-" tag.
	{in: map[string]interface{}{"Y": 1, "Z": 2}, ptr: new(T), out: T{Y: 1}},

	{in: map[string]interface{}{"alpha": "abc", "alphabet": "xyz"}, ptr: new(U), out: U{Alphabet: "abc"}},
	{in: map[string]interface{}{"alpha": "abc"}, ptr: new(U), out: U{Alphabet: "abc"}},
	{in: map[string]interface{}{"alphabet": "xyz"}, ptr: new(U), out: U{}},

	// array tests
	{in: []interface{}{1, 2, 3}, ptr: new([3]int), out: [3]int{1, 2, 3}},
	{in: []interface{}{1, 2, 3}, ptr: new([1]int), out: [1]int{1}},
	{in: []interface{}{1, 2, 3}, ptr: new([5]int), out: [5]int{1, 2, 3, 0, 0}},

	// empty array to interface test
	{in: map[string]interface{}{"T": []interface{}{}}, ptr: new(map[string]interface{}), out: map[string]interface{}{"T": []interface{}{}}},

	{
		in: map[string]interface{}{
			"Level0":  1,
			"Level1b": 2,
			"Level1c": 3,
			"level1d": 4,
			"Level1a": 5,
			"LEVEL1B": 6,
			"e": map[string]interface{}{
				"Level1a": 8,
				"Level1b": 9,
				"Level1c": 10,
				"Level1d": 11,
				"x":       12,
			},
			"Loop1": 13,
			"Loop2": 14,
			"X":     15,
			"Y":     16,
			"Z":     17,
		},
		ptr: new(Top),
		out: Top{
			Level0: 1,
			Embed0: Embed0{
				Level1b: 2,
				Level1c: 3,
			},
			Embed0a: &Embed0a{
				Level1a: 5,
				Level1b: 6,
			},
			Embed0b: &Embed0b{
				Level1a: 8,
				Level1b: 9,
				Level1c: 10,
				Level1d: 11,
			},
			Loop: Loop{
				Loop1: 13,
				Loop2: 14,
			},
			Embed0p: Embed0p{
				Point: image.Point{X: 15, Y: 16},
			},
			Embed0q: Embed0q{
				Point: Point{Z: 17},
			},
		},
	},
	{
		in:  map[string]interface{}{"hello": 1},
		ptr: new(Ambig),
		out: Ambig{First: 1},
	},
	{
		in:  map[string]interface{}{"X": 1, "Y": 2},
		ptr: new(S5),
		out: S5{S8: S8{S9: S9{Y: 2}}},
	},
	{
		in:  map[string]interface{}{"X": 1, "Y": 2},
		ptr: new(S10),
		out: S10{S13: S13{S8: S8{S9: S9{Y: 2}}}},
	},
}

func TestDecode(t *testing.T) {
	for i, tt := range decodeTests {
		if tt.ptr == nil {
			continue
		}

		// v = new(right-type)
		v := reflect.New(reflect.TypeOf(tt.ptr).Elem())

		err := Decode(v.Interface(), tt.in)
		if !jsonEqual(err, tt.err) {
			t.Errorf("#%d: got error %v want %v", i, err, tt.err)
			continue
		}

		if !jsonEqual(v.Elem().Interface(), tt.out) {
			fmt.Printf("%#v\n", v.Elem().Interface())
			fmt.Printf("%#v\n", tt.out)
			t.Errorf("#%d: mismatch\nhave: %+v\nwant: %+v", i, v.Elem().Interface(), tt.out)
			continue
		}

		// Check round trip.
		if tt.err == nil {
			enc, err := Encode(v.Interface())
			if err != nil {
				t.Errorf("#%d: error re-marshaling: %v", i, err)
				continue
			}
			vv := reflect.New(reflect.TypeOf(tt.ptr).Elem())

			if err := Decode(vv.Interface(), enc); err != nil {
				t.Errorf("#%d: error re-decodeing: %v", i, err)
				continue
			}
			if !jsonEqual(v.Elem().Interface(), vv.Elem().Interface()) {
				t.Errorf("#%d: mismatch\nhave: %#+v\nwant: %#+v", i, v.Elem().Interface(), vv.Elem().Interface())
				continue
			}
		}
	}
}

func TestStringKind(t *testing.T) {
	type aMap map[string]int

	var m1, m2 map[string]int
	m1 = map[string]int{
		"foo": 42,
	}

	data, err := Encode(m1)
	if err != nil {
		t.Errorf("Unexpected error encoding: %v", err)
	}

	err = Decode(&m2, data)
	if err != nil {
		t.Errorf("Unexpected error decoding: %v", err)
	}

	if !jsonEqual(m1, m2) {
		t.Error("Items should be equal after encoding and then decoding")
	}

}

// Test handling of unexported fields that should be ignored.
type unexportedFields struct {
	Name string
	m    map[string]interface{} `gorethink:"-"`
	m2   map[string]interface{} `gorethink:"abcd"`
}

func TestDecodeUnexported(t *testing.T) {
	input := map[string]interface{}{
		"Name": "Bob",
		"m": map[string]interface{}{
			"x": 123,
		},
		"m2": map[string]interface{}{
			"y": 123,
		},
		"abcd": map[string]interface{}{
			"z": 789,
		},
	}
	want := &unexportedFields{Name: "Bob"}

	out := &unexportedFields{}
	err := Decode(out, input)
	if err != nil {
		t.Errorf("got error %v, expected nil", err)
	}
	if !jsonEqual(out, want) {
		t.Errorf("got %q, want %q", out, want)
	}
}

type Foo struct {
	FooBar interface{} `gorethink:"foobar"`
}
type Bar struct {
	Baz int `gorethink:"baz"`
}

func jsonEqual(a, b interface{}) bool {
	ba, err := json.Marshal(a)
	if err != nil {
		panic(err)
	}
	bb, err := json.Marshal(b)
	if err != nil {
		panic(err)
	}

	return bytes.Compare(ba, bb) == 0
}
<|endoftext|>


<commit_before>package opt

import (
	"encoding/json"
	"reflect"

	"github.com/algolia/algoliasearch-client-go/algolia/errs"
)

type TypoToleranceOption struct {
	valueBool   bool
	valueString string
}

func TypoTolerance(value bool) *TypoToleranceOption {
	return &TypoToleranceOption{valueBool: value}
}

func TypoToleranceMin() *TypoToleranceOption {
	return &TypoToleranceOption{valueString: "min"}
}

func TypoToleranceStrict() *TypoToleranceOption {
	return &TypoToleranceOption{valueString: "strict"}
}

func (o TypoToleranceOption) Get() (bool, string) {
	return o.valueBool, o.valueString
}

func (o TypoToleranceOption) MarshalJSON() ([]byte, error) {
	if len(o.valueString) > 0 {
		return json.Marshal(o.valueString)
	}
	return json.Marshal(o.valueBool)
}

func (o *TypoToleranceOption) UnmarshalJSON(data []byte) error {
	if string(data) == "null" {
		o.valueBool = true
		return nil
	}

	var valueString string
	if err := json.Unmarshal(data, &valueString); err == nil {
		o.valueString = valueString
		return nil
	}

	var valueBool bool
	if err := json.Unmarshal(data, &valueBool); err == nil {
		o.valueBool = valueBool
		return nil
	}

	return errs.ErrJSONDecode(data, "TypoTolerance")
}

func (o *TypoToleranceOption) Equal(o2 *TypoToleranceOption) bool {
	if o2 == nil {
		return o.valueBool == true && o.valueString == ""
	}
	return reflect.DeepEqual(o, o2)
}

func TypoToleranceEqual(o1, o2 *TypoToleranceOption) bool {
	if o1 != nil {
		return o1.Equal(o2)
	}
	if o2 != nil {
		return o2.Equal(o1)
	}
	return true
}
<commit_msg>fixed: correctly deserialized boolean as strings for TypoTolerance option<commit_after>package opt

import (
	"encoding/json"
	"fmt"

	"github.com/algolia/algoliasearch-client-go/algolia/errs"
)

type TypoToleranceOption struct {
	value string
}

func TypoTolerance(value bool) *TypoToleranceOption {
	return &TypoToleranceOption{value: fmt.Sprintf("%t", value)}
}

func TypoToleranceMin() *TypoToleranceOption {
	return &TypoToleranceOption{value: "min"}
}

func TypoToleranceStrict() *TypoToleranceOption {
	return &TypoToleranceOption{value: "strict"}
}

func (o TypoToleranceOption) Get() (bool, string) {
	if o.value == "true" {
		return true, ""
	}
	if o.value == "false" {
		return false, ""
	}
	return false, o.value
}

func (o TypoToleranceOption) MarshalJSON() ([]byte, error) {
	return json.Marshal(o.value)
}

func (o *TypoToleranceOption) UnmarshalJSON(data []byte) error {
	if string(data) == "null" {
		o.value = "true"
		return nil
	}

	var v string
	if err := json.Unmarshal(data, &v); err == nil {
		o.value = v
		return nil
	}

	var b bool
	if err := json.Unmarshal(data, &b); err == nil {
		o.value = fmt.Sprintf("%t", b)
		return nil
	}

	return errs.ErrJSONDecode(data, "TypoTolerance")
}

func (o *TypoToleranceOption) Equal(o2 *TypoToleranceOption) bool {
	if o2 == nil {
		return o.value == "true"
	}
	return o.value == o2.value
}

func TypoToleranceEqual(o1, o2 *TypoToleranceOption) bool {
	if o1 != nil {
		return o1.Equal(o2)
	}
	if o2 != nil {
		return o2.Equal(o1)
	}
	return true
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"net/url"
	"os/exec"
	"strings"

	"github.com/coreos/go-etcd/etcd"
)

func ParseDiscovery() (discoveryHost, discoveryPath *string) {
	// Pull the ETCD_DISCOVERY env var and parse it for the etcd client usage
	file := "20-cloudinit.conf"
	cmd := fmt.Sprintf("cat %s | grep ETCD_DISCOVERY | cut -d '=' -f 3 | cut -d '\"' -f 1", file)
	out, err := exec.Command("sh", "-c", cmd).Output()

	discoveryURL := string(out)

	u, err := url.Parse(discoveryURL)
	if err != nil {
		panic(err)
	}

	discoveryHost = new(string)
	*discoveryHost = u.Scheme + "://" + u.Host

	path := strings.Split(u.Path, "/keys/")[1]
	discoveryPath = new(string)
	*discoveryPath = path

	return discoveryHost, discoveryPath
}

func main() {
	discoveryHost, discoveryPath := ParseDiscovery()

	// Connect to the etcd discovery to pull the nodes
	client := etcd.NewClient([]string{*discoveryHost})
	resp, _ := client.Get(*discoveryPath, true, false)

	for _, n := range resp.Node.Nodes {
		log.Printf("%s: %s\n", n.Key, n.Value)
	}
}
<commit_msg>Fix path of 20-cloudinit.conf<commit_after>package main

import (
	"fmt"
	"log"
	"net/url"
	"os/exec"
	"strings"

	"github.com/coreos/go-etcd/etcd"
)

func ParseDiscovery() (discoveryHost, discoveryPath *string) {
	// Pull the ETCD_DISCOVERY env var and parse it for the etcd client usage
	file := "/gopath/src/app/20-cloudinit.conf"
	cmd := fmt.Sprintf("cat %s | grep ETCD_DISCOVERY | cut -d '=' -f 3 | cut -d '\"' -f 1", file)
	out, err := exec.Command("sh", "-c", cmd).Output()

	discoveryURL := string(out)

	u, err := url.Parse(discoveryURL)
	if err != nil {
		panic(err)
	}

	discoveryHost = new(string)
	*discoveryHost = u.Scheme + "://" + u.Host

	path := strings.Split(u.Path, "/keys/")[1]
	discoveryPath = new(string)
	*discoveryPath = path

	return discoveryHost, discoveryPath
}

func main() {
	discoveryHost, discoveryPath := ParseDiscovery()

	// Connect to the etcd discovery to pull the nodes
	client := etcd.NewClient([]string{*discoveryHost})
	resp, _ := client.Get(*discoveryPath, true, false)

	for _, n := range resp.Node.Nodes {
		log.Printf("%s: %s\n", n.Key, n.Value)
	}
}
<|endoftext|>


<commit_before>package notifiers

import (
	"fmt"
	"strconv"

	"github.com/grafana/grafana/pkg/bus"
	"github.com/grafana/grafana/pkg/components/simplejson"
	"github.com/grafana/grafana/pkg/log"
	m "github.com/grafana/grafana/pkg/models"
	"github.com/grafana/grafana/pkg/services/alerting"
)

func init() {
	alerting.RegisterNotifier(&alerting.NotifierPlugin{
		Type:        "opsgenie",
		Name:        "OpsGenie",
		Description: "Sends notifications to OpsGenie",
		Factory:     NewOpsGenieNotifier,
		OptionsTemplate: `

OpsGenie settings

        API Key
        <input type="text" required class="gf-form-input max-width-22" ng-model="ctrl.model.settings.apiKey" placeholder="OpsGenie API Key"></input>

        <gf-form-switch
           class="gf-form"
           label="Auto close incidents"
           label-class="width-14"
           checked="ctrl.model.settings.autoClose"
           tooltip="Automatically close alerts in OpsGenie once the alert goes back to ok.">
        </gf-form-switch>

    `,
	})
}

var (
	opsgenieAlertURL string = "https://api.opsgenie.com/v2/alerts"
)

func NewOpsGenieNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
	autoClose := model.Settings.Get("autoClose").MustBool(true)
	apiKey := model.Settings.Get("apiKey").MustString()
	if apiKey == "" {
		return nil, alerting.ValidationError{Reason: "Could not find api key property in settings"}
	}

	return &OpsGenieNotifier{
		NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.Settings),
		ApiKey:       apiKey,
		AutoClose:    autoClose,
		log:          log.New("alerting.notifier.opsgenie"),
	}, nil
}

type OpsGenieNotifier struct {
	NotifierBase
	ApiKey    string
	AutoClose bool
	log       log.Logger
}

func (this *OpsGenieNotifier) Notify(evalContext *alerting.EvalContext) error {

	var err error
	switch evalContext.Rule.State {
	case m.AlertStateOK:
		if this.AutoClose {
			err = this.closeAlert(evalContext)
		}
	case m.AlertStateAlerting:
		err = this.createAlert(evalContext)
	}
	return err
}

func (this *OpsGenieNotifier) createAlert(evalContext *alerting.EvalContext) error {
	this.log.Info("Creating OpsGenie alert", "ruleId", evalContext.Rule.Id, "notification", this.Name)

	ruleUrl, err := evalContext.GetRuleUrl()
	if err != nil {
		this.log.Error("Failed get rule link", "error", err)
		return err
	}

	bodyJSON := simplejson.New()
	bodyJSON.Set("message", evalContext.Rule.Name)
	bodyJSON.Set("source", "Grafana")
	bodyJSON.Set("alias", "alertId-"+strconv.FormatInt(evalContext.Rule.Id, 10))
	bodyJSON.Set("description", fmt.Sprintf("%s - %s\n%s", evalContext.Rule.Name, ruleUrl, evalContext.Rule.Message))

	details := simplejson.New()
	details.Set("url", ruleUrl)
	if evalContext.ImagePublicUrl != "" {
		details.Set("image", evalContext.ImagePublicUrl)
	}

	bodyJSON.Set("details", details)
	body, _ := bodyJSON.MarshalJSON()

	cmd := &m.SendWebhookSync{
		Url:        opsgenieAlertURL,
		Body:       string(body),
		HttpMethod: "POST",
    		HttpHeader: map[string]string{
          		"Content-Type": "application/json",
      		"Authorization": fmt.Sprintf("GenieKey %s", this.ApiKey),
    		},
	}

	if err := bus.DispatchCtx(evalContext.Ctx, cmd); err != nil {
		this.log.Error("Failed to send notification to OpsGenie", "error", err, "body", string(body))
	}

	return nil
}

func (this *OpsGenieNotifier) closeAlert(evalContext *alerting.EvalContext) error {
	this.log.Info("Closing OpsGenie alert", "ruleId", evalContext.Rule.Id, "notification", this.Name)

	bodyJSON := simplejson.New()
	bodyJSON.Set("source", "Grafana")
	body, _ := bodyJSON.MarshalJSON()

	cmd := &m.SendWebhookSync{
		Url:        fmt.Sprintf("%s/alertId-%d/close?identifierType=alias", opsgenieAlertURL, evalContext.Rule.Id)
		Body:       string(body),
		HttpMethod: "POST",
    		HttpHeader: map[string]string{
          		"Content-Type": "application/json",
          		"Authorization": fmt.Sprintf("GenieKey %s", this.ApiKey),
    		},
	}

	if err := bus.DispatchCtx(evalContext.Ctx, cmd); err != nil {
		this.log.Error("Failed to send notification to OpsGenie", "error", err, "body", string(body))
		return err
	}

	return nil
}
<commit_msg>Add the missing comma<commit_after>package notifiers

import (
	"fmt"
	"strconv"

	"github.com/grafana/grafana/pkg/bus"
	"github.com/grafana/grafana/pkg/components/simplejson"
	"github.com/grafana/grafana/pkg/log"
	m "github.com/grafana/grafana/pkg/models"
	"github.com/grafana/grafana/pkg/services/alerting"
)

func init() {
	alerting.RegisterNotifier(&alerting.NotifierPlugin{
		Type:        "opsgenie",
		Name:        "OpsGenie",
		Description: "Sends notifications to OpsGenie",
		Factory:     NewOpsGenieNotifier,
		OptionsTemplate: `

OpsGenie settings

        API Key
        <input type="text" required class="gf-form-input max-width-22" ng-model="ctrl.model.settings.apiKey" placeholder="OpsGenie API Key"></input>

        <gf-form-switch
           class="gf-form"
           label="Auto close incidents"
           label-class="width-14"
           checked="ctrl.model.settings.autoClose"
           tooltip="Automatically close alerts in OpsGenie once the alert goes back to ok.">
        </gf-form-switch>

    `,
	})
}

var (
	opsgenieAlertURL string = "https://api.opsgenie.com/v2/alerts"
)

func NewOpsGenieNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
	autoClose := model.Settings.Get("autoClose").MustBool(true)
	apiKey := model.Settings.Get("apiKey").MustString()
	if apiKey == "" {
		return nil, alerting.ValidationError{Reason: "Could not find api key property in settings"}
	}

	return &OpsGenieNotifier{
		NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.Settings),
		ApiKey:       apiKey,
		AutoClose:    autoClose,
		log:          log.New("alerting.notifier.opsgenie"),
	}, nil
}

type OpsGenieNotifier struct {
	NotifierBase
	ApiKey    string
	AutoClose bool
	log       log.Logger
}

func (this *OpsGenieNotifier) Notify(evalContext *alerting.EvalContext) error {

	var err error
	switch evalContext.Rule.State {
	case m.AlertStateOK:
		if this.AutoClose {
			err = this.closeAlert(evalContext)
		}
	case m.AlertStateAlerting:
		err = this.createAlert(evalContext)
	}
	return err
}

func (this *OpsGenieNotifier) createAlert(evalContext *alerting.EvalContext) error {
	this.log.Info("Creating OpsGenie alert", "ruleId", evalContext.Rule.Id, "notification", this.Name)

	ruleUrl, err := evalContext.GetRuleUrl()
	if err != nil {
		this.log.Error("Failed get rule link", "error", err)
		return err
	}

	bodyJSON := simplejson.New()
	bodyJSON.Set("message", evalContext.Rule.Name)
	bodyJSON.Set("source", "Grafana")
	bodyJSON.Set("alias", "alertId-"+strconv.FormatInt(evalContext.Rule.Id, 10))
	bodyJSON.Set("description", fmt.Sprintf("%s - %s\n%s", evalContext.Rule.Name, ruleUrl, evalContext.Rule.Message))

	details := simplejson.New()
	details.Set("url", ruleUrl)
	if evalContext.ImagePublicUrl != "" {
		details.Set("image", evalContext.ImagePublicUrl)
	}

	bodyJSON.Set("details", details)
	body, _ := bodyJSON.MarshalJSON()

	cmd := &m.SendWebhookSync{
		Url:        opsgenieAlertURL,
		Body:       string(body),
		HttpMethod: "POST",
    		HttpHeader: map[string]string{
          		"Content-Type": "application/json",
      		"Authorization": fmt.Sprintf("GenieKey %s", this.ApiKey),
    		},
	}

	if err := bus.DispatchCtx(evalContext.Ctx, cmd); err != nil {
		this.log.Error("Failed to send notification to OpsGenie", "error", err, "body", string(body))
	}

	return nil
}

func (this *OpsGenieNotifier) closeAlert(evalContext *alerting.EvalContext) error {
	this.log.Info("Closing OpsGenie alert", "ruleId", evalContext.Rule.Id, "notification", this.Name)

	bodyJSON := simplejson.New()
	bodyJSON.Set("source", "Grafana")
	body, _ := bodyJSON.MarshalJSON()

	cmd := &m.SendWebhookSync{
		Url:        fmt.Sprintf("%s/alertId-%d/close?identifierType=alias", opsgenieAlertURL, evalContext.Rule.Id),
		Body:       string(body),
		HttpMethod: "POST",
    		HttpHeader: map[string]string{
          		"Content-Type": "application/json",
          		"Authorization": fmt.Sprintf("GenieKey %s", this.ApiKey),
    		},
	}

	if err := bus.DispatchCtx(evalContext.Ctx, cmd); err != nil {
		this.log.Error("Failed to send notification to OpsGenie", "error", err, "body", string(body))
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>// +build windows

package winconsole

import (
	"fmt"
	"testing"
)

func helpsTestParseInt16OrDefault(t *testing.T, expectedValue int16, shouldFail bool, input string, defaultValue int16, format string, args ...string) {
	value, err := parseInt16OrDefault(input, defaultValue)
	if nil != err && !shouldFail {
		t.Errorf("Unexpected error returned %v", err)
		t.Errorf(format, args)
	}
	if nil == err && shouldFail {
		t.Errorf("Should have failed as expected\n\tReturned value = %d", value)
		t.Errorf(format, args)
	}
	if expectedValue != value {
		t.Errorf("The value returned does not macth expected\n\tExpected:%v\n\t:Actual%v", expectedValue, value)
		t.Errorf(format, args)
	}
}

func TestParseInt16OrDefault(t *testing.T) {
	// empty string
	helpsTestParseInt16OrDefault(t, 0, false, "", 0, "Empty string returns default")
	helpsTestParseInt16OrDefault(t, 2, false, "", 2, "Empty string returns default")

	// normal case
	helpsTestParseInt16OrDefault(t, 0, false, "0", 0, "0 handled correctly")
	helpsTestParseInt16OrDefault(t, 111, false, "111", 2, "Normal")
	helpsTestParseInt16OrDefault(t, 111, false, "+111", 2, "+N")
	helpsTestParseInt16OrDefault(t, -111, false, "-111", 2, "-N")
	helpsTestParseInt16OrDefault(t, 0, false, "+0", 11, "+0")
	helpsTestParseInt16OrDefault(t, 0, false, "-0", 12, "-0")

	// ill formed strings
	helpsTestParseInt16OrDefault(t, 0, true, "abc", 0, "Invalid string")
	helpsTestParseInt16OrDefault(t, 42, true, "+= 23", 42, "Invalid string")
	helpsTestParseInt16OrDefault(t, 42, true, "123.45", 42, "float like")

}

func helpsTestGetNumberOfChars(t *testing.T, expected uint32, fromCoord COORD, toCoord COORD, screenSize COORD, format string, args ...interface{}) {
	actual := getNumberOfChars(fromCoord, toCoord, screenSize)
	mesg := fmt.Sprintf(format, args)
	assertTrue(t, expected == actual, fmt.Sprintf("%s Expected=%d, Actual=%d, Parameters = { fromCoord=%+v, toCoord=%+v, screenSize=%+v", mesg, expected, actual, fromCoord, toCoord, screenSize))
}

func TestGetNumberOfChars(t *testing.T) {
	// Note: The columns and lines are 0 based
	// Also that interval is "inclusive" means will have both start and end chars
	// This test only tests the number opf characters being written

	// all four corners
	maxWindow := COORD{X: 80, Y: 50}
	leftTop := COORD{X: 0, Y: 0}
	rightTop := COORD{X: 79, Y: 0}
	leftBottom := COORD{X: 0, Y: 49}
	rightBottom := COORD{X: 79, Y: 49}

	// same position
	helpsTestGetNumberOfChars(t, 1, COORD{X: 1, Y: 14}, COORD{X: 1, Y: 14}, COORD{X: 80, Y: 50}, "Same position random line")

	// four corners
	helpsTestGetNumberOfChars(t, 1, leftTop, leftTop, maxWindow, "Same position- leftTop")
	helpsTestGetNumberOfChars(t, 1, rightTop, rightTop, maxWindow, "Same position- rightTop")
	helpsTestGetNumberOfChars(t, 1, leftBottom, leftBottom, maxWindow, "Same position- leftBottom")
	helpsTestGetNumberOfChars(t, 1, rightBottom, rightBottom, maxWindow, "Same position- rightBottom")

	// from this char to next char on same line
	helpsTestGetNumberOfChars(t, 2, COORD{X: 0, Y: 0}, COORD{X: 1, Y: 0}, maxWindow, "Next position on same line")
	helpsTestGetNumberOfChars(t, 2, COORD{X: 1, Y: 14}, COORD{X: 2, Y: 14}, maxWindow, "Next position on same line")

	// from this char to next 10 chars on same line
	helpsTestGetNumberOfChars(t, 11, COORD{X: 0, Y: 0}, COORD{X: 10, Y: 0}, maxWindow, "Next position on same line")
	helpsTestGetNumberOfChars(t, 11, COORD{X: 1, Y: 14}, COORD{X: 11, Y: 14}, maxWindow, "Next position on same line")

	helpsTestGetNumberOfChars(t, 5, COORD{X: 3, Y: 11}, COORD{X: 7, Y: 11}, maxWindow, "To and from on same line")

	helpsTestGetNumberOfChars(t, 8, COORD{X: 0, Y: 34}, COORD{X: 7, Y: 34}, maxWindow, "Start of line to middle")
	helpsTestGetNumberOfChars(t, 4, COORD{X: 76, Y: 34}, COORD{X: 79, Y: 34}, maxWindow, "Middle to end of line")

	// multiple lines - 1
	helpsTestGetNumberOfChars(t, 81, COORD{X: 0, Y: 0}, COORD{X: 0, Y: 1}, maxWindow, "one line below same X")
	helpsTestGetNumberOfChars(t, 81, COORD{X: 10, Y: 10}, COORD{X: 10, Y: 11}, maxWindow, "one line below same X")

	// multiple lines - 2
	helpsTestGetNumberOfChars(t, 161, COORD{X: 0, Y: 0}, COORD{X: 0, Y: 2}, maxWindow, "one line below same X")
	helpsTestGetNumberOfChars(t, 161, COORD{X: 10, Y: 10}, COORD{X: 10, Y: 12}, maxWindow, "one line below same X")

	// multiple lines - 3
	helpsTestGetNumberOfChars(t, 241, COORD{X: 0, Y: 0}, COORD{X: 0, Y: 3}, maxWindow, "one line below same X")
	helpsTestGetNumberOfChars(t, 241, COORD{X: 10, Y: 10}, COORD{X: 10, Y: 13}, maxWindow, "one line below same X")

	// full line
	helpsTestGetNumberOfChars(t, 80, COORD{X: 0, Y: 0}, COORD{X: 79, Y: 0}, maxWindow, "Full line - first")
	helpsTestGetNumberOfChars(t, 80, COORD{X: 0, Y: 23}, COORD{X: 79, Y: 23}, maxWindow, "Full line - random")
	helpsTestGetNumberOfChars(t, 80, COORD{X: 0, Y: 49}, COORD{X: 79, Y: 49}, maxWindow, "Full line - last")

	// full screen
	helpsTestGetNumberOfChars(t, 80*50, leftTop, rightBottom, maxWindow, "full screen")

	helpsTestGetNumberOfChars(t, 80*50-1, COORD{X: 1, Y: 0}, rightBottom, maxWindow, "dropping first char to, end of screen")
	helpsTestGetNumberOfChars(t, 80*50-2, COORD{X: 2, Y: 0}, rightBottom, maxWindow, "dropping first two char to, end of screen")

	helpsTestGetNumberOfChars(t, 80*50-1, leftTop, COORD{X: 78, Y: 49}, maxWindow, "from start of screen, till last char-1")
	helpsTestGetNumberOfChars(t, 80*50-2, leftTop, COORD{X: 77, Y: 49}, maxWindow, "from start of screen, till last char-2")

	helpsTestGetNumberOfChars(t, 80*50-5, COORD{X: 4, Y: 0}, COORD{X: 78, Y: 49}, COORD{X: 80, Y: 50}, "from start of screen+4, till last char-1")
	helpsTestGetNumberOfChars(t, 80*50-6, COORD{X: 4, Y: 0}, COORD{X: 77, Y: 49}, COORD{X: 80, Y: 50}, "from start of screen+4, till last char-2")
}

var allForeground = []int16{
	ANSI_FOREGROUND_BLACK,
	ANSI_FOREGROUND_RED,
	ANSI_FOREGROUND_GREEN,
	ANSI_FOREGROUND_YELLOW,
	ANSI_FOREGROUND_BLUE,
	ANSI_FOREGROUND_MAGENTA,
	ANSI_FOREGROUND_CYAN,
	ANSI_FOREGROUND_WHITE,
	ANSI_FOREGROUND_DEFAULT,
}
var allBackground = []int16{
	ANSI_BACKGROUND_BLACK,
	ANSI_BACKGROUND_RED,
	ANSI_BACKGROUND_GREEN,
	ANSI_BACKGROUND_YELLOW,
	ANSI_BACKGROUND_BLUE,
	ANSI_BACKGROUND_MAGENTA,
	ANSI_BACKGROUND_CYAN,
	ANSI_BACKGROUND_WHITE,
	ANSI_BACKGROUND_DEFAULT,
}

func maskForeground(flag WORD) WORD {
	return flag & FOREGROUND_MASK_UNSET
}

func onlyForeground(flag WORD) WORD {
	return flag & FOREGROUND_MASK_SET
}

func maskBackground(flag WORD) WORD {
	return flag & BACKGROUND_MASK_UNSET
}

func onlyBackground(flag WORD) WORD {
	return flag & BACKGROUND_MASK_SET
}

func helpsTestGetWindowsTextAttributeForAnsiValue(t *testing.T, oldValue WORD /*, expected WORD*/, ansi int16, onlyMask WORD, restMask WORD) WORD {
	actual, err := getWindowsTextAttributeForAnsiValue(oldValue, FOREGROUND_MASK_SET, ansi)
	assertTrue(t, nil == err, "Should be no error")
	// assert that other bits are not affected
	if 0 != oldValue {
		assertTrue(t, (actual&restMask) == (oldValue&restMask), "The operation should not have affected other bits actual=%X oldValue=%X ansi=%d", actual, oldValue, ansi)
	}
	return actual
}

func TestBackgroundForAnsiValue(t *testing.T) {
	// Check that nothing else changes
	// background changes
	for _, state1 := range allBackground {
		for _, state2 := range allBackground {
			flag := WORD(0)
			flag = helpsTestGetWindowsTextAttributeForAnsiValue(t, flag, state1, BACKGROUND_MASK_SET, BACKGROUND_MASK_UNSET)
			flag = helpsTestGetWindowsTextAttributeForAnsiValue(t, flag, state2, BACKGROUND_MASK_SET, BACKGROUND_MASK_UNSET)
		}
	}
	// cummulative bcakground changes
	for _, state1 := range allBackground {
		flag := WORD(0)
		for _, state2 := range allBackground {
			flag = helpsTestGetWindowsTextAttributeForAnsiValue(t, flag, state1, BACKGROUND_MASK_SET, BACKGROUND_MASK_UNSET)
			flag = helpsTestGetWindowsTextAttributeForAnsiValue(t, flag, state2, BACKGROUND_MASK_SET, BACKGROUND_MASK_UNSET)
		}
	}
	// change background after foreground
	for _, state1 := range allForeground {
		for _, state2 := range allBackground {
			flag := WORD(0)
			flag = helpsTestGetWindowsTextAttributeForAnsiValue(t, flag, state1, FOREGROUND_MASK_SET, FOREGROUND_MASK_UNSET)
			flag = helpsTestGetWindowsTextAttributeForAnsiValue(t, flag, state2, BACKGROUND_MASK_SET, BACKGROUND_MASK_UNSET)
		}
	}
	// change background after change cumulative
	for _, state1 := range allForeground {
		flag := WORD(0)
		for _, state2 := range allBackground {
			flag = helpsTestGetWindowsTextAttributeForAnsiValue(t, flag, state1, FOREGROUND_MASK_SET, FOREGROUND_MASK_UNSET)
			flag = helpsTestGetWindowsTextAttributeForAnsiValue(t, flag, state2, BACKGROUND_MASK_SET, BACKGROUND_MASK_UNSET)
		}
	}
}

func TestForegroundForAnsiValue(t *testing.T) {
	// Check that nothing else changes
	for _, state1 := range allForeground {
		for _, state2 := range allForeground {
			flag := WORD(0)
			flag = helpsTestGetWindowsTextAttributeForAnsiValue(t, flag, state1, FOREGROUND_MASK_SET, FOREGROUND_MASK_UNSET)
			flag = helpsTestGetWindowsTextAttributeForAnsiValue(t, flag, state2, FOREGROUND_MASK_SET, FOREGROUND_MASK_UNSET)
		}
	}

	for _, state1 := range allForeground {
		flag := WORD(0)
		for _, state2 := range allForeground {
			flag = helpsTestGetWindowsTextAttributeForAnsiValue(t, flag, state1, FOREGROUND_MASK_SET, FOREGROUND_MASK_UNSET)
			flag = helpsTestGetWindowsTextAttributeForAnsiValue(t, flag, state2, FOREGROUND_MASK_SET, FOREGROUND_MASK_UNSET)
		}
	}
	for _, state1 := range allBackground {
		for _, state2 := range allForeground {
			flag := WORD(0)
			flag = helpsTestGetWindowsTextAttributeForAnsiValue(t, flag, state1, BACKGROUND_MASK_SET, BACKGROUND_MASK_UNSET)
			flag = helpsTestGetWindowsTextAttributeForAnsiValue(t, flag, state2, FOREGROUND_MASK_SET, FOREGROUND_MASK_UNSET)
		}
	}
	for _, state1 := range allBackground {
		flag := WORD(0)
		for _, state2 := range allForeground {
			flag = helpsTestGetWindowsTextAttributeForAnsiValue(t, flag, state1, BACKGROUND_MASK_SET, BACKGROUND_MASK_UNSET)
			flag = helpsTestGetWindowsTextAttributeForAnsiValue(t, flag, state2, FOREGROUND_MASK_SET, FOREGROUND_MASK_UNSET)
		}
	}
}
<commit_msg>trivial: typo cleanup<commit_after>// +build windows

package winconsole

import (
	"fmt"
	"testing"
)

func helpsTestParseInt16OrDefault(t *testing.T, expectedValue int16, shouldFail bool, input string, defaultValue int16, format string, args ...string) {
	value, err := parseInt16OrDefault(input, defaultValue)
	if nil != err && !shouldFail {
		t.Errorf("Unexpected error returned %v", err)
		t.Errorf(format, args)
	}
	if nil == err && shouldFail {
		t.Errorf("Should have failed as expected\n\tReturned value = %d", value)
		t.Errorf(format, args)
	}
	if expectedValue != value {
		t.Errorf("The value returned does not match expected\n\tExpected:%v\n\t:Actual%v", expectedValue, value)
		t.Errorf(format, args)
	}
}

func TestParseInt16OrDefault(t *testing.T) {
	// empty string
	helpsTestParseInt16OrDefault(t, 0, false, "", 0, "Empty string returns default")
	helpsTestParseInt16OrDefault(t, 2, false, "", 2, "Empty string returns default")

	// normal case
	helpsTestParseInt16OrDefault(t, 0, false, "0", 0, "0 handled correctly")
	helpsTestParseInt16OrDefault(t, 111, false, "111", 2, "Normal")
	helpsTestParseInt16OrDefault(t, 111, false, "+111", 2, "+N")
	helpsTestParseInt16OrDefault(t, -111, false, "-111", 2, "-N")
	helpsTestParseInt16OrDefault(t, 0, false, "+0", 11, "+0")
	helpsTestParseInt16OrDefault(t, 0, false, "-0", 12, "-0")

	// ill formed strings
	helpsTestParseInt16OrDefault(t, 0, true, "abc", 0, "Invalid string")
	helpsTestParseInt16OrDefault(t, 42, true, "+= 23", 42, "Invalid string")
	helpsTestParseInt16OrDefault(t, 42, true, "123.45", 42, "float like")

}

func helpsTestGetNumberOfChars(t *testing.T, expected uint32, fromCoord COORD, toCoord COORD, screenSize COORD, format string, args ...interface{}) {
	actual := getNumberOfChars(fromCoord, toCoord, screenSize)
	mesg := fmt.Sprintf(format, args)
	assertTrue(t, expected == actual, fmt.Sprintf("%s Expected=%d, Actual=%d, Parameters = { fromCoord=%+v, toCoord=%+v, screenSize=%+v", mesg, expected, actual, fromCoord, toCoord, screenSize))
}

func TestGetNumberOfChars(t *testing.T) {
	// Note: The columns and lines are 0 based
	// Also that interval is "inclusive" means will have both start and end chars
	// This test only tests the number opf characters being written

	// all four corners
	maxWindow := COORD{X: 80, Y: 50}
	leftTop := COORD{X: 0, Y: 0}
	rightTop := COORD{X: 79, Y: 0}
	leftBottom := COORD{X: 0, Y: 49}
	rightBottom := COORD{X: 79, Y: 49}

	// same position
	helpsTestGetNumberOfChars(t, 1, COORD{X: 1, Y: 14}, COORD{X: 1, Y: 14}, COORD{X: 80, Y: 50}, "Same position random line")

	// four corners
	helpsTestGetNumberOfChars(t, 1, leftTop, leftTop, maxWindow, "Same position- leftTop")
	helpsTestGetNumberOfChars(t, 1, rightTop, rightTop, maxWindow, "Same position- rightTop")
	helpsTestGetNumberOfChars(t, 1, leftBottom, leftBottom, maxWindow, "Same position- leftBottom")
	helpsTestGetNumberOfChars(t, 1, rightBottom, rightBottom, maxWindow, "Same position- rightBottom")

	// from this char to next char on same line
	helpsTestGetNumberOfChars(t, 2, COORD{X: 0, Y: 0}, COORD{X: 1, Y: 0}, maxWindow, "Next position on same line")
	helpsTestGetNumberOfChars(t, 2, COORD{X: 1, Y: 14}, COORD{X: 2, Y: 14}, maxWindow, "Next position on same line")

	// from this char to next 10 chars on same line
	helpsTestGetNumberOfChars(t, 11, COORD{X: 0, Y: 0}, COORD{X: 10, Y: 0}, maxWindow, "Next position on same line")
	helpsTestGetNumberOfChars(t, 11, COORD{X: 1, Y: 14}, COORD{X: 11, Y: 14}, maxWindow, "Next position on same line")

	helpsTestGetNumberOfChars(t, 5, COORD{X: 3, Y: 11}, COORD{X: 7, Y: 11}, maxWindow, "To and from on same line")

	helpsTestGetNumberOfChars(t, 8, COORD{X: 0, Y: 34}, COORD{X: 7, Y: 34}, maxWindow, "Start of line to middle")
	helpsTestGetNumberOfChars(t, 4, COORD{X: 76, Y: 34}, COORD{X: 79, Y: 34}, maxWindow, "Middle to end of line")

	// multiple lines - 1
	helpsTestGetNumberOfChars(t, 81, COORD{X: 0, Y: 0}, COORD{X: 0, Y: 1}, maxWindow, "one line below same X")
	helpsTestGetNumberOfChars(t, 81, COORD{X: 10, Y: 10}, COORD{X: 10, Y: 11}, maxWindow, "one line below same X")

	// multiple lines - 2
	helpsTestGetNumberOfChars(t, 161, COORD{X: 0, Y: 0}, COORD{X: 0, Y: 2}, maxWindow, "one line below same X")
	helpsTestGetNumberOfChars(t, 161, COORD{X: 10, Y: 10}, COORD{X: 10, Y: 12}, maxWindow, "one line below same X")

	// multiple lines - 3
	helpsTestGetNumberOfChars(t, 241, COORD{X: 0, Y: 0}, COORD{X: 0, Y: 3}, maxWindow, "one line below same X")
	helpsTestGetNumberOfChars(t, 241, COORD{X: 10, Y: 10}, COORD{X: 10, Y: 13}, maxWindow, "one line below same X")

	// full line
	helpsTestGetNumberOfChars(t, 80, COORD{X: 0, Y: 0}, COORD{X: 79, Y: 0}, maxWindow, "Full line - first")
	helpsTestGetNumberOfChars(t, 80, COORD{X: 0, Y: 23}, COORD{X: 79, Y: 23}, maxWindow, "Full line - random")
	helpsTestGetNumberOfChars(t, 80, COORD{X: 0, Y: 49}, COORD{X: 79, Y: 49}, maxWindow, "Full line - last")

	// full screen
	helpsTestGetNumberOfChars(t, 80*50, leftTop, rightBottom, maxWindow, "full screen")

	helpsTestGetNumberOfChars(t, 80*50-1, COORD{X: 1, Y: 0}, rightBottom, maxWindow, "dropping first char to, end of screen")
	helpsTestGetNumberOfChars(t, 80*50-2, COORD{X: 2, Y: 0}, rightBottom, maxWindow, "dropping first two char to, end of screen")

	helpsTestGetNumberOfChars(t, 80*50-1, leftTop, COORD{X: 78, Y: 49}, maxWindow, "from start of screen, till last char-1")
	helpsTestGetNumberOfChars(t, 80*50-2, leftTop, COORD{X: 77, Y: 49}, maxWindow, "from start of screen, till last char-2")

	helpsTestGetNumberOfChars(t, 80*50-5, COORD{X: 4, Y: 0}, COORD{X: 78, Y: 49}, COORD{X: 80, Y: 50}, "from start of screen+4, till last char-1")
	helpsTestGetNumberOfChars(t, 80*50-6, COORD{X: 4, Y: 0}, COORD{X: 77, Y: 49}, COORD{X: 80, Y: 50}, "from start of screen+4, till last char-2")
}

var allForeground = []int16{
	ANSI_FOREGROUND_BLACK,
	ANSI_FOREGROUND_RED,
	ANSI_FOREGROUND_GREEN,
	ANSI_FOREGROUND_YELLOW,
	ANSI_FOREGROUND_BLUE,
	ANSI_FOREGROUND_MAGENTA,
	ANSI_FOREGROUND_CYAN,
	ANSI_FOREGROUND_WHITE,
	ANSI_FOREGROUND_DEFAULT,
}
var allBackground = []int16{
	ANSI_BACKGROUND_BLACK,
	ANSI_BACKGROUND_RED,
	ANSI_BACKGROUND_GREEN,
	ANSI_BACKGROUND_YELLOW,
	ANSI_BACKGROUND_BLUE,
	ANSI_BACKGROUND_MAGENTA,
	ANSI_BACKGROUND_CYAN,
	ANSI_BACKGROUND_WHITE,
	ANSI_BACKGROUND_DEFAULT,
}

func maskForeground(flag WORD) WORD {
	return flag & FOREGROUND_MASK_UNSET
}

func onlyForeground(flag WORD) WORD {
	return flag & FOREGROUND_MASK_SET
}

func maskBackground(flag WORD) WORD {
	return flag & BACKGROUND_MASK_UNSET
}

func onlyBackground(flag WORD) WORD {
	return flag & BACKGROUND_MASK_SET
}

func helpsTestGetWindowsTextAttributeForAnsiValue(t *testing.T, oldValue WORD /*, expected WORD*/, ansi int16, onlyMask WORD, restMask WORD) WORD {
	actual, err := getWindowsTextAttributeForAnsiValue(oldValue, FOREGROUND_MASK_SET, ansi)
	assertTrue(t, nil == err, "Should be no error")
	// assert that other bits are not affected
	if 0 != oldValue {
		assertTrue(t, (actual&restMask) == (oldValue&restMask), "The operation should not have affected other bits actual=%X oldValue=%X ansi=%d", actual, oldValue, ansi)
	}
	return actual
}

func TestBackgroundForAnsiValue(t *testing.T) {
	// Check that nothing else changes
	// background changes
	for _, state1 := range allBackground {
		for _, state2 := range allBackground {
			flag := WORD(0)
			flag = helpsTestGetWindowsTextAttributeForAnsiValue(t, flag, state1, BACKGROUND_MASK_SET, BACKGROUND_MASK_UNSET)
			flag = helpsTestGetWindowsTextAttributeForAnsiValue(t, flag, state2, BACKGROUND_MASK_SET, BACKGROUND_MASK_UNSET)
		}
	}
	// cummulative bcakground changes
	for _, state1 := range allBackground {
		flag := WORD(0)
		for _, state2 := range allBackground {
			flag = helpsTestGetWindowsTextAttributeForAnsiValue(t, flag, state1, BACKGROUND_MASK_SET, BACKGROUND_MASK_UNSET)
			flag = helpsTestGetWindowsTextAttributeForAnsiValue(t, flag, state2, BACKGROUND_MASK_SET, BACKGROUND_MASK_UNSET)
		}
	}
	// change background after foreground
	for _, state1 := range allForeground {
		for _, state2 := range allBackground {
			flag := WORD(0)
			flag = helpsTestGetWindowsTextAttributeForAnsiValue(t, flag, state1, FOREGROUND_MASK_SET, FOREGROUND_MASK_UNSET)
			flag = helpsTestGetWindowsTextAttributeForAnsiValue(t, flag, state2, BACKGROUND_MASK_SET, BACKGROUND_MASK_UNSET)
		}
	}
	// change background after change cumulative
	for _, state1 := range allForeground {
		flag := WORD(0)
		for _, state2 := range allBackground {
			flag = helpsTestGetWindowsTextAttributeForAnsiValue(t, flag, state1, FOREGROUND_MASK_SET, FOREGROUND_MASK_UNSET)
			flag = helpsTestGetWindowsTextAttributeForAnsiValue(t, flag, state2, BACKGROUND_MASK_SET, BACKGROUND_MASK_UNSET)
		}
	}
}

func TestForegroundForAnsiValue(t *testing.T) {
	// Check that nothing else changes
	for _, state1 := range allForeground {
		for _, state2 := range allForeground {
			flag := WORD(0)
			flag = helpsTestGetWindowsTextAttributeForAnsiValue(t, flag, state1, FOREGROUND_MASK_SET, FOREGROUND_MASK_UNSET)
			flag = helpsTestGetWindowsTextAttributeForAnsiValue(t, flag, state2, FOREGROUND_MASK_SET, FOREGROUND_MASK_UNSET)
		}
	}

	for _, state1 := range allForeground {
		flag := WORD(0)
		for _, state2 := range allForeground {
			flag = helpsTestGetWindowsTextAttributeForAnsiValue(t, flag, state1, FOREGROUND_MASK_SET, FOREGROUND_MASK_UNSET)
			flag = helpsTestGetWindowsTextAttributeForAnsiValue(t, flag, state2, FOREGROUND_MASK_SET, FOREGROUND_MASK_UNSET)
		}
	}
	for _, state1 := range allBackground {
		for _, state2 := range allForeground {
			flag := WORD(0)
			flag = helpsTestGetWindowsTextAttributeForAnsiValue(t, flag, state1, BACKGROUND_MASK_SET, BACKGROUND_MASK_UNSET)
			flag = helpsTestGetWindowsTextAttributeForAnsiValue(t, flag, state2, FOREGROUND_MASK_SET, FOREGROUND_MASK_UNSET)
		}
	}
	for _, state1 := range allBackground {
		flag := WORD(0)
		for _, state2 := range allForeground {
			flag = helpsTestGetWindowsTextAttributeForAnsiValue(t, flag, state1, BACKGROUND_MASK_SET, BACKGROUND_MASK_UNSET)
			flag = helpsTestGetWindowsTextAttributeForAnsiValue(t, flag, state2, FOREGROUND_MASK_SET, FOREGROUND_MASK_UNSET)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2011-2015 visualfc <visualfc@gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package jsonfmt

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

	"github.com/visualfc/gotools/pkg/command"
)

var Command = &command.Command{
	Run:       runJsonFmt,
	UsageLine: "jsonfmt",
	Short:     "json format util",
	Long:      `json format util.`,
}

var (
	jsonFmtList    bool
	jsonFmtCompact bool
	jsonFmtWrite   bool
	jsonFmtDiff    bool
	jsonTabWidth   int
	jsonTabIndent  bool
)

func init() {
	Command.Flag.BoolVar(&jsonFmtList, "l", false, "list files whose formatting differs")
	Command.Flag.BoolVar(&jsonFmtCompact, "c", false, "compact json")
	Command.Flag.BoolVar(&jsonFmtWrite, "w", false, "write result to (source) file instead of stdout")
	Command.Flag.BoolVar(&jsonFmtDiff, "d", false, "display diffs instead of rewriting files")
	Command.Flag.IntVar(&jsonTabWidth, "tabwidth", 4, "tab width")
	Command.Flag.BoolVar(&jsonTabIndent, "tabs", false, "indent with tabs")
}

func runJsonFmt(cmd *command.Command, args []string) error {
	opt := &JsonFmtOption{}
	opt.List = jsonFmtList
	opt.Compact = jsonFmtCompact
	opt.IndentTab = jsonTabIndent
	opt.TabWidth = jsonTabWidth
	opt.Write = jsonFmtWrite
	opt.Diff = jsonFmtDiff

	if len(args) == 0 {
		if err := processJsonFile("<standard input>", cmd.Stdin, cmd.Stdout, true, opt); err != nil {
			return err
		}
	} else {
		for _, path := range args {
			switch dir, err := os.Stat(path); {
			case err != nil:
				reportJsonError(err)
			case dir.IsDir():
				filepath.Walk(path, func(path string, f os.FileInfo, err error) error {
					if err == nil && isJsonFile(f) {
						err = processJsonFile(path, nil, cmd.Stdout, false, opt)
					}
					if err != nil {
						reportJsonError(err)
					}
					return nil
				})
			default:
				if err := processJsonFile(path, nil, cmd.Stdout, false, opt); err != nil {
					reportJsonError(err)
				}
			}
		}
	}
	return nil
}

type JsonFmtOption struct {
	List      bool
	Compact   bool
	Format    bool
	Write     bool
	Diff      bool
	IndentTab bool
	TabWidth  int
}

func isJsonFile(f os.FileInfo) bool {
	// ignore non-Go files
	name := f.Name()
	return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".json")
}

func reportJsonError(err error) {
	fmt.Fprintf(os.Stderr, "%s\n", err)
}

func processJson(filename string, src []byte, opt *JsonFmtOption) ([]byte, error) {
	if opt.Compact {
		var out bytes.Buffer
		err := json.Compact(&out, src)
		if err != nil {
			return nil, err
		}
		return out.Bytes(), nil
	} else {
		var out bytes.Buffer
		var err error
		if opt.IndentTab {
			err = json.Indent(&out, src, "", "\t")
		} else {
			var indent string
			for i := 0; i < opt.TabWidth; i++ {
				indent += " "
			}
			err = json.Indent(&out, src, "", indent)
		}
		if err != nil {
			return nil, err
		}
		return out.Bytes(), nil
	}
	return src, nil
}

func processJsonFile(filename string, in io.Reader, out io.Writer, stdin bool, opt *JsonFmtOption) error {
	if in == nil {
		f, err := os.Open(filename)
		if err != nil {
			return err
		}
		defer f.Close()
		in = f
	}

	src, err := ioutil.ReadAll(in)
	if err != nil {
		return err
	}

	res, err := processJson(filename, src, opt)
	if err != nil {
		return err
	}

	if !bytes.Equal(src, res) {
		// formatting has changed
		if opt.List {
			fmt.Fprintln(out, filename)
		}
		if opt.Write {
			err = ioutil.WriteFile(filename, res, 0)
			if err != nil {
				return err
			}
		}
		if opt.Diff {
			data, err := diffJson(src, res)
			if err != nil {
				return fmt.Errorf("computing diff: %s", err)
			}
			fmt.Fprintf(out, "diff %s json/%s\n", filename, filename)
			out.Write(data)
		}
	}

	if !opt.List && !opt.Write && !opt.Diff {
		_, err = out.Write(res)
	}

	return err
}

func diffJson(b1, b2 []byte) (data []byte, err error) {
	f1, err := ioutil.TempFile("", "json")
	if err != nil {
		return
	}
	defer os.Remove(f1.Name())
	defer f1.Close()

	f2, err := ioutil.TempFile("", "json")
	if err != nil {
		return
	}
	defer os.Remove(f2.Name())
	defer f2.Close()

	f1.Write(b1)
	f2.Write(b2)

	data, err = exec.Command("diff", "-u", f1.Name(), f2.Name()).CombinedOutput()
	if len(data) > 0 {
		// diff exits with a non-zero status when the files don't match.
		// Ignore that failure as long as we get output.
		err = nil
	}
	return
}
<commit_msg>jsonfmt: use godiff lib<commit_after>// Copyright 2011-2015 visualfc <visualfc@gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package jsonfmt

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

	"github.com/visualfc/gotools/pkg/command"
	"github.com/visualfc/gotools/pkg/godiff"
)

var Command = &command.Command{
	Run:       runJsonFmt,
	UsageLine: "jsonfmt",
	Short:     "json format util",
	Long:      `json format util.`,
}

var (
	jsonFmtList    bool
	jsonFmtCompact bool
	jsonFmtWrite   bool
	jsonFmtDiff    bool
	jsonTabWidth   int
	jsonTabIndent  bool
)

func init() {
	Command.Flag.BoolVar(&jsonFmtList, "l", false, "list files whose formatting differs")
	Command.Flag.BoolVar(&jsonFmtCompact, "c", false, "compact json")
	Command.Flag.BoolVar(&jsonFmtWrite, "w", false, "write result to (source) file instead of stdout")
	Command.Flag.BoolVar(&jsonFmtDiff, "d", false, "display diffs instead of rewriting files")
	Command.Flag.IntVar(&jsonTabWidth, "tabwidth", 4, "tab width")
	Command.Flag.BoolVar(&jsonTabIndent, "tabs", false, "indent with tabs")
}

func runJsonFmt(cmd *command.Command, args []string) error {
	opt := &JsonFmtOption{}
	opt.List = jsonFmtList
	opt.Compact = jsonFmtCompact
	opt.IndentTab = jsonTabIndent
	opt.TabWidth = jsonTabWidth
	opt.Write = jsonFmtWrite
	opt.Diff = jsonFmtDiff

	if len(args) == 0 {
		if err := processJsonFile("<standard input>", cmd.Stdin, cmd.Stdout, true, opt); err != nil {
			return err
		}
	} else {
		for _, path := range args {
			switch dir, err := os.Stat(path); {
			case err != nil:
				reportJsonError(err)
			case dir.IsDir():
				filepath.Walk(path, func(path string, f os.FileInfo, err error) error {
					if err == nil && isJsonFile(f) {
						err = processJsonFile(path, nil, cmd.Stdout, false, opt)
					}
					if err != nil {
						reportJsonError(err)
					}
					return nil
				})
			default:
				if err := processJsonFile(path, nil, cmd.Stdout, false, opt); err != nil {
					reportJsonError(err)
				}
			}
		}
	}
	return nil
}

type JsonFmtOption struct {
	List      bool
	Compact   bool
	Format    bool
	Write     bool
	Diff      bool
	IndentTab bool
	TabWidth  int
}

func isJsonFile(f os.FileInfo) bool {
	// ignore non-Go files
	name := f.Name()
	return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".json")
}

func reportJsonError(err error) {
	fmt.Fprintf(os.Stderr, "%s\n", err)
}

func processJson(filename string, src []byte, opt *JsonFmtOption) ([]byte, error) {
	if opt.Compact {
		var out bytes.Buffer
		err := json.Compact(&out, src)
		if err != nil {
			return nil, err
		}
		return out.Bytes(), nil
	} else {
		var out bytes.Buffer
		var err error
		if opt.IndentTab {
			err = json.Indent(&out, src, "", "\t")
		} else {
			var indent string
			for i := 0; i < opt.TabWidth; i++ {
				indent += " "
			}
			err = json.Indent(&out, src, "", indent)
		}
		if err != nil {
			return nil, err
		}
		return out.Bytes(), nil
	}
	return src, nil
}

func processJsonFile(filename string, in io.Reader, out io.Writer, stdin bool, opt *JsonFmtOption) error {
	if in == nil {
		f, err := os.Open(filename)
		if err != nil {
			return err
		}
		defer f.Close()
		in = f
	}

	src, err := ioutil.ReadAll(in)
	if err != nil {
		return err
	}

	res, err := processJson(filename, src, opt)
	if err != nil {
		return err
	}

	if !bytes.Equal(src, res) {
		// formatting has changed
		if opt.List {
			fmt.Fprintln(out, filename)
		}
		if opt.Write {
			err = ioutil.WriteFile(filename, res, 0)
			if err != nil {
				return err
			}
		}
		if opt.Diff {
			data, err := diffJson(src, res)
			if err != nil {
				return fmt.Errorf("computing diff: %s", err)
			}
			fmt.Fprintf(out, "diff %s json/%s\n", filename, filename)
			out.Write(data)
		}
	}

	if !opt.List && !opt.Write && !opt.Diff {
		_, err = out.Write(res)
	}

	return err
}

func diffJson(src, res []byte) (data []byte, err error) {
	var dataTmp string // because godiff.UnifiedDiffString returns string
	dataTmp, err = godiff.UnifiedDiffString(string(src), string(res))
	data = []byte(dataTmp)
	return
}
<|endoftext|>


<commit_before>/*
 * Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
 *
 * 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.
 *
 * @author		Aeneas Rekkas <aeneas+oss@aeneas.io>
 * @copyright 	2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
 * @license 	Apache-2.0
 */

package jwk

import (
	"encoding/json"
	"time"

	"context"

	"github.com/jmoiron/sqlx"
	"github.com/ory/hydra/pkg"
	"github.com/ory/sqlcon"
	"github.com/pkg/errors"
	"github.com/rubenv/sql-migrate"
	"gopkg.in/square/go-jose.v2"
)

type SQLManager struct {
	DB     *sqlx.DB
	Cipher *AEAD
}

func NewSQLManager(db *sqlx.DB, key []byte) *SQLManager {
	return &SQLManager{DB: db, Cipher: &AEAD{Key: key}}
}

var Migrations = &migrate.MemoryMigrationSource{
	Migrations: []*migrate.Migration{
		{
			Id: "1",
			Up: []string{
				`CREATE TABLE IF NOT EXISTS hydra_jwk (
	sid     varchar(255) NOT NULL,
	kid 	varchar(255) NOT NULL,
	version int NOT NULL DEFAULT 0,
	keydata text NOT NULL,
	PRIMARY KEY (sid, kid)
)`,
			},
			Down: []string{
				"DROP TABLE hydra_jwk",
			},
		},
		{
			Id: "2",
			Up: []string{
				`ALTER TABLE hydra_jwk ADD created_at TIMESTAMP NOT NULL DEFAULT NOW()`,
			},
			Down: []string{
				`ALTER TABLE hydra_jwk DROP COLUMN created_at`,
			},
		},
		// See https://github.com/ory/hydra/issues/921
		{
			Id: "3",
			Up: []string{
				`DELETE FROM hydra_jwk WHERE sid='hydra.openid.id-token'`,
			},
			Down: []string{},
		},
	},
}

type sqlData struct {
	Set       string    `db:"sid"`
	KID       string    `db:"kid"`
	Version   int       `db:"version"`
	CreatedAt time.Time `db:"created_at"`
	Key       string    `db:"keydata"`
}

func (m *SQLManager) CreateSchemas() (int, error) {
	migrate.SetTable("hydra_jwk_migration")
	n, err := migrate.Exec(m.DB.DB, m.DB.DriverName(), Migrations, migrate.Up)
	if err != nil {
		return 0, errors.Wrapf(err, "Could not migrate sql schema, applied %d Migrations", n)
	}
	return n, nil
}

func (m *SQLManager) AddKey(ctx context.Context, set string, key *jose.JSONWebKey) error {
	out, err := json.Marshal(key)
	if err != nil {
		return errors.WithStack(err)
	}

	encrypted, err := m.Cipher.Encrypt(out)
	if err != nil {
		return errors.WithStack(err)
	}

	if _, err = m.DB.NamedExec(`INSERT INTO hydra_jwk (sid, kid, version, keydata) VALUES (:sid, :kid, :version, :keydata)`, &sqlData{
		Set:     set,
		KID:     key.KeyID,
		Version: 0,
		Key:     encrypted,
	}); err != nil {
		return sqlcon.HandleError(err)
	}
	return nil
}

func (m *SQLManager) AddKeySet(ctx context.Context, set string, keys *jose.JSONWebKeySet) error {
	tx, err := m.DB.Beginx()
	if err != nil {
		return errors.WithStack(err)
	}

	if err := m.addKeySet(ctx, tx, m.Cipher, set, keys); err != nil {
		if re := tx.Rollback(); re != nil {
			return errors.Wrap(err, re.Error())
		}
		return sqlcon.HandleError(err)
	}

	if err := tx.Commit(); err != nil {
		if re := tx.Rollback(); re != nil {
			return errors.Wrap(err, re.Error())
		}
		return sqlcon.HandleError(err)
	}
	return nil
}

func (m *SQLManager) addKeySet(ctx context.Context, tx *sqlx.Tx, cipher *AEAD, set string, keys *jose.JSONWebKeySet) error {
	for _, key := range keys.Keys {
		out, err := json.Marshal(key)
		if err != nil {
			return errors.WithStack(err)
		}

		encrypted, err := cipher.Encrypt(out)
		if err != nil {
			return errors.WithStack(err)
		}

		if _, err = tx.NamedExec(`INSERT INTO hydra_jwk (sid, kid, version, keydata) VALUES (:sid, :kid, :version, :keydata)`, &sqlData{
			Set:     set,
			KID:     key.KeyID,
			Version: 0,
			Key:     encrypted,
		}); err != nil {
			return sqlcon.HandleError(err)
		}
	}

	return nil
}

func (m *SQLManager) GetKey(ctx context.Context, set, kid string) (*jose.JSONWebKeySet, error) {
	var d sqlData
	if err := m.DB.Get(&d, m.DB.Rebind("SELECT * FROM hydra_jwk WHERE sid=? AND kid=? ORDER BY created_at DESC"), set, kid); err != nil {
		return nil, sqlcon.HandleError(err)
	}

	key, err := m.Cipher.Decrypt(d.Key)
	if err != nil {
		return nil, errors.WithStack(err)
	}

	var c jose.JSONWebKey
	if err := json.Unmarshal(key, &c); err != nil {
		return nil, errors.WithStack(err)
	}

	return &jose.JSONWebKeySet{
		Keys: []jose.JSONWebKey{c},
	}, nil
}

func (m *SQLManager) GetKeySet(ctx context.Context, set string) (*jose.JSONWebKeySet, error) {
	var ds []sqlData
	if err := m.DB.Select(&ds, m.DB.Rebind("SELECT * FROM hydra_jwk WHERE sid=? ORDER BY created_at DESC"), set); err != nil {
		return nil, sqlcon.HandleError(err)
	}

	if len(ds) == 0 {
		return nil, errors.Wrap(pkg.ErrNotFound, "")
	}

	keys := &jose.JSONWebKeySet{Keys: []jose.JSONWebKey{}}
	for _, d := range ds {
		key, err := m.Cipher.Decrypt(d.Key)
		if err != nil {
			return nil, errors.WithStack(err)
		}

		var c jose.JSONWebKey
		if err := json.Unmarshal(key, &c); err != nil {
			return nil, errors.WithStack(err)
		}
		keys.Keys = append(keys.Keys, c)
	}

	if len(keys.Keys) == 0 {
		return nil, errors.WithStack(pkg.ErrNotFound)
	}

	return keys, nil
}

func (m *SQLManager) DeleteKey(ctx context.Context, set, kid string) error {
	if _, err := m.DB.Exec(m.DB.Rebind(`DELETE FROM hydra_jwk WHERE sid=? AND kid=?`), set, kid); err != nil {
		return sqlcon.HandleError(err)
	}
	return nil
}

func (m *SQLManager) DeleteKeySet(ctx context.Context, set string) error {
	tx, err := m.DB.Beginx()
	if err != nil {
		return errors.WithStack(err)
	}

	if err := m.deleteKeySet(ctx, tx, set); err != nil {
		if re := tx.Rollback(); re != nil {
			return errors.Wrap(err, re.Error())
		}
		return sqlcon.HandleError(err)
	}

	if err := tx.Commit(); err != nil {
		if re := tx.Rollback(); re != nil {
			return errors.Wrap(err, re.Error())
		}
		return sqlcon.HandleError(err)
	}
	return nil
}

func (m *SQLManager) deleteKeySet(ctx context.Context, tx *sqlx.Tx, set string) error {
	if _, err := tx.Exec(m.DB.Rebind(`DELETE FROM hydra_jwk WHERE sid=?`), set); err != nil {
		return sqlcon.HandleError(err)
	}
	return nil
}

func (m *SQLManager) RotateKeys(new *AEAD) error {
	sids := make([]string, 0)
	if err := m.DB.Select(&sids, "SELECT sid FROM hydra_jwk GROUP BY sid"); err != nil {
		return sqlcon.HandleError(err)
	}

	sets := make([]jose.JSONWebKeySet, 0)
	for _, sid := range sids {
		set, err := m.GetKeySet(context.TODO(), sid)
		if err != nil {
			return errors.WithStack(err)
		}
		sets = append(sets, *set)
	}

	tx, err := m.DB.Beginx()
	if err != nil {
		return errors.WithStack(err)
	}

	for k, set := range sets {
		if err := m.deleteKeySet(context.TODO(), tx, sids[k]); err != nil {
			if re := tx.Rollback(); re != nil {
				return errors.Wrap(err, re.Error())
			}
			return sqlcon.HandleError(err)
		}

		if err := m.addKeySet(context.TODO(), tx, new, sids[k], &set); err != nil {
			if re := tx.Rollback(); re != nil {
				return errors.Wrap(err, re.Error())
			}
			return sqlcon.HandleError(err)
		}
	}

	if err := tx.Commit(); err != nil {
		if re := tx.Rollback(); re != nil {
			return errors.Wrap(err, re.Error())
		}
		return sqlcon.HandleError(err)
	}
	return nil
}
<commit_msg>jwk: use context aware db methods<commit_after>/*
 * Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
 *
 * 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.
 *
 * @author		Aeneas Rekkas <aeneas+oss@aeneas.io>
 * @copyright 	2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
 * @license 	Apache-2.0
 */

package jwk

import (
	"encoding/json"
	"time"

	"context"

	"github.com/jmoiron/sqlx"
	"github.com/ory/hydra/pkg"
	"github.com/ory/sqlcon"
	"github.com/pkg/errors"
	"github.com/rubenv/sql-migrate"
	"gopkg.in/square/go-jose.v2"
)

type SQLManager struct {
	DB     *sqlx.DB
	Cipher *AEAD
}

func NewSQLManager(db *sqlx.DB, key []byte) *SQLManager {
	return &SQLManager{DB: db, Cipher: &AEAD{Key: key}}
}

var Migrations = &migrate.MemoryMigrationSource{
	Migrations: []*migrate.Migration{
		{
			Id: "1",
			Up: []string{
				`CREATE TABLE IF NOT EXISTS hydra_jwk (
	sid     varchar(255) NOT NULL,
	kid 	varchar(255) NOT NULL,
	version int NOT NULL DEFAULT 0,
	keydata text NOT NULL,
	PRIMARY KEY (sid, kid)
)`,
			},
			Down: []string{
				"DROP TABLE hydra_jwk",
			},
		},
		{
			Id: "2",
			Up: []string{
				`ALTER TABLE hydra_jwk ADD created_at TIMESTAMP NOT NULL DEFAULT NOW()`,
			},
			Down: []string{
				`ALTER TABLE hydra_jwk DROP COLUMN created_at`,
			},
		},
		// See https://github.com/ory/hydra/issues/921
		{
			Id: "3",
			Up: []string{
				`DELETE FROM hydra_jwk WHERE sid='hydra.openid.id-token'`,
			},
			Down: []string{},
		},
	},
}

type sqlData struct {
	Set       string    `db:"sid"`
	KID       string    `db:"kid"`
	Version   int       `db:"version"`
	CreatedAt time.Time `db:"created_at"`
	Key       string    `db:"keydata"`
}

func (m *SQLManager) CreateSchemas() (int, error) {
	migrate.SetTable("hydra_jwk_migration")
	n, err := migrate.Exec(m.DB.DB, m.DB.DriverName(), Migrations, migrate.Up)
	if err != nil {
		return 0, errors.Wrapf(err, "Could not migrate sql schema, applied %d Migrations", n)
	}
	return n, nil
}

func (m *SQLManager) AddKey(ctx context.Context, set string, key *jose.JSONWebKey) error {
	out, err := json.Marshal(key)
	if err != nil {
		return errors.WithStack(err)
	}

	encrypted, err := m.Cipher.Encrypt(out)
	if err != nil {
		return errors.WithStack(err)
	}

	if _, err = m.DB.NamedExecContext(ctx, `INSERT INTO hydra_jwk (sid, kid, version, keydata) VALUES (:sid, :kid, :version, :keydata)`, &sqlData{
		Set:     set,
		KID:     key.KeyID,
		Version: 0,
		Key:     encrypted,
	}); err != nil {
		return sqlcon.HandleError(err)
	}
	return nil
}

func (m *SQLManager) AddKeySet(ctx context.Context, set string, keys *jose.JSONWebKeySet) error {
	tx, err := m.DB.BeginTxx(ctx, nil)
	if err != nil {
		return errors.WithStack(err)
	}

	if err := m.addKeySet(ctx, tx, m.Cipher, set, keys); err != nil {
		if re := tx.Rollback(); re != nil {
			return errors.Wrap(err, re.Error())
		}
		return sqlcon.HandleError(err)
	}

	if err := tx.Commit(); err != nil {
		if re := tx.Rollback(); re != nil {
			return errors.Wrap(err, re.Error())
		}
		return sqlcon.HandleError(err)
	}
	return nil
}

func (m *SQLManager) addKeySet(ctx context.Context, tx *sqlx.Tx, cipher *AEAD, set string, keys *jose.JSONWebKeySet) error {
	for _, key := range keys.Keys {
		out, err := json.Marshal(key)
		if err != nil {
			return errors.WithStack(err)
		}

		encrypted, err := cipher.Encrypt(out)
		if err != nil {
			return errors.WithStack(err)
		}

		if _, err = tx.NamedExecContext(ctx, `INSERT INTO hydra_jwk (sid, kid, version, keydata) VALUES (:sid, :kid, :version, :keydata)`, &sqlData{
			Set:     set,
			KID:     key.KeyID,
			Version: 0,
			Key:     encrypted,
		}); err != nil {
			return sqlcon.HandleError(err)
		}
	}

	return nil
}

func (m *SQLManager) GetKey(ctx context.Context, set, kid string) (*jose.JSONWebKeySet, error) {
	var d sqlData
	if err := m.DB.GetContext(ctx, &d, m.DB.Rebind("SELECT * FROM hydra_jwk WHERE sid=? AND kid=? ORDER BY created_at DESC"), set, kid); err != nil {
		return nil, sqlcon.HandleError(err)
	}

	key, err := m.Cipher.Decrypt(d.Key)
	if err != nil {
		return nil, errors.WithStack(err)
	}

	var c jose.JSONWebKey
	if err := json.Unmarshal(key, &c); err != nil {
		return nil, errors.WithStack(err)
	}

	return &jose.JSONWebKeySet{
		Keys: []jose.JSONWebKey{c},
	}, nil
}

func (m *SQLManager) GetKeySet(ctx context.Context, set string) (*jose.JSONWebKeySet, error) {
	var ds []sqlData
	if err := m.DB.SelectContext(ctx, &ds, m.DB.Rebind("SELECT * FROM hydra_jwk WHERE sid=? ORDER BY created_at DESC"), set); err != nil {
		return nil, sqlcon.HandleError(err)
	}

	if len(ds) == 0 {
		return nil, errors.Wrap(pkg.ErrNotFound, "")
	}

	keys := &jose.JSONWebKeySet{Keys: []jose.JSONWebKey{}}
	for _, d := range ds {
		key, err := m.Cipher.Decrypt(d.Key)
		if err != nil {
			return nil, errors.WithStack(err)
		}

		var c jose.JSONWebKey
		if err := json.Unmarshal(key, &c); err != nil {
			return nil, errors.WithStack(err)
		}
		keys.Keys = append(keys.Keys, c)
	}

	if len(keys.Keys) == 0 {
		return nil, errors.WithStack(pkg.ErrNotFound)
	}

	return keys, nil
}

func (m *SQLManager) DeleteKey(ctx context.Context, set, kid string) error {
	if _, err := m.DB.ExecContext(ctx, m.DB.Rebind(`DELETE FROM hydra_jwk WHERE sid=? AND kid=?`), set, kid); err != nil {
		return sqlcon.HandleError(err)
	}
	return nil
}

func (m *SQLManager) DeleteKeySet(ctx context.Context, set string) error {
	tx, err := m.DB.BeginTxx(ctx, nil)
	if err != nil {
		return errors.WithStack(err)
	}

	if err := m.deleteKeySet(ctx, tx, set); err != nil {
		if re := tx.Rollback(); re != nil {
			return errors.Wrap(err, re.Error())
		}
		return sqlcon.HandleError(err)
	}

	if err := tx.Commit(); err != nil {
		if re := tx.Rollback(); re != nil {
			return errors.Wrap(err, re.Error())
		}
		return sqlcon.HandleError(err)
	}
	return nil
}

func (m *SQLManager) deleteKeySet(ctx context.Context, tx *sqlx.Tx, set string) error {
	if _, err := tx.ExecContext(ctx, m.DB.Rebind(`DELETE FROM hydra_jwk WHERE sid=?`), set); err != nil {
		return sqlcon.HandleError(err)
	}
	return nil
}

func (m *SQLManager) RotateKeys(new *AEAD) error {
	sids := make([]string, 0)
	if err := m.DB.Select(&sids, "SELECT sid FROM hydra_jwk GROUP BY sid"); err != nil {
		return sqlcon.HandleError(err)
	}

	sets := make([]jose.JSONWebKeySet, 0)
	for _, sid := range sids {
		set, err := m.GetKeySet(context.TODO(), sid)
		if err != nil {
			return errors.WithStack(err)
		}
		sets = append(sets, *set)
	}

	tx, err := m.DB.Beginx()
	if err != nil {
		return errors.WithStack(err)
	}

	for k, set := range sets {
		if err := m.deleteKeySet(context.TODO(), tx, sids[k]); err != nil {
			if re := tx.Rollback(); re != nil {
				return errors.Wrap(err, re.Error())
			}
			return sqlcon.HandleError(err)
		}

		if err := m.addKeySet(context.TODO(), tx, new, sids[k], &set); err != nil {
			if re := tx.Rollback(); re != nil {
				return errors.Wrap(err, re.Error())
			}
			return sqlcon.HandleError(err)
		}
	}

	if err := tx.Commit(); err != nil {
		if re := tx.Rollback(); re != nil {
			return errors.Wrap(err, re.Error())
		}
		return sqlcon.HandleError(err)
	}
	return nil
}
<|endoftext|>


<commit_before>// Package proxy is a cli proxy
package proxy

import (
	"os"
	"strings"
	"time"

	"github.com/micro/cli"
	"github.com/micro/go-micro"
	"github.com/micro/go-micro/client"
	"github.com/micro/go-micro/config/options"
	"github.com/micro/go-micro/proxy"
	"github.com/micro/go-micro/proxy/grpc"
	"github.com/micro/go-micro/proxy/http"
	"github.com/micro/go-micro/proxy/mucp"
	"github.com/micro/go-micro/registry"
	"github.com/micro/go-micro/router"
	rs "github.com/micro/go-micro/router/service"
	"github.com/micro/go-micro/server"
	sgrpc "github.com/micro/go-micro/server/grpc"
	smucp "github.com/micro/go-micro/server/mucp"
	"github.com/micro/go-micro/util/log"
	"github.com/micro/go-micro/util/mux"
)

var (
	// Name of the proxy
	Name = "go.micro.proxy"
	// The address of the proxy
	Address = ":8081"
	// the proxy protocol
	Protocol = "mucp"
	// The endpoint host to route to
	Endpoint string
)

func run(ctx *cli.Context, srvOpts ...micro.Option) {
	log.Name("proxy")

	if len(ctx.GlobalString("server_name")) > 0 {
		Name = ctx.GlobalString("server_name")
	}
	if len(ctx.String("address")) > 0 {
		Address = ctx.String("address")
	}
	if len(ctx.String("endpoint")) > 0 {
		Endpoint = ctx.String("endpoint")
	}
	if len(ctx.String("protocol")) > 0 {
		Protocol = ctx.String("protocol")
	}

	// Init plugins
	for _, p := range Plugins() {
		p.Init(ctx)
	}

	// service opts
	srvOpts = append(srvOpts, micro.Name(Name))
	if i := time.Duration(ctx.GlobalInt("register_ttl")); i > 0 {
		srvOpts = append(srvOpts, micro.RegisterTTL(i*time.Second))
	}
	if i := time.Duration(ctx.GlobalInt("register_interval")); i > 0 {
		srvOpts = append(srvOpts, micro.RegisterInterval(i*time.Second))
	}

	// set address
	if len(Address) > 0 {
		srvOpts = append(srvOpts, micro.Address(Address))
	}

	// set the context
	var popts []options.Option

	// create new router
	var r router.Router

	routerName := ctx.String("router")
	routerAddr := ctx.String("router_address")

	ropts := []router.Option{
		router.Id(server.DefaultId),
		router.Client(client.DefaultClient),
		router.Address(routerAddr),
		router.Registry(registry.DefaultRegistry),
	}

	// check if we need to use the router service
	switch {
	case routerName == "go.micro.router":
		r = rs.NewRouter(ropts...)
	case len(routerAddr) > 0:
		r = rs.NewRouter(ropts...)
	default:
		r = router.NewRouter(ropts...)
	}

	// start the router
	if err := r.Start(); err != nil {
		log.Logf("Proxy error starting router: %s", err)
		os.Exit(1)
	}

	popts = append(popts, proxy.WithRouter(r))

	// new proxy
	var p proxy.Proxy
	var s server.Server

	// set endpoint
	if len(Endpoint) > 0 {
		switch {
		case strings.HasPrefix(Endpoint, "grpc://"):
			ep := strings.TrimPrefix(Endpoint, "grpc://")
			popts = append(popts, proxy.WithEndpoint(ep))
			p = grpc.NewProxy(popts...)
		case strings.HasPrefix(Endpoint, "http://"):
			// TODO: strip prefix?
			popts = append(popts, proxy.WithEndpoint(Endpoint))
			p = http.NewProxy(popts...)
		default:
			// TODO: strip prefix?
			popts = append(popts, proxy.WithEndpoint(Endpoint))
			p = mucp.NewProxy(popts...)
		}
	}

	// set based on protocol
	if p == nil && len(Protocol) > 0 {
		switch Protocol {
		case "http":
			p = http.NewProxy(popts...)
			// TODO: http server
		case "grpc":
			p = grpc.NewProxy(popts...)
			s = sgrpc.NewServer()
		default:
			p = mucp.NewProxy(popts...)
			s = smucp.NewServer()
		}
	}

	if len(Endpoint) > 0 {
		log.Logf("Proxy [%s] serving endpoint: %s", p.String(), Endpoint)
	} else {
		log.Logf("Proxy [%s] serving protocol: %s", p.String(), Protocol)
	}

	// prepend the server
	if s != nil {
		srvOpts = append([]micro.Option{micro.Server(s)}, srvOpts...)
	}

	// new service
	service := micro.NewService(srvOpts...)

	// create a new proxy muxer which includes the debug handler
	muxer := mux.New(Name, p)

	// set the router
	service.Server().Init(
		server.WithRouter(muxer),
	)

	// Run internal service
	if err := service.Run(); err != nil {
		log.Fatal(err)
	}
}

func Commands(options ...micro.Option) []cli.Command {
	command := cli.Command{
		Name:  "proxy",
		Usage: "Run the service proxy",
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:   "router",
				Usage:  "Set the router to use e.g default, go.micro.router",
				EnvVar: "MICRO_ROUTER",
			},
			cli.StringFlag{
				Name:   "router_address",
				Usage:  "Set the router address",
				EnvVar: "MICRO_ROUTER_ADDRESS",
			},
			cli.StringFlag{
				Name:   "address",
				Usage:  "Set the proxy http address e.g 0.0.0.0:8081",
				EnvVar: "MICRO_PROXY_ADDRESS",
			},
			cli.StringFlag{
				Name:   "protocol",
				Usage:  "Set the protocol used for proxying e.g mucp, grpc, http",
				EnvVar: "MICRO_PROXY_PROTOCOL",
			},
			cli.StringFlag{
				Name:   "endpoint",
				Usage:  "Set the endpoint to route to e.g greeter or localhost:9090",
				EnvVar: "MICRO_PROXY_ENDPOINT",
			},
		},
		Action: func(ctx *cli.Context) {
			run(ctx, options...)
		},
	}

	for _, p := range Plugins() {
		if cmds := p.Commands(); len(cmds) > 0 {
			command.Subcommands = append(command.Subcommands, cmds...)
		}

		if flags := p.Flags(); len(flags) > 0 {
			command.Flags = append(command.Flags, flags...)
		}
	}

	return []cli.Command{command}
}
<commit_msg>add separate server for proxy (#440)<commit_after>// Package proxy is a cli proxy
package proxy

import (
	"os"
	"strings"
	"time"

	"github.com/micro/cli"
	"github.com/micro/go-micro"
	"github.com/micro/go-micro/client"
	"github.com/micro/go-micro/config/options"
	"github.com/micro/go-micro/proxy"
	"github.com/micro/go-micro/proxy/grpc"
	"github.com/micro/go-micro/proxy/http"
	"github.com/micro/go-micro/proxy/mucp"
	"github.com/micro/go-micro/registry"
	"github.com/micro/go-micro/router"
	bmem "github.com/micro/go-micro/broker/memory"
	rmem "github.com/micro/go-micro/registry/memory"
	rs "github.com/micro/go-micro/router/service"
	"github.com/micro/go-micro/server"
	sgrpc "github.com/micro/go-micro/server/grpc"
	smucp "github.com/micro/go-micro/server/mucp"
	"github.com/micro/go-micro/util/log"
	"github.com/micro/go-micro/util/mux"
)

var (
	// Name of the proxy
	Name = "go.micro.proxy"
	// The address of the proxy
	Address = ":8081"
	// the proxy protocol
	Protocol = "mucp"
	// The endpoint host to route to
	Endpoint string
)

func run(ctx *cli.Context, srvOpts ...micro.Option) {
	log.Name("proxy")

	if len(ctx.GlobalString("server_name")) > 0 {
		Name = ctx.GlobalString("server_name")
	}
	if len(ctx.String("address")) > 0 {
		Address = ctx.String("address")
	}
	if len(ctx.String("endpoint")) > 0 {
		Endpoint = ctx.String("endpoint")
	}
	if len(ctx.String("protocol")) > 0 {
		Protocol = ctx.String("protocol")
	}

	// Init plugins
	for _, p := range Plugins() {
		p.Init(ctx)
	}

	// service opts
	srvOpts = append(srvOpts, micro.Name(Name))
	if i := time.Duration(ctx.GlobalInt("register_ttl")); i > 0 {
		srvOpts = append(srvOpts, micro.RegisterTTL(i*time.Second))
	}
	if i := time.Duration(ctx.GlobalInt("register_interval")); i > 0 {
		srvOpts = append(srvOpts, micro.RegisterInterval(i*time.Second))
	}

	// set the context
	var popts []options.Option

	// create new router
	var r router.Router

	routerName := ctx.String("router")
	routerAddr := ctx.String("router_address")

	ropts := []router.Option{
		router.Id(server.DefaultId),
		router.Client(client.DefaultClient),
		router.Address(routerAddr),
		router.Registry(registry.DefaultRegistry),
	}

	// check if we need to use the router service
	switch {
	case routerName == "go.micro.router":
		r = rs.NewRouter(ropts...)
	case len(routerAddr) > 0:
		r = rs.NewRouter(ropts...)
	default:
		r = router.NewRouter(ropts...)
	}

	// start the router
	if err := r.Start(); err != nil {
		log.Logf("Proxy error starting router: %s", err)
		os.Exit(1)
	}

	popts = append(popts, proxy.WithRouter(r))

	// new proxy
	var p proxy.Proxy
	var s server.Server

	// set endpoint
	if len(Endpoint) > 0 {
		switch {
		case strings.HasPrefix(Endpoint, "grpc://"):
			ep := strings.TrimPrefix(Endpoint, "grpc://")
			popts = append(popts, proxy.WithEndpoint(ep))
			p = grpc.NewProxy(popts...)
		case strings.HasPrefix(Endpoint, "http://"):
			// TODO: strip prefix?
			popts = append(popts, proxy.WithEndpoint(Endpoint))
			p = http.NewProxy(popts...)
		default:
			// TODO: strip prefix?
			popts = append(popts, proxy.WithEndpoint(Endpoint))
			p = mucp.NewProxy(popts...)
		}
	}

	// set based on protocol
	if p == nil && len(Protocol) > 0 {
		switch Protocol {
		case "http":
			p = http.NewProxy(popts...)
			// TODO: http server
		case "grpc":
			p = grpc.NewProxy(popts...)
			s = sgrpc.NewServer()
		default:
			p = mucp.NewProxy(popts...)
			s = smucp.NewServer()
		}
	}

	if len(Endpoint) > 0 {
		log.Logf("Proxy [%s] serving endpoint: %s", p.String(), Endpoint)
	} else {
		log.Logf("Proxy [%s] serving protocol: %s", p.String(), Protocol)
	}

	// prepend the server
	if s != nil {
		srvOpts = append([]micro.Option{micro.Server(s)}, srvOpts...)
	}

	// new service
	service := micro.NewService(srvOpts...)

	// create a new proxy muxer which includes the debug handler
	muxer := mux.New(Name, p)

	// set the router
	service.Server().Init(
		server.WithRouter(muxer),
	)

	// gen the straight up http server
	// set address
	srv := server.NewServer(
		server.Address(Address),
		// reset registry to memory
		server.Registry(rmem.NewRegistry()),
		// reset broker to memory
		server.Broker(bmem.NewBroker()),
		// hande it the router
		server.WithRouter(p),
	)

	// Start the server
	if err := srv.Start(); err != nil {
		log.Fatal(err)
	}

	// Run internal service
	if err := service.Run(); err != nil {
		log.Fatal(err)
	}

	// Stop the server
	if err := srv.Stop(); err != nil {
		log.Fatal(err)
	}
}

func Commands(options ...micro.Option) []cli.Command {
	command := cli.Command{
		Name:  "proxy",
		Usage: "Run the service proxy",
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:   "router",
				Usage:  "Set the router to use e.g default, go.micro.router",
				EnvVar: "MICRO_ROUTER",
			},
			cli.StringFlag{
				Name:   "router_address",
				Usage:  "Set the router address",
				EnvVar: "MICRO_ROUTER_ADDRESS",
			},
			cli.StringFlag{
				Name:   "address",
				Usage:  "Set the proxy http address e.g 0.0.0.0:8081",
				EnvVar: "MICRO_PROXY_ADDRESS",
			},
			cli.StringFlag{
				Name:   "protocol",
				Usage:  "Set the protocol used for proxying e.g mucp, grpc, http",
				EnvVar: "MICRO_PROXY_PROTOCOL",
			},
			cli.StringFlag{
				Name:   "endpoint",
				Usage:  "Set the endpoint to route to e.g greeter or localhost:9090",
				EnvVar: "MICRO_PROXY_ENDPOINT",
			},
		},
		Action: func(ctx *cli.Context) {
			run(ctx, options...)
		},
	}

	for _, p := range Plugins() {
		if cmds := p.Commands(); len(cmds) > 0 {
			command.Subcommands = append(command.Subcommands, cmds...)
		}

		if flags := p.Flags(); len(flags) > 0 {
			command.Flags = append(command.Flags, flags...)
		}
	}

	return []cli.Command{command}
}
<|endoftext|>