<commit_before>package json

import (
	"fmt"

	"github.com/cucumber/messages-go/v15"
)

type MessageLookup struct {
	gherkinDocumentByURI    map[string]*messages.GherkinDocument
	pickleByID              map[string]*messages.Pickle
	pickleStepByID          map[string]*messages.Pickle_PickleStep
	testCaseByID            map[string]*messages.TestCase
	testStepByID            map[string]*messages.TestCase_TestStep
	testCaseStartedByID     map[string]*messages.TestCaseStarted
	stepByID                map[string]*messages.GherkinDocument_Feature_Step
	scenarioByID            map[string]*messages.GherkinDocument_Feature_Scenario
	exampleByRowID          map[string]*messages.GherkinDocument_Feature_Scenario_Examples
	exampleRowByID          map[string]*messages.GherkinDocument_Feature_TableRow
	stepDefinitionByID      map[string]*messages.StepDefinition
	backgroundByStepID      map[string]*messages.GherkinDocument_Feature_Background
	tagByID                 map[string]*messages.GherkinDocument_Feature_Tag
	hookByID                map[string]*messages.Hook
	attachmentsByTestStepID map[string][]*messages.Attachment
	verbose                 bool
}

func (self *MessageLookup) Initialize(verbose bool) {
	self.gherkinDocumentByURI = make(map[string]*messages.GherkinDocument)
	self.pickleByID = make(map[string]*messages.Pickle)
	self.pickleStepByID = make(map[string]*messages.Pickle_PickleStep)
	self.testCaseByID = make(map[string]*messages.TestCase)
	self.testStepByID = make(map[string]*messages.TestCase_TestStep)
	self.testCaseStartedByID = make(map[string]*messages.TestCaseStarted)
	self.stepByID = make(map[string]*messages.GherkinDocument_Feature_Step)
	self.scenarioByID = make(map[string]*messages.GherkinDocument_Feature_Scenario)
	self.exampleByRowID = make(map[string]*messages.GherkinDocument_Feature_Scenario_Examples)
	self.exampleRowByID = make(map[string]*messages.GherkinDocument_Feature_TableRow)
	self.stepDefinitionByID = make(map[string]*messages.StepDefinition)
	self.backgroundByStepID = make(map[string]*messages.GherkinDocument_Feature_Background)
	self.tagByID = make(map[string]*messages.GherkinDocument_Feature_Tag)
	self.hookByID = make(map[string]*messages.Hook)
	self.attachmentsByTestStepID = make(map[string][]*messages.Attachment)

	self.verbose = verbose
}

func (self *MessageLookup) ProcessMessage(envelope *messages.Envelope) (err error) {
	switch m := envelope.Message.(type) {
	case *messages.Envelope_GherkinDocument:
		self.gherkinDocumentByURI[m.GherkinDocument.Uri] = m.GherkinDocument
		self.comment(fmt.Sprintf("Stored GherkinDocument: %s", m.GherkinDocument.Uri))
		for key, _ := range self.gherkinDocumentByURI {
			self.comment(fmt.Sprintf(" - %s ", key))
		}
		if m.GherkinDocument.Feature == nil {
			return nil
		}
		self.processTags(m.GherkinDocument.Feature.Tags)

		for _, child := range m.GherkinDocument.Feature.Children {
			self.processRule(child.GetRule())
			self.processBackground(child.GetBackground())
			self.processScenario(child.GetScenario())
		}

	case *messages.Envelope_Pickle:
		self.pickleByID[m.Pickle.Id] = m.Pickle

		for _, step := range m.Pickle.Steps {
			self.pickleStepByID[step.Id] = step
		}

	case *messages.Envelope_TestCase:
		self.testCaseByID[m.TestCase.Id] = m.TestCase

		for _, step := range m.TestCase.TestSteps {
			self.testStepByID[step.Id] = step
		}

	case *messages.Envelope_TestCaseStarted:
		self.testCaseStartedByID[m.TestCaseStarted.Id] = m.TestCaseStarted

	case *messages.Envelope_Attachment:
		attachments, ok := self.attachmentsByTestStepID[m.Attachment.TestStepId]
		if !ok {
			attachments = make([]*messages.Attachment, 0)
			self.attachmentsByTestStepID[m.Attachment.TestStepId] = attachments
		}
		attachments = append(attachments, m.Attachment)
		self.attachmentsByTestStepID[m.Attachment.TestStepId] = attachments

	case *messages.Envelope_StepDefinition:
		self.stepDefinitionByID[m.StepDefinition.Id] = m.StepDefinition

	case *messages.Envelope_Hook:
		self.hookByID[m.Hook.Id] = m.Hook
	}

	return nil
}

func (self *MessageLookup) processTags(tags []*messages.GherkinDocument_Feature_Tag) {
	for _, tag := range tags {
		self.tagByID[tag.Id] = tag
	}
}

func (self *MessageLookup) processRule(rule *messages.GherkinDocument_Feature_FeatureChild_Rule) {
	if rule != nil {
		for _, ruleChild := range rule.Children {
			self.processBackground(ruleChild.GetBackground())
			self.processScenario(ruleChild.GetScenario())
		}
	}
}

func (self *MessageLookup) processBackground(background *messages.GherkinDocument_Feature_Background) {
	if background != nil {
		for _, step := range background.Steps {
			self.backgroundByStepID[step.Id] = background
			self.stepByID[step.Id] = step
		}
	}
}

func (self *MessageLookup) processScenario(scenario *messages.GherkinDocument_Feature_Scenario) {
	if scenario != nil {
		self.scenarioByID[scenario.Id] = scenario
		self.processTags(scenario.Tags)

		for _, step := range scenario.Steps {
			self.stepByID[step.Id] = step
		}

		for _, example := range scenario.Examples {
			for _, row := range example.TableBody {
				// TODO: we may also need to add IDs to the examples
				self.exampleByRowID[row.Id] = example
				self.exampleRowByID[row.Id] = row
			}
		}
	}
}

func (self *MessageLookup) LookupGherkinDocument(uri string) *messages.GherkinDocument {
	item, ok := self.gherkinDocumentByURI[uri]
	if ok {
		self.informFoundKey(uri, "gherkinDocumentByURI")
	} else {
		self.informMissingKey(uri, "gherkinDocumentByURI")
	}
	return item
}

func (self *MessageLookup) LookupScenario(id string) *messages.GherkinDocument_Feature_Scenario {
	item, ok := self.scenarioByID[id]
	if ok {
		self.informFoundKey(id, "scenarioByID")
	} else {
		self.informMissingKey(id, "scenarioByID")
	}
	return item
}

func (self *MessageLookup) LookupPickle(id string) *messages.Pickle {
	item, ok := self.pickleByID[id]
	if ok {
		self.informFoundKey(id, "pickleByID")
	} else {
		self.informMissingKey(id, "pickleByID")
	}
	return item
}

func (self *MessageLookup) LookupStep(id string) *messages.GherkinDocument_Feature_Step {
	item, ok := self.stepByID[id]
	if ok {
		self.informFoundKey(id, "stepByID")
	} else {
		self.informMissingKey(id, "stepByID")
	}
	return item
}

func (self *MessageLookup) LookupExample(id string) *messages.GherkinDocument_Feature_Scenario_Examples {
	item, ok := self.exampleByRowID[id]
	if ok {
		self.informFoundKey(id, "exampleByRowID")
	} else {
		self.informMissingKey(id, "exampleByRowID")
	}
	return item
}

func (self *MessageLookup) LookupExampleRow(id string) *messages.GherkinDocument_Feature_TableRow {
	item, ok := self.exampleRowByID[id]
	if ok {
		self.informFoundKey(id, "exampleRowByID")
	} else {
		self.informMissingKey(id, "exampleRowByID")
	}
	return item
}

func (self *MessageLookup) LookupBackgroundByStepID(id string) *messages.GherkinDocument_Feature_Background {
	item, ok := self.backgroundByStepID[id]
	if ok {
		self.informFoundKey(id, "backgroundByStepID")
	} else {
		self.informMissingKey(id, "backgroundByStepID")
	}
	return item
}

func (self *MessageLookup) LookupTag(id string) *messages.GherkinDocument_Feature_Tag {
	item, ok := self.tagByID[id]
	if ok {
		self.informFoundKey(id, "tagByID")
	} else {
		self.informMissingKey(id, "tagByID")
	}
	return item
}

func (self *MessageLookup) LookupTestCaseStarted(id string) *messages.TestCaseStarted {
	item, ok := self.testCaseStartedByID[id]
	if ok {
		self.informFoundKey(id, "testCaseStartedByID")
	} else {
		self.informMissingKey(id, "testCaseStartedByID")
	}
	return item
}

func (self *MessageLookup) LookupTestCase(id string) *messages.TestCase {
	item, ok := self.testCaseByID[id]
	if ok {
		self.informFoundKey(id, "testCaseByID")
	} else {
		self.informMissingKey(id, "testCaseByID")
	}
	return item
}

func (self *MessageLookup) LookupTestStep(id string) *messages.TestCase_TestStep {
	item, ok := self.testStepByID[id]
	if ok {
		self.informFoundKey(id, "testStepByID")
	} else {
		self.informMissingKey(id, "testStepByID")
	}
	return item
}

func (self *MessageLookup) LookupPickleStep(id string) *messages.Pickle_PickleStep {
	item, ok := self.pickleStepByID[id]
	if ok {
		self.informFoundKey(id, "pickleStepByID")
	} else {
		self.informMissingKey(id, "pickleStepByID")
	}
	return item
}

func (self *MessageLookup) LookupStepDefinitions(ids []string) []*messages.StepDefinition {
	stepDefinitions := make([]*messages.StepDefinition, len(ids))
	for index, id := range ids {
		stepDefinitions[index] = self.LookupStepDefinition(id)
	}
	return stepDefinitions
}

func (self *MessageLookup) LookupStepDefinition(id string) *messages.StepDefinition {
	item, ok := self.stepDefinitionByID[id]
	if ok {
		self.informFoundKey(id, "stepDefinitionByID")
	} else {
		self.informMissingKey(id, "stepDefinitionByID")
	}
	return item
}

func (self *MessageLookup) LookupHook(id string) *messages.Hook {
	item, ok := self.hookByID[id]
	if ok {
		self.informFoundKey(id, "hookByID")
	} else {
		self.informMissingKey(id, "hookByID")
	}
	return item
}

func (self *MessageLookup) LookupAttachments(testStepId string) []*messages.Attachment {
	item, ok := self.attachmentsByTestStepID[testStepId]
	if ok {
		self.informFoundKey(testStepId, "attachmentsByTestStepID")
	} else {
		self.informMissingKey(testStepId, "attachmentsByTestStepID")
	}
	return item
}

func (self *MessageLookup) informFoundKey(key string, mapName string) {
	self.comment((fmt.Sprintf("Found item'%s' in %s", key, mapName)))
}

func (self *MessageLookup) informMissingKey(key string, mapName string) {
	self.comment((fmt.Sprintf("Unable to find '%s' in %s", key, mapName)))
}

func (self *MessageLookup) comment(message string) {
	if self.verbose {
		fmt.Println(fmt.Sprintf("// LookUp: %s", message))
	}
}
<commit_msg>Process example tags while processing scenarios in message lookup code<commit_after>package json

import (
	"fmt"

	"github.com/cucumber/messages-go/v15"
)

type MessageLookup struct {
	gherkinDocumentByURI    map[string]*messages.GherkinDocument
	pickleByID              map[string]*messages.Pickle
	pickleStepByID          map[string]*messages.Pickle_PickleStep
	testCaseByID            map[string]*messages.TestCase
	testStepByID            map[string]*messages.TestCase_TestStep
	testCaseStartedByID     map[string]*messages.TestCaseStarted
	stepByID                map[string]*messages.GherkinDocument_Feature_Step
	scenarioByID            map[string]*messages.GherkinDocument_Feature_Scenario
	exampleByRowID          map[string]*messages.GherkinDocument_Feature_Scenario_Examples
	exampleRowByID          map[string]*messages.GherkinDocument_Feature_TableRow
	stepDefinitionByID      map[string]*messages.StepDefinition
	backgroundByStepID      map[string]*messages.GherkinDocument_Feature_Background
	tagByID                 map[string]*messages.GherkinDocument_Feature_Tag
	hookByID                map[string]*messages.Hook
	attachmentsByTestStepID map[string][]*messages.Attachment
	verbose                 bool
}

