<commit_before>package testing

import (
	"bytes"
	"context"
	"sort"
	"testing"

	"github.com/google/go-cmp/cmp"
	platform "github.com/influxdata/influxdb"
	"github.com/influxdata/influxdb/mock"
)

const (
	idA = "020f755c3c082000"
	idB = "020f755c3c082001"
)

var macroCmpOptions = cmp.Options{
	cmp.Comparer(func(x, y []byte) bool {
		return bytes.Equal(x, y)
	}),
	cmp.Transformer("Sort", func(in []*platform.Macro) []*platform.Macro {
		out := append([]*platform.Macro(nil), in...)
		sort.Slice(out, func(i, j int) bool {
			return out[i].ID.String() > out[j].ID.String()
		})
		return out
	}),
}

// MacroFields defines fields for a macro test
type MacroFields struct {
	Macros      []*platform.Macro
	IDGenerator platform.IDGenerator
}

// MacroService tests all the service functions.
func MacroService(
	init func(MacroFields, *testing.T) (platform.MacroService, string, func()), t *testing.T,
) {
	tests := []struct {
		name string
		fn   func(init func(MacroFields, *testing.T) (platform.MacroService, string, func()),
			t *testing.T)
	}{
		{
			name: "CreateMacro",
			fn:   CreateMacro,
		},
		{
			name: "FindMacroByID",
			fn:   FindMacroByID,
		},
		{
			name: "UpdateMacro",
			fn:   UpdateMacro,
		},
		{
			name: "DeleteMacro",
			fn:   DeleteMacro,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			tt.fn(init, t)
		})
	}
}

// CreateMacro tests platform.MacroService CreateMacro interface method
func CreateMacro(init func(MacroFields, *testing.T) (platform.MacroService, string, func()), t *testing.T) {
	type args struct {
		macro *platform.Macro
	}
	type wants struct {
		err    error
		macros []*platform.Macro
	}

	tests := []struct {
		name   string
		fields MacroFields
		args   args
		wants  wants
	}{
		{
			name: "creating a macro assigns the macro an id and adds it to the store",
			fields: MacroFields{
				IDGenerator: &mock.IDGenerator{
					IDFn: func() platform.ID {
						return MustIDBase16(idA)
					},
				},
				Macros: []*platform.Macro{
					{
						ID:       MustIDBase16(idB),
						Name:     "existing-macro",
						Selected: []string{"b"},
						Arguments: &platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{"b"},
						},
					},
				},
			},
			args: args{
				macro: &platform.Macro{
					ID:       MustIDBase16(idA),
					Name:     "my-macro",
					Selected: []string{"a"},
					Arguments: &platform.MacroArguments{
						Type:   "constant",
						Values: platform.MacroConstantValues{"a"},
					},
				},
			},
			wants: wants{
				err: nil,
				macros: []*platform.Macro{
					{
						ID:       MustIDBase16(idB),
						Name:     "existing-macro",
						Selected: []string{"b"},
						Arguments: &platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{"b"},
						},
					},
					{
						ID:       MustIDBase16(idA),
						Name:     "my-macro",
						Selected: []string{"a"},
						Arguments: &platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{"a"},
						},
					},
				},
			},
		},
	}

	for _, tt := range tests {
		s, opPrefix, done := init(tt.fields, t)
		defer done()
		ctx := context.Background()

		err := s.CreateMacro(ctx, tt.args.macro)
		diffPlatformErrors(tt.name, err, tt.wants.err, opPrefix, t)

		macros, err := s.FindMacros(ctx)
		if err != nil {
			t.Fatalf("failed to retrieve macros: %v", err)
		}
		if diff := cmp.Diff(macros, tt.wants.macros, macroCmpOptions...); diff != "" {
			t.Fatalf("found unexpected macros -got/+want\ndiff %s", diff)
		}
	}
}