func (self *MessageLookup) Initialize(verbose bool) {
	self.gherkinDocumentByURI = make(map[string]*messages.GherkinDocument)
	self.pickleByID = make(map[string]*messages.Pickle)
	self.pickleStepByID = make(map[string]*messages.Pickle_PickleStep)
	self.testCaseByID = make(map[string]*messages.TestCase)
	self.testStepByID = make(map[string]*messages.TestCase_TestStep)
	self.testCaseStartedByID = make(map[string]*messages.TestCaseStarted)
	self.stepByID = make(map[string]*messages.GherkinDocument_Feature_Step)
	self.scenarioByID = make(map[string]*messages.GherkinDocument_Feature_Scenario)
	self.exampleByRowID = make(map[string]*messages.GherkinDocument_Feature_Scenario_Examples)
	self.exampleRowByID = make(map[string]*messages.GherkinDocument_Feature_TableRow)
	self.stepDefinitionByID = make(map[string]*messages.StepDefinition)
	self.backgroundByStepID = make(map[string]*messages.GherkinDocument_Feature_Background)
	self.tagByID = make(map[string]*messages.GherkinDocument_Feature_Tag)
	self.hookByID = make(map[string]*messages.Hook)
	self.attachmentsByTestStepID = make(map[string][]*messages.Attachment)

	self.verbose = verbose
}

func (self *MessageLookup) ProcessMessage(envelope *messages.Envelope) (err error) {
	switch m := envelope.Message.(type) {
	case *messages.Envelope_GherkinDocument:
		self.gherkinDocumentByURI[m.GherkinDocument.Uri] = m.GherkinDocument
		self.comment(fmt.Sprintf("Stored GherkinDocument: %s", m.GherkinDocument.Uri))
		for key, _ := range self.gherkinDocumentByURI {
			self.comment(fmt.Sprintf(" - %s ", key))
		}
		if m.GherkinDocument.Feature == nil {
			return nil
		}
		self.processTags(m.GherkinDocument.Feature.Tags)

		for _, child := range m.GherkinDocument.Feature.Children {
			self.processRule(child.GetRule())
			self.processBackground(child.GetBackground())
			self.processScenario(child.GetScenario())
		}

	case *messages.Envelope_Pickle:
		self.pickleByID[m.Pickle.Id] = m.Pickle

		for _, step := range m.Pickle.Steps {
			self.pickleStepByID[step.Id] = step
		}

	case *messages.Envelope_TestCase:
		self.testCaseByID[m.TestCase.Id] = m.TestCase

		for _, step := range m.TestCase.TestSteps {
			self.testStepByID[step.Id] = step
		}

	case *messages.Envelope_TestCaseStarted:
		self.testCaseStartedByID[m.TestCaseStarted.Id] = m.TestCaseStarted

	case *messages.Envelope_Attachment:
		attachments, ok := self.attachmentsByTestStepID[m.Attachment.TestStepId]
		if !ok {
			attachments = make([]*messages.Attachment, 0)
			self.attachmentsByTestStepID[m.Attachment.TestStepId] = attachments
		}
		attachments = append(attachments, m.Attachment)
		self.attachmentsByTestStepID[m.Attachment.TestStepId] = attachments

	case *messages.Envelope_StepDefinition:
		self.stepDefinitionByID[m.StepDefinition.Id] = m.StepDefinition

	case *messages.Envelope_Hook:
		self.hookByID[m.Hook.Id] = m.Hook
	}

	return nil
}

func (self *MessageLookup) processTags(tags []*messages.GherkinDocument_Feature_Tag) {
	for _, tag := range tags {
		self.tagByID[tag.Id] = tag
	}
}

func (self *MessageLookup) processRule(rule *messages.GherkinDocument_Feature_FeatureChild_Rule) {
	if rule != nil {
		for _, ruleChild := range rule.Children {
			self.processBackground(ruleChild.GetBackground())
			self.processScenario(ruleChild.GetScenario())
		}
	}
}

func (self *MessageLookup) processBackground(background *messages.GherkinDocument_Feature_Background) {
	if background != nil {
		for _, step := range background.Steps {
			self.backgroundByStepID[step.Id] = background
			self.stepByID[step.Id] = step
		}
	}
}

func (self *MessageLookup) processScenario(scenario *messages.GherkinDocument_Feature_Scenario) {
	if scenario != nil {
		self.scenarioByID[scenario.Id] = scenario
		self.processTags(scenario.Tags)

		for _, step := range scenario.Steps {
			self.stepByID[step.Id] = step
		}

		for _, example := range scenario.Examples {
			self.processTags(example.Tags)

			for _, row := range example.TableBody {
				// TODO: we may also need to add IDs to the examples
				self.exampleByRowID[row.Id] = example
				self.exampleRowByID[row.Id] = row
			}
		}
	}
}

func (self *MessageLookup) LookupGherkinDocument(uri string) *messages.GherkinDocument {
	item, ok := self.gherkinDocumentByURI[uri]
	if ok {
		self.informFoundKey(uri, "gherkinDocumentByURI")
	} else {
		self.informMissingKey(uri, "gherkinDocumentByURI")
	}
	return item
}

func (self *MessageLookup) LookupScenario(id string) *messages.GherkinDocument_Feature_Scenario {
	item, ok := self.scenarioByID[id]
	if ok {
		self.informFoundKey(id, "scenarioByID")
	} else {
		self.informMissingKey(id, "scenarioByID")
	}
	return item
}

func (self *MessageLookup) LookupPickle(id string) *messages.Pickle {
	item, ok := self.pickleByID[id]
	if ok {
		self.informFoundKey(id, "pickleByID")
	} else {
		self.informMissingKey(id, "pickleByID")
	}
	return item
}

func (self *MessageLookup) LookupStep(id string) *messages.GherkinDocument_Feature_Step {
	item, ok := self.stepByID[id]
	if ok {
		self.informFoundKey(id, "stepByID")
	} else {
		self.informMissingKey(id, "stepByID")
	}
	return item
}

func (self *MessageLookup) LookupExample(id string) *messages.GherkinDocument_Feature_Scenario_Examples {
	item, ok := self.exampleByRowID[id]
	if ok {
		self.informFoundKey(id, "exampleByRowID")
	} else {
		self.informMissingKey(id, "exampleByRowID")
	}
	return item
}

func (self *MessageLookup) LookupExampleRow(id string) *messages.GherkinDocument_Feature_TableRow {
	item, ok := self.exampleRowByID[id]
	if ok {
		self.informFoundKey(id, "exampleRowByID")
	} else {
		self.informMissingKey(id, "exampleRowByID")
	}
	return item
}

func (self *MessageLookup) LookupBackgroundByStepID(id string) *messages.GherkinDocument_Feature_Background {
	item, ok := self.backgroundByStepID[id]
	if ok {
		self.informFoundKey(id, "backgroundByStepID")
	} else {
		self.informMissingKey(id, "backgroundByStepID")
	}
	return item
}

func (self *MessageLookup) LookupTag(id string) *messages.GherkinDocument_Feature_Tag {
	item, ok := self.tagByID[id]
	if ok {
		self.informFoundKey(id, "tagByID")
	} else {
		self.informMissingKey(id, "tagByID")
	}
	return item
}

func (self *MessageLookup) LookupTestCaseStarted(id string) *messages.TestCaseStarted {
	item, ok := self.testCaseStartedByID[id]
	if ok {
		self.informFoundKey(id, "testCaseStartedByID")
	} else {
		self.informMissingKey(id, "testCaseStartedByID")
	}
	return item
}

func (self *MessageLookup) LookupTestCase(id string) *messages.TestCase {
	item, ok := self.testCaseByID[id]
	if ok {
		self.informFoundKey(id, "testCaseByID")
	} else {
		self.informMissingKey(id, "testCaseByID")
	}
	return item
}

func (self *MessageLookup) LookupTestStep(id string) *messages.TestCase_TestStep {
	item, ok := self.testStepByID[id]
	if ok {
		self.informFoundKey(id, "testStepByID")
	} else {
		self.informMissingKey(id, "testStepByID")
	}
	return item
}

func (self *MessageLookup) LookupPickleStep(id string) *messages.Pickle_PickleStep {
	item, ok := self.pickleStepByID[id]
	if ok {
		self.informFoundKey(id, "pickleStepByID")
	} else {
		self.informMissingKey(id, "pickleStepByID")
	}
	return item
}

func (self *MessageLookup) LookupStepDefinitions(ids []string) []*messages.StepDefinition {
	stepDefinitions := make([]*messages.StepDefinition, len(ids))
	for index, id := range ids {
		stepDefinitions[index] = self.LookupStepDefinition(id)
	}
	return stepDefinitions
}

func (self *MessageLookup) LookupStepDefinition(id string) *messages.StepDefinition {
	item, ok := self.stepDefinitionByID[id]
	if ok {
		self.informFoundKey(id, "stepDefinitionByID")
	} else {
		self.informMissingKey(id, "stepDefinitionByID")
	}
	return item
}

func (self *MessageLookup) LookupHook(id string) *messages.Hook {
	item, ok := self.hookByID[id]
	if ok {
		self.informFoundKey(id, "hookByID")
	} else {
		self.informMissingKey(id, "hookByID")
	}
	return item
}

func (self *MessageLookup) LookupAttachments(testStepId string) []*messages.Attachment {
	item, ok := self.attachmentsByTestStepID[testStepId]
	if ok {
		self.informFoundKey(testStepId, "attachmentsByTestStepID")
	} else {
		self.informMissingKey(testStepId, "attachmentsByTestStepID")
	}
	return item
}

func (self *MessageLookup) informFoundKey(key string, mapName string) {
	self.comment((fmt.Sprintf("Found item'%s' in %s", key, mapName)))
}

func (self *MessageLookup) informMissingKey(key string, mapName string) {
	self.comment((fmt.Sprintf("Unable to find '%s' in %s", key, mapName)))
}

func (self *MessageLookup) comment(message string) {
	if self.verbose {
		fmt.Println(fmt.Sprintf("// LookUp: %s", message))
	}
}
<|endoftext|>


<commit_before>package resource

import (
	"database/sql"
	"errors"
	"reflect"

	"github.com/jinzhu/gorm"
	"github.com/qor/qor"
	"github.com/qor/qor/utils"
	"github.com/qor/roles"
)

// ErrProcessorSkipLeft skip left processors error, if returned this error in validation, before callbacks, then qor will stop process following processors
var ErrProcessorSkipLeft = errors.New("resource: skip left")

type processor struct {
	Result     interface{}
	Resource   Resourcer
	Context    *qor.Context
	MetaValues *MetaValues
	SkipLeft   bool
}

// DecodeToResource decode meta values to resource result
func DecodeToResource(res Resourcer, result interface{}, metaValues *MetaValues, context *qor.Context) *processor {
	return &processor{Resource: res, Result: result, Context: context, MetaValues: metaValues}
}

func (processor *processor) checkSkipLeft(errs ...error) bool {
	if processor.SkipLeft {
		return true
	}

	for _, err := range errs {
		if err == ErrProcessorSkipLeft {
			processor.SkipLeft = true
			break
		}
	}
	return processor.SkipLeft
}

// Initialize initialize a processor
func (processor *processor) Initialize() error {
	err := processor.Resource.CallFindOne(processor.Result, processor.MetaValues, processor.Context)
	processor.checkSkipLeft(err)
	return err
}

// Validate run validators
func (processor *processor) Validate() error {
	var errs qor.Errors
	if processor.checkSkipLeft() {
		return nil
	}

	for _, v := range processor.Resource.GetResource().Validators {
		if errs.AddError(v.Handler(processor.Result, processor.MetaValues, processor.Context)); !errs.HasError() {
			if processor.checkSkipLeft(errs.GetErrors()...) {
				break
			}
		}
	}
	return errs
}

func (processor *processor) decode() (errs []error) {
	if processor.checkSkipLeft() || processor.MetaValues == nil {
		return
	}

	if destroy := processor.MetaValues.Get("_destroy"); destroy != nil {
		return
	}

	newRecord := true
	scope := &gorm.Scope{Value: processor.Result}
	if primaryField := scope.PrimaryField(); primaryField != nil {
		for _, metaValue := range processor.MetaValues.Values {
			if metaValue.Meta != nil && metaValue.Meta.GetFieldName() == primaryField.Name {
				if v := utils.ToString(metaValue.Value); v != "" && v != "0" {
					newRecord = false
				}
			}
		}
	}

	for _, metaValue := range processor.MetaValues.Values {
		meta := metaValue.Meta
		if meta == nil {
			continue
		}

		if newRecord && !meta.HasPermission(roles.Create, processor.Context) {
			continue
		} else if !newRecord && !meta.HasPermission(roles.Update, processor.Context) {
			continue
		}

		if setter := meta.GetSetter(); setter != nil {
			setter(processor.Result, metaValue, processor.Context)
		}

		if metaValue.MetaValues != nil && len(metaValue.MetaValues.Values) > 0 {
			if res := metaValue.Meta.GetResource(); res != nil && !reflect.ValueOf(res).IsNil() {
				field := reflect.Indirect(reflect.ValueOf(processor.Result)).FieldByName(meta.GetFieldName())
				// Only decode nested meta value into struct if no Setter defined
				if meta.GetSetter() == nil || reflect.Indirect(field).Type() == utils.ModelType(res.NewStruct()) {
					if _, ok := field.Addr().Interface().(sql.Scanner); !ok {
						decodeMetaValuesToField(res, field, metaValue, processor.Context)
					}
				}
			}
		}
	}

	return
}

// Start start processor
func (processor *processor) Start() error {
	var errs qor.Errors
	processor.Initialize()
	if errs.AddError(processor.Validate()); !errs.HasError() {
		errs.AddError(processor.Commit())
	}
	if errs.HasError() {
		return errs
	}
	return nil
}

// Commit commit data into result
func (processor *processor) Commit() error {
	var errs qor.Errors
	errs.AddError(processor.decode()...)
	if processor.checkSkipLeft(errs.GetErrors()...) {
		return nil
	}

	for _, p := range processor.Resource.GetResource().Processors {
		if err := p.Handler(processor.Result, processor.MetaValues, processor.Context); err != nil {
			if processor.checkSkipLeft(err) {
				break
			}
			errs.AddError(err)
		}
	}
	return errs
}
<commit_msg>Fix permission check when editing existing resource<commit_after>package resource

import (
	"database/sql"
	"errors"
	"reflect"

	"github.com/jinzhu/gorm"
	"github.com/qor/qor"
	"github.com/qor/qor/utils"
	"github.com/qor/roles"
)

// ErrProcessorSkipLeft skip left processors error, if returned this error in validation, before callbacks, then qor will stop process following processors
var ErrProcessorSkipLeft = errors.New("resource: skip left")

type processor struct {
	Result     interface{}
	Resource   Resourcer
	Context    *qor.Context
	MetaValues *MetaValues
	SkipLeft   bool
}

// DecodeToResource decode meta values to resource result
func DecodeToResource(res Resourcer, result interface{}, metaValues *MetaValues, context *qor.Context) *processor {
	return &processor{Resource: res, Result: result, Context: context, MetaValues: metaValues}
}

func (processor *processor) checkSkipLeft(errs ...error) bool {
	if processor.SkipLeft {
		return true
	}

	for _, err := range errs {
		if err == ErrProcessorSkipLeft {
			processor.SkipLeft = true
			break
		}
	}
	return processor.SkipLeft
}

// Initialize initialize a processor
func (processor *processor) Initialize() error {
	err := processor.Resource.CallFindOne(processor.Result, processor.MetaValues, processor.Context)
	processor.checkSkipLeft(err)
	return err
}

// Validate run validators
func (processor *processor) Validate() error {
	var errs qor.Errors
	if processor.checkSkipLeft() {
		return nil
	}

	for _, v := range processor.Resource.GetResource().Validators {
		if errs.AddError(v.Handler(processor.Result, processor.MetaValues, processor.Context)); !errs.HasError() {
			if processor.checkSkipLeft(errs.GetErrors()...) {
				break
			}
		}
	}
	return errs
}

func (processor *processor) decode() (errs []error) {
	if processor.checkSkipLeft() || processor.MetaValues == nil {
		return
	}

	if destroy := processor.MetaValues.Get("_destroy"); destroy != nil {
		return
	}

	newRecord := true
	scope := &gorm.Scope{Value: processor.Result}
	if primaryField := scope.PrimaryField(); primaryField != nil {
		if !primaryField.IsBlank {
			newRecord = false
		} else {
			for _, metaValue := range processor.MetaValues.Values {
				if metaValue.Meta != nil && metaValue.Meta.GetFieldName() == primaryField.Name {
					if v := utils.ToString(metaValue.Value); v != "" && v != "0" {
						newRecord = false
					}
				}
			}
		}
	}

	for _, metaValue := range processor.MetaValues.Values {
		meta := metaValue.Meta
		if meta == nil {
			continue
		}

		if newRecord && !meta.HasPermission(roles.Create, processor.Context) {
			continue
		} else if !newRecord && !meta.HasPermission(roles.Update, processor.Context) {
			continue
		}

		if setter := meta.GetSetter(); setter != nil {
			setter(processor.Result, metaValue, processor.Context)
		}

		if metaValue.MetaValues != nil && len(metaValue.MetaValues.Values) > 0 {
			if res := metaValue.Meta.GetResource(); res != nil && !reflect.ValueOf(res).IsNil() {
				field := reflect.Indirect(reflect.ValueOf(processor.Result)).FieldByName(meta.GetFieldName())
				// Only decode nested meta value into struct if no Setter defined
				if meta.GetSetter() == nil || reflect.Indirect(field).Type() == utils.ModelType(res.NewStruct()) {
					if _, ok := field.Addr().Interface().(sql.Scanner); !ok {
						decodeMetaValuesToField(res, field, metaValue, processor.Context)
					}
				}
			}
		}
	}

	return
}

// Start start processor
func (processor *processor) Start() error {
	var errs qor.Errors
	processor.Initialize()
	if errs.AddError(processor.Validate()); !errs.HasError() {
		errs.AddError(processor.Commit())
	}
	if errs.HasError() {
		return errs
	}
	return nil
}

// Commit commit data into result
func (processor *processor) Commit() error {
	var errs qor.Errors
	errs.AddError(processor.decode()...)
	if processor.checkSkipLeft(errs.GetErrors()...) {
		return nil
	}

	for _, p := range processor.Resource.GetResource().Processors {
		if err := p.Handler(processor.Result, processor.MetaValues, processor.Context); err != nil {
			if processor.checkSkipLeft(err) {
				break
			}
			errs.AddError(err)
		}
	}
	return errs
}
<|endoftext|>


<commit_before>package driver

import (
	"testing"
)

func TestWebVolatileKeyValueStore(t *testing.T) {
	testVolatileKeyValueStore(t, newSynchronizedVolatileKeyValueStore(newMemoryVolatileKeyValueStore(0, 0)))
}
<commit_msg>揮発性データコンテナ用スレッドセーフ化ラッパーの並列使用向けテストを追加<commit_after>package driver

import (
	"testing"
)

func TestWebVolatileKeyValueStore(t *testing.T) {
	testVolatileKeyValueStore(t, newSynchronizedVolatileKeyValueStore(newMemoryVolatileKeyValueStore(testStaleDur, testCaExpiDur)))
}

func TestSynchronizedConcurrentVolatileKeyValueStore(t *testing.T) {
	testConcurrentVolatileKeyValueStore(t, newSynchronizedVolatileKeyValueStore(newMemoryVolatileKeyValueStore(testStaleDur, testCaExpiDur)))
}