// FindMacroByID tests platform.MacroService FindMacroByID interface method
func FindMacroByID(init func(MacroFields, *testing.T) (platform.MacroService, string, func()), t *testing.T) {
	type args struct {
		id platform.ID
	}
	type wants struct {
		err   error
		macro *platform.Macro
	}

	tests := []struct {
		name   string
		fields MacroFields
		args   args
		wants  wants
	}{
		{
			name: "finding a macro that exists by id",
			fields: MacroFields{
				Macros: []*platform.Macro{
					{
						ID:   MustIDBase16(idA),
						Name: "existing-macro-a",
						Arguments: &platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
					{
						ID:   MustIDBase16(idB),
						Name: "existing-macro-b",
						Arguments: &platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
				},
			},
			args: args{
				id: MustIDBase16(idB),
			},
			wants: wants{
				err: nil,
				macro: &platform.Macro{
					ID:   MustIDBase16(idB),
					Name: "existing-macro-b",
					Arguments: &platform.MacroArguments{
						Type:   "constant",
						Values: platform.MacroConstantValues{},
					},
				},
			},
		},
		{
			name: "finding a non-existant macro",
			fields: MacroFields{
				Macros: []*platform.Macro{},
			},
			args: args{
				id: MustIDBase16(idA),
			},
			wants: wants{
				err: &platform.Error{
					Code: platform.ENotFound,
					Op:   platform.OpFindMacroByID,
					Msg:  "macro not found",
				},
				macro: nil,
			},
		},
	}

	for _, tt := range tests {
		s, opPrefix, done := init(tt.fields, t)
		defer done()
		ctx := context.Background()

		macro, err := s.FindMacroByID(ctx, tt.args.id)
		diffPlatformErrors(tt.name, err, tt.wants.err, opPrefix, t)

		if diff := cmp.Diff(macro, tt.wants.macro); diff != "" {
			t.Fatalf("found unexpected macro -got/+want\ndiff %s", diff)
		}
	}
}

// UpdateMacro tests platform.MacroService UpdateMacro interface method
func UpdateMacro(init func(MacroFields, *testing.T) (platform.MacroService, string, func()), t *testing.T) {
	type args struct {
		id     platform.ID
		update *platform.MacroUpdate
	}
	type wants struct {
		err    error
		macros []*platform.Macro
	}

	tests := []struct {
		name   string
		fields MacroFields
		args   args
		wants  wants
	}{
		{
			name: "updating a macro's name",
			fields: MacroFields{
				Macros: []*platform.Macro{
					{
						ID:   MustIDBase16(idA),
						Name: "existing-macro-a",
						Arguments: &platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
					{
						ID:   MustIDBase16(idB),
						Name: "existing-macro-b",
						Arguments: &platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
				},
			},
			args: args{
				id: MustIDBase16(idB),
				update: &platform.MacroUpdate{
					Name: "new-macro-b-name",
				},
			},
			wants: wants{
				err: nil,
				macros: []*platform.Macro{
					{
						ID:   MustIDBase16(idA),
						Name: "existing-macro-a",
						Arguments: &platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
					{
						ID:   MustIDBase16(idB),
						Name: "new-macro-b-name",
						Arguments: &platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
				},
			},
		},
		{
			name: "updating a non-existant macro fails",
			fields: MacroFields{
				Macros: []*platform.Macro{},
			},
			args: args{
				id: MustIDBase16(idA),
				update: &platform.MacroUpdate{
					Name: "howdy",
				},
			},
			wants: wants{
				err: &platform.Error{
					Op:   platform.OpUpdateMacro,
					Msg:  "macro not found",
					Code: platform.ENotFound,
				},
				macros: []*platform.Macro{},
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			s, opPrefix, done := init(tt.fields, t)
			defer done()
			ctx := context.Background()

			macro, err := s.UpdateMacro(ctx, tt.args.id, tt.args.update)
			diffPlatformErrors(tt.name, err, tt.wants.err, opPrefix, t)

			if macro != nil {
				if tt.args.update.Name != "" && macro.Name != tt.args.update.Name {
					t.Fatalf("macro name not updated")
				}
			}

			macros, err := s.FindMacros(ctx)
			if err != nil {
				t.Fatalf("failed to retrieve macros: %v", err)
			}
			if diff := cmp.Diff(macros, tt.wants.macros, macroCmpOptions...); diff != "" {
				t.Fatalf("found unexpected macros -got/+want\ndiff %s", diff)
			}
		})
	}
}

// DeleteMacro tests platform.MacroService DeleteMacro interface method
func DeleteMacro(init func(MacroFields, *testing.T) (platform.MacroService, string, func()), t *testing.T) {
	type args struct {
		id platform.ID
	}
	type wants struct {
		err    error
		macros []*platform.Macro
	}

	tests := []struct {
		name   string
		fields MacroFields
		args   args
		wants  wants
	}{
		{
			name: "deleting a macro",
			fields: MacroFields{
				Macros: []*platform.Macro{
					{
						ID:   MustIDBase16(idA),
						Name: "existing-macro",
						Arguments: &platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
				},
			},
			args: args{
				id: MustIDBase16(idA),
			},
			wants: wants{
				err:    nil,
				macros: []*platform.Macro{},
			},
		},
		{
			name: "deleting a macro that doesn't exist",
			fields: MacroFields{
				Macros: []*platform.Macro{
					{
						ID:   MustIDBase16(idA),
						Name: "existing-macro",
						Arguments: &platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
				},
			},
			args: args{
				id: MustIDBase16(idB),
			},
			wants: wants{
				err: &platform.Error{
					Code: platform.ENotFound,
					Op:   platform.OpDeleteMacro,
					Msg:  "macro not found",
				},
				macros: []*platform.Macro{
					{
						ID:   MustIDBase16(idA),
						Name: "existing-macro",
						Arguments: &platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
				},
			},
		},
	}

	for _, tt := range tests {
		s, opPrefix, done := init(tt.fields, t)
		defer done()
		ctx := context.Background()

		err := s.DeleteMacro(ctx, tt.args.id)
		defer s.ReplaceMacro(ctx, &platform.Macro{
			ID: tt.args.id,
		})
		diffPlatformErrors(tt.name, err, tt.wants.err, opPrefix, t)

		macros, err := s.FindMacros(ctx)
		if err != nil {
			t.Fatalf("failed to retrieve macros: %v", err)
		}
		if diff := cmp.Diff(macros, tt.wants.macros, macroCmpOptions...); diff != "" {
			t.Fatalf("found unexpected macros -got/+want\ndiff %s", diff)
		}
	}
}
<commit_msg>chore(testing): macro testing framework respect macro service interface<commit_after>package testing

import (
	"bytes"
	"context"
	"sort"
	"testing"

	"github.com/google/go-cmp/cmp"
	platform "github.com/influxdata/influxdb"
	"github.com/influxdata/influxdb/mock"
)

const (
	idA = "020f755c3c082000"
	idB = "020f755c3c082001"
)

var macroCmpOptions = cmp.Options{
	cmp.Comparer(func(x, y []byte) bool {
		return bytes.Equal(x, y)
	}),
	cmp.Transformer("Sort", func(in []*platform.Macro) []*platform.Macro {
		out := append([]*platform.Macro(nil), in...)
		sort.Slice(out, func(i, j int) bool {
			return out[i].ID.String() > out[j].ID.String()
		})
		return out
	}),
}

// MacroFields defines fields for a macro test
type MacroFields struct {
	Macros      []*platform.Macro
	IDGenerator platform.IDGenerator
}

// MacroService tests all the service functions.
func MacroService(
	init func(MacroFields, *testing.T) (platform.MacroService, string, func()), t *testing.T,
) {
	tests := []struct {
		name string
		fn   func(init func(MacroFields, *testing.T) (platform.MacroService, string, func()),
			t *testing.T)
	}{
		{
			name: "CreateMacro",
			fn:   CreateMacro,
		},
		{
			name: "FindMacroByID",
			fn:   FindMacroByID,
		},
		{
			name: "FindMacros",
			fn:   FindMacros,
		},
		{
			name: "UpdateMacro",
			fn:   UpdateMacro,
		},
		{
			name: "DeleteMacro",
			fn:   DeleteMacro,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			tt.fn(init, t)
		})
	}
}

// CreateMacro tests platform.MacroService CreateMacro interface method
func CreateMacro(init func(MacroFields, *testing.T) (platform.MacroService, string, func()), t *testing.T) {
	type args struct {
		macro *platform.Macro
	}
	type wants struct {
		err    error
		macros []*platform.Macro
	}

	tests := []struct {
		name   string
		fields MacroFields
		args   args
		wants  wants
	}{
		{
			name: "creating a macro assigns the macro an id and adds it to the store",
			fields: MacroFields{
				IDGenerator: &mock.IDGenerator{
					IDFn: func() platform.ID {
						return MustIDBase16(idA)
					},
				},
				Macros: []*platform.Macro{
					{
						ID:       MustIDBase16(idB),
						Name:     "existing-macro",
						Selected: []string{"b"},
						Arguments: &platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{"b"},
						},
					},
				},
			},
			args: args{
				macro: &platform.Macro{
					ID:       MustIDBase16(idA),
					Name:     "my-macro",
					Selected: []string{"a"},
					Arguments: &platform.MacroArguments{
						Type:   "constant",
						Values: platform.MacroConstantValues{"a"},
					},
				},
			},
			wants: wants{
				err: nil,
				macros: []*platform.Macro{
					{
						ID:       MustIDBase16(idB),
						Name:     "existing-macro",
						Selected: []string{"b"},
						Arguments: &platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{"b"},
						},
					},
					{
						ID:       MustIDBase16(idA),
						Name:     "my-macro",
						Selected: []string{"a"},
						Arguments: &platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{"a"},
						},
					},
				},
			},
		},
	}

	for _, tt := range tests {
		s, opPrefix, done := init(tt.fields, t)
		defer done()
		ctx := context.Background()

		err := s.CreateMacro(ctx, tt.args.macro)
		diffPlatformErrors(tt.name, err, tt.wants.err, opPrefix, t)

		macros, err := s.FindMacros(ctx, platform.MacroFilter{})
		if err != nil {
			t.Fatalf("failed to retrieve macros: %v", err)
		}
		if diff := cmp.Diff(macros, tt.wants.macros, macroCmpOptions...); diff != "" {
			t.Fatalf("found unexpected macros -got/+want\ndiff %s", diff)
		}
	}
}

// FindMacroByID tests platform.MacroService FindMacroByID interface method
func FindMacroByID(init func(MacroFields, *testing.T) (platform.MacroService, string, func()), t *testing.T) {
	type args struct {
		id platform.ID
	}
	type wants struct {
		err   error
		macro *platform.Macro
	}

	tests := []struct {
		name   string
		fields MacroFields
		args   args
		wants  wants
	}{
		{
			name: "finding a macro that exists by id",
			fields: MacroFields{
				Macros: []*platform.Macro{
					{
						ID:   MustIDBase16(idA),
						Name: "existing-macro-a",
						Arguments: &platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
					{
						ID:   MustIDBase16(idB),
						Name: "existing-macro-b",
						Arguments: &platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
				},
			},
			args: args{
				id: MustIDBase16(idB),
			},
			wants: wants{
				err: nil,
				macro: &platform.Macro{
					ID:   MustIDBase16(idB),
					Name: "existing-macro-b",
					Arguments: &platform.MacroArguments{
						Type:   "constant",
						Values: platform.MacroConstantValues{},
					},
				},
			},
		},
		{
			name: "finding a non-existant macro",
			fields: MacroFields{
				Macros: []*platform.Macro{},
			},
			args: args{
				id: MustIDBase16(idA),
			},
			wants: wants{
				err: &platform.Error{
					Code: platform.ENotFound,
					Op:   platform.OpFindMacroByID,
					Msg:  "macro not found",
				},
				macro: nil,
			},
		},
	}

	for _, tt := range tests {
		s, opPrefix, done := init(tt.fields, t)
		defer done()
		ctx := context.Background()

		macro, err := s.FindMacroByID(ctx, tt.args.id)
		diffPlatformErrors(tt.name, err, tt.wants.err, opPrefix, t)

		if diff := cmp.Diff(macro, tt.wants.macro); diff != "" {
			t.Fatalf("found unexpected macro -got/+want\ndiff %s", diff)
		}
	}
}

// FindMacros tests platform.macroService FindMacros interface method
func FindMacros(init func(MacroFields, *testing.T) (platform.MacroService, string, func()), t *testing.T) {
	// todo(leodido)
}

// UpdateMacro tests platform.MacroService UpdateMacro interface method
func UpdateMacro(init func(MacroFields, *testing.T) (platform.MacroService, string, func()), t *testing.T) {
	type args struct {
		id     platform.ID
		update *platform.MacroUpdate
	}
	type wants struct {
		err    error
		macros []*platform.Macro
	}

	tests := []struct {
		name   string
		fields MacroFields
		args   args
		wants  wants
	}{
		{
			name: "updating a macro's name",
			fields: MacroFields{
				Macros: []*platform.Macro{
					{
						ID:   MustIDBase16(idA),
						Name: "existing-macro-a",
						Arguments: &platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
					{
						ID:   MustIDBase16(idB),
						Name: "existing-macro-b",
						Arguments: &platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
				},
			},
			args: args{
				id: MustIDBase16(idB),
				update: &platform.MacroUpdate{
					Name: "new-macro-b-name",
				},
			},
			wants: wants{
				err: nil,
				macros: []*platform.Macro{
					{
						ID:   MustIDBase16(idA),
						Name: "existing-macro-a",
						Arguments: &platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
					{
						ID:   MustIDBase16(idB),
						Name: "new-macro-b-name",
						Arguments: &platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
				},
			},
		},
		{
			name: "updating a non-existant macro fails",
			fields: MacroFields{
				Macros: []*platform.Macro{},
			},
			args: args{
				id: MustIDBase16(idA),
				update: &platform.MacroUpdate{
					Name: "howdy",
				},
			},
			wants: wants{
				err: &platform.Error{
					Op:   platform.OpUpdateMacro,
					Msg:  "macro not found",
					Code: platform.ENotFound,
				},
				macros: []*platform.Macro{},
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			s, opPrefix, done := init(tt.fields, t)
			defer done()
			ctx := context.Background()

			macro, err := s.UpdateMacro(ctx, tt.args.id, tt.args.update)
			diffPlatformErrors(tt.name, err, tt.wants.err, opPrefix, t)

			if macro != nil {
				if tt.args.update.Name != "" && macro.Name != tt.args.update.Name {
					t.Fatalf("macro name not updated")
				}
			}

			macros, err := s.FindMacros(ctx, platform.MacroFilter{})
			if err != nil {
				t.Fatalf("failed to retrieve macros: %v", err)
			}
			if diff := cmp.Diff(macros, tt.wants.macros, macroCmpOptions...); diff != "" {
				t.Fatalf("found unexpected macros -got/+want\ndiff %s", diff)
			}
		})
	}
}

// DeleteMacro tests platform.MacroService DeleteMacro interface method
func DeleteMacro(init func(MacroFields, *testing.T) (platform.MacroService, string, func()), t *testing.T) {
	type args struct {
		id platform.ID
	}
	type wants struct {
		err    error
		macros []*platform.Macro
	}

	tests := []struct {
		name   string
		fields MacroFields
		args   args
		wants  wants
	}{
		{
			name: "deleting a macro",
			fields: MacroFields{
				Macros: []*platform.Macro{
					{
						ID:   MustIDBase16(idA),
						Name: "existing-macro",
						Arguments: &platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
				},
			},
			args: args{
				id: MustIDBase16(idA),
			},
			wants: wants{
				err:    nil,
				macros: []*platform.Macro{},
			},
		},
		{
			name: "deleting a macro that doesn't exist",
			fields: MacroFields{
				Macros: []*platform.Macro{
					{
						ID:   MustIDBase16(idA),
						Name: "existing-macro",
						Arguments: &platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
				},
			},
			args: args{
				id: MustIDBase16(idB),
			},
			wants: wants{
				err: &platform.Error{
					Code: platform.ENotFound,
					Op:   platform.OpDeleteMacro,
					Msg:  "macro not found",
				},
				macros: []*platform.Macro{
					{
						ID:   MustIDBase16(idA),
						Name: "existing-macro",
						Arguments: &platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
				},
			},
		},
	}

	for _, tt := range tests {
		s, opPrefix, done := init(tt.fields, t)
		defer done()
		ctx := context.Background()

		err := s.DeleteMacro(ctx, tt.args.id)
		defer s.ReplaceMacro(ctx, &platform.Macro{
			ID: tt.args.id,
		})
		diffPlatformErrors(tt.name, err, tt.wants.err, opPrefix, t)

		macros, err := s.FindMacros(ctx, platform.MacroFilter{})
		if err != nil {
			t.Fatalf("failed to retrieve macros: %v", err)
		}
		if diff := cmp.Diff(macros, tt.wants.macros, macroCmpOptions...); diff != "" {
			t.Fatalf("found unexpected macros -got/+want\ndiff %s", diff)
		}
	}
}
<|endoftext|>


<commit_before>package cssrc

import (
	"fmt"
	"github.com/davyxu/tabtoy/util"
	"github.com/davyxu/tabtoy/v3/gen/bindata"
	"github.com/davyxu/tabtoy/v3/model"
	"text/template"
)

var UsefulFunc = template.FuncMap{}

func wrapSingleValue(globals *model.Globals, valueType *model.TypeDefine, value string) string {
	switch {
	case valueType.FieldType == "string": // 字符串

		// C#特殊优化
		if value == "" {
			return "string.Empty"
		}

		return util.StringWrap(util.StringEscape(value))
	case valueType.FieldType == "float32":
		return value
	case globals.Types.IsEnumKind(valueType.FieldType): // 枚举
		t := globals.Types.ResolveEnum(valueType.FieldType, value)
		if t != nil {
			return t.Define.ObjectType + "." + t.Define.FieldName
		}

		return ""
	case valueType.FieldType == "bool":

		v, _ := model.ParseBool(value)
		if v {
			return "true"
		}

		return "false"
	}

	if value == "" {
		return model.FetchDefaultValue(valueType.FieldType)
	}

	return value
}

func init() {
	UsefulFunc["CSType"] = func(tf *model.TypeDefine) string {

		convertedType := model.LanguagePrimitive(tf.FieldType, "cs")

		if tf.IsArray() {
			return fmt.Sprintf("List<%s>", convertedType)
		}

		return convertedType
	}

	UsefulFunc["CSTag"] = func(globals *model.Globals, fieldIndex int, tf *model.TypeDefine) string {

		tag := bindata.MakeTag(globals, tf, fieldIndex)

		return fmt.Sprintf("0x%x", tag)
	}

	UsefulFunc["CSStructTag"] = func() string {

		return fmt.Sprintf("0x%x", bindata.MakeTagStructArray())
	}

	UsefulFunc["CSReader"] = func(globals *model.Globals, tf *model.TypeDefine) (ret string) {

		convertedType := model.LanguagePrimitive(tf.FieldType, "cs")

		switch {
		case convertedType == "float":
			ret = "Float"
		case convertedType == "double":
			ret = "Double"
		case convertedType == "string":
			ret = "String"
		case convertedType == "bool":
			ret = "Bool"
		case globals.Types.IsEnumKind(tf.FieldType):
			ret = "Enum"
		default:
			ret = convertedType
		}

		return
	}

	UsefulFunc["CSDefaultValue"] = func(globals *model.Globals, tf *model.TypeDefine) string {

		convertedType := model.LanguagePrimitive(tf.FieldType, "cs")

		if tf.IsArray() {
			return fmt.Sprintf("new List<%s>()", convertedType)
		} else {
			return wrapSingleValue(globals, tf, "")
		}

	}

	UsefulFunc["IsWarpFieldName"] = func(globals *model.Globals, tf *model.TypeDefine) bool {

		if globals.CanDoAction(model.ActionNoGennFieldCsharp, tf) {
			return false
		}
		return true
	}

}
<commit_msg>修复C#代码生成中, 字段为浮点数时, 输出默认值错误问题<commit_after>package cssrc

import (
	"fmt"
	"github.com/davyxu/tabtoy/util"
	"github.com/davyxu/tabtoy/v3/gen/bindata"
	"github.com/davyxu/tabtoy/v3/model"
	"text/template"
)

var UsefulFunc = template.FuncMap{}

func wrapSingleValue(globals *model.Globals, valueType *model.TypeDefine, value string) string {
	switch {
	case valueType.FieldType == "string": // 字符串

		// C#特殊优化
		if value == "" {
			return "string.Empty"
		}

		return util.StringWrap(util.StringEscape(value))
	case globals.Types.IsEnumKind(valueType.FieldType): // 枚举
		t := globals.Types.ResolveEnum(valueType.FieldType, value)
		if t != nil {
			return t.Define.ObjectType + "." + t.Define.FieldName
		}

		return ""
	case valueType.FieldType == "bool":

		v, _ := model.ParseBool(value)
		if v {
			return "true"
		}

		return "false"
	}

	if value == "" {
		return model.FetchDefaultValue(valueType.FieldType)
	}

	return value
}

func init() {
	UsefulFunc["CSType"] = func(tf *model.TypeDefine) string {

		convertedType := model.LanguagePrimitive(tf.FieldType, "cs")

		if tf.IsArray() {
			return fmt.Sprintf("List<%s>", convertedType)
		}

		return convertedType
	}

	UsefulFunc["CSTag"] = func(globals *model.Globals, fieldIndex int, tf *model.TypeDefine) string {

		tag := bindata.MakeTag(globals, tf, fieldIndex)

		return fmt.Sprintf("0x%x", tag)
	}

	UsefulFunc["CSStructTag"] = func() string {

		return fmt.Sprintf("0x%x", bindata.MakeTagStructArray())
	}

	UsefulFunc["CSReader"] = func(globals *model.Globals, tf *model.TypeDefine) (ret string) {

		convertedType := model.LanguagePrimitive(tf.FieldType, "cs")

		switch {
		case convertedType == "float":
			ret = "Float"
		case convertedType == "double":
			ret = "Double"
		case convertedType == "string":
			ret = "String"
		case convertedType == "bool":
			ret = "Bool"
		case globals.Types.IsEnumKind(tf.FieldType):
			ret = "Enum"
		default:
			ret = convertedType
		}

		return
	}

	UsefulFunc["CSDefaultValue"] = func(globals *model.Globals, tf *model.TypeDefine) string {

		convertedType := model.LanguagePrimitive(tf.FieldType, "cs")

		if tf.IsArray() {
			return fmt.Sprintf("new List<%s>()", convertedType)
		} else {
			return wrapSingleValue(globals, tf, "")
		}

	}

	UsefulFunc["IsWarpFieldName"] = func(globals *model.Globals, tf *model.TypeDefine) bool {

		if globals.CanDoAction(model.ActionNoGennFieldCsharp, tf) {
			return false
		}
		return true
	}

}
<|endoftext|>


<commit_before>package replacer

import (
	"bytes"

	"github.com/json-iterator/go"
)

var json = jsoniter.ConfigFastest

type domainConfig struct {
	apiReplaces                []replace
	apiOfficialLongpollReplace replace
	apiLongpollReplace         replace
	siteHlsReplace             replace
}

type Replacer struct {
	domains map[string]*domainConfig
}

type ReplaceContext struct {
	// vk-proxy domain name
	BaseDomain string

	Domain string
	Path   string

	FilterFeed bool
}

func (r *Replacer) getDomainConfig(domain string) *domainConfig {
	cfg, ok := r.domains[domain]
	if !ok {
		var replacementStart = []byte(`\/\/` + domain + `\/_\/`)
		var jsonUrlPrefix = []byte(`"https:`)
		var mVkCom = []byte(`m.vk.com`)
		cfg = &domainConfig{}
		cfg.apiReplaces = []replace{
			newStringReplace(`"https:\/\/vk.com\/video_hls.php`, `"https:\/\/`+domain+`\/@vk.com\/video_hls.php`),
			newRegexFastReplace(`\\/\\/[-_a-zA-Z0-9]{1,15}\.(?:userapi\.com|vk-cdn\.net|vk\.(?:me|com)|vkuser(?:live|video|audio)\.(?:net|com))\\/`,
				func(src, dst []byte, start, end int) []byte {
					// check if url has valid prefix (like in regexp backreference)
					if start < 7 || !bytes.Equal(src[start-7:start], jsonUrlPrefix) {
						goto cancel
					}
					// do not proxy m.vk.com domain (bugged articles)
					if bytes.Equal(src[start+4:end-2], mVkCom) {
						goto cancel
					}
					dst = append(dst, replacementStart...)
					dst = append(dst, src[start+4:end]...)
					return dst
				cancel:
					return append(dst, src[start:end]...)
				}),
			newRegexReplace(`"https:\\/\\/vk\.com\\/((?:\\/)?images\\/|sticker(:?\\/|s_)|doc-?[0-9]+_)`, `"https:\/\/`+domain+`\/_\/vk.com\/$1`),
		}
		cfg.apiOfficialLongpollReplace = newStringReplace(`"server":"api.vk.com\/newuim`, `"server":"`+domain+`\/_\/api.vk.com\/newuim`)
		cfg.apiLongpollReplace = newStringReplace(`"server":"`, `"server":"`+domain+`\/_\/`)
		cfg.siteHlsReplace = newRegexReplace(`https:\/\/([-_a-zA-Z0-9]+\.(?:userapi\.com|vk-cdn\.net|vk\.me|vkuser(?:live|video)\.(?:net|com)))\/`, `https://`+domain+`/_/$1/`)
		if r.domains == nil {
			r.domains = make(map[string]*domainConfig)
		}
		r.domains[domain] = cfg
	}
	return cfg
}

func (r *Replacer) DoReplace(body []byte, ctx ReplaceContext) []byte {
	config := r.getDomainConfig(ctx.BaseDomain)

	if ctx.Domain == "vk.com" {
		if ctx.Path == "/video_hls.php" {
			body = config.siteHlsReplace.apply(body)
		}
	} else {
		for _, replace := range config.apiReplaces {
			body = replace.apply(body)
		}

		// Replace longpoll server
		if ctx.Path == "/method/messages.getLongPollServer" {
			body = config.apiLongpollReplace.apply(body)
		} else

		// Replace longpoll server for official app
		if ctx.Path == "/method/execute" ||
			ctx.Path == "/method/execute.imGetLongPollHistoryExtended" ||
			ctx.Path == "/method/execute.imLpInit" {
			body = config.apiOfficialLongpollReplace.apply(body)
		}

		if ctx.FilterFeed {
			if ctx.Path == "/method/execute.getNewsfeedSmart" ||
				ctx.Path == "/method/newsfeed.get" {
				var parsed map[string]interface{}
				if err := json.Unmarshal(body, &parsed); err == nil {
					if parsed["response"] != nil {
						response := parsed["response"].(map[string]interface{})
						mod0 := false
						mod := false
						if response["items"] != nil {
							newItems, mod := filterFeed(response["items"].([]interface{}))
							if mod {
								mod0 = true
								response["items"] = newItems
							}
						}
						response, mod = tryInsertPost(response)
						if mod {
							mod0 = true
							parsed["response"] = response
						}
						if mod0 {
							body, err = json.Marshal(parsed)
						}
					}
				}
			}
		}
	}

	return body
}

func filterFeed(items []interface{}) ([]interface{}, bool) {
	removed := 0
	for i := len(items) - 1; i >= 0; i-- {
		post := items[i].(map[string]interface{})
		if post["type"] == "ads" || (post["type"] == "post" && post["marked_as_ads"] != nil && post["marked_as_ads"].(float64) == 1) {
			items[i] = items[len(items)-1]
			items[len(items)-1] = nil
			items = items[:len(items)-1]
			removed++
		}
	}
	if removed > 0 {
		newItems := make([]interface{}, len(items))
		copy(newItems, items)
		return newItems, true
	}
	return nil, false
}
<commit_msg>Поддержка api.vk.me<commit_after>package replacer

import (
	"bytes"

	"github.com/json-iterator/go"
)

var json = jsoniter.ConfigFastest

type domainConfig struct {
	apiReplaces                []replace
	apiOfficialLongpollReplace replace
	apiVkmeLongpollReplace     replace
	apiLongpollReplace         replace
	siteHlsReplace             replace
}

type Replacer struct {
	domains map[string]*domainConfig
}

type ReplaceContext struct {
	// vk-proxy domain name
	BaseDomain string

	Domain string
	Path   string

	FilterFeed bool
}

func (r *Replacer) getDomainConfig(domain string) *domainConfig {
	cfg, ok := r.domains[domain]
	if !ok {
		var replacementStart = []byte(`\/\/` + domain + `\/_\/`)
		var jsonUrlPrefix = []byte(`"https:`)
		var mVkCom = []byte(`m.vk.com`)
		cfg = &domainConfig{}
		cfg.apiReplaces = []replace{
			newStringReplace(`"https:\/\/vk.com\/video_hls.php`, `"https:\/\/`+domain+`\/@vk.com\/video_hls.php`),
			newRegexFastReplace(`\\/\\/[-_a-zA-Z0-9]{1,15}\.(?:userapi\.com|vk-cdn\.net|vk\.(?:me|com)|vkuser(?:live|video|audio)\.(?:net|com))\\/`,
				func(src, dst []byte, start, end int) []byte {
					// check if url has valid prefix (like in regexp backreference)
					if start < 7 || !bytes.Equal(src[start-7:start], jsonUrlPrefix) {
						goto cancel
					}
					// do not proxy m.vk.com domain (bugged articles)
					if bytes.Equal(src[start+4:end-2], mVkCom) {
						goto cancel
					}
					dst = append(dst, replacementStart...)
					dst = append(dst, src[start+4:end]...)
					return dst
				cancel:
					return append(dst, src[start:end]...)
				}),
			newRegexReplace(`"https:\\/\\/vk\.com\\/((?:\\/)?images\\/|sticker(:?\\/|s_)|doc-?[0-9]+_)`, `"https:\/\/`+domain+`\/_\/vk.com\/$1`),
		}
		cfg.apiOfficialLongpollReplace = newStringReplace(`"server":"api.vk.com\/newuim`, `"server":"`+domain+`\/_\/api.vk.com\/newuim`)
		cfg.apiVkmeLongpollReplace = newStringReplace(`"server":"api.vk.me\/uim`, `"server":"`+domain+`\/_\/api.vk.me\/uim`)
		cfg.apiLongpollReplace = newStringReplace(`"server":"`, `"server":"`+domain+`\/_\/`)
		cfg.siteHlsReplace = newRegexReplace(`https:\/\/([-_a-zA-Z0-9]+\.(?:userapi\.com|vk-cdn\.net|vk\.me|vkuser(?:live|video)\.(?:net|com)))\/`, `https://`+domain+`/_/$1/`)
		if r.domains == nil {
			r.domains = make(map[string]*domainConfig)
		}
		r.domains[domain] = cfg
	}
	return cfg
}

func (r *Replacer) DoReplace(body []byte, ctx ReplaceContext) []byte {
	config := r.getDomainConfig(ctx.BaseDomain)

	if ctx.Domain == "vk.com" {
		if ctx.Path == "/video_hls.php" {
			body = config.siteHlsReplace.apply(body)
		}
	} else {
		for _, replace := range config.apiReplaces {
			body = replace.apply(body)
		}

		// Replace longpoll server
		if ctx.Path == "/method/messages.getLongPollServer" {
			body = config.apiLongpollReplace.apply(body)
		} else

		// Replace longpoll server for official app
		if ctx.Path == "/method/execute" ||
			ctx.Path == "/method/execute.imGetLongPollHistoryExtended" ||
			ctx.Path == "/method/execute.imLpInit" {
			body = config.apiOfficialLongpollReplace.apply(body)
			body = config.apiVkmeLongpollReplace.apply(body)
		}

		if ctx.FilterFeed {
			if ctx.Path == "/method/execute.getNewsfeedSmart" ||
				ctx.Path == "/method/newsfeed.get" {
				var parsed map[string]interface{}
				if err := json.Unmarshal(body, &parsed); err == nil {
					if parsed["response"] != nil {
						response := parsed["response"].(map[string]interface{})
						mod0 := false
						mod := false
						if response["items"] != nil {
							newItems, mod := filterFeed(response["items"].([]interface{}))
							if mod {
								mod0 = true
								response["items"] = newItems
							}
						}
						response, mod = tryInsertPost(response)
						if mod {
							mod0 = true
							parsed["response"] = response
						}
						if mod0 {
							body, err = json.Marshal(parsed)
						}
					}
				}
			}
		}
	}

	return body
}

func filterFeed(items []interface{}) ([]interface{}, bool) {
	removed := 0
	for i := len(items) - 1; i >= 0; i-- {
		post := items[i].(map[string]interface{})
		if post["type"] == "ads" || (post["type"] == "post" && post["marked_as_ads"] != nil && post["marked_as_ads"].(float64) == 1) {
			items[i] = items[len(items)-1]
			items[len(items)-1] = nil
			items = items[:len(items)-1]
			removed++
		}
	}
	if removed > 0 {
		newItems := make([]interface{}, len(items))
		copy(newItems, items)
		return newItems, true
	}
	return nil, false
}
<|endoftext|>


<commit_before>package repofile

import (
	"fmt"
	"os"
	"os/user"
	"path"
	"path/filepath"
	"runtime"

	"github.com/arteev/logger"
)

//RepositoryFile - current file of repository
var (
	repositoryFile = "repository.sqlite"
	isDefaultRepo  = true
)

func init() {
	searchLocation()
}

func searchLocation() {
	//workdir
	if _, err := os.Stat(repositoryFile); err == nil {
		return
	}
	var cfgLocation string
	//appdata | ~/.config
	if u, err := user.Current(); err == nil {
		if runtime.GOOS == "windows" {
			cfgLocation = filepath.Join(u.HomeDir, os.Getenv("APPDATA"), "dsql", repositoryFile)
		} else {
			cfgLocation = filepath.Join(u.HomeDir, ".config", "dsql", repositoryFile)
		}
		if _, err := os.Stat(cfgLocation); err == nil {
			repositoryFile = cfgLocation
		}
        return
	}
	//folder dsql
	absPath, _ := filepath.Abs(path.Dir(os.Args[0]))
	inAppLocation := path.Join(absPath, repositoryFile)
	if _, err := os.Stat(inAppLocation); err == nil {
		repositoryFile = inAppLocation
		return
	}
	if cfgLocation != "" {
		repositoryFile = cfgLocation
	}
}

//SetRepositoryFile - set new location repository file
func SetRepositoryFile(filename string) {
	if !isDefaultRepo {
		panic(fmt.Errorf("can't twice change repository file "))
	}
	if filename != "" {
		isDefaultRepo = false
		repositoryFile = filename
	}
}

//GetRepositoryFile - get current location repository file
func GetRepositoryFile() string {
	return repositoryFile
}

//IsDefault returns location repository file is default
func IsDefault() bool {
	return isDefaultRepo
}

//PrepareLocation - make directories for repository files
func PrepareLocation() {
	dir := path.Dir(repositoryFile)
	if dir == "" {
		return
	}
	perm := 0700
	if err := os.MkdirAll(dir, os.FileMode(perm)); err != nil {
		logger.Error.Println(err)
	}
}
<commit_msg>repo file: fix appdata<commit_after>package repofile

import (
	"fmt"
	"os"
	"os/user"
	"path"
	"path/filepath"
	"runtime"

	"github.com/arteev/logger"
)

//RepositoryFile - current file of repository
var (
	repositoryFile = "repository.sqlite"
	isDefaultRepo  = true
)

func init() {
	searchLocation()
}

func searchLocation() {
	//workdir
	if _, err := os.Stat(repositoryFile); err == nil {
		return
	}
	var cfgLocation string
	//appdata | ~/.config
	if u, err := user.Current(); err == nil {
		if runtime.GOOS == "windows" {
			cfgLocation = filepath.Join(u.HomeDir, os.Getenv("APPDATA"), "dsql", repositoryFile)
		} else {
			cfgLocation = filepath.Join(u.HomeDir, ".config", "dsql", repositoryFile)
		}
		if _, err := os.Stat(cfgLocation); err == nil {
			repositoryFile = cfgLocation
            return
		}

	}
	//folder dsql
	absPath, _ := filepath.Abs(path.Dir(os.Args[0]))
	inAppLocation := path.Join(absPath, repositoryFile)
	if _, err := os.Stat(inAppLocation); err == nil {
		repositoryFile = inAppLocation
		return
	}
	if cfgLocation != "" {
		repositoryFile = cfgLocation
	}
}

//SetRepositoryFile - set new location repository file
func SetRepositoryFile(filename string) {
	if !isDefaultRepo {
		panic(fmt.Errorf("can't twice change repository file "))
	}
	if filename != "" {
		isDefaultRepo = false
		repositoryFile = filename
	}
}

//GetRepositoryFile - get current location repository file
func GetRepositoryFile() string {
	return repositoryFile
}

//IsDefault returns location repository file is default
func IsDefault() bool {
	return isDefaultRepo
}

//PrepareLocation - make directories for repository files
func PrepareLocation() {
	dir := path.Dir(repositoryFile)
	if dir == "" {
		return
	}
	perm := 0700
	if err := os.MkdirAll(dir, os.FileMode(perm)); err != nil {
		logger.Error.Println(err)
	}
}
<|endoftext|>


<commit_before>package reporter

import (
	"fmt"

	"github.com/Songmu/horenso"
	"github.com/bluele/slack"
)

// GetAttachments get attachments for message
func GetAttachments(r horenso.Report, items []string) []*slack.Attachment {
	var attachments []*slack.Attachment

	var a slack.Attachment
	a.Fallback = "horenso Reporter"
	a.AuthorName = "horenso Reporter"

	if *r.ExitCode == 0 {
		a.Color = "#32B232"
	} else {
		a.Color = "#FF0000"
	}

	fields := []*slack.AttachmentField{}

	if IsSelectedItem("Result", items) {
		fields = append(fields, &slack.AttachmentField{
			Title: "Result",
			Value: fmt.Sprintf("%v", r.Result),
			Short: true,
		})
	}

	if IsSelectedItem("Output", items) {
		fields = append(fields, &slack.AttachmentField{
			Title: "Output",
			Value: fmt.Sprintf("%v", r.Output),
			Short: true,
		})
	}

	if IsSelectedItem("Stdout", items) {
		fields = append(fields, &slack.AttachmentField{
			Title: "Stdout",
			Value: fmt.Sprintf("%v", r.Stdout),
			Short: true,
		})
	}

	if IsSelectedItem("Stderr", items) {
		fields = append(fields, &slack.AttachmentField{
			Title: "Stderr",
			Value: fmt.Sprintf("%v", r.Stderr),
			Short: true,
		})
	}

	if IsSelectedItem("Command", items) {
		fields = append(fields, &slack.AttachmentField{
			Title: "Command",
			Value: fmt.Sprintf("%v", r.Command),
			Short: true,
		})
	}

	if IsSelectedItem("CommandArgs", items) {
		fields = append(fields, &slack.AttachmentField{
			Title: "CommandArgs",
			Value: fmt.Sprintf("%v", r.CommandArgs),
			Short: true,
		})
	}

	if IsSelectedItem("Pid", items) {
		fields = append(fields, &slack.AttachmentField{
			Title: "Pid",
			Value: fmt.Sprintf("%d", r.Pid),
			Short: true,
		})
	}

	if IsSelectedItem("ExitCode", items) {
		fields = append(fields, &slack.AttachmentField{
			Title: "ExitCode",
			Value: fmt.Sprintf("%d", *r.ExitCode),
			Short: true,
		})
	}

	if IsSelectedItem("StartAt", items) {
		fields = append(fields, &slack.AttachmentField{
			Title: "StartAt",
			Value: fmt.Sprintf("%v", r.StartAt),
			Short: true,
		})
	}
	if IsSelectedItem("EndAt", items) {
		fields = append(fields, &slack.AttachmentField{
			Title: "EndAt",
			Value: fmt.Sprintf("%v", r.EndAt),
			Short: true,
		})
	}
	if IsSelectedItem("Hostname", items) {
		fields = append(fields, &slack.AttachmentField{
			Title: "Hostname",
			Value: fmt.Sprintf("%v", r.Hostname),
			Short: true,
		})
	}
	if IsSelectedItem("SystemTime", items) {
		fields = append(fields, &slack.AttachmentField{
			Title: "SystemTime",
			Value: fmt.Sprintf("%f", *r.SystemTime),
			Short: true,
		})
	}
	if IsSelectedItem("UserTime", items) {
		fields = append(fields, &slack.AttachmentField{
			Title: "UserTime",
			Value: fmt.Sprintf("%f", *r.UserTime),
			Short: true,
		})
	}

	a.Fields = fields

	return append(attachments, &a)
}

// GetSlackChatPostMessageOpt message options for message
func GetSlackChatPostMessageOpt(r horenso.Report, items []string) slack.ChatPostMessageOpt {
	return slack.ChatPostMessageOpt{
		Attachments: GetAttachments(r, items),
	}
}

// SendReportToSlack send Report to Slack
func SendReportToSlack(api *slack.Slack, r horenso.Report, id string, m string, items []string) {
	opt := GetSlackChatPostMessageOpt(r, items)

	err := api.ChatPostMessage(id, m, &opt)
	if err != nil {
		panic(err)
	}
}

// IsSelectedItem returns key exists in slice
func IsSelectedItem(a string, list []string) bool {
	if len(list) == 0 {
		return false
	}

	if list[0] == "all" {
		return true
	}

	for _, b := range list {
		if b == a {
			return true
		}
	}
	return false
}
<commit_msg>Change message format<commit_after>package reporter

import (
	"fmt"

	"github.com/Songmu/horenso"
	"github.com/bluele/slack"
)

// GetAttachments get attachments for message
func GetAttachments(r horenso.Report, items []string) []*slack.Attachment {
	var attachments []*slack.Attachment

	var a slack.Attachment
	a.Fallback = "horenso Reporter"
	a.AuthorName = "horenso Reporter"

	if *r.ExitCode == 0 {
		a.Color = "#32B232"
	} else {
		a.Color = "#FF0000"
	}

	fields := []*slack.AttachmentField{}

	if IsSelectedItem("Result", items) {
		fields = append(fields, &slack.AttachmentField{
			Title: "Result",
			Value: fmt.Sprintf("%v", r.Result),
			Short: false,
		})
	}

	if IsSelectedItem("Output", items) {
		fields = append(fields, &slack.AttachmentField{
			Title: "Output",
			Value: fmt.Sprintf("%v", r.Output),
			Short: false,
		})
	}

	if IsSelectedItem("Stdout", items) {
		fields = append(fields, &slack.AttachmentField{
			Title: "Stdout",
			Value: fmt.Sprintf("%v", r.Stdout),
			Short: false,
		})
	}

	if IsSelectedItem("Stderr", items) {
		fields = append(fields, &slack.AttachmentField{
			Title: "Stderr",
			Value: fmt.Sprintf("%v", r.Stderr),
			Short: false,
		})
	}

	if IsSelectedItem("Command", items) {
		fields = append(fields, &slack.AttachmentField{
			Title: "Command",
			Value: fmt.Sprintf("%v", r.Command),
			Short: true,
		})
	}

	if IsSelectedItem("CommandArgs", items) {
		fields = append(fields, &slack.AttachmentField{
			Title: "CommandArgs",
			Value: fmt.Sprintf("%v", r.CommandArgs),
			Short: true,
		})
	}

	if IsSelectedItem("Pid", items) {
		fields = append(fields, &slack.AttachmentField{
			Title: "Pid",
			Value: fmt.Sprintf("%d", r.Pid),
			Short: true,
		})
	}

	if IsSelectedItem("ExitCode", items) {
		fields = append(fields, &slack.AttachmentField{
			Title: "ExitCode",
			Value: fmt.Sprintf("%d", *r.ExitCode),
			Short: true,
		})
	}

	if IsSelectedItem("StartAt", items) {
		fields = append(fields, &slack.AttachmentField{
			Title: "StartAt",
			Value: fmt.Sprintf("%v", r.StartAt),
			Short: true,
		})
	}
	if IsSelectedItem("EndAt", items) {
		fields = append(fields, &slack.AttachmentField{
			Title: "EndAt",
			Value: fmt.Sprintf("%v", r.EndAt),
			Short: true,
		})
	}
	if IsSelectedItem("Hostname", items) {
		fields = append(fields, &slack.AttachmentField{
			Title: "Hostname",
			Value: fmt.Sprintf("%v", r.Hostname),
			Short: true,
		})
	}
	if IsSelectedItem("SystemTime", items) {
		fields = append(fields, &slack.AttachmentField{
			Title: "SystemTime",
			Value: fmt.Sprintf("%f", *r.SystemTime),
			Short: true,
		})
	}
	if IsSelectedItem("UserTime", items) {
		fields = append(fields, &slack.AttachmentField{
			Title: "UserTime",
			Value: fmt.Sprintf("%f", *r.UserTime),
			Short: true,
		})
	}

	a.Fields = fields

	return append(attachments, &a)
}

// GetSlackChatPostMessageOpt message options for message
func GetSlackChatPostMessageOpt(r horenso.Report, items []string) slack.ChatPostMessageOpt {
	return slack.ChatPostMessageOpt{
		Attachments: GetAttachments(r, items),
	}
}

// SendReportToSlack send Report to Slack
func SendReportToSlack(api *slack.Slack, r horenso.Report, id string, m string, items []string) {
	opt := GetSlackChatPostMessageOpt(r, items)

	err := api.ChatPostMessage(id, m, &opt)
	if err != nil {
		panic(err)
	}
}

// IsSelectedItem returns key exists in slice
func IsSelectedItem(a string, list []string) bool {
	if len(list) == 0 {
		return false
	}

	if list[0] == "all" {
		return true
	}

	for _, b := range list {
		if b == a {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package repos

import (
	"errors"
	"log"
	"strings"
	"time"

	"github.com/khades/servbot/models"
	"gopkg.in/mgo.v2/bson"
)

var autoMessageCollectionName = "autoMessages"

func DecrementAutoMessages(channelID *string) {
	channelInfo, error := GetChannelInfo(channelID)
	games := []string{""}
	if error == nil && channelInfo.StreamStatus.Online == true {
		games = append(games, channelInfo.StreamStatus.Game)
	}
	Db.C(autoMessageCollectionName).UpdateAll(bson.M{
		"channelid": *channelID,
		"message":   bson.M{"$ne": ""},
		"$or": []bson.M{
			bson.M{"game": bson.M{"$in": games}},
			bson.M{"game": bson.M{"$exists": false}}}},
		bson.M{"$inc": bson.M{"messagethreshold": -1}})
}
func RemoveInactiveAutoMessages(channelID *string) (*[]models.AutoMessage, error) {
	var result []models.AutoMessage
	error := Db.C(autoMessageCollectionName).Find(bson.M{
		"channelid": *channelID,
		"message":   ""}).All(&result)
	return &result, error
}
func GetCurrentAutoMessages() (*[]models.AutoMessage, error) {
	//log.Println("AutoMessage: Getting Current AutoMessages")
	var result []models.AutoMessage
	error := Db.C(autoMessageCollectionName).Find(bson.M{
		"message":           bson.M{"$ne": ""},
		"messagethreshold":  bson.M{"$lte": 0},
		"durationthreshold": bson.M{"$lte": time.Now()}}).All(&result)
	log.Printf("AutoMessage: Got %d AutoMessages", len(result))
	//log.Println(error)
	return &result, error
}

func ResetAutoMessageThreshold(autoMessage *models.AutoMessage) {
	log.Printf("AutoMessage: Resetting AutoMessage %s", autoMessage.ID)
	now := time.Now()
	Db.C(autoMessageCollectionName).Update(bson.M{"_id": autoMessage.ID}, bson.M{"$set": bson.M{
		"messagethreshold":  autoMessage.MessageLimit,
		"durationthreshold": now.Add(autoMessage.DurationLimit)}})
}

func GetAutoMessage(id *string, channelID *string) (*models.AutoMessageWithHistory, error) {
	var result models.AutoMessageWithHistory
	objectID := bson.ObjectIdHex(*id)
	error := Db.C(autoMessageCollectionName).Find(bson.M{"_id": objectID, "channelid": *channelID}).One(&result)
	return &result, error
}

func GetAutoMessages(channelID *string) (*[]models.AutoMessageWithHistory, error) {
	var result []models.AutoMessageWithHistory
	error := Db.C(autoMessageCollectionName).Find(bson.M{"channelid": *channelID}).All(&result)
	return &result, error
}
func CreateAutoMessage(autoMessageUpdate *models.AutoMessageUpdate) (*bson.ObjectId, error) {
	id := bson.NewObjectId()
	now := time.Now()
	if strings.TrimSpace(autoMessageUpdate.Message) == "" || autoMessageUpdate.DurationLimit < 60 || autoMessageUpdate.MessageLimit < 20 {
		return nil, errors.New("Validation Failed")
	}
	var durationLimit = time.Second * time.Duration(autoMessageUpdate.DurationLimit)
	Db.C(autoMessageCollectionName).Insert(
		models.AutoMessageWithHistory{
			AutoMessage: models.AutoMessage{
				ID:                id,
				ChannelID:         autoMessageUpdate.ChannelID,
				Message:           autoMessageUpdate.Message,
				MessageThreshold:  autoMessageUpdate.MessageLimit,
				MessageLimit:      autoMessageUpdate.MessageLimit,
				Game:              autoMessageUpdate.Game,
				DurationLimit:     durationLimit,
				DurationThreshold: now.Add(durationLimit)},
			History: []models.AutoMessageHistory{
				models.AutoMessageHistory{
					User:          autoMessageUpdate.User,
					UserID:        autoMessageUpdate.UserID,
					Game:          autoMessageUpdate.Game,
					Date:          now,
					Message:       autoMessageUpdate.Message,
					MessageLimit:  autoMessageUpdate.MessageLimit,
					DurationLimit: durationLimit}}})
	return &id, nil
}

func UpdateAutoMessage(autoMessageUpdate *models.AutoMessageUpdate) error {
	if autoMessageUpdate.DurationLimit < 60 || autoMessageUpdate.MessageLimit < 20 {
		return errors.New("Validation Failed")
	}
	now := time.Now()
	var durationLimit = time.Second * time.Duration(autoMessageUpdate.DurationLimit)
	Db.C(autoMessageCollectionName).Update(
		bson.M{"_id": bson.ObjectIdHex(autoMessageUpdate.ID), "channelid": autoMessageUpdate.ChannelID},
		bson.M{
			"$push": bson.M{
				"history": bson.M{
					"$each": []models.AutoMessageHistory{models.AutoMessageHistory{
						User:          autoMessageUpdate.User,
						UserID:        autoMessageUpdate.UserID,
						Game:          autoMessageUpdate.Game,
						Date:          now,
						Message:       autoMessageUpdate.Message,
						MessageLimit:  autoMessageUpdate.MessageLimit,
						DurationLimit: durationLimit}},
					"$sort":  bson.M{"date": -1},
					"$slice": 5}},

			"$set": models.AutoMessage{
				ChannelID:         autoMessageUpdate.ChannelID,
				Message:           autoMessageUpdate.Message,
				MessageThreshold:  autoMessageUpdate.MessageLimit,
				MessageLimit:      autoMessageUpdate.MessageLimit,
				Game:              autoMessageUpdate.Game,
				DurationLimit:     durationLimit,
				DurationThreshold: now.Add(durationLimit)}})
	return nil
}
<commit_msg>Debug: removing inactive automessages<commit_after>package repos

import (
	"errors"
	"log"
	"strings"
	"time"

	"github.com/khades/servbot/models"
	"gopkg.in/mgo.v2/bson"
)

var autoMessageCollectionName = "autoMessages"

func DecrementAutoMessages(channelID *string) {
	channelInfo, error := GetChannelInfo(channelID)
	games := []string{""}
	if error == nil && channelInfo.StreamStatus.Online == true {
		games = append(games, channelInfo.StreamStatus.Game)
	}
	Db.C(autoMessageCollectionName).UpdateAll(bson.M{
		"channelid": *channelID,
		"message":   bson.M{"$ne": ""},
		"$or": []bson.M{
			bson.M{"game": bson.M{"$in": games}},
			bson.M{"game": bson.M{"$exists": false}}}},
		bson.M{"$inc": bson.M{"messagethreshold": -1}})
}
func RemoveInactiveAutoMessages(channelID *string) (*[]models.AutoMessage, error) {
	var result []models.AutoMessage
	error := Db.C(autoMessageCollectionName).Find(bson.M{
		"channelid": *channelID,
		"message":   "",
		"history.date":
			bson.M{"$not": bson.M{"$gte": time.Now().Add(24 * -7 * time.Hour)}}}).All(&result)
	return &result, error
}
func GetCurrentAutoMessages() (*[]models.AutoMessage, error) {
	//log.Println("AutoMessage: Getting Current AutoMessages")
	var result []models.AutoMessage
	error := Db.C(autoMessageCollectionName).Find(bson.M{
		"message":           bson.M{"$ne": ""},
		"messagethreshold":  bson.M{"$lte": 0},
		"durationthreshold": bson.M{"$lte": time.Now()}}).All(&result)
	log.Printf("AutoMessage: Got %d AutoMessages", len(result))
	//log.Println(error)
	return &result, error
}

func ResetAutoMessageThreshold(autoMessage *models.AutoMessage) {
	log.Printf("AutoMessage: Resetting AutoMessage %s", autoMessage.ID)
	now := time.Now()
	Db.C(autoMessageCollectionName).Update(bson.M{"_id": autoMessage.ID}, bson.M{"$set": bson.M{
		"messagethreshold":  autoMessage.MessageLimit,
		"durationthreshold": now.Add(autoMessage.DurationLimit)}})
}

func GetAutoMessage(id *string, channelID *string) (*models.AutoMessageWithHistory, error) {
	var result models.AutoMessageWithHistory
	objectID := bson.ObjectIdHex(*id)
	error := Db.C(autoMessageCollectionName).Find(bson.M{"_id": objectID, "channelid": *channelID}).One(&result)
	return &result, error
}

func GetAutoMessages(channelID *string) (*[]models.AutoMessageWithHistory, error) {
	var result []models.AutoMessageWithHistory
	error := Db.C(autoMessageCollectionName).Find(bson.M{"channelid": *channelID}).All(&result)
	return &result, error
}
func CreateAutoMessage(autoMessageUpdate *models.AutoMessageUpdate) (*bson.ObjectId, error) {
	id := bson.NewObjectId()
	now := time.Now()
	if strings.TrimSpace(autoMessageUpdate.Message) == "" || autoMessageUpdate.DurationLimit < 60 || autoMessageUpdate.MessageLimit < 20 {
		return nil, errors.New("Validation Failed")
	}
	var durationLimit = time.Second * time.Duration(autoMessageUpdate.DurationLimit)
	Db.C(autoMessageCollectionName).Insert(
		models.AutoMessageWithHistory{
			AutoMessage: models.AutoMessage{
				ID:                id,
				ChannelID:         autoMessageUpdate.ChannelID,
				Message:           autoMessageUpdate.Message,
				MessageThreshold:  autoMessageUpdate.MessageLimit,
				MessageLimit:      autoMessageUpdate.MessageLimit,
				Game:              autoMessageUpdate.Game,
				DurationLimit:     durationLimit,
				DurationThreshold: now.Add(durationLimit)},
			History: []models.AutoMessageHistory{
				models.AutoMessageHistory{
					User:          autoMessageUpdate.User,
					UserID:        autoMessageUpdate.UserID,
					Game:          autoMessageUpdate.Game,
					Date:          now,
					Message:       autoMessageUpdate.Message,
					MessageLimit:  autoMessageUpdate.MessageLimit,
					DurationLimit: durationLimit}}})
	return &id, nil
}

func UpdateAutoMessage(autoMessageUpdate *models.AutoMessageUpdate) error {
	if autoMessageUpdate.DurationLimit < 60 || autoMessageUpdate.MessageLimit < 20 {
		return errors.New("Validation Failed")
	}
	now := time.Now()
	var durationLimit = time.Second * time.Duration(autoMessageUpdate.DurationLimit)
	Db.C(autoMessageCollectionName).Update(
		bson.M{"_id": bson.ObjectIdHex(autoMessageUpdate.ID), "channelid": autoMessageUpdate.ChannelID},
		bson.M{
			"$push": bson.M{
				"history": bson.M{
					"$each": []models.AutoMessageHistory{models.AutoMessageHistory{
						User:          autoMessageUpdate.User,
						UserID:        autoMessageUpdate.UserID,
						Game:          autoMessageUpdate.Game,
						Date:          now,
						Message:       autoMessageUpdate.Message,
						MessageLimit:  autoMessageUpdate.MessageLimit,
						DurationLimit: durationLimit}},
					"$sort":  bson.M{"date": -1},
					"$slice": 5}},

			"$set": models.AutoMessage{
				ChannelID:         autoMessageUpdate.ChannelID,
				Message:           autoMessageUpdate.Message,
				MessageThreshold:  autoMessageUpdate.MessageLimit,
				MessageLimit:      autoMessageUpdate.MessageLimit,
				Game:              autoMessageUpdate.Game,
				DurationLimit:     durationLimit,
				DurationThreshold: now.Add(durationLimit)}})
	return nil
}
<|endoftext|>


<commit_before>package raygun4go

import (
	"errors"
	"io/ioutil"
	"net/http"
	"net/url"
	"testing"

	"github.com/kaeuferportal/stack2struct"
	. "github.com/smartystreets/goconvey/convey"
)

func TestRequestData(t *testing.T) {
	Convey("#NewRequestData", t, func() {
		u := "http://www.example.com?foo=bar&fizz[]=buzz&fizz[]=buzz2"
		r, _ := http.NewRequest("GET", u, nil)

		Convey("empty if no request given", func() {
			d := newRequestData(nil)
			So(d, ShouldResemble, requestData{})
		})

		Convey("basic data", func() {
			r.RemoteAddr = "1.2.3.4"

			d := newRequestData(r)
			So(d.HostName, ShouldEqual, "www.example.com")
			So(d.URL, ShouldEqual, u)
			So(d.HTTPMethod, ShouldEqual, "GET")
			So(d.IPAddress, ShouldResemble, "1.2.3.4")
		})

		Convey("Form", func() {
			r.PostForm = url.Values{
				"foo":  []string{"bar"},
				"fizz": []string{"buzz", "buzz2"},
			}
			expected := map[string]string{
				"foo":  "bar",
				"fizz": "[buzz; buzz2]",
			}

			d := newRequestData(r)
			So(d.Form, ShouldResemble, expected)
		})

		Convey("QueryString", func() {
			expected := map[string]string{
				"foo":    "bar",
				"fizz[]": "[buzz; buzz2]",
			}

			d := newRequestData(r)
			So(d.QueryString, ShouldResemble, expected)
		})

		Convey("Headers", func() {
			r.Header = map[string][]string{
				"foo":  []string{"bar"},
				"fizz": []string{"buzz"},
			}
			expected := map[string]string{
				"foo":  "bar",
				"fizz": "buzz",
			}

			d := newRequestData(r)
			So(d.Headers, ShouldResemble, expected)
		})
	})
}

func TestErrorData(t *testing.T) {
	Convey("#NewErrorData", t, func() {
		trace, _ := ioutil.ReadFile("_fixtures/stack_trace")
		e := errors.New("test error")
		stack := make(stackTrace, 0, 0)
		stack2struct.Parse(trace, &stack)

		d := newErrorData(e, stack[3:])

		expected := stackTrace{
			stackTraceElement{11, "foo/package1", "filename1.go", "method1·001()"},
			stackTraceElement{22, "foo/package2", "filename2.go", "(*action).method2(0x208304420)"},
		}
		So(d.Message, ShouldEqual, "test error")
		So(d.StackTrace[0], ShouldResemble, expected[0])
		So(d.StackTrace[1], ShouldResemble, expected[1])
	})
}

func TestUser(t *testing.T) {
	Convey("has an exported identifier", t, func() {
		u := user{"test"}
		So(u.Identifier, ShouldEqual, "test")
	})
}

func TestContext(t *testing.T) {
	Convey("has an exported identifier", t, func() {
		c := context{"test"}
		So(c.Identifier, ShouldEqual, "test")
	})
}

func Test(t *testing.T) {
	Convey("", t, func() {
	})
}
<commit_msg>gofmt -s<commit_after>package raygun4go

import (
	"errors"
	"io/ioutil"
	"net/http"
	"net/url"
	"testing"

	"github.com/kaeuferportal/stack2struct"
	. "github.com/smartystreets/goconvey/convey"
)

func TestRequestData(t *testing.T) {
	Convey("#NewRequestData", t, func() {
		u := "http://www.example.com?foo=bar&fizz[]=buzz&fizz[]=buzz2"
		r, _ := http.NewRequest("GET", u, nil)

		Convey("empty if no request given", func() {
			d := newRequestData(nil)
			So(d, ShouldResemble, requestData{})
		})

		Convey("basic data", func() {
			r.RemoteAddr = "1.2.3.4"

			d := newRequestData(r)
			So(d.HostName, ShouldEqual, "www.example.com")
			So(d.URL, ShouldEqual, u)
			So(d.HTTPMethod, ShouldEqual, "GET")
			So(d.IPAddress, ShouldResemble, "1.2.3.4")
		})

		Convey("Form", func() {
			r.PostForm = url.Values{
				"foo":  []string{"bar"},
				"fizz": []string{"buzz", "buzz2"},
			}
			expected := map[string]string{
				"foo":  "bar",
				"fizz": "[buzz; buzz2]",
			}

			d := newRequestData(r)
			So(d.Form, ShouldResemble, expected)
		})

		Convey("QueryString", func() {
			expected := map[string]string{
				"foo":    "bar",
				"fizz[]": "[buzz; buzz2]",
			}

			d := newRequestData(r)
			So(d.QueryString, ShouldResemble, expected)
		})

		Convey("Headers", func() {
			r.Header = map[string][]string{
				"foo":  {"bar"},
				"fizz": {"buzz"},
			}
			expected := map[string]string{
				"foo":  "bar",
				"fizz": "buzz",
			}

			d := newRequestData(r)
			So(d.Headers, ShouldResemble, expected)
		})
	})
}

func TestErrorData(t *testing.T) {
	Convey("#NewErrorData", t, func() {
		trace, _ := ioutil.ReadFile("_fixtures/stack_trace")
		e := errors.New("test error")
		stack := make(stackTrace, 0, 0)
		stack2struct.Parse(trace, &stack)

		d := newErrorData(e, stack[3:])

		expected := stackTrace{
			stackTraceElement{11, "foo/package1", "filename1.go", "method1·001()"},
			stackTraceElement{22, "foo/package2", "filename2.go", "(*action).method2(0x208304420)"},
		}
		So(d.Message, ShouldEqual, "test error")
		So(d.StackTrace[0], ShouldResemble, expected[0])
		So(d.StackTrace[1], ShouldResemble, expected[1])
	})
}

func TestUser(t *testing.T) {
	Convey("has an exported identifier", t, func() {
		u := user{"test"}
		So(u.Identifier, ShouldEqual, "test")
	})
}

func TestContext(t *testing.T) {
	Convey("has an exported identifier", t, func() {
		c := context{"test"}
		So(c.Identifier, ShouldEqual, "test")
	})
}

func Test(t *testing.T) {
	Convey("", t, func() {
	})
}
<|endoftext|>


<commit_before>/*
 *    Copyright (C) 2014-2017 Christian Muehlhaeuser
 *
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Affero General Public License as published
 *    by the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *    Authors:
 *      Christian Muehlhaeuser <muesli@gmail.com>
 */

// Package webbee is a Bee that starts an HTTP server and fires events for
// incoming requests.
package webbee

import (
	"encoding/json"
	"io/ioutil"
	"net/http"
	"strings"

	"github.com/hoisie/web"

	"github.com/muesli/beehive/bees"
)

// WebBee is a Bee that starts an HTTP server and fires events for incoming
// requests.
type WebBee struct {
	bees.Bee

	addr string
	path string

	eventChan chan bees.Event
}

func (mod *WebBee) triggerJSONEvent(resp *[]byte) {
	var payload interface{}
	err := json.Unmarshal(*resp, &payload)
	if err != nil {
		mod.LogErrorf("Error: %s", err)
		return
	}

	ev := bees.Event{
		Bee:  mod.Name(),
		Name: "post",
		Options: []bees.Placeholder{
			{
				Name:  "json",
				Type:  "map",
				Value: payload,
			},
			{
				Name:  "ip",
				Type:  "string",
				Value: "tbd",
			},
		},
	}

	j := make(map[string]interface{})
	err = json.Unmarshal(*resp, &j)
	if err != nil {
		mod.LogErrorf("Error: %s", err)
		return
	}

	for k, v := range j {
		mod.Logf("POST JSON param: %s = %+v\n", k, v)

		ph := bees.Placeholder{
			Name:  k,
			Type:  "string",
			Value: v,
		}
		ev.Options = append(ev.Options, ph)
	}

	mod.eventChan <- ev
}

// Run executes the Bee's event loop.
func (mod *WebBee) Run(cin chan bees.Event) {
	mod.eventChan = cin

	web.Get(mod.path, mod.getRequest)
	web.Post(mod.path, mod.postRequest)

	web.Run(mod.addr)

	for {
		select {
		case <-mod.SigChan:
			web.Close()
			return

		default:
		}
	}
}

// Action triggers the action passed to it.
func (mod *WebBee) Action(action bees.Action) []bees.Placeholder {
	outs := []bees.Placeholder{}

	switch action.Name {
	case "post":
		url := ""
		j := ""
		action.Options.Bind("url", &url)
		action.Options.Bind("json", &j)

		buf := strings.NewReader(j)
		resp, err := http.Post(url, "application/json", buf)
		if err != nil {
			mod.LogErrorf("Error: %s", err)
			return outs
		}

		b, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			mod.LogErrorf("Error: %s", err)
			return outs
		}

		mod.triggerJSONEvent(&b)

	default:
		panic("Unknown action triggered in " + mod.Name() + ": " + action.Name)
	}

	return outs
}

// getRequest gets called for incoming GET requests
func (mod *WebBee) getRequest(ctx *web.Context) {
	ev := bees.Event{
		Bee:  mod.Name(),
		Name: "get",
		Options: []bees.Placeholder{
			{
				Name:  "ip",
				Type:  "string",
				Value: "tbd",
			},
		},
	}

	for k, v := range ctx.Params {
		mod.Logln("GET param:", k, "=", v)

		ph := bees.Placeholder{
			Name:  k,
			Type:  "string",
			Value: v,
		}
		ev.Options = append(ev.Options, ph)
	}

	mod.eventChan <- ev
}

// postRequest gets called for incoming POST requests
func (mod *WebBee) postRequest(ctx *web.Context) {
	b, err := ioutil.ReadAll(ctx.Request.Body)
	if err != nil {
		mod.LogErrorf("Error: %s", err)
		return
	}

	mod.triggerJSONEvent(&b)
}

// ReloadOptions parses the config options and initializes the Bee.
func (mod *WebBee) ReloadOptions(options bees.BeeOptions) {
	mod.SetOptions(options)

	options.Bind("address", &mod.addr)
	options.Bind("path", &mod.path)
}
<commit_msg>Get rid of default select-case in WebBee<commit_after>/*
 *    Copyright (C) 2014-2017 Christian Muehlhaeuser
 *
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Affero General Public License as published
 *    by the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *    Authors:
 *      Christian Muehlhaeuser <muesli@gmail.com>
 */

// Package webbee is a Bee that starts an HTTP server and fires events for
// incoming requests.
package webbee

import (
	"encoding/json"
	"io/ioutil"
	"net/http"
	"strings"

	"github.com/hoisie/web"

	"github.com/muesli/beehive/bees"
)

// WebBee is a Bee that starts an HTTP server and fires events for incoming
// requests.
type WebBee struct {
	bees.Bee

	addr string
	path string

	eventChan chan bees.Event
}

func (mod *WebBee) triggerJSONEvent(resp *[]byte) {
	var payload interface{}
	err := json.Unmarshal(*resp, &payload)
	if err != nil {
		mod.LogErrorf("Error: %s", err)
		return
	}

	ev := bees.Event{
		Bee:  mod.Name(),
		Name: "post",
		Options: []bees.Placeholder{
			{
				Name:  "json",
				Type:  "map",
				Value: payload,
			},
			{
				Name:  "ip",
				Type:  "string",
				Value: "tbd",
			},
		},
	}

	j := make(map[string]interface{})
	err = json.Unmarshal(*resp, &j)
	if err != nil {
		mod.LogErrorf("Error: %s", err)
		return
	}

	for k, v := range j {
		mod.Logf("POST JSON param: %s = %+v\n", k, v)

		ph := bees.Placeholder{
			Name:  k,
			Type:  "string",
			Value: v,
		}
		ev.Options = append(ev.Options, ph)
	}

	mod.eventChan <- ev
}

// Run executes the Bee's event loop.
func (mod *WebBee) Run(cin chan bees.Event) {
	mod.eventChan = cin

	web.Get(mod.path, mod.getRequest)
	web.Post(mod.path, mod.postRequest)

	web.Run(mod.addr)
	defer web.Close()

	select {
	case <-mod.SigChan:
		return
	}
}

// Action triggers the action passed to it.
func (mod *WebBee) Action(action bees.Action) []bees.Placeholder {
	outs := []bees.Placeholder{}

	switch action.Name {
	case "post":
		url := ""
		j := ""
		action.Options.Bind("url", &url)
		action.Options.Bind("json", &j)

		buf := strings.NewReader(j)
		resp, err := http.Post(url, "application/json", buf)
		if err != nil {
			mod.LogErrorf("Error: %s", err)
			return outs
		}

		b, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			mod.LogErrorf("Error: %s", err)
			return outs
		}

		mod.triggerJSONEvent(&b)

	default:
		panic("Unknown action triggered in " + mod.Name() + ": " + action.Name)
	}

	return outs
}

// getRequest gets called for incoming GET requests
func (mod *WebBee) getRequest(ctx *web.Context) {
	ev := bees.Event{
		Bee:  mod.Name(),
		Name: "get",
		Options: []bees.Placeholder{
			{
				Name:  "ip",
				Type:  "string",
				Value: "tbd",
			},
		},
	}

	for k, v := range ctx.Params {
		mod.Logln("GET param:", k, "=", v)

		ph := bees.Placeholder{
			Name:  k,
			Type:  "string",
			Value: v,
		}
		ev.Options = append(ev.Options, ph)
	}

	mod.eventChan <- ev
}

// postRequest gets called for incoming POST requests
func (mod *WebBee) postRequest(ctx *web.Context) {
	b, err := ioutil.ReadAll(ctx.Request.Body)
	if err != nil {
		mod.LogErrorf("Error: %s", err)
		return
	}

	mod.triggerJSONEvent(&b)
}

// ReloadOptions parses the config options and initializes the Bee.
func (mod *WebBee) ReloadOptions(options bees.BeeOptions) {
	mod.SetOptions(options)

	options.Bind("address", &mod.addr)
	options.Bind("path", &mod.path)
}
<|endoftext|>


<commit_before>package versions

import (
	"encoding/json"
	"reflect"
	"testing"
)

// Make sure our set implementations all actually implement the interface
var _ setI = setBound{}
var _ setI = setExact{}
var _ setI = setExtreme(true)
var _ setI = setIntersection{}
var _ setI = setSubtract{}
var _ setI = setUnion{}
var _ setI = setReleased{}

func TestSetHas(t *testing.T) {
	tests := []struct {
		Set  Set
		Has  Version
		Want bool
	}{
		{
			All,
			Unspecified,
			true,
		},
		{
			None,
			Unspecified,
			false,
		},
		{
			All.Subtract(Only(MustParseVersion("1.0.0"))),
			Unspecified,
			false, // any sort of constraint removes the special Unspecified version
		},
		{
			InitialDevelopment,
			Unspecified,
			false,
		},
		{
			InitialDevelopment,
			MustParseVersion("0.0.2"),
			true,
		},
		{
			InitialDevelopment,
			MustParseVersion("1.0.0"),
			false,
		},
		{
			Released,
			MustParseVersion("1.0.0"),
			true,
		},
		{
			Released,
			MustParseVersion("1.0.0-beta1"),
			false,
		},
		{
			Prerelease,
			MustParseVersion("1.0.0"),
			false,
		},
		{
			Prerelease,
			MustParseVersion("1.0.0-beta1"),
			true,
		},
		{
			Union(
				Only(MustParseVersion("1.0.0")),
				Only(MustParseVersion("1.1.0")),
			),
			MustParseVersion("1.0.0"),
			true,
		},
		{
			Union(
				Only(MustParseVersion("1.0.0")),
				Only(MustParseVersion("1.1.0")),
			),
			MustParseVersion("1.1.0"),
			true,
		},
		{
			Union(
				Only(MustParseVersion("1.0.0")),
				Only(MustParseVersion("1.1.0")),
			),
			MustParseVersion("1.2.0"),
			false,
		},
		{
			Union(
				Only(MustParseVersion("1.0.0")),
				Only(MustParseVersion("1.1.0")),
				Only(MustParseVersion("1.2.0")),
			),
			MustParseVersion("1.2.0"),
			true,
		},
		{
			Intersection(
				AtLeast(MustParseVersion("1.0.0")),
				OlderThan(MustParseVersion("2.0.0")),
			),
			MustParseVersion("0.0.2"),
			false,
		},
		{
			Intersection(
				AtLeast(MustParseVersion("1.0.0")),
				OlderThan(MustParseVersion("2.0.0")),
			),
			MustParseVersion("1.0.0"),
			true,
		},
		{
			Intersection(
				AtLeast(MustParseVersion("1.0.0")),
				OlderThan(MustParseVersion("2.0.0")),
			),
			MustParseVersion("1.2.3"),
			true,
		},
		{
			Intersection(
				AtLeast(MustParseVersion("1.0.0")),
				OlderThan(MustParseVersion("2.0.0")),
			),
			MustParseVersion("2.0.0"),
			false,
		},
		{
			Intersection(
				AtLeast(MustParseVersion("1.0.0")),
				OlderThan(MustParseVersion("2.0.0")),
			),
			MustParseVersion("2.0.1"),
			false,
		},
		{
			All.Subtract(Only(MustParseVersion("0.9.0"))),
			MustParseVersion("0.9.0"),
			false,
		},
		{
			All.Subtract(Only(MustParseVersion("0.9.0"))),
			MustParseVersion("0.9.1"),
			true,
		},
		{
			All.Subtract(Only(MustParseVersion("0.9.0"))),
			MustParseVersion("0.9.1"),
			true,
		},
		{
			Union(
				All,
				Only(MustParseVersion("1.0.1")),
			).AllRequested(),
			MustParseVersion("1.0.1"),
			true,
		},
		{
			Union(
				All,
				Only(MustParseVersion("1.0.1")),
			).AllRequested(),
			MustParseVersion("1.0.2"),
			false,
		},
		{
			Intersection(
				All,
				Only(MustParseVersion("1.0.1")),
			).AllRequested(),
			MustParseVersion("1.0.1"),
			true,
		},
		{
			Intersection(
				All,
				Only(MustParseVersion("1.0.1")),
			).AllRequested(),
			MustParseVersion("1.0.2"),
			false,
		},
		{
			Intersection(
				AtLeast(MustParseVersion("2.0.0")),
				Only(MustParseVersion("1.0.1")),
			).AllRequested(),
			MustParseVersion("1.0.1"),
			false,
		},
		{
			Only(
				MustParseVersion("1.0.1"),
			).Subtract(
				AtLeast(MustParseVersion("1.0.0")),
			).AllRequested(),
			MustParseVersion("1.0.1"),
			false,
		},
		{
			MustMakeSet(MeetingConstraintsStringRuby(">= 1.0.0")),
			MustParseVersion("1.0.0"),
			true,
		},
		{
			MustMakeSet(MeetingConstraintsStringRuby(">= 1.0.0")),
			MustParseVersion("1.0.0-beta1"),
			false,
		},
		{
			MustMakeSet(MeetingConstraintsStringRuby(">= 1.0.0")),
			MustParseVersion("2.0.0-beta1"),
			false,
		},
		{
			MustMakeSet(MeetingConstraintsStringRuby("2.0.0-beta1")),
			MustParseVersion("2.0.0-beta1"),
			true,
		},
		{
			MustMakeSet(MeetingConstraintsStringRuby(">= 1.0.0")),
			MustParseVersion("1.0.1"),
			true,
		},
		{
			MustMakeSet(MeetingConstraintsStringRuby(">= 1.0.0")).AllRequested(),
			MustParseVersion("0.0.1"),
			false,
		},
		{
			MustMakeSet(MeetingConstraintsStringRuby(">= 1.0.0")).AllRequested(),
			MustParseVersion("1.0.0-beta1"),
			false,
		},
		{
			MustMakeSet(MeetingConstraintsStringRuby(">= 1.0.0")).AllRequested(),
			MustParseVersion("2.0.0-beta1"),
			false,
		},
		{
			MustMakeSet(MeetingConstraintsStringRuby("2.0.0-beta1")).AllRequested(),
			MustParseVersion("2.0.0-beta1"),
			true,
		},
		{
			MustMakeSet(MeetingConstraintsStringRuby(">= 1.0.0")).WithoutUnrequestedPrereleases(),
			MustParseVersion("0.0.1"),
			false,
		},
		{
			MustMakeSet(MeetingConstraintsStringRuby(">= 1.0.0")).WithoutUnrequestedPrereleases(),
			MustParseVersion("1.0.0"),
			true,
		},
		{
			MustMakeSet(MeetingConstraintsStringRuby(">= 1.0.0")).WithoutUnrequestedPrereleases(),
			MustParseVersion("1.0.0-beta1"),
			false,
		},
		{
			MustMakeSet(MeetingConstraintsStringRuby(">= 1.0.0")).WithoutUnrequestedPrereleases(),
			MustParseVersion("2.0.0-beta1"),
			false,
		},
		{
			MustMakeSet(MeetingConstraintsStringRuby("2.0.0-beta1")).WithoutUnrequestedPrereleases(),
			MustParseVersion("2.0.0-beta1"),
			true,
		},
	}

	for _, test := range tests {
		t.Run(test.Set.GoString(), func(t *testing.T) {
			got := test.Set.Has(test.Has)

			if got != test.Want {
				t.Errorf(
					"wrong result\nset:     %#v\nversion: %#v\ngot:     %#v\nwant:    %#v",
					test.Set,
					test.Has,
					got, test.Want,
				)
			}
		})
	}
}

func TestSetJSON(t *testing.T) {
	j := []byte(`"^1 || 2.0.0"`)
	var got Set
	err := json.Unmarshal(j, &got)
	if err != nil {
		t.Fatal(err)
	}

	want := Intersection(
		Released,
		Union(
			Intersection(
				AtLeast(MustParseVersion("1.0.0")),
				OlderThan(MustParseVersion("2.0.0")),
			),
			Only(MustParseVersion("2.0.0")),
		),
	)

	if !reflect.DeepEqual(got, want) {
		t.Errorf("wrong result\ngot:  %#v\nwant :%#v", got, want)
	}
}
<commit_msg>versions: Add unit tests for ruby-style pessimistic constraints<commit_after>package versions

import (
	"encoding/json"
	"reflect"
	"testing"
)

// Make sure our set implementations all actually implement the interface
var _ setI = setBound{}
var _ setI = setExact{}
var _ setI = setExtreme(true)
var _ setI = setIntersection{}
var _ setI = setSubtract{}
var _ setI = setUnion{}
var _ setI = setReleased{}

func TestSetHas(t *testing.T) {
	tests := []struct {
		Set  Set
		Has  Version
		Want bool
	}{
		{
			All,
			Unspecified,
			true,
		},
		{
			None,
			Unspecified,
			false,
		},
		{
			All.Subtract(Only(MustParseVersion("1.0.0"))),
			Unspecified,
			false, // any sort of constraint removes the special Unspecified version
		},
		{
			InitialDevelopment,
			Unspecified,
			false,
		},
		{
			InitialDevelopment,
			MustParseVersion("0.0.2"),
			true,
		},
		{
			InitialDevelopment,
			MustParseVersion("1.0.0"),
			false,
		},
		{
			Released,
			MustParseVersion("1.0.0"),
			true,
		},
		{
			Released,
			MustParseVersion("1.0.0-beta1"),
			false,
		},
		{
			Prerelease,
			MustParseVersion("1.0.0"),
			false,
		},
		{
			Prerelease,
			MustParseVersion("1.0.0-beta1"),
			true,
		},
		{
			Union(
				Only(MustParseVersion("1.0.0")),
				Only(MustParseVersion("1.1.0")),
			),
			MustParseVersion("1.0.0"),
			true,
		},
		{
			Union(
				Only(MustParseVersion("1.0.0")),
				Only(MustParseVersion("1.1.0")),
			),
			MustParseVersion("1.1.0"),
			true,
		},
		{
			Union(
				Only(MustParseVersion("1.0.0")),
				Only(MustParseVersion("1.1.0")),
			),
			MustParseVersion("1.2.0"),
			false,
		},
		{
			Union(
				Only(MustParseVersion("1.0.0")),
				Only(MustParseVersion("1.1.0")),
				Only(MustParseVersion("1.2.0")),
			),
			MustParseVersion("1.2.0"),
			true,
		},
		{
			Intersection(
				AtLeast(MustParseVersion("1.0.0")),
				OlderThan(MustParseVersion("2.0.0")),
			),
			MustParseVersion("0.0.2"),
			false,
		},
		{
			Intersection(
				AtLeast(MustParseVersion("1.0.0")),
				OlderThan(MustParseVersion("2.0.0")),
			),
			MustParseVersion("1.0.0"),
			true,
		},
		{
			Intersection(
				AtLeast(MustParseVersion("1.0.0")),
				OlderThan(MustParseVersion("2.0.0")),
			),
			MustParseVersion("1.2.3"),
			true,
		},
		{
			Intersection(
				AtLeast(MustParseVersion("1.0.0")),
				OlderThan(MustParseVersion("2.0.0")),
			),
			MustParseVersion("2.0.0"),
			false,
		},
		{
			Intersection(
				AtLeast(MustParseVersion("1.0.0")),
				OlderThan(MustParseVersion("2.0.0")),
			),
			MustParseVersion("2.0.1"),
			false,
		},
		{
			All.Subtract(Only(MustParseVersion("0.9.0"))),
			MustParseVersion("0.9.0"),
			false,
		},
		{
			All.Subtract(Only(MustParseVersion("0.9.0"))),
			MustParseVersion("0.9.1"),
			true,
		},
		{
			All.Subtract(Only(MustParseVersion("0.9.0"))),
			MustParseVersion("0.9.1"),
			true,
		},
		{
			Union(
				All,
				Only(MustParseVersion("1.0.1")),
			).AllRequested(),
			MustParseVersion("1.0.1"),
			true,
		},
		{
			Union(
				All,
				Only(MustParseVersion("1.0.1")),
			).AllRequested(),
			MustParseVersion("1.0.2"),
			false,
		},
		{
			Intersection(
				All,
				Only(MustParseVersion("1.0.1")),
			).AllRequested(),
			MustParseVersion("1.0.1"),
			true,
		},
		{
			Intersection(
				All,
				Only(MustParseVersion("1.0.1")),
			).AllRequested(),
			MustParseVersion("1.0.2"),
			false,
		},
		{
			Intersection(
				AtLeast(MustParseVersion("2.0.0")),
				Only(MustParseVersion("1.0.1")),
			).AllRequested(),
			MustParseVersion("1.0.1"),
			false,
		},
		{
			Only(
				MustParseVersion("1.0.1"),
			).Subtract(
				AtLeast(MustParseVersion("1.0.0")),
			).AllRequested(),
			MustParseVersion("1.0.1"),
			false,
		},
		{
			MustMakeSet(MeetingConstraintsStringRuby(">= 1.0.0")),
			MustParseVersion("1.0.0"),
			true,
		},
		{
			MustMakeSet(MeetingConstraintsStringRuby(">= 1.0.0")),
			MustParseVersion("1.0.0-beta1"),
			false,
		},
		{
			MustMakeSet(MeetingConstraintsStringRuby(">= 1.0.0")),
			MustParseVersion("2.0.0-beta1"),
			false,
		},
		{
			MustMakeSet(MeetingConstraintsStringRuby("2.0.0-beta1")),
			MustParseVersion("2.0.0-beta1"),
			true,
		},
		{
			MustMakeSet(MeetingConstraintsStringRuby(">= 1.0.0")),
			MustParseVersion("1.0.1"),
			true,
		},
		{
			MustMakeSet(MeetingConstraintsStringRuby(">= 1.0.0")).AllRequested(),
			MustParseVersion("0.0.1"),
			false,
		},
		{
			MustMakeSet(MeetingConstraintsStringRuby(">= 1.0.0")).AllRequested(),
			MustParseVersion("1.0.0-beta1"),
			false,
		},
		{
			MustMakeSet(MeetingConstraintsStringRuby(">= 1.0.0")).AllRequested(),
			MustParseVersion("2.0.0-beta1"),
			false,
		},
		{
			MustMakeSet(MeetingConstraintsStringRuby("2.0.0-beta1")).AllRequested(),
			MustParseVersion("2.0.0-beta1"),
			true,
		},
		{
			MustMakeSet(MeetingConstraintsStringRuby(">= 1.0.0")).WithoutUnrequestedPrereleases(),
			MustParseVersion("0.0.1"),
			false,
		},
		{
			MustMakeSet(MeetingConstraintsStringRuby(">= 1.0.0")).WithoutUnrequestedPrereleases(),
			MustParseVersion("1.0.0"),
			true,
		},
		{
			MustMakeSet(MeetingConstraintsStringRuby(">= 1.0.0")).WithoutUnrequestedPrereleases(),
			MustParseVersion("1.0.0-beta1"),
			false,
		},
		{
			MustMakeSet(MeetingConstraintsStringRuby(">= 1.0.0")).WithoutUnrequestedPrereleases(),
			MustParseVersion("2.0.0-beta1"),
			false,
		},
		{
			MustMakeSet(MeetingConstraintsStringRuby("2.0.0-beta1")).WithoutUnrequestedPrereleases(),
			MustParseVersion("2.0.0-beta1"),
			true,
		},
		{
			MustMakeSet(MeetingConstraintsStringRuby("~> 1.2.3")),
			MustParseVersion("1.2.3"),
			true,
		},
		{
			MustMakeSet(MeetingConstraintsStringRuby("~> 1.2.3")),
			MustParseVersion("1.2.5"),
			true,
		},
		{
			MustMakeSet(MeetingConstraintsStringRuby("~> 1.2.3")),
			MustParseVersion("1.3.0"),
			false,
		},
		{
			MustMakeSet(MeetingConstraintsStringRuby("~> 1.2")),
			MustParseVersion("1.2.3"),
			true,
		},
		{
			MustMakeSet(MeetingConstraintsStringRuby("~> 1.2")),
			MustParseVersion("1.2.5"),
			true,
		},
		{
			MustMakeSet(MeetingConstraintsStringRuby("~> 1.2")),
			MustParseVersion("1.3.0"),
			true,
		},
		{
			MustMakeSet(MeetingConstraintsStringRuby("~> 1.2")),
			MustParseVersion("2.0.0"),
			false,
		},
		{
			MustMakeSet(MeetingConstraintsStringRuby("~> 1")),
			MustParseVersion("1.2.3"),
			true,
		},
		{
			MustMakeSet(MeetingConstraintsStringRuby("~> 1")),
			MustParseVersion("1.2.5"),
			true,
		},
		{
			MustMakeSet(MeetingConstraintsStringRuby("~> 1")),
			MustParseVersion("1.3.0"),
			true,
		},
		{
			MustMakeSet(MeetingConstraintsStringRuby("~> 1")),
			MustParseVersion("2.0.0"),
			false,
		},
	}

	for _, test := range tests {
		t.Run(test.Set.GoString(), func(t *testing.T) {
			got := test.Set.Has(test.Has)

			if got != test.Want {
				t.Errorf(
					"wrong result\nset:     %#v\nversion: %#v\ngot:     %#v\nwant:    %#v",
					test.Set,
					test.Has,
					got, test.Want,
				)
			}
		})
	}
}

func TestSetJSON(t *testing.T) {
	j := []byte(`"^1 || 2.0.0"`)
	var got Set
	err := json.Unmarshal(j, &got)
	if err != nil {
		t.Fatal(err)
	}

	want := Intersection(
		Released,
		Union(
			Intersection(
				AtLeast(MustParseVersion("1.0.0")),
				OlderThan(MustParseVersion("2.0.0")),
			),
			Only(MustParseVersion("2.0.0")),
		),
	)

	if !reflect.DeepEqual(got, want) {
		t.Errorf("wrong result\ngot:  %#v\nwant :%#v", got, want)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"github.com/DATA-DOG/godog"
	"io/ioutil"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"os"
	"strings"
)

const (
	JENKINS_HOST string = "JENKINS_HOST"
)

var jenkinsHostUrl string = os.Getenv(JENKINS_HOST)
var jenkinsLogin string = jenkinsHostUrl + "/login"
var requestUrl string
var body string
var pluginsResp string
var cookieJar *cookiejar.Jar
var crumb JenkinsCrumb
var httpClient *http.Client

type JenkinsCrumb struct {
	Crumb             string `json:"crumb"`
	CrumbRequestField string `json: "crumbRequestField"`
}

func init() {
	createNewHttpClient()
}

func createNewCookieJar() {
	cookieJar, _ = cookiejar.New(&cookiejar.Options{})
}

func createNewHttpClient() {
	createNewCookieJar()

	httpClient = &http.Client{
		Jar: cookieJar,
	}
}

func thereIsAJenkinsInstall() error {
	requestUrl = jenkinsHostUrl + "/login"
	return nil
}

func getBodyString(resp *http.Response) string {
	defer resp.Body.Close()
	body_bytes, err := ioutil.ReadAll(resp.Body)

	if err != nil {
		return fmt.Sprintf("%s", err)
	}

	return string(body_bytes)
}

func iAccessTheLoginScreen() error {
	resp, err := http.Get(requestUrl)
	if err != nil {
		return err
	}

	body = getBodyString(resp)
	return nil
}

func jenkinsShouldBeUnlocked() error {
	if strings.Contains(body, "Unlock Jenkins") {
		return fmt.Errorf("expected %s not to contain 'Unlock Jenkins'", body)
	}
	return nil
}

func iAccessPluginManagement() error {
	u := jenkinsHostUrl + "/pluginManager/api/xml?depth=1"
	pluginsResp, err := http.Get(u)
	if err != nil {
		return err
	}
	body = getBodyString(pluginsResp)
	return nil
}

func allThePluginsAreInstalled() error {
	if !strings.Contains(body, "<shortName>cucumber-reports</shortName>") {
		return fmt.Errorf("expected %s to contain 'cucumber-reports'", body)
	}
	return nil
}

func getNewJenkinsCrumb() error {
	u := jenkinsHostUrl + "/crumbIssuer/api/json"
	resp, err := httpClient.Get(u)

	defer resp.Body.Close()

	if err != nil {
		return fmt.Errorf("expected response from crumbIssuer, got: %s", body)
	}

	body_bytes, _ := ioutil.ReadAll(resp.Body)

	if ! strings.Contains(body, `{"_class":"hudson.security.csrf.DefaultCrumbIssuer","crumb":`) {
		return fmt.Errorf("expected %s to contain '/logout' link", body)
	}

	json.Unmarshal(body_bytes, &crumb)

	return nil
}

func iHaveLoggedIntoJenkins() error {

	getNewJenkinsCrumb()

	loginUrl := jenkinsHostUrl + "/j_acegi_security_check"
	jenkinsPassword := os.Getenv("JENKINS_PASSWORD")

	resp, err := httpClient.PostForm(loginUrl,
		url.Values{"j_username": {"administrator"}, "j_password": {jenkinsPassword}, "Jenkins-Crumb": {crumb.Crumb}})

	defer resp.Body.Close()

	if err != nil {
		fmt.Printf("%s", err)
	}

	body, _ := ioutil.ReadAll(resp.Body)

	if !strings.Contains(string(body), `<a href="/logout"><b>log out</b></a>`) {
		return fmt.Errorf("expected %s to contain '/logout' link", body)
	}

	return nil
}

func FeatureContext(s *godog.Suite) {
	s.Step(`^there is a jenkins install$`, thereIsAJenkinsInstall)

	s.Step(`^I have logged into Jenkins$`, iHaveLoggedIntoJenkins)

	s.Step(`^I access the login screen$`, iAccessTheLoginScreen)
	s.Step(`^jenkins should be unlocked$`, jenkinsShouldBeUnlocked)

	s.Step(`^I access plugin management$`, iAccessPluginManagement)
	s.Step(`^all the plugins are installed$`, allThePluginsAreInstalled)
}<commit_msg>Changed iAccessPluginManagement to use httpClient<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"github.com/DATA-DOG/godog"
	"io/ioutil"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"os"
	"strings"
)

const (
	JENKINS_HOST string = "JENKINS_HOST"
)

var jenkinsHostUrl string = os.Getenv(JENKINS_HOST)
var jenkinsLogin string = jenkinsHostUrl + "/login"
var requestUrl string
var body string
var pluginsResp string
var cookieJar *cookiejar.Jar
var crumb JenkinsCrumb
var httpClient *http.Client

type JenkinsCrumb struct {
	Crumb             string `json:"crumb"`
	CrumbRequestField string `json: "crumbRequestField"`
}

func init() {
	createNewHttpClient()
}

func createNewCookieJar() {
	cookieJar, _ = cookiejar.New(&cookiejar.Options{})
}

func createNewHttpClient() {
	createNewCookieJar()

	httpClient = &http.Client{
		Jar: cookieJar,
	}
}

func thereIsAJenkinsInstall() error {
	requestUrl = jenkinsHostUrl + "/login"
	return nil
}

func getBodyString(resp *http.Response)(string, error) {
	defer resp.Body.Close()
	body_bytes, err := ioutil.ReadAll(resp.Body)

	if err != nil {
		return "", fmt.Errorf("%s", err)
	}

	return string(body_bytes), nil
}

func iAccessTheLoginScreen() error {
	resp, err := http.Get(requestUrl)
	if err != nil {
		return err
	}

	body, _ = getBodyString(resp)
	return nil
}

func jenkinsShouldBeUnlocked() error {
	if strings.Contains(body, "Unlock Jenkins") {
		return fmt.Errorf("expected %s not to contain 'Unlock Jenkins'", body)
	}
	return nil
}

func iAccessPluginManagement() error {
	u := jenkinsHostUrl + "/pluginManager/api/xml?depth=1"
	pluginsResp, err := httpClient.Get(u)

	if err != nil {
		return err
	}
	body, _ = getBodyString(pluginsResp)
	return nil
}

func allThePluginsAreInstalled() error {
	if !strings.Contains(body, "<shortName>cucumber-reports</shortName>") {
		return fmt.Errorf("expected %s to contain 'cucumber-reports'", body)
	}
	return nil
}

func getNewJenkinsCrumb() error {
	u := jenkinsHostUrl + "/crumbIssuer/api/json"
	resp, err := httpClient.Get(u)

	if err != nil {
		return fmt.Errorf("expected response from crumbIssuer, got: %s", body)
	}

	defer resp.Body.Close()

	body_bytes, _ := ioutil.ReadAll(resp.Body)

	if ! strings.Contains(body, `{"_class":"hudson.security.csrf.DefaultCrumbIssuer","crumb":`) {
		return fmt.Errorf("expected %s to contain '/logout' link", body)
	}

	json.Unmarshal(body_bytes, &crumb)

	return nil
}

func iHaveLoggedIntoJenkins() error {

	getNewJenkinsCrumb()

	loginUrl := jenkinsHostUrl + "/j_acegi_security_check"
	jenkinsPassword := os.Getenv("JENKINS_PASSWORD")

	resp, err := httpClient.PostForm(loginUrl,
		url.Values{"j_username": {"administrator"}, "j_password": {jenkinsPassword}, "Jenkins-Crumb": {crumb.Crumb}})

	if err != nil {
		return fmt.Errorf("%s", err)
	}
	defer resp.Body.Close()

	body, _ := ioutil.ReadAll(resp.Body)

	if !strings.Contains(string(body), `<a href="/logout"><b>log out</b></a>`) {
		return fmt.Errorf("expected %s to contain '/logout' link", body)
	}

	return nil
}

func FeatureContext(s *godog.Suite) {
	s.Step(`^there is a jenkins install$`, thereIsAJenkinsInstall)

	s.Step(`^I have logged into Jenkins$`, iHaveLoggedIntoJenkins)

	s.Step(`^I access the login screen$`, iAccessTheLoginScreen)
	s.Step(`^jenkins should be unlocked$`, jenkinsShouldBeUnlocked)

	s.Step(`^I access plugin management$`, iAccessPluginManagement)
	s.Step(`^all the plugins are installed$`, allThePluginsAreInstalled)
}<|endoftext|>