func TestSynchronizedConcurrentVolatileKeyValueStoreConsistency(t *testing.T) {
	testConcurrentVolatileKeyValueStoreConsistency(t, newSynchronizedVolatileKeyValueStore(newMemoryVolatileKeyValueStore(testStaleDur, testCaExpiDur)))
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2014 VMware, Inc. All Rights Reserved.

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 govmomi

import "github.com/vmware/govmomi/vim25/types"

type Datacenter struct {
	types.ManagedObjectReference
}

func (f Datacenter) Reference() types.ManagedObjectReference {
	return f.ManagedObjectReference
}
<commit_msg>Function to retrieve datacenter folders<commit_after>/*
Copyright (c) 2014 VMware, Inc. All Rights Reserved.

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 govmomi

import (
	"github.com/vmware/govmomi/vim25/mo"
	"github.com/vmware/govmomi/vim25/types"
)

type DatacenterFolders struct {
	VmFolder        Folder
	HostFolder      Folder
	DatastoreFolder Folder
	NetworkFolder   Folder
}

type Datacenter struct {
	types.ManagedObjectReference
}

func (d Datacenter) Reference() types.ManagedObjectReference {
	return d.ManagedObjectReference
}

func (d *Datacenter) Folders(c *Client) (*DatacenterFolders, error) {
	var md mo.Datacenter

	ps := []string{"vmFolder", "hostFolder", "datastoreFolder", "networkFolder"}
	err := c.Properties(d.Reference(), ps, &md)
	if err != nil {
		return nil, err
	}

	df := &DatacenterFolders{
		VmFolder:        Folder{md.VmFolder},
		HostFolder:      Folder{md.HostFolder},
		DatastoreFolder: Folder{md.DatastoreFolder},
		NetworkFolder:   Folder{md.NetworkFolder},
	}

	return df, nil
}
<|endoftext|>


<commit_before>package MySQLProtocol

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

func Test_Attributes(t *testing.T) {
	var values = []struct {
		packet Proto
	}{
		{packet: Proto{data: StringToPacket(`
            61 03 5f 6f    73 09 64 65 62 69 61 6e    ord.a._os.debian
36 2e 30 0c 5f 63 6c 69    65 6e 74 5f 6e 61 6d 65    6.0._client_name
08 6c 69 62 6d 79 73 71    6c 04 5f 70 69 64 05 32    .libmysql._pid.2
32 33 34 34 0f 5f 63 6c    69 65 6e 74 5f 76 65 72    2344._client_ver
73 69 6f 6e 08 35 2e 36    2e 36 2d 6d 39 09 5f 70    sion.5.6.6-m9._p
6c 61 74 66 6f 72 6d 06    78 38 36 5f 36 34 03 66    latform.x86_64.f
6f 6f 03 62 61 72                                     oo.bar
`)}},
	}
	var pkt Attributes

	for _, value := range values {

		pkt = value.packet.GetAttributes()
		assert.Equal(t, pkt.BuildAttributes(), value.packet.data, "")
	}
}
<commit_msg>Fix attribute test to use a packet slice<commit_after>package MySQLProtocol

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

var Attributes_test_packets = []struct {
        packet Proto
    }{
    {packet: Proto{data: StringToPacket(`
            61 03 5f 6f    73 09 64 65 62 69 61 6e    ord.a._os.debian
36 2e 30 0c 5f 63 6c 69    65 6e 74 5f 6e 61 6d 65    6.0._client_name
08 6c 69 62 6d 79 73 71    6c 04 5f 70 69 64 05 32    .libmysql._pid.2
32 33 34 34 0f 5f 63 6c    69 65 6e 74 5f 76 65 72    2344._client_ver
73 69 6f 6e 08 35 2e 36    2e 36 2d 6d 39 09 5f 70    sion.5.6.6-m9._p
6c 61 74 66 6f 72 6d 06    78 38 36 5f 36 34 03 66    latform.x86_64.f
6f 6f 03 62 61 72                                     oo.bar
`)}},
	}

func Test_Attributes(t *testing.T) {
	var pkt Attributes

	for _, value := range Attributes_test_packets {

		pkt = value.packet.GetAttributes()
		assert.Equal(t, pkt.BuildAttributes(), value.packet.data, "")
	}
}
<|endoftext|>


<commit_before>package main_test

import (
	"context"
	"os"
	"path"
	"testing"
	"time"

	"github.com/matryer/is"

	"github.com/magnusbaeck/logstash-filter-verifier/v2/internal/app/daemon"
	"github.com/magnusbaeck/logstash-filter-verifier/v2/internal/app/daemon/run"
	"github.com/magnusbaeck/logstash-filter-verifier/v2/internal/daemon/api/grpc"
	"github.com/magnusbaeck/logstash-filter-verifier/v2/internal/daemon/file"
	"github.com/magnusbaeck/logstash-filter-verifier/v2/internal/logging"
)

func TestIntegration(t *testing.T) {
	if os.Getenv("INTEGRATION_TEST") != "1" {
		t.Skip("integration test skipped, enable with env var `INTEGRATION_TEST=1`")
	}

	is := is.New(t)

	// FIXME: use test logger
	testLogger := &logging.LoggerMock{
		DebugFunc:    func(args ...interface{}) { t.Log(args...) },
		DebugfFunc:   func(format string, args ...interface{}) { t.Logf(format, args...) },
		ErrorFunc:    func(args ...interface{}) { t.Log(args...) },
		ErrorfFunc:   func(format string, args ...interface{}) { t.Logf(format, args...) },
		FatalFunc:    func(args ...interface{}) { t.Log(args...) },
		FatalfFunc:   func(format string, args ...interface{}) { t.Logf(format, args...) },
		InfoFunc:     func(args ...interface{}) { t.Log(args...) },
		InfofFunc:    func(format string, args ...interface{}) { t.Logf(format, args...) },
		WarningFunc:  func(args ...interface{}) { t.Log(args...) },
		WarningfFunc: func(format string, args ...interface{}) { t.Logf(format, args...) },
	}

	tempdir := t.TempDir()
	// Start Daemon
	socket := path.Join(tempdir, "integration_test.socket")
	logstashPath := path.Join("3rdparty/logstash-7.10.0/bin/logstash")
	if !file.Exists(logstashPath) {
		t.Fatalf("Logstash needs to be present in %q for the integration tests to work", logstashPath)
	}

	// FIXME: use test logger
	log := testLogger
	server := daemon.New(socket, logstashPath, log)

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	go func() {
		defer cancel()

		is := is.New(t)

		defer server.Cleanup()

		err := server.Run(ctx)
		is.NoErr(err)
	}()

	i := 0
	for {
		if file.Exists(socket) {
			break
		}
		time.Sleep(100 * time.Millisecond)
		i++
		if i >= 20 {
			t.Fatalf("wait for socket file failed")
		}
	}

	// Run tests
	cases := []struct {
		name      string
		pipeline  string
		basePath  string
		testcases string
	}{
		{
			name: "basic_pipeline",
		},
		{
			name: "conditional_output",
		},
		{
			name: "pipeline_to_pipeline",
		},
	}

	for _, tc := range cases {
		t.Run(tc.name, func(t *testing.T) {
			client, err := run.New(
				path.Join(tempdir, "integration_test.socket"),
				log,
				"testdata/"+tc.name+".yml",
				"testdata/"+tc.name,
				"testdata/testcases/"+tc.name,
			)
			is.NoErr(err)

			err = client.Run()
			is.NoErr(err)
		})
	}

	_, err := server.Shutdown(context.Background(), &grpc.ShutdownRequest{})
	is.NoErr(err)

	<-ctx.Done()
}
<commit_msg>Add timeout to integration tests<commit_after>package main_test

import (
	"context"
	"os"
	"path"
	"testing"
	"time"

	"github.com/matryer/is"

	"github.com/magnusbaeck/logstash-filter-verifier/v2/internal/app/daemon"
	"github.com/magnusbaeck/logstash-filter-verifier/v2/internal/app/daemon/run"
	"github.com/magnusbaeck/logstash-filter-verifier/v2/internal/daemon/api/grpc"
	"github.com/magnusbaeck/logstash-filter-verifier/v2/internal/daemon/file"
	"github.com/magnusbaeck/logstash-filter-verifier/v2/internal/logging"
)

func TestIntegration(t *testing.T) {
	if os.Getenv("INTEGRATION_TEST") != "1" {
		t.Skip("integration test skipped, enable with env var `INTEGRATION_TEST=1`")
	}

	is := is.New(t)

	testLogger := &logging.LoggerMock{
		DebugFunc:    func(args ...interface{}) { t.Log(args...) },
		DebugfFunc:   func(format string, args ...interface{}) { t.Logf(format, args...) },
		ErrorFunc:    func(args ...interface{}) { t.Log(args...) },
		ErrorfFunc:   func(format string, args ...interface{}) { t.Logf(format, args...) },
		FatalFunc:    func(args ...interface{}) { t.Log(args...) },
		FatalfFunc:   func(format string, args ...interface{}) { t.Logf(format, args...) },
		InfoFunc:     func(args ...interface{}) { t.Log(args...) },
		InfofFunc:    func(format string, args ...interface{}) { t.Logf(format, args...) },
		WarningFunc:  func(args ...interface{}) { t.Log(args...) },
		WarningfFunc: func(format string, args ...interface{}) { t.Logf(format, args...) },
	}

	tempdir := t.TempDir()
	// Start Daemon
	socket := path.Join(tempdir, "integration_test.socket")
	logstashPath := path.Join("3rdparty/logstash-7.10.0/bin/logstash")
	if !file.Exists(logstashPath) {
		t.Fatalf("Logstash needs to be present in %q for the integration tests to work", logstashPath)
	}

	log := testLogger
	server := daemon.New(socket, logstashPath, log)

	ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
	defer cancel()

	go func() {
		defer cancel()

		is := is.New(t)

		defer server.Cleanup()

		err := server.Run(ctx)
		is.NoErr(err)
	}()

	i := 0
	for {
		if file.Exists(socket) {
			break
		}
		time.Sleep(100 * time.Millisecond)
		i++
		if i >= 20 {
			t.Fatalf("wait for socket file failed")
		}
	}

	// Run tests
	cases := []struct {
		name      string
		pipeline  string
		basePath  string
		testcases string
	}{
		{
			name: "basic_pipeline",
		},
		{
			name: "conditional_output",
		},
		{
			name: "pipeline_to_pipeline",
		},
	}

	for _, tc := range cases {
		t.Run(tc.name, func(t *testing.T) {
			client, err := run.New(
				path.Join(tempdir, "integration_test.socket"),
				log,
				"testdata/"+tc.name+".yml",
				"testdata/"+tc.name,
				"testdata/testcases/"+tc.name,
			)
			is.NoErr(err)

			err = client.Run()
			is.NoErr(err)
		})
	}

	_, err := server.Shutdown(context.Background(), &grpc.ShutdownRequest{})
	is.NoErr(err)

	<-ctx.Done()
}
<|endoftext|>


<commit_before><commit_msg>[master] Fix spelling errors (#1348)<commit_after><|endoftext|>


<commit_before>package kindergarten

import (
	"fmt"
	"sort"
	"strings"
)

// Define the Garden type here.
type Garden struct {
	diagram  []string
	children []string
}

var cupCodeToPlant = map[string]string{
	"R": "radishes",
	"C": "clover",
	"G": "grass",
	"V": "violets",
}

// The diagram argument starts each row with a '\n'.  This allows Go's
// raw string literals to present diagrams in source code nicely as two
// rows flush left, for example,
//
//     diagram := `
//     VVCCGG
//     VVCCGG`

func NewGarden(diagram string, children []string) (*Garden, error) {
	if !isValidDiagram(diagram) {
		return &Garden{}, fmt.Errorf("invalid diagram")
	}
	if !isValidNames(children) {
		return &Garden{}, fmt.Errorf("invalid names")
	}
	clone := make([]string, len(children))
	copy(clone, children)
	sort.Strings(clone)
	fmt.Printf("clone %v\n", clone)
	return &Garden{diagram: getDiagramRows(diagram), children: clone}, nil
}

func (g *Garden) Plants(child string) (plants []string, ok bool) {
	// fmt.Printf("diagrams %v\n", g.diagram)
	index := indexOf(g.children, child)
	if index == -1 {
		return []string{}, false
	}
	column := index * 2
	cups := []string{
		string(g.diagram[0][column]),
		string(g.diagram[0][column+1]),
		string(g.diagram[1][column]),
		string(g.diagram[1][column+1]),
	}
	for _, cup := range cups {
		plants = append(plants, cupCodeToPlant[cup])
	}
	return plants, true
}

func isValidNames(names []string) bool {
	seen := map[string]bool{}
	for _, name := range names {
		_, ok := seen[name]
		if ok {
			return false // encountered duplicate name
		}
		seen[name] = true
	}
	return true
}

func isValidDiagram(diagram string) bool {
	return strings.HasPrefix(diagram, "\n") && isEvenRows(diagram) && isEvenCups(diagram) && isValidCupCodes(diagram)
}

func isEvenRows(diagram string) bool {
	rows := getDiagramRows(diagram)
	return len(rows[0]) == len(rows[1])
}

func isEvenCups(diagram string) bool {
	rows := getDiagramRows(diagram)
	return len(rows[0])%2 == 0
}

func isValidCupCodes(diagram string) bool {
	rows := getDiagramRows(diagram)
	for _, row := range rows {
		for _, cupCode := range row {
			_, ok := cupCodeToPlant[string(cupCode)]
			if !ok {
				return false
			}
		}
	}
	return true
}

func getDiagramRows(diagram string) (rows []string) {
	trimmed := strings.Trim(diagram, "\n")
	return strings.Split(trimmed, "\n")
}

func indexOf(slice []string, element string) int {
	for i, v := range slice {
		if v == element {
			return i
		}
	}
	return -1
}
<commit_msg>Refactor to use one line for assignment and conditional<commit_after>package kindergarten

import (
	"fmt"
	"sort"
	"strings"
)

// Define the Garden type here.
type Garden struct {
	diagram  []string
	children []string
}

var cupCodeToPlant = map[string]string{
	"R": "radishes",
	"C": "clover",
	"G": "grass",
	"V": "violets",
}

// The diagram argument starts each row with a '\n'.  This allows Go's
// raw string literals to present diagrams in source code nicely as two
// rows flush left, for example,
//
//     diagram := `
//     VVCCGG
//     VVCCGG`

func NewGarden(diagram string, children []string) (*Garden, error) {
	if !isValidDiagram(diagram) {
		return &Garden{}, fmt.Errorf("invalid diagram")
	}
	if !isValidNames(children) {
		return &Garden{}, fmt.Errorf("invalid names")
	}
	clone := make([]string, len(children))
	copy(clone, children)
	sort.Strings(clone)
	return &Garden{diagram: getDiagramRows(diagram), children: clone}, nil
}

func (g *Garden) Plants(child string) (plants []string, ok bool) {
	index := indexOf(g.children, child)
	if index == -1 {
		return []string{}, false
	}
	column := index * 2
	cups := []string{
		string(g.diagram[0][column]),
		string(g.diagram[0][column+1]),
		string(g.diagram[1][column]),
		string(g.diagram[1][column+1]),
	}
	for _, cup := range cups {
		plants = append(plants, cupCodeToPlant[cup])
	}
	return plants, true
}

func isValidNames(names []string) bool {
	seen := map[string]bool{}
	for _, name := range names {
		if _, ok := seen[name]; ok {
			// encountered duplicate name
			return false
		}
		seen[name] = true
	}
	return true
}

func isValidDiagram(diagram string) bool {
	return strings.HasPrefix(diagram, "\n") &&
		isEvenRows(diagram) &&
		isEvenCups(diagram) &&
		isValidCupCodes(diagram)
}

func isEvenRows(diagram string) bool {
	rows := getDiagramRows(diagram)
	return len(rows[0]) == len(rows[1])
}

func isEvenCups(diagram string) bool {
	rows := getDiagramRows(diagram)
	return len(rows[0])%2 == 0
}

func isValidCupCodes(diagram string) bool {
	rows := getDiagramRows(diagram)
	for _, row := range rows {
		for _, cupCode := range row {
			if _, ok := cupCodeToPlant[string(cupCode)]; !ok {
				return false
			}
		}
	}
	return true
}

func getDiagramRows(diagram string) (rows []string) {
	trimmed := strings.Trim(diagram, "\n")
	return strings.Split(trimmed, "\n")
}

func indexOf(slice []string, element string) int {
	for i, v := range slice {
		if v == element {
			return i
		}
	}
	return -1
}
<|endoftext|>


<commit_before><commit_msg>Use signature algorithm from the wpr-go root cert.<commit_after><|endoftext|>


<commit_before>package juggler_test

import (
	"net/http/httptest"
	"strings"
	"sync"
	"sync/atomic"
	"testing"
	"time"

	"golang.org/x/net/context"

	"github.com/PuerkitoBio/exp/juggler"
	"github.com/PuerkitoBio/exp/juggler/broker/redisbroker"
	"github.com/PuerkitoBio/exp/juggler/callee"
	"github.com/PuerkitoBio/exp/juggler/internal/jugglertest"
	"github.com/PuerkitoBio/exp/juggler/internal/redistest"
	"github.com/PuerkitoBio/exp/juggler/msg"
	"github.com/gorilla/websocket"
)

// IntgConfig holds the configuration of an integration test execution.
type IntgConfig struct {
	RedisPoolMaxActive   int
	RedisPoolMaxIdle     int
	RedisPoolIdleTimeout time.Duration

	BrokerBlockingTimeout time.Duration
	BrokerCallCap         int
	BrokerResultCap       int

	ServerReadLimit               int64
	ServerReadTimeout             time.Duration
	ServerWriteLimit              int64
	ServerWriteTimeout            time.Duration
	ServerAcquireWriteLockTimeout time.Duration

	NCallees          int // number of callees listening on the URIs
	NWorkersPerCallee int // number of workers per callee
	NClients          int // number of clients generating calls

	NURIs         int           // number of different URIs to pick from at random
	NChannels     int           // number of different channels to pick from at random
	Duration      time.Duration // duration of the test
	ClientMsgRate time.Duration // send a message at this rate
	ServerPubRate time.Duration // publish a server-side event at this rate
	ThunkDelay    time.Duration // artificial delay of the call
}

type runStats struct {
	Call    int64
	Pub     int64
	Sub     int64
	Unsb    int64
	Exp     int64
	OK      int64
	Err     int64
	Res     int64
	Evnt    int64
	Unknown int64
}

func TestIntegration(t *testing.T) {
	if testing.Short() {
		t.Skip("integration tests don't run with the -short flag")
	}
	runIntegrationTest(t, &IntgConfig{}) // TODO : parse flags into IntgConfig
}

func serverStatsHandler(stats *runStats) juggler.Handler {
	return juggler.HandlerFunc(func(ctx context.Context, c *juggler.Conn, m msg.Msg) {
		switch m.Type() {
		case msg.CallMsg:
			atomic.AddInt64(&stats.Call)
		case msg.PubMsg:
			atomic.AddInt64(&stats.Pub)
		case msg.SubMsg:
			atomic.AddInt64(&stats.Sub)
		case msg.UnsbMsg:
			atomic.AddInt64(&stats.Unsb)
		case msg.ExpMsg:
			atomic.AddInt64(&stats.Exp)
		case msg.OKMsg:
			atomic.AddInt64(&stats.OK)
		case msg.ErrMsg:
			atomic.AddInt64(&stats.Err)
		case msg.ResMsg:
			atomic.AddInt64(&stats.Res)
		case msg.EvntMsg:
			atomic.AddInt64(&stats.Evnt)
		default:
			atomic.AddInt64(&stats.Unknown)
		}
		juggler.ProcessMsg(ctx, c, m)
	})
}

func clientStatsHandler(stats *runStats) ClientHandler {
	return juggler.ClientHandlerFunc(func(ctx context.Context, c *juggler.Client, m msg.Msg) {
		switch m.Type() {
		case msg.CallMsg:
			atomic.AddInt64(&stats.Call)
		case msg.PubMsg:
			atomic.AddInt64(&stats.Pub)
		case msg.SubMsg:
			atomic.AddInt64(&stats.Sub)
		case msg.UnsbMsg:
			atomic.AddInt64(&stats.Unsb)
		case msg.ExpMsg:
			atomic.AddInt64(&stats.Exp)
		case msg.OKMsg:
			atomic.AddInt64(&stats.OK)
		case msg.ErrMsg:
			atomic.AddInt64(&stats.Err)
		case msg.ResMsg:
			atomic.AddInt64(&stats.Res)
		case msg.EvntMsg:
			atomic.AddInt64(&stats.Evnt)
		default:
			atomic.AddInt64(&stats.Unknown)
		}
	})
}

func runIntegrationTest(t *testing.T, conf *IntgConfig) {
	dbgl := &jugglertest.DebugLog{T: t}

	// start/create:
	// 1. redis-server
	// 2. redis pool and broker
	// 3. juggler server
	// 4. m callees
	// 5. n clients

	// 1. redis-server
	cmd, port := redistest.StartServer(t, nil)
	defer cmd.Process.Kill()

	// 2. create the redis pool and broker
	pool := redistest.NewPool(t, ":"+port)
	pool.MaxActive = conf.RedisPoolMaxActive
	pool.MaxIdle = conf.RedisPoolMaxIdle
	pool.IdleTimeout = conf.RedisPoolIdleTimeout
	brk := &redisbroker.Broker{
		Pool:    pool,
		Dial:    pool.Dial,
		LogFunc: dbgl.Printf,

		BlockingTimeout: conf.BrokerBlockingTimeout,
		CallCap:         conf.BrokerCallCap,
		ResultCap:       conf.BrokerResultCap,
	}

	// 3. create the juggler server
	var srvStats runStats
	srv := &juggler.Server{
		CallerBroker: brk,
		PubSubBroker: brk,
		LogFunc:      dbgl.Printf,

		ReadHandler:  serverStatsHandler(&srvStats),
		WriteHandler: serverStatsHandler(&srvStats),

		ReadLimit:               conf.ServerReadLimit,
		ReadTimeout:             conf.ServerReadTimeout,
		WriteLimit:              conf.ServerWriteLimit,
		WriteTimeout:            conf.ServerWriteTimeout,
		AcquireWriteLockTimeout: conf.ServerAcquireWriteLockTimeout,
	}
	upg := &websocket.Upgrader{Subprotocols: juggler.Subprotocols}
	httpsrv := httptest.NewServer(juggler.Upgrade(upg, srv))
	defer httpsrv.Close()

	// TODO : get URIs
	uris := []string{}
	thunk := func(cp *msg.CallPayload) (interface{}, error) {
		time.Sleep(conf.ThunkDelay)
		return "ok", nil
	}

	// 4. start m callees
	calleeStarted := make(chan struct{})
	for i := 0; i < conf.NCallees; i++ {
		go func() {
			cle := callee.Callee{
				Broker:  brk,
				LogFunc: dbgl.Printf,
			}

			conn, err := brk.Calls(uris...)
			if err != nil {
				t.Fatalf("failed to get CallsConn: %v", err)
			}
			defer conn.Close()
			ch := conn.Calls()

			for j := 0; j < conf.NWorkersPerCallee; j++ {
				go func() {
					calleeStarted <- struct{}{}
					for cp := range ch {
						if err := cle.InvokeAndStoreResult(cp, thunk); err != nil {
							t.Fatalf("InvokeAndStoreResult failed: %v", err)
						}
					}
				}()
			}
		}()
	}

	// 5. start n clients
	var clientStats runStats
	clientStarted := make(chan struct{})
	wg := sync.WaitGroup{}
	wg.Add(conf.NClients)

	for i := 0; i < conf.NClients; i++ {
		go func() {
			defer wg.Done()

			cli, err := juggler.Dial(&websocket.Dialer{}, strings.Replace(httpsrv.URL, "http:", "ws:", 1), nil,
				juggler.SetHandler(clientStatsHandler(&clientStats)))
			if err != nil {
				t.Fatalf("Dial failed: %v", err)
			}
			_ = cli

			// TODO : run predetermined requests...
			clientStarted <- struct{}{}
		}()
	}

	// wait for callees to come online
	for i, cnt := 0, conf.NCallees*conf.NWorkersPerCallee; i < cnt; i++ {
		<-calleeStarted
	}
	// start clients
	for i := 0; i < conf.NClients; i++ {
		<-clientStarted
	}
	// wait for completion
	wg.Wait()
}
<commit_msg>juggler: dry stats increment in handlers<commit_after>package juggler_test

import (
	"net/http/httptest"
	"strings"
	"sync"
	"sync/atomic"
	"testing"
	"time"

	"golang.org/x/net/context"

	"github.com/PuerkitoBio/exp/juggler"
	"github.com/PuerkitoBio/exp/juggler/broker/redisbroker"
	"github.com/PuerkitoBio/exp/juggler/callee"
	"github.com/PuerkitoBio/exp/juggler/internal/jugglertest"
	"github.com/PuerkitoBio/exp/juggler/internal/redistest"
	"github.com/PuerkitoBio/exp/juggler/msg"
	"github.com/gorilla/websocket"
)

// IntgConfig holds the configuration of an integration test execution.
type IntgConfig struct {
	RedisPoolMaxActive   int
	RedisPoolMaxIdle     int
	RedisPoolIdleTimeout time.Duration

	BrokerBlockingTimeout time.Duration
	BrokerCallCap         int
	BrokerResultCap       int

	ServerReadLimit               int64
	ServerReadTimeout             time.Duration
	ServerWriteLimit              int64
	ServerWriteTimeout            time.Duration
	ServerAcquireWriteLockTimeout time.Duration

	NCallees          int // number of callees listening on the URIs
	NWorkersPerCallee int // number of workers per callee
	NClients          int // number of clients generating calls

	NURIs         int           // number of different URIs to pick from at random
	NChannels     int           // number of different channels to pick from at random
	Duration      time.Duration // duration of the test
	ClientMsgRate time.Duration // send a message at this rate
	ServerPubRate time.Duration // publish a server-side event at this rate
	ThunkDelay    time.Duration // artificial delay of the call
}

type runStats struct {
	Call    int64
	Pub     int64
	Sub     int64
	Unsb    int64
	Exp     int64
	OK      int64
	Err     int64
	Res     int64
	Evnt    int64
	Unknown int64
}

func TestIntegration(t *testing.T) {
	if testing.Short() {
		t.Skip("integration tests don't run with the -short flag")
	}
	runIntegrationTest(t, &IntgConfig{}) // TODO : parse flags into IntgConfig
}

func incStats(stats *runStats, m msg.Msg) {
	switch m.Type() {
	case msg.CallMsg:
		atomic.AddInt64(&stats.Call, 1)
	case msg.PubMsg:
		atomic.AddInt64(&stats.Pub, 1)
	case msg.SubMsg:
		atomic.AddInt64(&stats.Sub, 1)
	case msg.UnsbMsg:
		atomic.AddInt64(&stats.Unsb, 1)
	case msg.ExpMsg:
		atomic.AddInt64(&stats.Exp, 1)
	case msg.OKMsg:
		atomic.AddInt64(&stats.OK, 1)
	case msg.ErrMsg:
		atomic.AddInt64(&stats.Err, 1)
	case msg.ResMsg:
		atomic.AddInt64(&stats.Res, 1)
	case msg.EvntMsg:
		atomic.AddInt64(&stats.Evnt, 1)
	default:
		atomic.AddInt64(&stats.Unknown, 1)
	}
}

func serverStatsHandler(stats *runStats) juggler.Handler {
	return juggler.HandlerFunc(func(ctx context.Context, c *juggler.Conn, m msg.Msg) {
		incStats(stats, m)
		juggler.ProcessMsg(ctx, c, m)
	})
}

func clientStatsHandler(stats *runStats) juggler.ClientHandler {
	return juggler.ClientHandlerFunc(func(ctx context.Context, c *juggler.Client, m msg.Msg) {
		incStats(stats, m)
	})
}

func runIntegrationTest(t *testing.T, conf *IntgConfig) {
	dbgl := &jugglertest.DebugLog{T: t}

	// start/create:
	// 1. redis-server
	// 2. redis pool and broker
	// 3. juggler server
	// 4. m callees
	// 5. n clients

	// 1. redis-server
	cmd, port := redistest.StartServer(t, nil)
	defer cmd.Process.Kill()

	// 2. create the redis pool and broker
	pool := redistest.NewPool(t, ":"+port)
	pool.MaxActive = conf.RedisPoolMaxActive
	pool.MaxIdle = conf.RedisPoolMaxIdle
	pool.IdleTimeout = conf.RedisPoolIdleTimeout
	brk := &redisbroker.Broker{
		Pool:    pool,
		Dial:    pool.Dial,
		LogFunc: dbgl.Printf,

		BlockingTimeout: conf.BrokerBlockingTimeout,
		CallCap:         conf.BrokerCallCap,
		ResultCap:       conf.BrokerResultCap,
	}

	// 3. create the juggler server
	var srvStats runStats
	srv := &juggler.Server{
		CallerBroker: brk,
		PubSubBroker: brk,
		LogFunc:      dbgl.Printf,

		ReadHandler:  serverStatsHandler(&srvStats),
		WriteHandler: serverStatsHandler(&srvStats),

		ReadLimit:               conf.ServerReadLimit,
		ReadTimeout:             conf.ServerReadTimeout,
		WriteLimit:              conf.ServerWriteLimit,
		WriteTimeout:            conf.ServerWriteTimeout,
		AcquireWriteLockTimeout: conf.ServerAcquireWriteLockTimeout,
	}
	upg := &websocket.Upgrader{Subprotocols: juggler.Subprotocols}
	httpsrv := httptest.NewServer(juggler.Upgrade(upg, srv))
	defer httpsrv.Close()

	// TODO : get URIs
	uris := []string{}
	thunk := func(cp *msg.CallPayload) (interface{}, error) {
		time.Sleep(conf.ThunkDelay)
		return "ok", nil
	}

	// 4. start m callees
	calleeStarted := make(chan struct{})
	for i := 0; i < conf.NCallees; i++ {
		go func() {
			cle := callee.Callee{
				Broker:  brk,
				LogFunc: dbgl.Printf,
			}

			conn, err := brk.Calls(uris...)
			if err != nil {
				t.Fatalf("failed to get CallsConn: %v", err)
			}
			defer conn.Close()
			ch := conn.Calls()

			for j := 0; j < conf.NWorkersPerCallee; j++ {
				go func() {
					calleeStarted <- struct{}{}
					for cp := range ch {
						if err := cle.InvokeAndStoreResult(cp, thunk); err != nil {
							t.Fatalf("InvokeAndStoreResult failed: %v", err)
						}
					}
				}()
			}
		}()
	}

	// 5. start n clients
	var clientStats runStats
	clientStarted := make(chan struct{})
	wg := sync.WaitGroup{}
	wg.Add(conf.NClients)

	for i := 0; i < conf.NClients; i++ {
		go func() {
			defer wg.Done()

			cli, err := juggler.Dial(&websocket.Dialer{}, strings.Replace(httpsrv.URL, "http:", "ws:", 1), nil,
				juggler.SetHandler(clientStatsHandler(&clientStats)))
			if err != nil {
				t.Fatalf("Dial failed: %v", err)
			}
			_ = cli

			// TODO : run predetermined requests...
			clientStarted <- struct{}{}
		}()
	}

	// wait for callees to come online
	for i, cnt := 0, conf.NCallees*conf.NWorkersPerCallee; i < cnt; i++ {
		<-calleeStarted
	}
	// start clients
	for i := 0; i < conf.NClients; i++ {
		<-clientStarted
	}
	// wait for completion
	wg.Wait()
}
<|endoftext|>


<commit_before>// +build integration

package main

import "testing"

// var fooAddr = flag.String(...)
//
// func TestToo(t *testing.T) {
//     f, err := foo.Connect(*fooAddr)
//     // ...
// }

// go test takes build tags just like go build, so you can call go test -tags=integration. It also synthesizes a package main which calls flag.Parse,
// so any flags declared and visible will be processed and available to your tests.
//
// When you do this	Run this
// Save	go fmt (or goimports)
// Build	go vet, golint, and maybe go test
// Deploy	go test -tags=integration
//
// or is the gcm style t.Short() better?

func TestGoogleAuth(t *testing.T) {
	// t.Fatal("Google+ first sign-in (registration) failed with valid credentials")
	// t.Fatal("Google+ second sign-in (regular) failed with valid credentials")
	// t.Fatal("Google+ sign-in passed with invalid credentials")
	// t.Fatal("Authentication was not ACKed")
}

func TestClientCertAuth(t *testing.T) {
	// t.Fatal("Authentication failed with a valid client certificate")
	// t.Fatal("Authenticated with invalid/expired client certificate")
	// t.Fatal("Authentication was not ACKed")
}

func TestTokenAuth(t *testing.T) {
	// t.Fatal("Authentication failed with a valid token")
	// t.Fatal("Authenticated with invalid/expired token")
	// t.Fatal("Authentication was not ACKed")
}

func TestReceiveOfflineQueue(t *testing.T) {
	// t.Fatal("Failed to receive queued messages after coming online")
	// t.Fatal("Failed to send ACK for received message queue")
}

func TestSendEcho(t *testing.T) {
	// t.Fatal("Failed to send a message to the echo user")
	// t.Fatal("Failed to send batch message to the echo user")
	// t.Fatal("Failed to send large message to the echo user")
	// t.Fatal("Did not receive ACK for a message sent")
	// t.Fatal("Failed to receive a response from echo user")
	// t.Fatal("Could not send an ACK for an incoming message")
}

func TestStop(t *testing.T) {
	// todo: this should be a listener/queue test if we don't use any goroutines in the Server struct methods
	// t.Fatal("Failed to stop the server gracefully: not all the goroutines were terminated properly")
	// t.Fatal("Failed to stop the server gracefully: server did not wait for ongoing read/write operations")
}

// is this listener test? or do we handle these errors in the server?
func TestTimeout(t *testing.T) {
	// t.Fatal("Send timout did not occur")
	// t.Fatal("Wait timeout did not occur")
}

// same question here..
func TestDisconnect(t *testing.T) {
	// t.Fatal("Client method.close request was not handled properly")
	// t.Fatal("Client disconnect was not handled gracefully")
	// t.Fatal("Server method.close request was not handled properly")
	// t.Fatal("Server disconnect was not handled gracefully")
}

func TestPing(t *testing.T) {
	// t.Fatal("Pong/ACK was not sent for ping")
}
<commit_msg>add short mode check<commit_after>// +build integration

package main

import "testing"

// var fooAddr = flag.String(...)
//
// func TestToo(t *testing.T) {
//     f, err := foo.Connect(*fooAddr)
//     // ...
// }

// go test takes build tags just like go build, so you can call go test -tags=integration. It also synthesizes a package main which calls flag.Parse,
// so any flags declared and visible will be processed and available to your tests.
//
// When you do this	Run this
// Save	go fmt (or goimports)
// Build	go vet, golint, and maybe go test
// Deploy	go test -tags=integration
//
// or is the gcm style t.Short() better?

func TestGoogleAuth(t *testing.T) {
	// t.Fatal("Google+ first sign-in (registration) failed with valid credentials")
	// t.Fatal("Google+ second sign-in (regular) failed with valid credentials")
	// t.Fatal("Google+ sign-in passed with invalid credentials")
	// t.Fatal("Authentication was not ACKed")
}

func TestClientCertAuth(t *testing.T) {
	// t.Fatal("Authentication failed with a valid client certificate")
	// t.Fatal("Authenticated with invalid/expired client certificate")
	// t.Fatal("Authentication was not ACKed")
}

func TestTokenAuth(t *testing.T) {
	// t.Fatal("Authentication failed with a valid token")
	// t.Fatal("Authenticated with invalid/expired token")
	// t.Fatal("Authentication was not ACKed")
}

func TestReceiveOfflineQueue(t *testing.T) {
	// t.Fatal("Failed to receive queued messages after coming online")
	// t.Fatal("Failed to send ACK for received message queue")
}

func TestSendEcho(t *testing.T) {
	// t.Fatal("Failed to send a message to the echo user")
	// t.Fatal("Failed to send batch message to the echo user")
	// t.Fatal("Failed to send large message to the echo user")
	// t.Fatal("Did not receive ACK for a message sent")
	// t.Fatal("Failed to receive a response from echo user")
	// t.Fatal("Could not send an ACK for an incoming message")
}

func TestStop(t *testing.T) {
	// todo: this should be a listener/queue test if we don't use any goroutines in the Server struct methods
	// t.Fatal("Failed to stop the server gracefully: not all the goroutines were terminated properly")
	// t.Fatal("Failed to stop the server gracefully: server did not wait for ongoing read/write operations")
}

// is this listener test? or do we handle these errors in the server?
func TestTimeout(t *testing.T) {
	// t.Fatal("Send timout did not occur")
	// t.Fatal("Wait timeout did not occur")
}

// same question here..
func TestDisconnect(t *testing.T) {
	// t.Fatal("Client method.close request was not handled properly")
	// t.Fatal("Client disconnect was not handled gracefully")
	// t.Fatal("Server method.close request was not handled properly")
	// t.Fatal("Server disconnect was not handled gracefully")
}

func TestPing(t *testing.T) {
	// t.Fatal("Pong/ACK was not sent for ping")
}

func getConn(t *testing.T) *Conn {
	if testing.Short() {
		t.Skip("Skipping integration test in short testing mode")
	} else if host == "" || senderID == "" || apiKey == "" {
		t.Skip("Skipping integration test due to missing GCM environment variables")
	}

	return nil
}
<|endoftext|>


<commit_before>package kloud

import (
	"fmt"
	"koding/kites/kloud/contexthelper/publickeys"
	"koding/kites/kloud/contexthelper/request"
	"koding/kites/kloud/eventer"
	"koding/kites/kloud/machinestate"
	"strings"

	"github.com/koding/kite"
	"golang.org/x/net/context"
)

type ControlResult struct {
	EventId string `json:"eventId"`
}

type machineFunc func(context.Context, interface{}) error

// statePair defines a methods start and final states
type statePair struct {
	start machinestate.State
	final machinestate.State
}

var states = map[string]*statePair{
	"build":          &statePair{start: machinestate.Building, final: machinestate.Running},
	"start":          &statePair{start: machinestate.Starting, final: machinestate.Running},
	"stop":           &statePair{start: machinestate.Stopping, final: machinestate.Stopped},
	"destroy":        &statePair{start: machinestate.Terminating, final: machinestate.Terminated},
	"restart":        &statePair{start: machinestate.Rebooting, final: machinestate.Running},
	"resize":         &statePair{start: machinestate.Pending, final: machinestate.Running},
	"reinit":         &statePair{start: machinestate.Terminating, final: machinestate.Running},
	"createSnapshot": &statePair{start: machinestate.Snapshotting, final: machinestate.Running},
	"deleteSnapshot": &statePair{start: machinestate.Snapshotting, final: machinestate.Running},
}

// coreMethods is running and returning the response for the given machineFunc.
// This method is used to avoid duplicate codes in many codes (because we do
// the same steps for each of them).
func (k *Kloud) coreMethods(r *kite.Request, fn machineFunc) (result interface{}, reqErr error) {
	// calls with zero arguments causes args to be nil. Check it that we
	// don't get a beloved panic
	if r.Args == nil {
		return nil, NewError(ErrNoArguments)
	}

	var args struct {
		MachineId string
		Provider  string
	}

	if err := r.Args.One().Unmarshal(&args); err != nil {
		return nil, err
	}

	if args.MachineId == "" {
		return nil, NewError(ErrMachineIdMissing)
	}

	if args.Provider == "" {
		return nil, NewError(ErrProviderIsMissing)
	}

	k.track(args.Provider, args.MachineId, r.Method)

	// Lock the machine id so no one else can access it. It means this
	// kloud instance is now responsible for this machine id. Its basically
	// a distributed lock. It's unlocked when there is an error or if the
	// method call is finished (unlocking is done inside the responsible
	// method calls).
	if r.Method != "info" {
		if err := k.Locker.Lock(args.MachineId); err != nil {
			return nil, err
		}

		// if something goes wrong after step reset the document which is was
		// set in the by previous step by Locker.Lock(). If there is no error,
		// the lock will be unlocked in the respective method  function.
		defer func() {
			if reqErr != nil {
				// otherwise that means Locker.Lock or something else in
				// ControlFunc failed. Reset the lock again so it can be acquired by
				// others.
				k.Locker.Unlock(args.MachineId)
			}
		}()
	}

	k.Log.Debug("args %+v", args)

	provider, ok := k.providers[args.Provider]
	if !ok {
		return nil, NewError(ErrProviderNotFound)
	}

	p, ok := provider.(Provider)
	if !ok {
		return nil, NewError(ErrProviderNotImplemented)
	}

	ctx := request.NewContext(context.Background(), r)
	// add publicKeys to be deployed to the machine, the machine provider is
	// responsible of deploying it to the machine while building it.
	ctx = publickeys.NewContext(ctx, k.PublicKeys)

	if k.ContextCreator != nil {
		ctx = k.ContextCreator(ctx)
	}

	// each method has his own unique eventer
	eventId := r.Method + "-" + args.MachineId
	ev := k.NewEventer(eventId)
	ctx = eventer.NewContext(ctx, ev)

	machine, err := p.Machine(ctx, args.MachineId)
	if err != nil {
		return nil, err
	}

	stater, ok := machine.(Stater)
	if !ok {
		return nil, NewError(ErrStaterNotImplemented)
	}
	currentState := stater.State()

	// Check if the given method is in valid methods of that current state. For
	// example if the method is "build", and the state is "stopped" than this
	// will return an error.
	if !methodIn(r.Method, stater.State().ValidMethods()...) {
		return nil, fmt.Errorf("%s not allowed for current state '%s'. Allowed methods are: %v",
			r.Method, strings.ToLower(stater.State().String()), stater.State().ValidMethods())
	}

	pair, ok := states[r.Method]
	if !ok {
		return nil, fmt.Errorf("no state pair available for %s", r.Method)
	}

	ev.Push(&eventer.Event{
		Message: r.Method + " started",
		Status:  pair.start,
	})

	// Start our core method in a goroutine to not block it for the client
	// side. However we do return an event id which is an unique for tracking
	// the current status of the running method.
	go func() {
		finalEvent := &eventer.Event{
			Message:    r.Method + " finished",
			Status:     pair.final,
			Percentage: 100,
		}

		err := fn(ctx, machine)
		if err != nil {
			k.Log.Error("[%s][%s] %s error: %s", args.Provider, args.MachineId, r.Method, err)
			finalEvent.Error = strings.ToTitle(r.Method) + " failed. Please contact support."
			finalEvent.Status = currentState // fallback to to old state
		}

		ev.Push(finalEvent)
		k.Locker.Unlock(args.MachineId)
	}()

	return ControlResult{
		EventId: eventId,
	}, nil
}

func (k *Kloud) GetMachine(r *kite.Request) (resp interface{}, reqErr error) {
	// calls with zero arguments causes args to be nil. Check it that we
	// don't get a beloved panic
	if r.Args == nil {
		return nil, NewError(ErrNoArguments)
	}

	var args struct {
		MachineId string
		Provider  string
	}

	if err := r.Args.One().Unmarshal(&args); err != nil {
		return nil, err
	}

	if args.MachineId == "" {
		return nil, NewError(ErrMachineIdMissing)
	}

	// Lock the machine id so no one else can access it. It means this
	// kloud instance is now responsible for this machine id. Its basically
	// a distributed lock. It's unlocked when there is an error or if the
	// method call is finished (unlocking is done inside the responsible
	// method calls).
	if r.Method != "info" {
		if err := k.Locker.Lock(args.MachineId); err != nil {
			return nil, err
		}

		// if something goes wrong after step reset the document which is was
		// set in the by previous step by Locker.Lock(). If there is no error,
		// the lock will be unlocked in the respective method  function.
		defer func() {
			if reqErr != nil {
				// otherwise that means Locker.Lock or something else in
				// ControlFunc failed. Reset the lock again so it can be acquired by
				// others.
				k.Locker.Unlock(args.MachineId)
			}
		}()
	}

	provider, ok := k.providers[args.Provider]
	if !ok {
		return nil, NewError(ErrProviderAvailable)
	}

	p, ok := provider.(Provider)
	if !ok {
		return nil, NewError(ErrProviderNotImplemented)
	}

	ctx := request.NewContext(context.Background(), r)

	return p.Machine(ctx, args.MachineId)
}

// methodIn checks if the method exist in the given methods
func methodIn(method string, methods ...string) bool {
	for _, m := range methods {
		if method == m {
			return true
		}
	}
	return false
}
<commit_msg>kloud: add start/finish logs<commit_after>package kloud

import (
	"fmt"
	"koding/kites/kloud/contexthelper/publickeys"
	"koding/kites/kloud/contexthelper/request"
	"koding/kites/kloud/eventer"
	"koding/kites/kloud/machinestate"
	"strings"
	"time"

	"github.com/koding/kite"
	"golang.org/x/net/context"
)

type ControlResult struct {
	EventId string `json:"eventId"`
}

type machineFunc func(context.Context, interface{}) error

// statePair defines a methods start and final states
type statePair struct {
	start machinestate.State
	final machinestate.State
}

var states = map[string]*statePair{
	"build":          &statePair{start: machinestate.Building, final: machinestate.Running},
	"start":          &statePair{start: machinestate.Starting, final: machinestate.Running},
	"stop":           &statePair{start: machinestate.Stopping, final: machinestate.Stopped},
	"destroy":        &statePair{start: machinestate.Terminating, final: machinestate.Terminated},
	"restart":        &statePair{start: machinestate.Rebooting, final: machinestate.Running},
	"resize":         &statePair{start: machinestate.Pending, final: machinestate.Running},
	"reinit":         &statePair{start: machinestate.Terminating, final: machinestate.Running},
	"createSnapshot": &statePair{start: machinestate.Snapshotting, final: machinestate.Running},
	"deleteSnapshot": &statePair{start: machinestate.Snapshotting, final: machinestate.Running},
}

// coreMethods is running and returning the response for the given machineFunc.
// This method is used to avoid duplicate codes in many codes (because we do
// the same steps for each of them).
func (k *Kloud) coreMethods(r *kite.Request, fn machineFunc) (result interface{}, reqErr error) {
	// calls with zero arguments causes args to be nil. Check it that we
	// don't get a beloved panic
	if r.Args == nil {
		return nil, NewError(ErrNoArguments)
	}

	var args struct {
		MachineId string
		Provider  string
	}

	if err := r.Args.One().Unmarshal(&args); err != nil {
		return nil, err
	}

	if args.MachineId == "" {
		return nil, NewError(ErrMachineIdMissing)
	}

	if args.Provider == "" {
		return nil, NewError(ErrProviderIsMissing)
	}

	k.track(args.Provider, args.MachineId, r.Method)

	// Lock the machine id so no one else can access it. It means this
	// kloud instance is now responsible for this machine id. Its basically
	// a distributed lock. It's unlocked when there is an error or if the
	// method call is finished (unlocking is done inside the responsible
	// method calls).
	if r.Method != "info" {
		if err := k.Locker.Lock(args.MachineId); err != nil {
			return nil, err
		}

		// if something goes wrong after step reset the document which is was
		// set in the by previous step by Locker.Lock(). If there is no error,
		// the lock will be unlocked in the respective method  function.
		defer func() {
			if reqErr != nil {
				// otherwise that means Locker.Lock or something else in
				// ControlFunc failed. Reset the lock again so it can be acquired by
				// others.
				k.Locker.Unlock(args.MachineId)
			}
		}()
	}

	k.Log.Debug("args %+v", args)

	provider, ok := k.providers[args.Provider]
	if !ok {
		return nil, NewError(ErrProviderNotFound)
	}

	p, ok := provider.(Provider)
	if !ok {
		return nil, NewError(ErrProviderNotImplemented)
	}

	ctx := request.NewContext(context.Background(), r)
	// add publicKeys to be deployed to the machine, the machine provider is
	// responsible of deploying it to the machine while building it.
	ctx = publickeys.NewContext(ctx, k.PublicKeys)

	if k.ContextCreator != nil {
		ctx = k.ContextCreator(ctx)
	}

	// each method has his own unique eventer
	eventId := r.Method + "-" + args.MachineId
	ev := k.NewEventer(eventId)
	ctx = eventer.NewContext(ctx, ev)

	machine, err := p.Machine(ctx, args.MachineId)
	if err != nil {
		return nil, err
	}

	stater, ok := machine.(Stater)
	if !ok {
		return nil, NewError(ErrStaterNotImplemented)
	}
	currentState := stater.State()

	// Check if the given method is in valid methods of that current state. For
	// example if the method is "build", and the state is "stopped" than this
	// will return an error.
	if !methodIn(r.Method, stater.State().ValidMethods()...) {
		return nil, fmt.Errorf("%s not allowed for current state '%s'. Allowed methods are: %v",
			r.Method, strings.ToLower(stater.State().String()), stater.State().ValidMethods())
	}

	pair, ok := states[r.Method]
	if !ok {
		return nil, fmt.Errorf("no state pair available for %s", r.Method)
	}

	ev.Push(&eventer.Event{
		Message: r.Method + " started",
		Status:  pair.start,
	})

	// Start our core method in a goroutine to not block it for the client
	// side. However we do return an event id which is an unique for tracking
	// the current status of the running method.
	go func() {
		finalEvent := &eventer.Event{
			Message:    r.Method + " finished",
			Status:     pair.final,
			Percentage: 100,
		}

		k.Log.Info("[%s] ======> %s started <======", args.Provider, args.MachineId, strings.ToUpper(r.Method))
		start := time.Now()

		err := fn(ctx, machine)
		if err != nil {
			k.Log.Error("[%s][%s] %s error: %s", args.Provider, args.MachineId, r.Method, err)
			finalEvent.Error = strings.ToTitle(r.Method) + " failed. Please contact support."
			finalEvent.Status = currentState // fallback to to old state
		}

		k.Log.Info("[%s] ======> %s finished (time: %s) <======",
			args.Provider, args.MachineId, strings.ToUpper(r.Method), time.Since(start))

		ev.Push(finalEvent)
		k.Locker.Unlock(args.MachineId)
	}()

	return ControlResult{
		EventId: eventId,
	}, nil
}

func (k *Kloud) GetMachine(r *kite.Request) (resp interface{}, reqErr error) {
	// calls with zero arguments causes args to be nil. Check it that we
	// don't get a beloved panic
	if r.Args == nil {
		return nil, NewError(ErrNoArguments)
	}

	var args struct {
		MachineId string
		Provider  string
	}

	if err := r.Args.One().Unmarshal(&args); err != nil {
		return nil, err
	}

	if args.MachineId == "" {
		return nil, NewError(ErrMachineIdMissing)
	}

	// Lock the machine id so no one else can access it. It means this
	// kloud instance is now responsible for this machine id. Its basically
	// a distributed lock. It's unlocked when there is an error or if the
	// method call is finished (unlocking is done inside the responsible
	// method calls).
	if r.Method != "info" {
		if err := k.Locker.Lock(args.MachineId); err != nil {
			return nil, err
		}

		// if something goes wrong after step reset the document which is was
		// set in the by previous step by Locker.Lock(). If there is no error,
		// the lock will be unlocked in the respective method  function.
		defer func() {
			if reqErr != nil {
				// otherwise that means Locker.Lock or something else in
				// ControlFunc failed. Reset the lock again so it can be acquired by
				// others.
				k.Locker.Unlock(args.MachineId)
			}
		}()
	}

	provider, ok := k.providers[args.Provider]
	if !ok {
		return nil, NewError(ErrProviderAvailable)
	}

	p, ok := provider.(Provider)
	if !ok {
		return nil, NewError(ErrProviderNotImplemented)
	}

	ctx := request.NewContext(context.Background(), r)

	return p.Machine(ctx, args.MachineId)
}

// methodIn checks if the method exist in the given methods
func methodIn(method string, methods ...string) bool {
	for _, m := range methods {
		if method == m {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package luks

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"runtime"
	"strconv"
	"testing"
	"time"

	"github.com/anatol/vmtest"
	"github.com/tmc/scp"
	"golang.org/x/crypto/ssh"
)

func TestBootInQemu(t *testing.T) {
	cmd := exec.Command("go", "test", "-c", "examples/end2end_test.go", "-o", "luks_end2end_test")
	if testing.Verbose() {
		log.Print("compile in-qemu test binary")
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
	}
	err := cmd.Run()
	if err != nil {
		t.Fatal(err)
	}
	defer os.Remove("luks_end2end_test")

	// These integration tests use QEMU with a statically-compiled kernel (to avoid inintramfs) and a specially
	// prepared rootfs. See [instructions](https://github.com/anatol/vmtest/blob/master/docs/prepare_image.md)
	// how to prepare these binaries.
	opts := vmtest.QemuOptions{
		OperatingSystem: vmtest.OS_LINUX,
		Kernel:          "bzImage",
		Params:          []string{"-net", "user,hostfwd=tcp::10022-:22", "-net", "nic", "-enable-kvm", "-cpu", "host", "-m", "8G", "-smp", strconv.Itoa(runtime.NumCPU())},
		Disks:           []string{"rootfs.qcow2"},
		Append:          []string{"root=/dev/sda", "rw"},
		Verbose:         testing.Verbose(),
		Timeout:         50 * time.Second,
	}
	// Run QEMU instance
	qemu, err := vmtest.NewQemu(&opts)
	if err != nil {
		t.Fatal(err)
	}
	// Stop QEMU at the end of the test case
	defer qemu.Stop()

	config := &ssh.ClientConfig{
		User:            "root",
		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
	}

	conn, err := ssh.Dial("tcp", "localhost:10022", config)
	if err != nil {
		t.Fatal(err)
	}
	defer conn.Close()

	sess, err := conn.NewSession()
	if err != nil {
		t.Fatal(err)
	}
	defer sess.Close()

	scpSess, err := conn.NewSession()
	if err != nil {
		t.Fatal(err)
	}

	if err := scp.CopyPath("luks_end2end_test", "luks_end2end_test", scpSess); err != nil {
		t.Error(err)
	}

	testCmd := "./luks_end2end_test -test.parallel " + strconv.Itoa(runtime.NumCPU())
	if testing.Verbose() {
		testCmd += " -test.v"
	}

	output, err := sess.CombinedOutput(testCmd)
	if testing.Verbose() {
		fmt.Print(string(output))
	}
	if err != nil {
		t.Fatal(err)
	}
}
<commit_msg>Add possiblility to disable KVM in tests<commit_after>package luks

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"runtime"
	"strconv"
	"testing"
	"time"

	"github.com/anatol/vmtest"
	"github.com/tmc/scp"
	"golang.org/x/crypto/ssh"
)

func TestBootInQemu(t *testing.T) {
	cmd := exec.Command("go", "test", "-c", "examples/end2end_test.go", "-o", "luks_end2end_test")
	if testing.Verbose() {
		log.Print("compile in-qemu test binary")
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
	}
	err := cmd.Run()
	if err != nil {
		t.Fatal(err)
	}
	defer os.Remove("luks_end2end_test")

	// These integration tests use QEMU with a statically-compiled kernel (to avoid inintramfs) and a specially
	// prepared rootfs. See [instructions](https://github.com/anatol/vmtest/blob/master/docs/prepare_image.md)
	// how to prepare these binaries.
	params := []string{"-net", "user,hostfwd=tcp::10022-:22", "-net", "nic", "-m", "8G", "-smp", strconv.Itoa(runtime.NumCPU())}
	if os.Getenv("TEST_DISABLE_KVM") != "1" {
		params = append(params, "-enable-kvm", "-cpu", "host")
	}
	opts := vmtest.QemuOptions{
		OperatingSystem: vmtest.OS_LINUX,
		Kernel:          "bzImage",
		Params:          params,
		Disks:           []string{"rootfs.qcow2"},
		Append:          []string{"root=/dev/sda", "rw"},
		Verbose:         testing.Verbose(),
		Timeout:         50 * time.Second,
	}
	// Run QEMU instance
	qemu, err := vmtest.NewQemu(&opts)
	if err != nil {
		t.Fatal(err)
	}
	// Stop QEMU at the end of the test case
	defer qemu.Stop()

	config := &ssh.ClientConfig{
		User:            "root",
		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
	}

	conn, err := ssh.Dial("tcp", "localhost:10022", config)
	if err != nil {
		t.Fatal(err)
	}
	defer conn.Close()

	sess, err := conn.NewSession()
	if err != nil {
		t.Fatal(err)
	}
	defer sess.Close()

	scpSess, err := conn.NewSession()
	if err != nil {
		t.Fatal(err)
	}

	if err := scp.CopyPath("luks_end2end_test", "luks_end2end_test", scpSess); err != nil {
		t.Error(err)
	}

	testCmd := "./luks_end2end_test -test.parallel " + strconv.Itoa(runtime.NumCPU())
	if testing.Verbose() {
		testCmd += " -test.v"
	}

	output, err := sess.CombinedOutput(testCmd)
	if testing.Verbose() {
		fmt.Print(string(output))
	}
	if err != nil {
		t.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package models

import (
	"errors"
	"time"

	"github.com/koding/bongo"
)

// todo Scope function for this struct
// in order not to fetch passive accounts
type ChannelParticipant struct {
	// unique identifier of the channel
	Id int64 `json:"id"`

	// Id of the channel
	ChannelId int64 `json:"channelId"              sql:"NOT NULL"`

	// Id of the account
	AccountId int64 `json:"accountId"              sql:"NOT NULL"`

	// Status of the participant in the channel
	StatusConstant string `json:"statusConstant"   sql:"NOT NULL;TYPE:VARCHAR(100);"`

	// date of the user's last access to regarding channel
	LastSeenAt time.Time `json:"lastSeenAt"        sql:"NOT NULL"`

	// Creation date of the channel channel participant
	CreatedAt time.Time `json:"createdAt"          sql:"NOT NULL"`

	// Modification date of the channel participant's status
	UpdatedAt time.Time `json:"updatedAt"          sql:"NOT NULL"`
}

// here is why i did this not-so-good constants
// https://code.google.com/p/go/issues/detail?id=359
const (
	ChannelParticipant_STATUS_ACTIVE          = "active"
	ChannelParticipant_STATUS_LEFT            = "left"
	ChannelParticipant_STATUS_REQUEST_PENDING = "requestPending"
)

func NewChannelParticipant() *ChannelParticipant {
	return &ChannelParticipant{}
}

func (c *ChannelParticipant) GetId() int64 {
	return c.Id
}

func (c *ChannelParticipant) TableName() string {
	return "channel_participant"
}

func (c *ChannelParticipant) BeforeSave() {
	c.LastSeenAt = time.Now().UTC()
}

func (c *ChannelParticipant) BeforeUpdate() {
	c.LastSeenAt = time.Now().UTC()
}

func (c *ChannelParticipant) Create() error {
	return bongo.B.Create(c)
}

func (c *ChannelParticipant) Update() error {
	return bongo.B.Update(c)
}

func (c *ChannelParticipant) Some(data interface{}, q *bongo.Query) error {
	return bongo.B.Some(c, data, q)
}

func (c *ChannelParticipant) FetchParticipant() error {
	if c.ChannelId == 0 {
		return errors.New("ChannelId is not set")
	}

	if c.AccountId == 0 {
		return errors.New("AccountId is not set")
	}

	selector := map[string]interface{}{
		"channel_id": c.ChannelId,
		"account_id": c.AccountId,
		// "status_constant":     ChannelParticipant_STATUS_ACTIVE,
	}

	err := bongo.B.One(c, c, selector)
	if err != nil {
		return err
	}

	return nil
}

func (c *ChannelParticipant) FetchUnreadCount() (int, error) {
	cml := NewChannelMessageList()
	return cml.UnreadCount(c)
}

func (c *ChannelParticipant) Delete() error {
	selector := bongo.Partial{
		"account_id": c.AccountId,
		"channel_id": c.ChannelId,
	}
	if err := bongo.B.One(c, c, selector); err != nil {
		return err
	}

	return bongo.B.UpdatePartial(c,
		bongo.Partial{
			"status_constant": ChannelParticipant_STATUS_LEFT,
		},
	)
}

func (c *ChannelParticipant) List() ([]ChannelParticipant, error) {
	var participants []ChannelParticipant

	if c.ChannelId == 0 {
		return participants, errors.New("ChannelId is not set")
	}
	query := &bongo.Query{
		Selector: map[string]interface{}{
			"channel_id":      c.ChannelId,
			"status_constant": ChannelParticipant_STATUS_ACTIVE,
		},
	}

	err := bongo.B.Some(c, &participants, query)
	if err != nil {
		return nil, err
	}

	return participants, nil
}

func (c *ChannelParticipant) FetchParticipatedChannelIds(a *Account) ([]int64, error) {

	if a.Id == 0 {
		return nil, errors.New("Account.Id is not set")
	}

	var channelIds []int64

	if err := bongo.B.DB.Table(c.TableName()).
		Order("created_at desc").
		Where("account_id = ?", a.Id).
		Pluck("channel_id", &channelIds).
		Error; err != nil {
		return nil, err
	}

	return channelIds, nil
}
<commit_msg>Social: implement and use new One function<commit_after>package models

import (
	"errors"
	"time"

	"github.com/koding/bongo"
)

// todo Scope function for this struct
// in order not to fetch passive accounts
type ChannelParticipant struct {
	// unique identifier of the channel
	Id int64 `json:"id"`

	// Id of the channel
	ChannelId int64 `json:"channelId"              sql:"NOT NULL"`

	// Id of the account
	AccountId int64 `json:"accountId"              sql:"NOT NULL"`

	// Status of the participant in the channel
	StatusConstant string `json:"statusConstant"   sql:"NOT NULL;TYPE:VARCHAR(100);"`

	// date of the user's last access to regarding channel
	LastSeenAt time.Time `json:"lastSeenAt"        sql:"NOT NULL"`

	// Creation date of the channel channel participant
	CreatedAt time.Time `json:"createdAt"          sql:"NOT NULL"`

	// Modification date of the channel participant's status
	UpdatedAt time.Time `json:"updatedAt"          sql:"NOT NULL"`
}

// here is why i did this not-so-good constants
// https://code.google.com/p/go/issues/detail?id=359
const (
	ChannelParticipant_STATUS_ACTIVE          = "active"
	ChannelParticipant_STATUS_LEFT            = "left"
	ChannelParticipant_STATUS_REQUEST_PENDING = "requestPending"
)

func NewChannelParticipant() *ChannelParticipant {
	return &ChannelParticipant{}
}

func (c *ChannelParticipant) GetId() int64 {
	return c.Id
}

func (c *ChannelParticipant) TableName() string {
	return "channel_participant"
}

func (c *ChannelParticipant) BeforeSave() {
	c.LastSeenAt = time.Now().UTC()
}

func (c *ChannelParticipant) BeforeUpdate() {
	c.LastSeenAt = time.Now().UTC()
}

func (c *ChannelParticipant) Create() error {
	return bongo.B.Create(c)
}

func (c *ChannelParticipant) Update() error {
	return bongo.B.Update(c)
}

func (c *ChannelParticipant) One(q *bongo.Query) error {
	return bongo.B.One(c, c, q)
}

func (c *ChannelParticipant) Some(data interface{}, q *bongo.Query) error {
	return bongo.B.Some(c, data, q)
}

func (c *ChannelParticipant) FetchParticipant() error {
	if c.ChannelId == 0 {
		return errors.New("ChannelId is not set")
	}

	if c.AccountId == 0 {
		return errors.New("AccountId is not set")
	}

	selector := map[string]interface{}{
		"channel_id": c.ChannelId,
		"account_id": c.AccountId,
		// "status_constant":     ChannelParticipant_STATUS_ACTIVE,
	}

	err := c.One(bongo.NewQS(selector))
	if err != nil {
		return err
	}

	return nil
}

func (c *ChannelParticipant) FetchUnreadCount() (int, error) {
	cml := NewChannelMessageList()
	return cml.UnreadCount(c)
}

func (c *ChannelParticipant) Delete() error {
	selector := bongo.Partial{
		"account_id": c.AccountId,
		"channel_id": c.ChannelId,
	}

	if err := c.One(bongo.NewQS(selector)); err != nil {
		return err
	}

	return bongo.B.UpdatePartial(c,
		bongo.Partial{
			"status_constant": ChannelParticipant_STATUS_LEFT,
		},
	)
}

func (c *ChannelParticipant) List() ([]ChannelParticipant, error) {
	var participants []ChannelParticipant

	if c.ChannelId == 0 {
		return participants, errors.New("ChannelId is not set")
	}
	query := &bongo.Query{
		Selector: map[string]interface{}{
			"channel_id":      c.ChannelId,
			"status_constant": ChannelParticipant_STATUS_ACTIVE,
		},
	}

	err := bongo.B.Some(c, &participants, query)
	if err != nil {
		return nil, err
	}

	return participants, nil
}

func (c *ChannelParticipant) FetchParticipatedChannelIds(a *Account) ([]int64, error) {

	if a.Id == 0 {
		return nil, errors.New("Account.Id is not set")
	}

	var channelIds []int64

	if err := bongo.B.DB.Table(c.TableName()).
		Order("created_at desc").
		Where("account_id = ?", a.Id).
		Pluck("channel_id", &channelIds).
		Error; err != nil {
		return nil, err
	}

	return channelIds, nil
}
<|endoftext|>