From 0a74f33d630dff322c3e06250702f66b1d5714d2 Mon Sep 17 00:00:00 2001 From: Konrad Kleine Date: Fri, 27 Jul 2018 07:55:07 +0200 Subject: [PATCH 01/10] update events system --- controller/iteration.go | 10 +- controller/label.go | 9 +- controller/work_item_events_test.go | 50 ++-- workitem/event/event_repository.go | 228 +++++++----------- .../event/event_repository_blackbox_test.go | 99 ++++---- 5 files changed, 174 insertions(+), 222 deletions(-) diff --git a/controller/iteration.go b/controller/iteration.go index ebc12824a4..738b08ba59 100644 --- a/controller/iteration.go +++ b/controller/iteration.go @@ -518,11 +518,17 @@ func ConvertIteration(request *http.Request, itr iteration.Iteration, additional // ConvertIterationSimple converts a simple Iteration ID into a Generic Reletionship func ConvertIterationSimple(request *http.Request, id interface{}) *app.GenericData { t := iteration.APIStringTypeIteration - i := fmt.Sprint(id) + var i string + switch t := id.(type) { + case string: + i = t + case uuid.UUID: + i = t.String() + } return &app.GenericData{ Type: &t, ID: &i, - Links: createIterationLinks(request, id), + Links: createIterationLinks(request, i), } } diff --git a/controller/label.go b/controller/label.go index 5e94718c23..2b5866e418 100644 --- a/controller/label.go +++ b/controller/label.go @@ -13,6 +13,7 @@ import ( "github.com/fabric8-services/fabric8-wit/rest" "github.com/fabric8-services/fabric8-wit/space" "github.com/goadesign/goa" + uuid "github.com/satori/go.uuid" ) // LabelController implements the label resource. @@ -164,7 +165,13 @@ func ConvertLabelsSimple(request *http.Request, labelIDs []interface{}) []*app.G // ConvertLabelSimple converts a Label ID into a Generic Reletionship func ConvertLabelSimple(request *http.Request, labelID interface{}) *app.GenericData { t := label.APIStringTypeLabels - i := labelID.(string) + var i string + switch t := labelID.(type) { + case string: + i = t + case uuid.UUID: + i = t.String() + } return &app.GenericData{ Type: &t, ID: &i, diff --git a/controller/work_item_events_test.go b/controller/work_item_events_test.go index 749adca5bf..afa75bf255 100644 --- a/controller/work_item_events_test.go +++ b/controller/work_item_events_test.go @@ -40,7 +40,7 @@ func (s *TestEvent) TestListEvent() { s.T().Run("event list ok - state", func(t *testing.T) { fxt := tf.NewTestFixture(s.T(), s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1)) svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) - EventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) + eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) payload := app.UpdateWorkitemPayload{ @@ -57,7 +57,7 @@ func (s *TestEvent) TestListEvent() { }, } test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) - res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, EventCtrl, fxt.WorkItems[0].ID, nil, nil) + res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") require.NotEmpty(t, eventList) require.Len(t, eventList.Data, 1) @@ -68,7 +68,7 @@ func (s *TestEvent) TestListEvent() { s.T().Run("event list ok - title", func(t *testing.T) { fxt := tf.NewTestFixture(s.T(), s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1)) svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) - EventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) + eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) payload := app.UpdateWorkitemPayload{ @@ -85,7 +85,7 @@ func (s *TestEvent) TestListEvent() { }, } test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) - res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, EventCtrl, fxt.WorkItems[0].ID, nil, nil) + res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") require.NotEmpty(t, eventList) require.Len(t, eventList.Data, 1) @@ -113,7 +113,7 @@ func (s *TestEvent) TestListEvent() { }), ) svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) - EventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) + eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) payload := app.UpdateWorkitemPayload{ @@ -131,7 +131,7 @@ func (s *TestEvent) TestListEvent() { }, } test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) - res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, EventCtrl, fxt.WorkItems[0].ID, nil, nil) + res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") require.NotEmpty(t, eventList) require.Len(t, eventList.Data, 1) @@ -159,7 +159,7 @@ func (s *TestEvent) TestListEvent() { }), ) svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) - EventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) + eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) payload := app.UpdateWorkitemPayload{ @@ -177,7 +177,7 @@ func (s *TestEvent) TestListEvent() { }, } test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) - res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, EventCtrl, fxt.WorkItems[0].ID, nil, nil) + res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") require.NotEmpty(t, eventList) require.Len(t, eventList.Data, 1) @@ -188,7 +188,7 @@ func (s *TestEvent) TestListEvent() { s.T().Run("event list ok - description", func(t *testing.T) { fxt := tf.NewTestFixture(s.T(), s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1)) svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) - EventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) + eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) payload := app.UpdateWorkitemPayload{ @@ -205,7 +205,7 @@ func (s *TestEvent) TestListEvent() { }, } test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) - res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, EventCtrl, fxt.WorkItems[0].ID, nil, nil) + res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") require.NotEmpty(t, eventList) require.Len(t, eventList.Data, 1) @@ -216,7 +216,7 @@ func (s *TestEvent) TestListEvent() { s.T().Run("event list ok - assigned", func(t *testing.T) { fxt := tf.NewTestFixture(s.T(), s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1)) svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) - EventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) + eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) assignee := []string{fxt.Identities[0].ID.String()} workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) @@ -234,7 +234,7 @@ func (s *TestEvent) TestListEvent() { }, } test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) - res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, EventCtrl, fxt.WorkItems[0].ID, nil, nil) + res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") require.NotEmpty(t, eventList) require.Len(t, eventList.Data, 1) @@ -245,7 +245,7 @@ func (s *TestEvent) TestListEvent() { s.T().Run("event list ok - label", func(t *testing.T) { fxt := tf.NewTestFixture(t, s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1), tf.Labels(2)) svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) - EventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) + eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) wiCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) u := app.UpdateWorkitemPayload{ @@ -279,7 +279,7 @@ func (s *TestEvent) TestListEvent() { require.NotNil(t, updatedWI.Data.Relationships.Labels.Links) assert.Len(t, updatedWI.Data.Relationships.Labels.Data, 2) - res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, EventCtrl, fxt.WorkItems[0].ID, nil, nil) + res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") require.NotEmpty(t, eventList) require.Len(t, eventList.Data, 1) @@ -290,7 +290,7 @@ func (s *TestEvent) TestListEvent() { s.T().Run("event list ok - iteration", func(t *testing.T) { fxt := tf.NewTestFixture(s.T(), s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1)) svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) - EventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) + eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) payload := app.UpdateWorkitemPayload{ @@ -298,7 +298,7 @@ func (s *TestEvent) TestListEvent() { Type: APIStringTypeWorkItem, ID: &fxt.WorkItems[0].ID, Attributes: map[string]interface{}{ - workitem.SystemIteration: fxt.Iterations[0].ID.String(), + workitem.SystemIteration: fxt.Iterations[0].ID, workitem.SystemVersion: fxt.WorkItems[0].Version, }, Relationships: &app.WorkItemRelationships{ @@ -307,7 +307,7 @@ func (s *TestEvent) TestListEvent() { }, } test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) - res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, EventCtrl, fxt.WorkItems[0].ID, nil, nil) + res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") require.NotEmpty(t, eventList) require.Len(t, eventList.Data, 1) @@ -318,7 +318,7 @@ func (s *TestEvent) TestListEvent() { s.T().Run("event list ok - area", func(t *testing.T) { fxt := tf.NewTestFixture(s.T(), s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1)) svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) - EventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) + eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) payload := app.UpdateWorkitemPayload{ @@ -335,7 +335,7 @@ func (s *TestEvent) TestListEvent() { }, } test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) - res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, EventCtrl, fxt.WorkItems[0].ID, nil, nil) + res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") require.NotEmpty(t, eventList) require.Len(t, eventList.Data, 1) @@ -346,8 +346,8 @@ func (s *TestEvent) TestListEvent() { s.T().Run("event list - empty", func(t *testing.T) { fxt := tf.NewTestFixture(s.T(), s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1)) svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) - EventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) - res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, EventCtrl, fxt.WorkItems[0].ID, nil, nil) + eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) + res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-no-event.res.errors.payload.golden.json"), eventList) compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-no-event.res.errors.headers.golden.json"), res.Header()) @@ -356,7 +356,7 @@ func (s *TestEvent) TestListEvent() { s.T().Run("many events", func(t *testing.T) { fxt := tf.NewTestFixture(s.T(), s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1), tf.Iterations(2)) svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) - EventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) + eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) payload1 := app.UpdateWorkitemPayload{ @@ -373,7 +373,7 @@ func (s *TestEvent) TestListEvent() { }, } test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload1) // update iteration - res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, EventCtrl, fxt.WorkItems[0].ID, nil, nil) + res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") require.NotEmpty(t, eventList) require.Len(t, eventList.Data, 1) @@ -393,7 +393,7 @@ func (s *TestEvent) TestListEvent() { }, } test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload2) // update assignee - res, eventList = test.ListWorkItemEventsOK(t, svc.Context, svc, EventCtrl, fxt.WorkItems[0].ID, nil, nil) + res, eventList = test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) require.NotEmpty(t, eventList) require.Len(t, eventList.Data, 2) @@ -411,7 +411,7 @@ func (s *TestEvent) TestListEvent() { }, } test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload3) // update iteration - res, eventList = test.ListWorkItemEventsOK(t, svc.Context, svc, EventCtrl, fxt.WorkItems[0].ID, nil, nil) + res, eventList = test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") require.NotEmpty(t, eventList) require.Len(t, eventList.Data, 3) diff --git a/workitem/event/event_repository.go b/workitem/event/event_repository.go index 2bb6e25403..a70265e3c8 100644 --- a/workitem/event/event_repository.go +++ b/workitem/event/event_repository.go @@ -2,7 +2,6 @@ package event import ( "context" - "fmt" "reflect" "github.com/jinzhu/gorm" @@ -11,7 +10,6 @@ import ( "github.com/fabric8-services/fabric8-wit/account" "github.com/fabric8-services/fabric8-wit/errors" - "github.com/fabric8-services/fabric8-wit/rendering" "github.com/fabric8-services/fabric8-wit/workitem" ) @@ -48,181 +46,127 @@ type GormEventRepository struct { func (r *GormEventRepository) List(ctx context.Context, wiID uuid.UUID) ([]Event, error) { revisionList, err := r.wiRevisionRepo.List(ctx, wiID) if err != nil { - return nil, errs.Wrapf(err, "error during fetching event list") + return nil, errs.Wrapf(err, "failed to list revisions for work item: %s", wiID) } if revisionList == nil { return []Event{}, nil } wi, err := r.workItemRepo.LoadByID(ctx, wiID) if err != nil { - return nil, errs.Wrapf(err, "error during fetching event list") + return nil, errs.Wrapf(err, "failed to load work item: %s", wiID) } wiType, err := r.workItemTypeRepo.Load(ctx, wi.Type) if err != nil { - return nil, errs.Wrapf(err, "error during fetching event list") + return nil, errs.Wrapf(err, "failed to load work item type: %s", wiType) } eventList := []Event{} for k := 1; k < len(revisionList); k++ { - modifierID, err := r.identityRepo.Load(ctx, revisionList[k].ModifierIdentity) + + oldRev := revisionList[k-1] + newRev := revisionList[k] + + modifierID, err := r.identityRepo.Load(ctx, newRev.ModifierIdentity) if err != nil { - return nil, errs.Wrapf(err, "error during fetching event list") + return nil, errs.Wrapf(err, "failed to load modifier identity %s", newRev.ModifierIdentity) } - for fieldName, field := range wiType.Fields { - switch fieldType := field.Type.(type) { - case workitem.ListType: - switch fieldType.ComponentType.Kind { - case workitem.KindLabel, workitem.KindUser, workitem.KindBoardColumn: - var p []interface{} - var n []interface{} - - previousValues := revisionList[k-1].WorkItemFields[fieldName] - newValues := revisionList[k].WorkItemFields[fieldName] - switch previousValues.(type) { - case nil: - p = []interface{}{} - case []interface{}: - for _, v := range previousValues.([]interface{}) { - p = append(p, v) - } - } - switch newValues.(type) { - case nil: - n = []interface{}{} - case []interface{}: - for _, v := range newValues.([]interface{}) { - n = append(n, v) - } + for fieldName, fieldDef := range wiType.Fields { - } + oldVal := oldRev.WorkItemFields[fieldName] + newVal := newRev.WorkItemFields[fieldName] - // Avoid duplicate entries for empty labels or assignees - if reflect.DeepEqual(p, n) == false { - wie := Event{ - ID: revisionList[k].ID, - Name: fieldName, - Timestamp: revisionList[k].Time, - Modifier: modifierID.ID, - Old: p, - New: n, - } - eventList = append(eventList, wie) - } - default: - return nil, errors.NewNotFoundError("Unknown field:", fieldName) - } - case workitem.EnumType: - var p string - var n string + event := Event{ + ID: revisionList[k].ID, + Name: fieldName, + Timestamp: revisionList[k].Time, + Modifier: modifierID.ID, + Old: oldVal, + New: newVal, + } - previousValue := revisionList[k-1].WorkItemFields[fieldName] - newValue := revisionList[k].WorkItemFields[fieldName] + /// The enum type can be handled by the simple type since it's just + // an single value after all. Let's overwrite the field type if + // doable. + ft := fieldDef.Type + enumType, isEnumType := ft.(workitem.EnumType) + if isEnumType { + ft = enumType.BaseType + } + + switch fieldType := ft.(type) { + case workitem.ListType: + var p, n []interface{} + var ok bool - switch previousValue.(type) { + switch t := oldVal.(type) { case nil: - p = "" - case interface{}: - p, _ = previousValue.(string) + p = []interface{}{} + case []interface{}: + converted, err := fieldType.ConvertFromModel(t) + if err != nil { + return nil, errs.Wrapf(err, "failed to convert old value for field %s from storage representation: %+v", fieldName, t) + } + p, ok = converted.([]interface{}) + if !ok { + return nil, errs.Errorf("failed to convert old value for field %s from to []interface{}: %+v", fieldName, t) + } } - switch newValue.(type) { + switch t := newVal.(type) { case nil: - n = "" - case interface{}: - n, _ = newValue.(string) - - } - if p != n { - wie := Event{ - ID: revisionList[k].ID, - Name: fieldName, - Timestamp: revisionList[k].Time, - Modifier: modifierID.ID, - Old: p, - New: n, + n = []interface{}{} + case []interface{}: + converted, err := fieldType.ConvertFromModel(t) + if err != nil { + return nil, errs.Wrapf(err, "failed to convert new value for field %s from storage representation: %+v", fieldName, t) } - eventList = append(eventList, wie) - } - case workitem.SimpleType: - switch fieldType.Kind { - case workitem.KindMarkup: - var p string - var n string - - previousValue := revisionList[k-1].WorkItemFields[fieldName] - newValue := revisionList[k].WorkItemFields[fieldName] - - switch previousValue.(type) { - case nil: - p = "" - case map[string]interface{}: - pv := rendering.NewMarkupContentFromMap(previousValue.(map[string]interface{})) - p = pv.Content + n, ok = converted.([]interface{}) + if !ok { + return nil, errs.Errorf("failed to convert new value for field %s from to []interface{}: %+v", fieldName, t) } + } - switch newValue.(type) { - case nil: - n = "" - case map[string]interface{}: - nv := rendering.NewMarkupContentFromMap(newValue.(map[string]interface{})) - n = nv.Content - + // Avoid duplicate entries for empty labels or assignees, etc. + if !reflect.DeepEqual(p, n) { + event.Old = p + event.New = n + eventList = append(eventList, event) + } + case workitem.SimpleType: + switch fieldType.GetKind() { + case workitem.KindString, + workitem.KindFloat, + workitem.KindInteger, + workitem.KindIteration, + workitem.KindBoardColumn, + workitem.KindArea, + workitem.KindLabel, + workitem.KindMarkup: + + // compensate conversion from storage if this really was an enum field + converter := fieldType.ConvertFromModel + if isEnumType { + converter = enumType.ConvertFromModel } - if p != n { - wie := Event{ - ID: revisionList[k].ID, - Name: fieldName, - Timestamp: revisionList[k].Time, - Modifier: modifierID.ID, - Old: p, - New: n, - } - eventList = append(eventList, wie) + p, err := converter(oldVal) + if err != nil { + return nil, errs.Wrapf(err, "failed to convert old value for field %s from storage representation: %+v", fieldName, oldVal) } - case workitem.KindString, workitem.KindIteration, workitem.KindArea, workitem.KindFloat, workitem.KindInteger: - var p string - var n string - - previousValue := revisionList[k-1].WorkItemFields[fieldName] - newValue := revisionList[k].WorkItemFields[fieldName] - - switch v := previousValue.(type) { - case nil: - p = "" - case float32, float64, int: - p = fmt.Sprintf("%g", previousValue) - case string: - p = v - default: - return nil, errors.NewConversionError("Failed to convert") + n, err := converter(newVal) + if err != nil { + return nil, errs.Wrapf(err, "failed to convert new value for field %s from storage representation: %+v", fieldName, newVal) } - switch v := newValue.(type) { - case nil: - n = "" - case float32, float64, int: - n = fmt.Sprintf("%g", newValue) - case string: - n = v - default: - return nil, errors.NewConversionError("Failed to convert") - } - if p != n { - wie := Event{ - ID: revisionList[k].ID, - Name: fieldName, - Timestamp: revisionList[k].Time, - Modifier: modifierID.ID, - Old: p, - New: n, - } - eventList = append(eventList, wie) + if !reflect.DeepEqual(p, n) { + event.Old = p + event.New = n + eventList = append(eventList, event) } } default: - return nil, errors.NewNotFoundError("Unknown field:", fieldName) + return nil, errors.NewNotFoundError("unknown field type", fieldName) } } } diff --git a/workitem/event/event_repository_blackbox_test.go b/workitem/event/event_repository_blackbox_test.go index cc7bd88076..40d3ea60af 100644 --- a/workitem/event/event_repository_blackbox_test.go +++ b/workitem/event/event_repository_blackbox_test.go @@ -1,7 +1,6 @@ package event_test import ( - "strconv" "testing" "github.com/fabric8-services/fabric8-wit/gormtestsupport" @@ -10,6 +9,7 @@ import ( tf "github.com/fabric8-services/fabric8-wit/test/testfixture" "github.com/fabric8-services/fabric8-wit/workitem" "github.com/fabric8-services/fabric8-wit/workitem/event" + uuid "github.com/satori/go.uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" @@ -59,9 +59,9 @@ func (s *eventRepoBlackBoxTest) TestList() { require.NoError(t, err) require.NotEmpty(t, eventList) require.Len(t, eventList, 1) - assert.Equal(t, eventList[0].Name, workitem.SystemAssignees) + assert.Equal(t, workitem.SystemAssignees, eventList[0].Name) assert.Empty(t, eventList[0].Old) - assert.Equal(t, fxt.Identities[0].ID.String(), eventList[0].New.([]interface{})[0]) + assert.Equal(t, fxt.Identities[0].ID, eventList[0].New.([]interface{})[0]) assignee = []string{fxt.Identities[1].ID.String()} wiNew.Fields[workitem.SystemAssignees] = assignee @@ -72,11 +72,11 @@ func (s *eventRepoBlackBoxTest) TestList() { eventList, err = s.wiEventRepo.List(s.Ctx, fxt.WorkItems[0].ID) require.NotEmpty(t, eventList) require.Len(t, eventList, 2) - assert.Equal(t, eventList[1].Name, workitem.SystemAssignees) + assert.Equal(t, workitem.SystemAssignees, eventList[1].Name) assert.NotEmpty(t, eventList[1].Old) assert.NotEmpty(t, eventList[1].New) - assert.Equal(t, fxt.Identities[0].ID.String(), eventList[0].New.([]interface{})[0]) - assert.Equal(t, fxt.Identities[1].ID.String(), eventList[1].New.([]interface{})[0]) + assert.Equal(t, fxt.Identities[0].ID, eventList[0].New.([]interface{})[0]) + assert.Equal(t, fxt.Identities[1].ID, eventList[1].New.([]interface{})[0]) }) s.T().Run("event assignee - previous assignee nil", func(t *testing.T) { @@ -93,9 +93,9 @@ func (s *eventRepoBlackBoxTest) TestList() { require.NoError(t, err) require.NotEmpty(t, eventList) require.Len(t, eventList, 1) - assert.Equal(t, eventList[0].Name, workitem.SystemAssignees) + assert.Equal(t, workitem.SystemAssignees, eventList[0].Name) assert.Empty(t, eventList[0].Old) - assert.Equal(t, fxt.Identities[0].ID.String(), eventList[0].New.([]interface{})[0]) + assert.Equal(t, fxt.Identities[0].ID, eventList[0].New.([]interface{})[0]) }) s.T().Run("event description", func(t *testing.T) { @@ -112,8 +112,8 @@ func (s *eventRepoBlackBoxTest) TestList() { require.NoError(t, err) require.NotEmpty(t, eventList) require.Len(t, eventList, 1) - require.Equal(t, "description1", eventList[0].Old) - require.Equal(t, "description2", eventList[0].New) + require.Equal(t, oldDescription, eventList[0].Old) + require.Equal(t, newDescription, eventList[0].New) require.Equal(t, wiNew.Fields[workitem.SystemDescription], newDescription) }) @@ -130,9 +130,9 @@ func (s *eventRepoBlackBoxTest) TestList() { require.NoError(t, err) require.NotEmpty(t, eventList) require.Len(t, eventList, 1) - assert.Equal(t, eventList[0].Name, workitem.SystemAssignees) + assert.Equal(t, workitem.SystemAssignees, eventList[0].Name) assert.Empty(t, eventList[0].Old) - assert.Equal(t, fxt.Identities[0].ID.String(), eventList[0].New.([]interface{})[0]) + assert.Equal(t, fxt.Identities[0].ID, eventList[0].New.([]interface{})[0]) wiNew.Fields[workitem.SystemAssignees] = []string{} wiNew.Version = fxt.WorkItems[0].Version + 1 @@ -142,7 +142,7 @@ func (s *eventRepoBlackBoxTest) TestList() { eventList, err = s.wiEventRepo.List(s.Ctx, fxt.WorkItems[0].ID) require.NotEmpty(t, eventList) require.Len(t, eventList, 2) - assert.Equal(t, eventList[1].Name, workitem.SystemAssignees) + assert.Equal(t, workitem.SystemAssignees, eventList[1].Name) assert.Empty(t, eventList[1].New) }) @@ -159,9 +159,9 @@ func (s *eventRepoBlackBoxTest) TestList() { require.NoError(t, err) require.NotEmpty(t, eventList) require.Len(t, eventList, 1) - assert.Equal(t, eventList[0].Name, workitem.SystemAssignees) + assert.Equal(t, workitem.SystemAssignees, eventList[0].Name) assert.Empty(t, eventList[0].Old) - assert.Equal(t, fxt.Identities[0].ID.String(), eventList[0].New.([]interface{})[0]) + assert.Equal(t, fxt.Identities[0].ID, eventList[0].New.([]interface{})[0]) wiNew.Fields[workitem.SystemAssignees] = []string{fxt.Identities[1].ID.String()} wiNew.Version = fxt.WorkItems[0].Version + 1 @@ -171,8 +171,8 @@ func (s *eventRepoBlackBoxTest) TestList() { eventList, err = s.wiEventRepo.List(s.Ctx, fxt.WorkItems[0].ID) require.NotEmpty(t, eventList) require.Len(t, eventList, 2) - assert.Equal(t, eventList[1].Name, workitem.SystemAssignees) - assert.Equal(t, fxt.Identities[1].ID.String(), eventList[1].New.([]interface{})[0]) + assert.Equal(t, workitem.SystemAssignees, eventList[1].Name) + assert.Equal(t, fxt.Identities[1].ID, eventList[1].New.([]interface{})[0]) }) s.T().Run("state change from new to open", func(t *testing.T) { @@ -185,7 +185,7 @@ func (s *eventRepoBlackBoxTest) TestList() { require.NoError(t, err) require.NotEmpty(t, eventList) require.Len(t, eventList, 1) - assert.Equal(t, eventList[0].Name, workitem.SystemState) + assert.Equal(t, workitem.SystemState, eventList[0].Name) assert.Equal(t, workitem.SystemStateResolved, eventList[0].New) }) @@ -193,9 +193,10 @@ func (s *eventRepoBlackBoxTest) TestList() { fxt := tf.NewTestFixture(t, s.DB, tf.WorkItems(1)) - label := []string{"label1"} + labelID1 := uuid.NewV4() + labels := []uuid.UUID{labelID1} - fxt.WorkItems[0].Fields[workitem.SystemLabels] = label + fxt.WorkItems[0].Fields[workitem.SystemLabels] = labels wiNew, err := s.wiRepo.Save(s.Ctx, fxt.WorkItems[0].SpaceID, *fxt.WorkItems[0], fxt.Identities[0].ID) require.NoError(t, err) require.Len(t, wiNew.Fields[workitem.SystemLabels].([]interface{}), 1) @@ -203,12 +204,13 @@ func (s *eventRepoBlackBoxTest) TestList() { require.NoError(t, err) require.NotEmpty(t, eventList) require.Len(t, eventList, 1) - assert.Equal(t, eventList[0].Name, workitem.SystemLabels) + assert.Equal(t, workitem.SystemLabels, eventList[0].Name) assert.Empty(t, eventList[0].Old) - assert.Equal(t, "label1", eventList[0].New.([]interface{})[0]) + assert.Equal(t, labelID1, eventList[0].New.([]interface{})[0]) - label = []string{"label2"} - wiNew.Fields[workitem.SystemLabels] = label + labelID2 := uuid.NewV4() + labels = []uuid.UUID{labelID2} + wiNew.Fields[workitem.SystemLabels] = labels wiNew.Version = fxt.WorkItems[0].Version + 1 wiNew, err = s.wiRepo.Save(s.Ctx, fxt.WorkItems[0].SpaceID, *wiNew, fxt.Identities[0].ID) require.NoError(t, err) @@ -216,20 +218,21 @@ func (s *eventRepoBlackBoxTest) TestList() { eventList, err = s.wiEventRepo.List(s.Ctx, fxt.WorkItems[0].ID) require.NotEmpty(t, eventList) require.Len(t, eventList, 2) - assert.Equal(t, eventList[1].Name, workitem.SystemLabels) + assert.Equal(t, workitem.SystemLabels, eventList[1].Name) assert.NotEmpty(t, eventList[1].Old) assert.NotEmpty(t, eventList[1].New) - assert.Equal(t, "label1", eventList[0].New.([]interface{})[0]) - assert.Equal(t, "label2", eventList[1].New.([]interface{})[0]) + assert.Equal(t, labelID1, eventList[0].New.([]interface{})[0]) + assert.Equal(t, labelID2, eventList[1].New.([]interface{})[0]) }) s.T().Run("event label - previous label nil", func(t *testing.T) { fxt := tf.NewTestFixture(t, s.DB, tf.WorkItems(1)) - label := []string{"label1"} + labelID1 := uuid.NewV4() + labels := []uuid.UUID{labelID1} - fxt.WorkItems[0].Fields[workitem.SystemLabels] = label + fxt.WorkItems[0].Fields[workitem.SystemLabels] = labels wiNew, err := s.wiRepo.Save(s.Ctx, fxt.WorkItems[0].SpaceID, *fxt.WorkItems[0], fxt.Identities[0].ID) require.NoError(t, err) require.Len(t, wiNew.Fields[workitem.SystemLabels].([]interface{}), 1) @@ -237,7 +240,7 @@ func (s *eventRepoBlackBoxTest) TestList() { require.NoError(t, err) require.NotEmpty(t, eventList) require.Len(t, eventList, 1) - assert.Equal(t, eventList[0].Name, workitem.SystemLabels) + assert.Equal(t, workitem.SystemLabels, eventList[0].Name) assert.Empty(t, eventList[0].Old) }) @@ -245,9 +248,10 @@ func (s *eventRepoBlackBoxTest) TestList() { fxt := tf.NewTestFixture(t, s.DB, tf.WorkItems(1)) - label := []string{"label1"} + labelID1 := uuid.NewV4() + labels := []string{labelID1.String()} - fxt.WorkItems[0].Fields[workitem.SystemLabels] = label + fxt.WorkItems[0].Fields[workitem.SystemLabels] = labels wiNew, err := s.wiRepo.Save(s.Ctx, fxt.WorkItems[0].SpaceID, *fxt.WorkItems[0], fxt.Identities[0].ID) require.NoError(t, err) require.Len(t, wiNew.Fields[workitem.SystemLabels].([]interface{}), 1) @@ -255,7 +259,7 @@ func (s *eventRepoBlackBoxTest) TestList() { require.NoError(t, err) require.NotEmpty(t, eventList) require.Len(t, eventList, 1) - assert.Equal(t, eventList[0].Name, workitem.SystemLabels) + assert.Equal(t, workitem.SystemLabels, eventList[0].Name) assert.Empty(t, eventList[0].Old) wiNew.Fields[workitem.SystemLabels] = []string{} @@ -266,7 +270,7 @@ func (s *eventRepoBlackBoxTest) TestList() { eventList, err = s.wiEventRepo.List(s.Ctx, fxt.WorkItems[0].ID) require.NotEmpty(t, eventList) require.Len(t, eventList, 2) - assert.Equal(t, eventList[1].Name, workitem.SystemLabels) + assert.Equal(t, workitem.SystemLabels, eventList[1].Name) assert.Empty(t, eventList[1].New) }) @@ -280,7 +284,7 @@ func (s *eventRepoBlackBoxTest) TestList() { require.NoError(t, err) require.NotEmpty(t, eventList) require.Len(t, eventList, 1) - assert.Equal(t, eventList[0].Name, workitem.SystemIteration) + assert.Equal(t, workitem.SystemIteration, eventList[0].Name) assert.Empty(t, eventList[0].Old) wiNew.Fields[workitem.SystemIteration] = fxt.Iterations[1].ID.String() @@ -289,7 +293,7 @@ func (s *eventRepoBlackBoxTest) TestList() { require.NoError(t, err) eventList, err = s.wiEventRepo.List(s.Ctx, fxt.WorkItems[0].ID) require.Len(t, eventList, 2) - assert.Equal(t, eventList[1].Name, workitem.SystemIteration) + assert.Equal(t, workitem.SystemIteration, eventList[1].Name) }) s.T().Run("Field with Kind", func(t *testing.T) { @@ -317,13 +321,9 @@ func (s *eventRepoBlackBoxTest) TestList() { require.NoError(t, err) eventList, err := s.wiEventRepo.List(s.Ctx, fxt.WorkItems[0].ID) require.Len(t, eventList, 1) - assert.Equal(t, eventList[0].Name, fieldName) - oldStr, _ := eventList[0].Old.(string) - old, _ := strconv.ParseFloat(oldStr, 64) - assert.Equal(t, old, initialValue) - newStr, _ := eventList[0].New.(string) - new, _ := strconv.ParseFloat(newStr, 64) - assert.Equal(t, new, updatedValue) + assert.Equal(t, fieldName, eventList[0].Name) + assert.Equal(t, initialValue, eventList[0].Old) + assert.Equal(t, updatedValue, eventList[0].New) }) t.Run("Int", func(t *testing.T) { @@ -350,21 +350,16 @@ func (s *eventRepoBlackBoxTest) TestList() { require.NoError(t, err) eventList, err := s.wiEventRepo.List(s.Ctx, fxt.WorkItems[0].ID) require.Len(t, eventList, 1) - assert.Equal(t, eventList[0].Name, fieldName) - oldStr, _ := eventList[0].Old.(string) - old, _ := strconv.ParseInt(oldStr, 10, 0) - assert.EqualValues(t, old, initialValue) - newStr, _ := eventList[0].New.(string) - new, _ := strconv.ParseInt(newStr, 10, 0) - assert.EqualValues(t, new, updatedValue) + assert.Equal(t, fieldName, eventList[0].Name) + assert.EqualValues(t, initialValue, eventList[0].Old) + assert.EqualValues(t, updatedValue, eventList[0].New) }) }) s.T().Run("multiple events", func(t *testing.T) { fxt := tf.NewTestFixture(t, s.DB, tf.WorkItems(1)) - label := []string{"label1"} - fxt.WorkItems[0].Fields[workitem.SystemLabels] = label + fxt.WorkItems[0].Fields[workitem.SystemLabels] = []uuid.UUID{uuid.NewV4()} fxt.WorkItems[0].Fields[workitem.SystemState] = workitem.SystemStateResolved _, err := s.wiRepo.Save(s.Ctx, fxt.WorkItems[0].SpaceID, *fxt.WorkItems[0], fxt.Identities[0].ID) require.NoError(t, err) From e32b79c377e3c5952eef63c9b2966fee607c80ff Mon Sep 17 00:00:00 2001 From: Konrad Kleine Date: Fri, 27 Jul 2018 08:05:19 +0200 Subject: [PATCH 02/10] Allow any value (not only strings) for event old/new --- design/work_item_event.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/design/work_item_event.go b/design/work_item_event.go index c5e2c85cb8..0cee367212 100644 --- a/design/work_item_event.go +++ b/design/work_item_event.go @@ -29,10 +29,10 @@ var eventAttributes = a.Type("EventAttributes", func() { a.Attribute("name", d.String, "The name of the event occured", func() { a.Example("closed") }) - a.Attribute("oldValue", d.String, "The user who was assigned to (or unassigned from). Only for 'assigned' and 'unassigned' events.", func() { + a.Attribute("oldValue", d.Any, "The user who was assigned to (or unassigned from). Only for 'assigned' and 'unassigned' events.", func() { a.Example("813a456e-1c8a-48df-ac15-84065ee039f7") }) - a.Attribute("newValue", d.String, "The user who performed the assignment (or unassignment). Only for 'assigned' and 'unassigned' events..", func() { + a.Attribute("newValue", d.Any, "The user who performed the assignment (or unassignment). Only for 'assigned' and 'unassigned' events..", func() { a.Example("813a456e-1c8a-48df-ac15-84065ee039f7") }) a.Required("timestamp", "name") From e906d664f08ae76e3e138a79684d39baaac49aa5 Mon Sep 17 00:00:00 2001 From: Konrad Kleine Date: Fri, 27 Jul 2018 08:06:15 +0200 Subject: [PATCH 03/10] The fields API doesn't deliver UUIDs yet, so stick to strings --- .../event/event_repository_blackbox_test.go | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/workitem/event/event_repository_blackbox_test.go b/workitem/event/event_repository_blackbox_test.go index 40d3ea60af..a98fec992e 100644 --- a/workitem/event/event_repository_blackbox_test.go +++ b/workitem/event/event_repository_blackbox_test.go @@ -61,7 +61,7 @@ func (s *eventRepoBlackBoxTest) TestList() { require.Len(t, eventList, 1) assert.Equal(t, workitem.SystemAssignees, eventList[0].Name) assert.Empty(t, eventList[0].Old) - assert.Equal(t, fxt.Identities[0].ID, eventList[0].New.([]interface{})[0]) + assert.Equal(t, fxt.Identities[0].ID.String(), eventList[0].New.([]interface{})[0]) assignee = []string{fxt.Identities[1].ID.String()} wiNew.Fields[workitem.SystemAssignees] = assignee @@ -75,8 +75,8 @@ func (s *eventRepoBlackBoxTest) TestList() { assert.Equal(t, workitem.SystemAssignees, eventList[1].Name) assert.NotEmpty(t, eventList[1].Old) assert.NotEmpty(t, eventList[1].New) - assert.Equal(t, fxt.Identities[0].ID, eventList[0].New.([]interface{})[0]) - assert.Equal(t, fxt.Identities[1].ID, eventList[1].New.([]interface{})[0]) + assert.Equal(t, fxt.Identities[0].ID.String(), eventList[0].New.([]interface{})[0]) + assert.Equal(t, fxt.Identities[1].ID.String(), eventList[1].New.([]interface{})[0]) }) s.T().Run("event assignee - previous assignee nil", func(t *testing.T) { @@ -95,7 +95,7 @@ func (s *eventRepoBlackBoxTest) TestList() { require.Len(t, eventList, 1) assert.Equal(t, workitem.SystemAssignees, eventList[0].Name) assert.Empty(t, eventList[0].Old) - assert.Equal(t, fxt.Identities[0].ID, eventList[0].New.([]interface{})[0]) + assert.Equal(t, fxt.Identities[0].ID.String(), eventList[0].New.([]interface{})[0]) }) s.T().Run("event description", func(t *testing.T) { @@ -114,7 +114,7 @@ func (s *eventRepoBlackBoxTest) TestList() { require.Len(t, eventList, 1) require.Equal(t, oldDescription, eventList[0].Old) require.Equal(t, newDescription, eventList[0].New) - require.Equal(t, wiNew.Fields[workitem.SystemDescription], newDescription) + require.Equal(t, newDescription, wiNew.Fields[workitem.SystemDescription]) }) s.T().Run("event assignee - new assignee nil", func(t *testing.T) { @@ -132,7 +132,7 @@ func (s *eventRepoBlackBoxTest) TestList() { require.Len(t, eventList, 1) assert.Equal(t, workitem.SystemAssignees, eventList[0].Name) assert.Empty(t, eventList[0].Old) - assert.Equal(t, fxt.Identities[0].ID, eventList[0].New.([]interface{})[0]) + assert.Equal(t, fxt.Identities[0].ID.String(), eventList[0].New.([]interface{})[0]) wiNew.Fields[workitem.SystemAssignees] = []string{} wiNew.Version = fxt.WorkItems[0].Version + 1 @@ -161,7 +161,7 @@ func (s *eventRepoBlackBoxTest) TestList() { require.Len(t, eventList, 1) assert.Equal(t, workitem.SystemAssignees, eventList[0].Name) assert.Empty(t, eventList[0].Old) - assert.Equal(t, fxt.Identities[0].ID, eventList[0].New.([]interface{})[0]) + assert.Equal(t, fxt.Identities[0].ID.String(), eventList[0].New.([]interface{})[0]) wiNew.Fields[workitem.SystemAssignees] = []string{fxt.Identities[1].ID.String()} wiNew.Version = fxt.WorkItems[0].Version + 1 @@ -172,7 +172,7 @@ func (s *eventRepoBlackBoxTest) TestList() { require.NotEmpty(t, eventList) require.Len(t, eventList, 2) assert.Equal(t, workitem.SystemAssignees, eventList[1].Name) - assert.Equal(t, fxt.Identities[1].ID, eventList[1].New.([]interface{})[0]) + assert.Equal(t, fxt.Identities[1].ID.String(), eventList[1].New.([]interface{})[0]) }) s.T().Run("state change from new to open", func(t *testing.T) { @@ -194,7 +194,7 @@ func (s *eventRepoBlackBoxTest) TestList() { fxt := tf.NewTestFixture(t, s.DB, tf.WorkItems(1)) labelID1 := uuid.NewV4() - labels := []uuid.UUID{labelID1} + labels := []string{labelID1.String()} fxt.WorkItems[0].Fields[workitem.SystemLabels] = labels wiNew, err := s.wiRepo.Save(s.Ctx, fxt.WorkItems[0].SpaceID, *fxt.WorkItems[0], fxt.Identities[0].ID) @@ -206,10 +206,10 @@ func (s *eventRepoBlackBoxTest) TestList() { require.Len(t, eventList, 1) assert.Equal(t, workitem.SystemLabels, eventList[0].Name) assert.Empty(t, eventList[0].Old) - assert.Equal(t, labelID1, eventList[0].New.([]interface{})[0]) + assert.Equal(t, labelID1.String(), eventList[0].New.([]interface{})[0]) labelID2 := uuid.NewV4() - labels = []uuid.UUID{labelID2} + labels = []string{labelID2.String()} wiNew.Fields[workitem.SystemLabels] = labels wiNew.Version = fxt.WorkItems[0].Version + 1 wiNew, err = s.wiRepo.Save(s.Ctx, fxt.WorkItems[0].SpaceID, *wiNew, fxt.Identities[0].ID) @@ -221,8 +221,8 @@ func (s *eventRepoBlackBoxTest) TestList() { assert.Equal(t, workitem.SystemLabels, eventList[1].Name) assert.NotEmpty(t, eventList[1].Old) assert.NotEmpty(t, eventList[1].New) - assert.Equal(t, labelID1, eventList[0].New.([]interface{})[0]) - assert.Equal(t, labelID2, eventList[1].New.([]interface{})[0]) + assert.Equal(t, labelID1.String(), eventList[0].New.([]interface{})[0]) + assert.Equal(t, labelID2.String(), eventList[1].New.([]interface{})[0]) }) s.T().Run("event label - previous label nil", func(t *testing.T) { @@ -230,7 +230,7 @@ func (s *eventRepoBlackBoxTest) TestList() { fxt := tf.NewTestFixture(t, s.DB, tf.WorkItems(1)) labelID1 := uuid.NewV4() - labels := []uuid.UUID{labelID1} + labels := []string{labelID1.String()} fxt.WorkItems[0].Fields[workitem.SystemLabels] = labels wiNew, err := s.wiRepo.Save(s.Ctx, fxt.WorkItems[0].SpaceID, *fxt.WorkItems[0], fxt.Identities[0].ID) @@ -359,7 +359,7 @@ func (s *eventRepoBlackBoxTest) TestList() { s.T().Run("multiple events", func(t *testing.T) { fxt := tf.NewTestFixture(t, s.DB, tf.WorkItems(1)) - fxt.WorkItems[0].Fields[workitem.SystemLabels] = []uuid.UUID{uuid.NewV4()} + fxt.WorkItems[0].Fields[workitem.SystemLabels] = []string{uuid.NewV4().String()} fxt.WorkItems[0].Fields[workitem.SystemState] = workitem.SystemStateResolved _, err := s.wiRepo.Save(s.Ctx, fxt.WorkItems[0].SpaceID, *fxt.WorkItems[0], fxt.Identities[0].ID) require.NoError(t, err) From 66f153f0930859fecb8c7bb3502066d07a43fe9f Mon Sep 17 00:00:00 2001 From: Konrad Kleine Date: Fri, 27 Jul 2018 08:36:06 +0200 Subject: [PATCH 04/10] Fixup --- controller/area.go | 11 ++++++++--- .../event/list/ok-kindFloat.res.payload.golden.json | 4 ++-- .../event/list/ok-kindInt.res.payload.golden.json | 4 ++-- controller/work_item_events_test.go | 2 +- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/controller/area.go b/controller/area.go index f509465590..26e4b0b7c9 100644 --- a/controller/area.go +++ b/controller/area.go @@ -1,7 +1,6 @@ package controller import ( - "fmt" "net/http" "github.com/fabric8-services/fabric8-wit/ptr" @@ -262,11 +261,17 @@ func ConvertArea(db application.DB, request *http.Request, ar area.Area, options // ConvertAreaSimple converts a simple area ID into a Generic Reletionship func ConvertAreaSimple(request *http.Request, id interface{}) *app.GenericData { t := area.APIStringTypeAreas - i := fmt.Sprint(id) + var i string + switch t := id.(type) { + case string: + i = t + case uuid.UUID: + i = t.String() + } return &app.GenericData{ Type: &t, ID: &i, - Links: createAreaLinks(request, id), + Links: createAreaLinks(request, i), } } diff --git a/controller/test-files/event/list/ok-kindFloat.res.payload.golden.json b/controller/test-files/event/list/ok-kindFloat.res.payload.golden.json index 0e20e5af67..2509f1c74e 100755 --- a/controller/test-files/event/list/ok-kindFloat.res.payload.golden.json +++ b/controller/test-files/event/list/ok-kindFloat.res.payload.golden.json @@ -3,8 +3,8 @@ { "attributes": { "name": "myFloatType", - "newValue": "2.99", - "oldValue": "1.99", + "newValue": 2.99, + "oldValue": 1.99, "timestamp": "0001-01-01T00:00:00Z" }, "id": "00000000-0000-0000-0000-000000000001", diff --git a/controller/test-files/event/list/ok-kindInt.res.payload.golden.json b/controller/test-files/event/list/ok-kindInt.res.payload.golden.json index bbea3bbf19..5808c39361 100755 --- a/controller/test-files/event/list/ok-kindInt.res.payload.golden.json +++ b/controller/test-files/event/list/ok-kindInt.res.payload.golden.json @@ -3,8 +3,8 @@ { "attributes": { "name": "myIntType", - "newValue": "4235", - "oldValue": "200", + "newValue": 4235, + "oldValue": 200, "timestamp": "0001-01-01T00:00:00Z" }, "id": "00000000-0000-0000-0000-000000000001", diff --git a/controller/work_item_events_test.go b/controller/work_item_events_test.go index afa75bf255..c68d5a38d2 100644 --- a/controller/work_item_events_test.go +++ b/controller/work_item_events_test.go @@ -298,7 +298,7 @@ func (s *TestEvent) TestListEvent() { Type: APIStringTypeWorkItem, ID: &fxt.WorkItems[0].ID, Attributes: map[string]interface{}{ - workitem.SystemIteration: fxt.Iterations[0].ID, + workitem.SystemIteration: fxt.Iterations[0].ID.String(), workitem.SystemVersion: fxt.WorkItems[0].Version, }, Relationships: &app.WorkItemRelationships{ From 7849d0e398248a8e11ae55d06513bfdb382cd6f7 Mon Sep 17 00:00:00 2001 From: Konrad Kleine Date: Fri, 27 Jul 2018 08:41:26 +0200 Subject: [PATCH 05/10] Fix comment and error message --- workitem/event/event_repository.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/workitem/event/event_repository.go b/workitem/event/event_repository.go index a70265e3c8..8a857ea23a 100644 --- a/workitem/event/event_repository.go +++ b/workitem/event/event_repository.go @@ -85,9 +85,8 @@ func (r *GormEventRepository) List(ctx context.Context, wiID uuid.UUID) ([]Event New: newVal, } - /// The enum type can be handled by the simple type since it's just - // an single value after all. Let's overwrite the field type if - // doable. + // The enum type can be handled by the simple type since it's just a + // single value after all. ft := fieldDef.Type enumType, isEnumType := ft.(workitem.EnumType) if isEnumType { @@ -166,7 +165,7 @@ func (r *GormEventRepository) List(ctx context.Context, wiID uuid.UUID) ([]Event } } default: - return nil, errors.NewNotFoundError("unknown field type", fieldName) + return nil, errors.NewNotFoundError("unknown field type", fieldType.GetKind().String()) } } } From 8f874deb2af0a17c28521de943d9182e0bb7b81e Mon Sep 17 00:00:00 2001 From: Konrad Kleine Date: Mon, 30 Jul 2018 17:11:11 +0200 Subject: [PATCH 06/10] tests for single/list non-relational field kinds. Fix JSONAPI --- controller/area.go | 18 +- controller/codebase.go | 15 + controller/iteration.go | 17 +- controller/label.go | 10 +- .../list/ok-area.res.payload.golden.json | 22 +- .../list/ok-assignees.res.payload.golden.json | 21 +- .../ok-description.res.payload.golden.json | 15 +- .../list/ok-iteration.res.payload.golden.json | 22 +- .../list/ok-kindFloat.res.payload.golden.json | 10 +- .../list/ok-kindInt.res.payload.golden.json | 10 +- .../list/ok-labels.res.payload.golden.json | 26 +- .../list/ok-state.res.payload.golden.json | 10 +- .../list/ok-title.res.payload.golden.json | 10 +- .../list/ok.bool_list.res.payload.golden.json | 44 + .../ok.bool_single.res.payload.golden.json | 23 + .../ok.float_list.res.payload.golden.json | 44 + .../ok.float_single.res.payload.golden.json | 23 + .../ok.integer_list.res.payload.golden.json | 44 + .../ok.integer_single.res.payload.golden.json | 23 + .../ok.markup_list.res.payload.golden.json | 53 ++ .../ok.markup_single.res.payload.golden.json | 26 + .../ok.string_list.res.payload.golden.json | 44 + .../ok.string_single.res.payload.golden.json | 23 + .../list/ok.url_list.res.payload.golden.json | 44 + .../ok.url_single.res.payload.golden.json | 23 + controller/users.go | 24 +- controller/work_item_board.go | 16 + controller/work_item_events.go | 300 +++--- controller/work_item_events_test.go | 897 +++++++++++------- design/work_item_event.go | 9 +- workitem/enum_type.go | 2 +- workitem/event/event.go | 13 +- workitem/event/event_repository.go | 49 +- workitem/field_definition.go | 38 +- workitem/field_definition_blackbox_test.go | 23 + workitem/field_test_data.go | 2 +- workitem/simple_type.go | 39 +- 37 files changed, 1312 insertions(+), 720 deletions(-) create mode 100755 controller/test-files/event/list/ok.bool_list.res.payload.golden.json create mode 100755 controller/test-files/event/list/ok.bool_single.res.payload.golden.json create mode 100755 controller/test-files/event/list/ok.float_list.res.payload.golden.json create mode 100755 controller/test-files/event/list/ok.float_single.res.payload.golden.json create mode 100755 controller/test-files/event/list/ok.integer_list.res.payload.golden.json create mode 100755 controller/test-files/event/list/ok.integer_single.res.payload.golden.json create mode 100755 controller/test-files/event/list/ok.markup_list.res.payload.golden.json create mode 100755 controller/test-files/event/list/ok.markup_single.res.payload.golden.json create mode 100755 controller/test-files/event/list/ok.string_list.res.payload.golden.json create mode 100755 controller/test-files/event/list/ok.string_single.res.payload.golden.json create mode 100755 controller/test-files/event/list/ok.url_list.res.payload.golden.json create mode 100755 controller/test-files/event/list/ok.url_single.res.payload.golden.json diff --git a/controller/area.go b/controller/area.go index 26e4b0b7c9..5bf79df6dc 100644 --- a/controller/area.go +++ b/controller/area.go @@ -258,10 +258,9 @@ func ConvertArea(db application.DB, request *http.Request, ar area.Area, options return i } -// ConvertAreaSimple converts a simple area ID into a Generic Reletionship +// ConvertAreaSimple converts a simple area ID into a Generic Relationship func ConvertAreaSimple(request *http.Request, id interface{}) *app.GenericData { - t := area.APIStringTypeAreas - var i string + i := "" switch t := id.(type) { case string: i = t @@ -269,16 +268,7 @@ func ConvertAreaSimple(request *http.Request, id interface{}) *app.GenericData { i = t.String() } return &app.GenericData{ - Type: &t, - ID: &i, - Links: createAreaLinks(request, i), - } -} - -func createAreaLinks(request *http.Request, id interface{}) *app.GenericLinks { - relatedURL := rest.AbsoluteURL(request, app.AreaHref(id)) - return &app.GenericLinks{ - Self: &relatedURL, - Related: &relatedURL, + Type: ptr.String(area.APIStringTypeAreas), + ID: &i, } } diff --git a/controller/codebase.go b/controller/codebase.go index 67e4496060..4cbfa00005 100644 --- a/controller/codebase.go +++ b/controller/codebase.go @@ -474,6 +474,21 @@ func getBranch(projects []che.WorkspaceProject, codebaseURL string) string { return "" } +// ConvertCodebaseSimple converts a simple codebase ID into a Generic Relationship +func ConvertCodebaseSimple(request *http.Request, id interface{}) *app.GenericData { + i := "" + switch t := id.(type) { + case string: + i = t + case uuid.UUID: + i = t.String() + } + return &app.GenericData{ + Type: ptr.String(APIStringTypeCodebase), + ID: &i, + } +} + // ConvertCodebase converts between internal and external REST representation func ConvertCodebase(request *http.Request, codebase codebase.Codebase, options ...CodebaseConvertFunc) *app.Codebase { relatedURL := rest.AbsoluteURL(request, app.CodebaseHref(codebase.ID)) diff --git a/controller/iteration.go b/controller/iteration.go index 738b08ba59..35101a0ecc 100644 --- a/controller/iteration.go +++ b/controller/iteration.go @@ -12,6 +12,7 @@ import ( "github.com/fabric8-services/fabric8-wit/jsonapi" "github.com/fabric8-services/fabric8-wit/log" "github.com/fabric8-services/fabric8-wit/login" + "github.com/fabric8-services/fabric8-wit/ptr" "github.com/fabric8-services/fabric8-wit/rest" "github.com/fabric8-services/fabric8-wit/space" "github.com/fabric8-services/fabric8-wit/space/authz" @@ -517,8 +518,7 @@ func ConvertIteration(request *http.Request, itr iteration.Iteration, additional // ConvertIterationSimple converts a simple Iteration ID into a Generic Reletionship func ConvertIterationSimple(request *http.Request, id interface{}) *app.GenericData { - t := iteration.APIStringTypeIteration - var i string + i := "" switch t := id.(type) { case string: i = t @@ -526,17 +526,8 @@ func ConvertIterationSimple(request *http.Request, id interface{}) *app.GenericD i = t.String() } return &app.GenericData{ - Type: &t, - ID: &i, - Links: createIterationLinks(request, i), - } -} - -func createIterationLinks(request *http.Request, id interface{}) *app.GenericLinks { - relatedURL := rest.AbsoluteURL(request, app.IterationHref(id)) - return &app.GenericLinks{ - Self: &relatedURL, - Related: &relatedURL, + Type: ptr.String(iteration.APIStringTypeIteration), + ID: &i, } } diff --git a/controller/label.go b/controller/label.go index 2b5866e418..0a9236d5da 100644 --- a/controller/label.go +++ b/controller/label.go @@ -10,6 +10,7 @@ import ( "github.com/fabric8-services/fabric8-wit/jsonapi" "github.com/fabric8-services/fabric8-wit/label" "github.com/fabric8-services/fabric8-wit/login" + "github.com/fabric8-services/fabric8-wit/ptr" "github.com/fabric8-services/fabric8-wit/rest" "github.com/fabric8-services/fabric8-wit/space" "github.com/goadesign/goa" @@ -153,7 +154,7 @@ func ConvertLabels(appl application.Application, request *http.Request, labels [ return ls } -// ConvertLabelsSimple converts an array of Label IDs into a Generic Reletionship List +// ConvertLabelsSimple converts an array of Label IDs into a Generic Relationship List func ConvertLabelsSimple(request *http.Request, labelIDs []interface{}) []*app.GenericData { ops := make([]*app.GenericData, 0, len(labelIDs)) for _, labelID := range labelIDs { @@ -162,10 +163,9 @@ func ConvertLabelsSimple(request *http.Request, labelIDs []interface{}) []*app.G return ops } -// ConvertLabelSimple converts a Label ID into a Generic Reletionship +// ConvertLabelSimple converts a Label ID into a Generic Relationship func ConvertLabelSimple(request *http.Request, labelID interface{}) *app.GenericData { - t := label.APIStringTypeLabels - var i string + i := "" switch t := labelID.(type) { case string: i = t @@ -173,7 +173,7 @@ func ConvertLabelSimple(request *http.Request, labelID interface{}) *app.Generic i = t.String() } return &app.GenericData{ - Type: &t, + Type: ptr.String(label.APIStringTypeLabels), ID: &i, } } diff --git a/controller/test-files/event/list/ok-area.res.payload.golden.json b/controller/test-files/event/list/ok-area.res.payload.golden.json index 6ec35591c3..a5a947adbd 100755 --- a/controller/test-files/event/list/ok-area.res.payload.golden.json +++ b/controller/test-files/event/list/ok-area.res.payload.golden.json @@ -3,29 +3,21 @@ { "attributes": { "name": "system.area", - "newValue": null, - "oldValue": null, - "timestamp": "0001-01-01T00:00:00Z" + "timestamp": "0001-01-01T00:00:00Z", + "workItemTypeID": "00000000-0000-0000-0000-000000000001" }, - "id": "00000000-0000-0000-0000-000000000001", + "id": "00000000-0000-0000-0000-000000000002", "relationships": { "modifier": { "data": { - "id": "00000000-0000-0000-0000-000000000002", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000002" - }, + "id": "00000000-0000-0000-0000-000000000003", "type": "identities" } }, "newValue": { "data": [ { - "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/areas/00000000-0000-0000-0000-000000000003", - "self": "http:///api/areas/00000000-0000-0000-0000-000000000003" - }, + "id": "00000000-0000-0000-0000-000000000004", "type": "areas" } ] @@ -34,10 +26,6 @@ "data": [ { "id": "", - "links": { - "related": "http:///api/areas/", - "self": "http:///api/areas/" - }, "type": "areas" } ] diff --git a/controller/test-files/event/list/ok-assignees.res.payload.golden.json b/controller/test-files/event/list/ok-assignees.res.payload.golden.json index 4f15982c30..b8db0ce197 100755 --- a/controller/test-files/event/list/ok-assignees.res.payload.golden.json +++ b/controller/test-files/event/list/ok-assignees.res.payload.golden.json @@ -3,34 +3,25 @@ { "attributes": { "name": "system.assignees", - "newValue": null, - "oldValue": null, - "timestamp": "0001-01-01T00:00:00Z" + "timestamp": "0001-01-01T00:00:00Z", + "workItemTypeID": "00000000-0000-0000-0000-000000000001" }, - "id": "00000000-0000-0000-0000-000000000001", + "id": "00000000-0000-0000-0000-000000000002", "relationships": { "modifier": { "data": { - "id": "00000000-0000-0000-0000-000000000002", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000002" - }, + "id": "00000000-0000-0000-0000-000000000003", "type": "identities" } }, "newValue": { "data": [ { - "id": "00000000-0000-0000-0000-000000000002", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000002", - "self": "http:///api/users/00000000-0000-0000-0000-000000000002" - }, + "id": "00000000-0000-0000-0000-000000000003", "type": "users" } ] - }, - "oldValue": {} + } }, "type": "events" } diff --git a/controller/test-files/event/list/ok-description.res.payload.golden.json b/controller/test-files/event/list/ok-description.res.payload.golden.json index dfabee8855..e889d5917a 100755 --- a/controller/test-files/event/list/ok-description.res.payload.golden.json +++ b/controller/test-files/event/list/ok-description.res.payload.golden.json @@ -3,18 +3,19 @@ { "attributes": { "name": "system.description", - "newValue": null, + "newValue": { + "content": "# Description is modified1", + "markup": "Markdown" + }, "oldValue": null, - "timestamp": "0001-01-01T00:00:00Z" + "timestamp": "0001-01-01T00:00:00Z", + "workItemTypeID": "00000000-0000-0000-0000-000000000001" }, - "id": "00000000-0000-0000-0000-000000000001", + "id": "00000000-0000-0000-0000-000000000002", "relationships": { "modifier": { "data": { - "id": "00000000-0000-0000-0000-000000000002", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000002" - }, + "id": "00000000-0000-0000-0000-000000000003", "type": "identities" } } diff --git a/controller/test-files/event/list/ok-iteration.res.payload.golden.json b/controller/test-files/event/list/ok-iteration.res.payload.golden.json index 5a6ccd6bf3..6892f49e43 100755 --- a/controller/test-files/event/list/ok-iteration.res.payload.golden.json +++ b/controller/test-files/event/list/ok-iteration.res.payload.golden.json @@ -3,29 +3,21 @@ { "attributes": { "name": "system.iteration", - "newValue": null, - "oldValue": null, - "timestamp": "0001-01-01T00:00:00Z" + "timestamp": "0001-01-01T00:00:00Z", + "workItemTypeID": "00000000-0000-0000-0000-000000000001" }, - "id": "00000000-0000-0000-0000-000000000001", + "id": "00000000-0000-0000-0000-000000000002", "relationships": { "modifier": { "data": { - "id": "00000000-0000-0000-0000-000000000002", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000002" - }, + "id": "00000000-0000-0000-0000-000000000003", "type": "identities" } }, "newValue": { "data": [ { - "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/iterations/00000000-0000-0000-0000-000000000003", - "self": "http:///api/iterations/00000000-0000-0000-0000-000000000003" - }, + "id": "00000000-0000-0000-0000-000000000004", "type": "iterations" } ] @@ -34,10 +26,6 @@ "data": [ { "id": "", - "links": { - "related": "http:///api/iterations/", - "self": "http:///api/iterations/" - }, "type": "iterations" } ] diff --git a/controller/test-files/event/list/ok-kindFloat.res.payload.golden.json b/controller/test-files/event/list/ok-kindFloat.res.payload.golden.json index 2509f1c74e..8ac03d28d2 100755 --- a/controller/test-files/event/list/ok-kindFloat.res.payload.golden.json +++ b/controller/test-files/event/list/ok-kindFloat.res.payload.golden.json @@ -5,16 +5,14 @@ "name": "myFloatType", "newValue": 2.99, "oldValue": 1.99, - "timestamp": "0001-01-01T00:00:00Z" + "timestamp": "0001-01-01T00:00:00Z", + "workItemTypeID": "00000000-0000-0000-0000-000000000001" }, - "id": "00000000-0000-0000-0000-000000000001", + "id": "00000000-0000-0000-0000-000000000002", "relationships": { "modifier": { "data": { - "id": "00000000-0000-0000-0000-000000000002", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000002" - }, + "id": "00000000-0000-0000-0000-000000000003", "type": "identities" } } diff --git a/controller/test-files/event/list/ok-kindInt.res.payload.golden.json b/controller/test-files/event/list/ok-kindInt.res.payload.golden.json index 5808c39361..b967329ed3 100755 --- a/controller/test-files/event/list/ok-kindInt.res.payload.golden.json +++ b/controller/test-files/event/list/ok-kindInt.res.payload.golden.json @@ -5,16 +5,14 @@ "name": "myIntType", "newValue": 4235, "oldValue": 200, - "timestamp": "0001-01-01T00:00:00Z" + "timestamp": "0001-01-01T00:00:00Z", + "workItemTypeID": "00000000-0000-0000-0000-000000000001" }, - "id": "00000000-0000-0000-0000-000000000001", + "id": "00000000-0000-0000-0000-000000000002", "relationships": { "modifier": { "data": { - "id": "00000000-0000-0000-0000-000000000002", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000002" - }, + "id": "00000000-0000-0000-0000-000000000003", "type": "identities" } } diff --git a/controller/test-files/event/list/ok-labels.res.payload.golden.json b/controller/test-files/event/list/ok-labels.res.payload.golden.json index da175cc0de..9eb504ac3c 100755 --- a/controller/test-files/event/list/ok-labels.res.payload.golden.json +++ b/controller/test-files/event/list/ok-labels.res.payload.golden.json @@ -3,40 +3,28 @@ { "attributes": { "name": "system.labels", - "newValue": null, - "oldValue": null, - "timestamp": "0001-01-01T00:00:00Z" + "timestamp": "0001-01-01T00:00:00Z", + "workItemTypeID": "00000000-0000-0000-0000-000000000001" }, - "id": "00000000-0000-0000-0000-000000000001", + "id": "00000000-0000-0000-0000-000000000002", "relationships": { "modifier": { "data": { - "id": "00000000-0000-0000-0000-000000000002", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000002" - }, + "id": "00000000-0000-0000-0000-000000000003", "type": "identities" } }, "newValue": { "data": [ { - "id": "00000000-0000-0000-0000-000000000003", + "id": "00000000-0000-0000-0000-000000000004", "type": "labels" }, { - "id": "00000000-0000-0000-0000-000000000004", + "id": "00000000-0000-0000-0000-000000000005", "type": "labels" } - ], - "links": { - "related": "http:///api/workitems/00000000-0000-0000-0000-000000000005/labels" - } - }, - "oldValue": { - "links": { - "related": "http:///api/workitems/00000000-0000-0000-0000-000000000005/labels" - } + ] } }, "type": "events" diff --git a/controller/test-files/event/list/ok-state.res.payload.golden.json b/controller/test-files/event/list/ok-state.res.payload.golden.json index b334308cf7..1f90a2437c 100755 --- a/controller/test-files/event/list/ok-state.res.payload.golden.json +++ b/controller/test-files/event/list/ok-state.res.payload.golden.json @@ -5,16 +5,14 @@ "name": "system.state", "newValue": "resolved", "oldValue": "new", - "timestamp": "0001-01-01T00:00:00Z" + "timestamp": "0001-01-01T00:00:00Z", + "workItemTypeID": "00000000-0000-0000-0000-000000000001" }, - "id": "00000000-0000-0000-0000-000000000001", + "id": "00000000-0000-0000-0000-000000000002", "relationships": { "modifier": { "data": { - "id": "00000000-0000-0000-0000-000000000002", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000002" - }, + "id": "00000000-0000-0000-0000-000000000003", "type": "identities" } } diff --git a/controller/test-files/event/list/ok-title.res.payload.golden.json b/controller/test-files/event/list/ok-title.res.payload.golden.json index 4678f5a52c..20edb6fdfc 100755 --- a/controller/test-files/event/list/ok-title.res.payload.golden.json +++ b/controller/test-files/event/list/ok-title.res.payload.golden.json @@ -5,16 +5,14 @@ "name": "system.title", "newValue": "New Title", "oldValue": "work item 00000000-0000-0000-0000-000000000001", - "timestamp": "0001-01-01T00:00:00Z" + "timestamp": "0001-01-01T00:00:00Z", + "workItemTypeID": "00000000-0000-0000-0000-000000000002" }, - "id": "00000000-0000-0000-0000-000000000002", + "id": "00000000-0000-0000-0000-000000000003", "relationships": { "modifier": { "data": { - "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, + "id": "00000000-0000-0000-0000-000000000004", "type": "identities" } } diff --git a/controller/test-files/event/list/ok.bool_list.res.payload.golden.json b/controller/test-files/event/list/ok.bool_list.res.payload.golden.json new file mode 100755 index 0000000000..a9d593c3b6 --- /dev/null +++ b/controller/test-files/event/list/ok.bool_list.res.payload.golden.json @@ -0,0 +1,44 @@ +{ + "data": [ + { + "attributes": { + "name": "bool_single", + "newValue": true, + "oldValue": null, + "timestamp": "0001-01-01T00:00:00Z", + "workItemTypeID": "00000000-0000-0000-0000-000000000001" + }, + "id": "00000000-0000-0000-0000-000000000002", + "relationships": { + "modifier": { + "data": { + "id": "00000000-0000-0000-0000-000000000003", + "type": "identities" + } + } + }, + "type": "events" + }, + { + "attributes": { + "name": "bool_list", + "newValue": [ + true, + false + ], + "timestamp": "0001-01-01T00:00:00Z", + "workItemTypeID": "00000000-0000-0000-0000-000000000001" + }, + "id": "00000000-0000-0000-0000-000000000004", + "relationships": { + "modifier": { + "data": { + "id": "00000000-0000-0000-0000-000000000003", + "type": "identities" + } + } + }, + "type": "events" + } + ] +} \ No newline at end of file diff --git a/controller/test-files/event/list/ok.bool_single.res.payload.golden.json b/controller/test-files/event/list/ok.bool_single.res.payload.golden.json new file mode 100755 index 0000000000..561642756d --- /dev/null +++ b/controller/test-files/event/list/ok.bool_single.res.payload.golden.json @@ -0,0 +1,23 @@ +{ + "data": [ + { + "attributes": { + "name": "bool_single", + "newValue": true, + "oldValue": null, + "timestamp": "0001-01-01T00:00:00Z", + "workItemTypeID": "00000000-0000-0000-0000-000000000001" + }, + "id": "00000000-0000-0000-0000-000000000002", + "relationships": { + "modifier": { + "data": { + "id": "00000000-0000-0000-0000-000000000003", + "type": "identities" + } + } + }, + "type": "events" + } + ] +} \ No newline at end of file diff --git a/controller/test-files/event/list/ok.float_list.res.payload.golden.json b/controller/test-files/event/list/ok.float_list.res.payload.golden.json new file mode 100755 index 0000000000..4687da7ead --- /dev/null +++ b/controller/test-files/event/list/ok.float_list.res.payload.golden.json @@ -0,0 +1,44 @@ +{ + "data": [ + { + "attributes": { + "name": "float_single", + "newValue": 0.1, + "oldValue": null, + "timestamp": "0001-01-01T00:00:00Z", + "workItemTypeID": "00000000-0000-0000-0000-000000000001" + }, + "id": "00000000-0000-0000-0000-000000000002", + "relationships": { + "modifier": { + "data": { + "id": "00000000-0000-0000-0000-000000000003", + "type": "identities" + } + } + }, + "type": "events" + }, + { + "attributes": { + "name": "float_list", + "newValue": [ + 0.1, + -1111.1 + ], + "timestamp": "0001-01-01T00:00:00Z", + "workItemTypeID": "00000000-0000-0000-0000-000000000001" + }, + "id": "00000000-0000-0000-0000-000000000004", + "relationships": { + "modifier": { + "data": { + "id": "00000000-0000-0000-0000-000000000003", + "type": "identities" + } + } + }, + "type": "events" + } + ] +} \ No newline at end of file diff --git a/controller/test-files/event/list/ok.float_single.res.payload.golden.json b/controller/test-files/event/list/ok.float_single.res.payload.golden.json new file mode 100755 index 0000000000..629c9614ea --- /dev/null +++ b/controller/test-files/event/list/ok.float_single.res.payload.golden.json @@ -0,0 +1,23 @@ +{ + "data": [ + { + "attributes": { + "name": "float_single", + "newValue": 0.1, + "oldValue": null, + "timestamp": "0001-01-01T00:00:00Z", + "workItemTypeID": "00000000-0000-0000-0000-000000000001" + }, + "id": "00000000-0000-0000-0000-000000000002", + "relationships": { + "modifier": { + "data": { + "id": "00000000-0000-0000-0000-000000000003", + "type": "identities" + } + } + }, + "type": "events" + } + ] +} \ No newline at end of file diff --git a/controller/test-files/event/list/ok.integer_list.res.payload.golden.json b/controller/test-files/event/list/ok.integer_list.res.payload.golden.json new file mode 100755 index 0000000000..12fc4bfcbe --- /dev/null +++ b/controller/test-files/event/list/ok.integer_list.res.payload.golden.json @@ -0,0 +1,44 @@ +{ + "data": [ + { + "attributes": { + "name": "integer_single", + "newValue": 0, + "oldValue": null, + "timestamp": "0001-01-01T00:00:00Z", + "workItemTypeID": "00000000-0000-0000-0000-000000000001" + }, + "id": "00000000-0000-0000-0000-000000000002", + "relationships": { + "modifier": { + "data": { + "id": "00000000-0000-0000-0000-000000000003", + "type": "identities" + } + } + }, + "type": "events" + }, + { + "attributes": { + "name": "integer_list", + "newValue": [ + 0, + 333 + ], + "timestamp": "0001-01-01T00:00:00Z", + "workItemTypeID": "00000000-0000-0000-0000-000000000001" + }, + "id": "00000000-0000-0000-0000-000000000004", + "relationships": { + "modifier": { + "data": { + "id": "00000000-0000-0000-0000-000000000003", + "type": "identities" + } + } + }, + "type": "events" + } + ] +} \ No newline at end of file diff --git a/controller/test-files/event/list/ok.integer_single.res.payload.golden.json b/controller/test-files/event/list/ok.integer_single.res.payload.golden.json new file mode 100755 index 0000000000..beab8f40d4 --- /dev/null +++ b/controller/test-files/event/list/ok.integer_single.res.payload.golden.json @@ -0,0 +1,23 @@ +{ + "data": [ + { + "attributes": { + "name": "integer_single", + "newValue": 0, + "oldValue": null, + "timestamp": "0001-01-01T00:00:00Z", + "workItemTypeID": "00000000-0000-0000-0000-000000000001" + }, + "id": "00000000-0000-0000-0000-000000000002", + "relationships": { + "modifier": { + "data": { + "id": "00000000-0000-0000-0000-000000000003", + "type": "identities" + } + } + }, + "type": "events" + } + ] +} \ No newline at end of file diff --git a/controller/test-files/event/list/ok.markup_list.res.payload.golden.json b/controller/test-files/event/list/ok.markup_list.res.payload.golden.json new file mode 100755 index 0000000000..a4e51fec65 --- /dev/null +++ b/controller/test-files/event/list/ok.markup_list.res.payload.golden.json @@ -0,0 +1,53 @@ +{ + "data": [ + { + "attributes": { + "name": "markup_single", + "newValue": { + "content": "plain text", + "markup": "PlainText" + }, + "oldValue": null, + "timestamp": "0001-01-01T00:00:00Z", + "workItemTypeID": "00000000-0000-0000-0000-000000000001" + }, + "id": "00000000-0000-0000-0000-000000000002", + "relationships": { + "modifier": { + "data": { + "id": "00000000-0000-0000-0000-000000000003", + "type": "identities" + } + } + }, + "type": "events" + }, + { + "attributes": { + "name": "markup_list", + "newValue": [ + { + "content": "plain text", + "markup": "PlainText" + }, + { + "content": "default", + "markup": "PlainText" + } + ], + "timestamp": "0001-01-01T00:00:00Z", + "workItemTypeID": "00000000-0000-0000-0000-000000000001" + }, + "id": "00000000-0000-0000-0000-000000000004", + "relationships": { + "modifier": { + "data": { + "id": "00000000-0000-0000-0000-000000000003", + "type": "identities" + } + } + }, + "type": "events" + } + ] +} \ No newline at end of file diff --git a/controller/test-files/event/list/ok.markup_single.res.payload.golden.json b/controller/test-files/event/list/ok.markup_single.res.payload.golden.json new file mode 100755 index 0000000000..d40bd4a34f --- /dev/null +++ b/controller/test-files/event/list/ok.markup_single.res.payload.golden.json @@ -0,0 +1,26 @@ +{ + "data": [ + { + "attributes": { + "name": "markup_single", + "newValue": { + "content": "plain text", + "markup": "PlainText" + }, + "oldValue": null, + "timestamp": "0001-01-01T00:00:00Z", + "workItemTypeID": "00000000-0000-0000-0000-000000000001" + }, + "id": "00000000-0000-0000-0000-000000000002", + "relationships": { + "modifier": { + "data": { + "id": "00000000-0000-0000-0000-000000000003", + "type": "identities" + } + } + }, + "type": "events" + } + ] +} \ No newline at end of file diff --git a/controller/test-files/event/list/ok.string_list.res.payload.golden.json b/controller/test-files/event/list/ok.string_list.res.payload.golden.json new file mode 100755 index 0000000000..849a2e5e70 --- /dev/null +++ b/controller/test-files/event/list/ok.string_list.res.payload.golden.json @@ -0,0 +1,44 @@ +{ + "data": [ + { + "attributes": { + "name": "string_single", + "newValue": "foo", + "oldValue": null, + "timestamp": "0001-01-01T00:00:00Z", + "workItemTypeID": "00000000-0000-0000-0000-000000000001" + }, + "id": "00000000-0000-0000-0000-000000000002", + "relationships": { + "modifier": { + "data": { + "id": "00000000-0000-0000-0000-000000000003", + "type": "identities" + } + } + }, + "type": "events" + }, + { + "attributes": { + "name": "string_list", + "newValue": [ + "foo", + "bar" + ], + "timestamp": "0001-01-01T00:00:00Z", + "workItemTypeID": "00000000-0000-0000-0000-000000000001" + }, + "id": "00000000-0000-0000-0000-000000000004", + "relationships": { + "modifier": { + "data": { + "id": "00000000-0000-0000-0000-000000000003", + "type": "identities" + } + } + }, + "type": "events" + } + ] +} \ No newline at end of file diff --git a/controller/test-files/event/list/ok.string_single.res.payload.golden.json b/controller/test-files/event/list/ok.string_single.res.payload.golden.json new file mode 100755 index 0000000000..e81283dbd9 --- /dev/null +++ b/controller/test-files/event/list/ok.string_single.res.payload.golden.json @@ -0,0 +1,23 @@ +{ + "data": [ + { + "attributes": { + "name": "string_single", + "newValue": "foo", + "oldValue": null, + "timestamp": "0001-01-01T00:00:00Z", + "workItemTypeID": "00000000-0000-0000-0000-000000000001" + }, + "id": "00000000-0000-0000-0000-000000000002", + "relationships": { + "modifier": { + "data": { + "id": "00000000-0000-0000-0000-000000000003", + "type": "identities" + } + } + }, + "type": "events" + } + ] +} \ No newline at end of file diff --git a/controller/test-files/event/list/ok.url_list.res.payload.golden.json b/controller/test-files/event/list/ok.url_list.res.payload.golden.json new file mode 100755 index 0000000000..afe208fd70 --- /dev/null +++ b/controller/test-files/event/list/ok.url_list.res.payload.golden.json @@ -0,0 +1,44 @@ +{ + "data": [ + { + "attributes": { + "name": "url_single", + "newValue": "127.0.0.1", + "oldValue": null, + "timestamp": "0001-01-01T00:00:00Z", + "workItemTypeID": "00000000-0000-0000-0000-000000000001" + }, + "id": "00000000-0000-0000-0000-000000000002", + "relationships": { + "modifier": { + "data": { + "id": "00000000-0000-0000-0000-000000000003", + "type": "identities" + } + } + }, + "type": "events" + }, + { + "attributes": { + "name": "url_list", + "newValue": [ + "127.0.0.1", + "http://www.openshift.io" + ], + "timestamp": "0001-01-01T00:00:00Z", + "workItemTypeID": "00000000-0000-0000-0000-000000000001" + }, + "id": "00000000-0000-0000-0000-000000000004", + "relationships": { + "modifier": { + "data": { + "id": "00000000-0000-0000-0000-000000000003", + "type": "identities" + } + } + }, + "type": "events" + } + ] +} \ No newline at end of file diff --git a/controller/test-files/event/list/ok.url_single.res.payload.golden.json b/controller/test-files/event/list/ok.url_single.res.payload.golden.json new file mode 100755 index 0000000000..870f27dca2 --- /dev/null +++ b/controller/test-files/event/list/ok.url_single.res.payload.golden.json @@ -0,0 +1,23 @@ +{ + "data": [ + { + "attributes": { + "name": "url_single", + "newValue": "127.0.0.1", + "oldValue": null, + "timestamp": "0001-01-01T00:00:00Z", + "workItemTypeID": "00000000-0000-0000-0000-000000000001" + }, + "id": "00000000-0000-0000-0000-000000000002", + "relationships": { + "modifier": { + "data": { + "id": "00000000-0000-0000-0000-000000000003", + "type": "identities" + } + } + }, + "type": "events" + } + ] +} \ No newline at end of file diff --git a/controller/users.go b/controller/users.go index 6c5580106c..12ae5edd5c 100644 --- a/controller/users.go +++ b/controller/users.go @@ -12,7 +12,7 @@ import ( idpackage "github.com/fabric8-services/fabric8-wit/id" "github.com/fabric8-services/fabric8-wit/jsonapi" "github.com/fabric8-services/fabric8-wit/log" - "github.com/fabric8-services/fabric8-wit/rest" + "github.com/fabric8-services/fabric8-wit/ptr" "github.com/fabric8-services/fabric8-wit/token" "github.com/fabric8-services/fabric8-wit/rest/proxy" @@ -311,19 +311,15 @@ func ConvertUsersSimple(request *http.Request, identityIDs []interface{}) []*app // ConvertUserSimple converts a simple Identity ID into a Generic Reletionship func ConvertUserSimple(request *http.Request, identityID interface{}) *app.GenericData { - t := "users" - i := fmt.Sprint(identityID) - return &app.GenericData{ - Type: &t, - ID: &i, - Links: createUserLinks(request, identityID), + i := "" + switch t := identityID.(type) { + case string: + i = t + case uuid.UUID: + i = t.String() } -} - -func createUserLinks(request *http.Request, identityID interface{}) *app.GenericLinks { - relatedURL := rest.AbsoluteURL(request, app.UsersHref(identityID)) - return &app.GenericLinks{ - Self: &relatedURL, - Related: &relatedURL, + return &app.GenericData{ + Type: ptr.String("users"), + ID: &i, } } diff --git a/controller/work_item_board.go b/controller/work_item_board.go index 2051bf7e41..0fe9365dbd 100644 --- a/controller/work_item_board.go +++ b/controller/work_item_board.go @@ -11,6 +11,7 @@ import ( "github.com/fabric8-services/fabric8-wit/workitem" "github.com/goadesign/goa" errs "github.com/pkg/errors" + uuid "github.com/satori/go.uuid" ) // WorkItemBoardController implements the work_item_board resource. @@ -111,3 +112,18 @@ func ConvertBoardFromModel(request *http.Request, b workitem.Board) *app.WorkIte return res } + +// ConvertBoardColumnSimple converts a simple boardcolumn ID into a Generic Relationship +func ConvertBoardColumnSimple(request *http.Request, id interface{}) *app.GenericData { + i := "" + switch t := id.(type) { + case string: + i = t + case uuid.UUID: + i = t.String() + } + return &app.GenericData{ + Type: ptr.String(APIBoardColumns), + ID: &i, + } +} diff --git a/controller/work_item_events.go b/controller/work_item_events.go index 1e4d32e5fd..3613ec4778 100644 --- a/controller/work_item_events.go +++ b/controller/work_item_events.go @@ -1,14 +1,13 @@ package controller import ( - "fmt" + "context" "net/http" "github.com/fabric8-services/fabric8-wit/app" "github.com/fabric8-services/fabric8-wit/application" "github.com/fabric8-services/fabric8-wit/jsonapi" "github.com/fabric8-services/fabric8-wit/ptr" - "github.com/fabric8-services/fabric8-wit/rest" "github.com/fabric8-services/fabric8-wit/workitem" "github.com/fabric8-services/fabric8-wit/workitem/event" "github.com/goadesign/goa" @@ -47,175 +46,182 @@ func (c *EventsController) List(ctx *app.ListWorkItemEventsContext) error { if err != nil { return jsonapi.JSONErrorResponse(ctx, err) } + var convertedEvents []*app.Event return ctx.ConditionalEntities(eventList, c.config.GetCacheControlEvents, func() error { - res := &app.EventList{} - res.Data = ConvertEvents(c.db, ctx.Request, eventList, ctx.WiID) - return ctx.OK(res) + wi, err := c.db.WorkItems().LoadByID(ctx, ctx.WiID) + if err != nil { + return errs.Wrapf(err, "failed to load work item with ID: %s", ctx.WiID) + } + convertedEvents, err = ConvertEvents(ctx, c.db, ctx.Request, eventList, ctx.WiID, wi.SpaceID) + if err != nil { + return errs.Wrapf(err, "failed to convert events") + } + return ctx.OK(&app.EventList{ + Data: convertedEvents, + }) + }) + if err != nil { + return jsonapi.JSONErrorResponse(ctx, err) + } + return ctx.OK(&app.EventList{ + Data: convertedEvents, }) } // ConvertEvents from internal to external REST representation -func ConvertEvents(appl application.Application, request *http.Request, eventList []event.Event, wiID uuid.UUID) []*app.Event { +func ConvertEvents(ctx context.Context, appl application.Application, request *http.Request, eventList []event.Event, wiID uuid.UUID, spaceID uuid.UUID) ([]*app.Event, error) { var ls = []*app.Event{} for _, i := range eventList { - ls = append(ls, ConvertEvent(appl, request, i, wiID)) + converted, err := ConvertEvent(ctx, appl, request, i, wiID, spaceID) + if err != nil { + return nil, errs.Wrapf(err, "failed to convert event: %+v", i) + } + ls = append(ls, converted) } - return ls + return ls, nil } // ConvertEvent converts from internal to external REST representation -func ConvertEvent(appl application.Application, request *http.Request, wiEvent event.Event, wiID uuid.UUID) *app.Event { - relatedCreatorLink := rest.AbsoluteURL(request, fmt.Sprintf("%s/%s", usersEndpoint, wiEvent.Modifier.String())) - relatedURL := rest.AbsoluteURL(request, app.WorkitemHref(wiID)) - labelsRelated := relatedURL + "/labels" - modifier := &app.RelationGeneric{ - Data: &app.GenericData{ - Type: ptr.String(APIStringTypeUser), - ID: ptr.String(wiEvent.Modifier.String()), - Links: &app.GenericLinks{ - Related: &relatedCreatorLink, - }, - }, +func ConvertEvent(ctx context.Context, appl application.Application, req *http.Request, wiEvent event.Event, wiID uuid.UUID, spaceID uuid.UUID) (*app.Event, error) { + // find out about background details on the field that was modified + wit, err := appl.WorkItemTypes().Load(ctx, wiEvent.WorkItemTypeID) + if err != nil { + return nil, errs.Wrapf(err, "failed to load work item type: %s", wiEvent.WorkItemTypeID) + } + fieldName := wiEvent.Name + fieldDef, ok := wit.Fields[fieldName] + if !ok { + return nil, errs.Errorf("failed to find field \"%s\" in work item type: %s (%s)", fieldName, wit.Name, wit.ID) } - var e *app.Event - switch wiEvent.Name { - case workitem.SystemState, workitem.SystemTitle: - e = &app.Event{ - Type: event.APIStringTypeEvents, - ID: &wiEvent.ID, - Attributes: map[string]interface{}{ - "name": wiEvent.Name, - "newValue": wiEvent.New, - "oldValue": wiEvent.Old, - "timestamp": wiEvent.Timestamp, + e := app.Event{ + Type: event.APIStringTypeEvents, + ID: &wiEvent.ID, + Attributes: &app.EventAttributes{ + Name: wiEvent.Name, + Timestamp: wiEvent.Timestamp, + WorkItemTypeID: &wiEvent.WorkItemTypeID, + }, + Relationships: &app.EventRelations{ + Modifier: &app.RelationGeneric{ + Data: &app.GenericData{ + Type: ptr.String(APIStringTypeUser), + ID: ptr.String(wiEvent.Modifier.String()), + }, }, + }, + } - Relationships: &app.EventRelations{ - Modifier: modifier, - }, + handle := func(kind workitem.Kind, val interface{}) (interface{}, bool) { + switch kind { + case workitem.KindString, + workitem.KindInteger, + workitem.KindFloat, + workitem.KindBoolean, + workitem.KindURL, + workitem.KindMarkup, + workitem.KindDuration, // TODO(kwk): get rid of duration + workitem.KindInstant: + return val, false + case workitem.KindIteration: + return ConvertIterationSimple(req, val), true + case workitem.KindUser: + return ConvertUserSimple(req, val), true + case workitem.KindLabel: + return ConvertLabelSimple(req, val), true + case workitem.KindBoardColumn: + return ConvertBoardColumnSimple(req, val), true + case workitem.KindArea: + return ConvertAreaSimple(req, val), true + case workitem.KindCodebase: + return ConvertCodebaseSimple(req, val), true } - case workitem.SystemDescription: - e = &app.Event{ - Type: event.APIStringTypeEvents, - ID: &wiEvent.ID, - Attributes: map[string]interface{}{ - "name": wiEvent.Name, - "newValue": nil, - "oldValue": nil, - "timestamp": wiEvent.Timestamp, - }, + return nil, false + } - Relationships: &app.EventRelations{ - Modifier: modifier, - }, + kind := fieldDef.Type.GetKind() + if kind == workitem.KindEnum { + enumType, ok := fieldDef.Type.(workitem.EnumType) + if !ok { + return nil, errs.Errorf("failed to convert field \"%s\" to enum type: %+v", fieldName, fieldDef) } - case workitem.SystemArea: - old := ConvertAreaSimple(request, wiEvent.Old) - new := ConvertAreaSimple(request, wiEvent.New) - e = &app.Event{ - Type: event.APIStringTypeEvents, - ID: &wiEvent.ID, - Attributes: map[string]interface{}{ - "name": wiEvent.Name, - "newValue": nil, - "oldValue": nil, - "timestamp": wiEvent.Timestamp, - }, + kind = enumType.BaseType.GetKind() + } - Relationships: &app.EventRelations{ - Modifier: modifier, - OldValue: &app.RelationGenericList{ - Data: []*app.GenericData{old}, + // handle all single value fields (including enums) + if kind != workitem.KindList { + oldVal, useRel := handle(kind, wiEvent.Old) + newVal, _ := handle(kind, wiEvent.New) + // update the event with the given values and find out if + if useRel { + e.Relationships.OldValue = &app.RelationGenericList{ + Data: []*app.GenericData{ + oldVal.(*app.GenericData), }, - NewValue: &app.RelationGenericList{ - Data: []*app.GenericData{new}, + } + e.Relationships.NewValue = &app.RelationGenericList{ + Data: []*app.GenericData{ + newVal.(*app.GenericData), }, - }, + } + } else { + e.Attributes.OldValue = &oldVal + e.Attributes.NewValue = &newVal } - case workitem.SystemIteration: - old := ConvertIterationSimple(request, wiEvent.Old) - new := ConvertIterationSimple(request, wiEvent.New) - e = &app.Event{ - Type: event.APIStringTypeEvents, - ID: &wiEvent.ID, - Attributes: map[string]interface{}{ - "name": wiEvent.Name, - "newValue": nil, - "oldValue": nil, - "timestamp": wiEvent.Timestamp, - }, + return &e, nil + } - Relationships: &app.EventRelations{ - Modifier: modifier, - OldValue: &app.RelationGenericList{ - Data: []*app.GenericData{old}, - }, - NewValue: &app.RelationGenericList{ - Data: []*app.GenericData{new}, - }, - }, - } - case workitem.SystemAssignees: - e = &app.Event{ - Type: event.APIStringTypeEvents, - ID: &wiEvent.ID, - Attributes: map[string]interface{}{ - "name": wiEvent.Name, - "newValue": nil, - "oldValue": nil, - "timestamp": wiEvent.Timestamp, - }, - Relationships: &app.EventRelations{ - Modifier: modifier, - OldValue: &app.RelationGenericList{ - Data: ConvertUsersSimple(request, wiEvent.Old.([]interface{})), - }, - NewValue: &app.RelationGenericList{ - Data: ConvertUsersSimple(request, wiEvent.New.([]interface{})), - }, - }, - } - case workitem.SystemLabels: - e = &app.Event{ - Type: event.APIStringTypeEvents, - ID: &wiEvent.ID, - Attributes: map[string]interface{}{ - "name": wiEvent.Name, - "newValue": nil, - "oldValue": nil, - "timestamp": wiEvent.Timestamp, - }, - Relationships: &app.EventRelations{ - Modifier: modifier, - OldValue: &app.RelationGenericList{ - Data: ConvertLabelsSimple(request, wiEvent.Old.([]interface{})), - Links: &app.GenericLinks{ - Related: &labelsRelated, - }, - }, - NewValue: &app.RelationGenericList{ - Data: ConvertLabelsSimple(request, wiEvent.New.([]interface{})), - Links: &app.GenericLinks{ - Related: &labelsRelated, - }, - }, - }, + // handle multi-value fields + listType, ok := fieldDef.Type.(workitem.ListType) + if !ok { + return nil, errs.Errorf("failed to convert field \"%s\" to list type: %+v", fieldName, fieldDef) + } + componentTypeKind := listType.ComponentType.GetKind() + + arrOld, ok := wiEvent.Old.([]interface{}) + if !ok { + return nil, errs.Errorf("failed to convert old value of field \"%s\" to []interface{}: %+v", fieldName, wiEvent.Old) + } + arrNew, ok := wiEvent.New.([]interface{}) + if !ok { + return nil, errs.Errorf("failed to convert old value of field \"%s\" to []interface{}: %+v", fieldName, wiEvent.Old) + } + + for i, o := range arrOld { + oldVal, useRel := handle(componentTypeKind, o) + if useRel { + if i == 0 { + e.Relationships.OldValue = &app.RelationGenericList{ + Data: make([]*app.GenericData, len(arrOld)), + } + } + e.Relationships.OldValue.Data[i] = oldVal.(*app.GenericData) + } else { + if i == 0 { + var ifObj interface{} = make([]interface{}, len(arrOld)) + e.Attributes.OldValue = &ifObj + } + (*e.Attributes.OldValue).([]interface{})[i] = oldVal } - default: - e = &app.Event{ - Type: event.APIStringTypeEvents, - ID: &wiEvent.ID, - Attributes: map[string]interface{}{ - "name": wiEvent.Name, - "newValue": wiEvent.New, - "oldValue": wiEvent.Old, - "timestamp": wiEvent.Timestamp, - }, - Relationships: &app.EventRelations{ - Modifier: modifier, - }, + } + + for i, n := range arrNew { + newVal, useRel := handle(componentTypeKind, n) + if useRel { + if i == 0 { + e.Relationships.NewValue = &app.RelationGenericList{ + Data: make([]*app.GenericData, len(arrNew)), + } + } + e.Relationships.NewValue.Data[i] = newVal.(*app.GenericData) + } else { + if i == 0 { + var ifObj interface{} = make([]interface{}, len(arrNew)) + e.Attributes.NewValue = &ifObj + } + (*e.Attributes.NewValue).([]interface{})[i] = newVal } } - return e + + return &e, nil } diff --git a/controller/work_item_events_test.go b/controller/work_item_events_test.go index c68d5a38d2..82cd09290d 100644 --- a/controller/work_item_events_test.go +++ b/controller/work_item_events_test.go @@ -9,13 +9,11 @@ import ( "github.com/fabric8-services/fabric8-wit/app/test" . "github.com/fabric8-services/fabric8-wit/controller" "github.com/fabric8-services/fabric8-wit/gormtestsupport" - "github.com/fabric8-services/fabric8-wit/label" "github.com/fabric8-services/fabric8-wit/resource" "github.com/fabric8-services/fabric8-wit/rest" testsupport "github.com/fabric8-services/fabric8-wit/test" tf "github.com/fabric8-services/fabric8-wit/test/testfixture" "github.com/fabric8-services/fabric8-wit/workitem" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" ) @@ -37,383 +35,544 @@ func (s *TestEvent) SetupTest() { func (s *TestEvent) TestListEvent() { - s.T().Run("event list ok - state", func(t *testing.T) { - fxt := tf.NewTestFixture(s.T(), s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1)) - svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) - eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) - workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) - spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) - payload := app.UpdateWorkitemPayload{ - Data: &app.WorkItem{ - Type: APIStringTypeWorkItem, - ID: &fxt.WorkItems[0].ID, - Attributes: map[string]interface{}{ - workitem.SystemState: "resolved", - workitem.SystemVersion: fxt.WorkItems[0].Version, - }, - Relationships: &app.WorkItemRelationships{ - Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), - }, - }, - } - test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) - res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) - safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") - require.NotEmpty(t, eventList) - require.Len(t, eventList.Data, 1) - compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-state.res.payload.golden.json"), eventList) - compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-state.res.headers.golden.json"), res.Header()) - }) + // s.T().Run("event list ok - state", func(t *testing.T) { + // fxt := tf.NewTestFixture(t, s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1)) + // svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) + // eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) + // workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) + // spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) + // payload := app.UpdateWorkitemPayload{ + // Data: &app.WorkItem{ + // Type: APIStringTypeWorkItem, + // ID: &fxt.WorkItems[0].ID, + // Attributes: map[string]interface{}{ + // workitem.SystemState: "resolved", + // workitem.SystemVersion: fxt.WorkItems[0].Version, + // }, + // Relationships: &app.WorkItemRelationships{ + // Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), + // }, + // }, + // } + // test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) + // res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) + // safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") + // require.NotEmpty(t, eventList) + // require.Len(t, eventList.Data, 1) + // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-state.res.payload.golden.json"), eventList) + // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-state.res.headers.golden.json"), res.Header()) + // }) - s.T().Run("event list ok - title", func(t *testing.T) { - fxt := tf.NewTestFixture(s.T(), s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1)) - svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) - eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) - workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) - spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) - payload := app.UpdateWorkitemPayload{ - Data: &app.WorkItem{ - Type: APIStringTypeWorkItem, - ID: &fxt.WorkItems[0].ID, - Attributes: map[string]interface{}{ - workitem.SystemTitle: "New Title", - workitem.SystemVersion: fxt.WorkItems[0].Version, - }, - Relationships: &app.WorkItemRelationships{ - Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), - }, - }, - } - test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) - res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) - safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") - require.NotEmpty(t, eventList) - require.Len(t, eventList.Data, 1) - compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-title.res.payload.golden.json"), eventList) - compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-title.res.headers.golden.json"), res.Header()) - }) + // s.T().Run("event list ok - title", func(t *testing.T) { + // fxt := tf.NewTestFixture(t, s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1)) + // svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) + // eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) + // workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) + // spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) + // payload := app.UpdateWorkitemPayload{ + // Data: &app.WorkItem{ + // Type: APIStringTypeWorkItem, + // ID: &fxt.WorkItems[0].ID, + // Attributes: map[string]interface{}{ + // workitem.SystemTitle: "New Title", + // workitem.SystemVersion: fxt.WorkItems[0].Version, + // }, + // Relationships: &app.WorkItemRelationships{ + // Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), + // }, + // }, + // } + // test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) + // res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) + // safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") + // require.NotEmpty(t, eventList) + // require.Len(t, eventList.Data, 1) + // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-title.res.payload.golden.json"), eventList) + // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-title.res.headers.golden.json"), res.Header()) + // }) - s.T().Run("event list ok - Field Type Float", func(t *testing.T) { - fieldName := "myFloatType" - fxt := tf.NewTestFixture(t, s.DB, - tf.CreateWorkItemEnvironment(), - tf.WorkItemTypes(1, func(fxt *tf.TestFixture, idx int) error { - fxt.WorkItemTypes[idx].Fields = map[string]workitem.FieldDefinition{ - fieldName: { - Type: &workitem.SimpleType{Kind: workitem.KindFloat}, - }, - } - return nil - }), - tf.WorkItems(1, func(fxt *tf.TestFixture, idx int) error { - fxt.WorkItems[idx].Type = fxt.WorkItemTypes[idx].ID - fxt.WorkItems[idx].Fields[fieldName] = 1.99 - fxt.WorkItems[idx].Fields[workitem.SystemTitle] = "My workitem" - return nil - }), - ) - svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) - eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) - workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) - spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) - payload := app.UpdateWorkitemPayload{ - Data: &app.WorkItem{ - Type: APIStringTypeWorkItem, - ID: &fxt.WorkItems[0].ID, - Attributes: map[string]interface{}{ - workitem.SystemTitle: fxt.WorkItems[0].Fields[workitem.SystemTitle], - fieldName: 2.99, - workitem.SystemVersion: fxt.WorkItems[0].Version, - }, - Relationships: &app.WorkItemRelationships{ - Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), - }, - }, - } - test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) - res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) - safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") - require.NotEmpty(t, eventList) - require.Len(t, eventList.Data, 1) - compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-kindFloat.res.payload.golden.json"), eventList) - compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-kindFloat.res.headers.golden.json"), res.Header()) - }) + // s.T().Run("event list ok - Field Type Float", func(t *testing.T) { + // fieldName := "myFloatType" + // fxt := tf.NewTestFixture(t, s.DB, + // tf.CreateWorkItemEnvironment(), + // tf.WorkItemTypes(1, func(fxt *tf.TestFixture, idx int) error { + // fxt.WorkItemTypes[idx].Fields = map[string]workitem.FieldDefinition{ + // fieldName: { + // Type: &workitem.SimpleType{Kind: workitem.KindFloat}, + // }, + // } + // return nil + // }), + // tf.WorkItems(1, func(fxt *tf.TestFixture, idx int) error { + // fxt.WorkItems[idx].Type = fxt.WorkItemTypes[idx].ID + // fxt.WorkItems[idx].Fields[fieldName] = 1.99 + // fxt.WorkItems[idx].Fields[workitem.SystemTitle] = "My workitem" + // return nil + // }), + // ) + // svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) + // eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) + // workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) + // spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) + // payload := app.UpdateWorkitemPayload{ + // Data: &app.WorkItem{ + // Type: APIStringTypeWorkItem, + // ID: &fxt.WorkItems[0].ID, + // Attributes: map[string]interface{}{ + // workitem.SystemTitle: fxt.WorkItems[0].Fields[workitem.SystemTitle], + // fieldName: 2.99, + // workitem.SystemVersion: fxt.WorkItems[0].Version, + // }, + // Relationships: &app.WorkItemRelationships{ + // Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), + // }, + // }, + // } + // test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) + // res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) + // safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") + // require.NotEmpty(t, eventList) + // require.Len(t, eventList.Data, 1) + // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-kindFloat.res.payload.golden.json"), eventList) + // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-kindFloat.res.headers.golden.json"), res.Header()) + // }) - s.T().Run("event list ok - Field Type Int", func(t *testing.T) { - fieldName := "myIntType" - fxt := tf.NewTestFixture(t, s.DB, - tf.CreateWorkItemEnvironment(), - tf.WorkItemTypes(1, func(fxt *tf.TestFixture, idx int) error { - fxt.WorkItemTypes[idx].Fields = map[string]workitem.FieldDefinition{ - fieldName: { - Type: &workitem.SimpleType{Kind: workitem.KindInteger}, - }, - } - return nil - }), - tf.WorkItems(1, func(fxt *tf.TestFixture, idx int) error { - fxt.WorkItems[idx].Type = fxt.WorkItemTypes[idx].ID - fxt.WorkItems[idx].Fields[fieldName] = 200 - fxt.WorkItems[idx].Fields[workitem.SystemTitle] = "My workitem" - return nil - }), - ) - svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) - eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) - workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) - spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) - payload := app.UpdateWorkitemPayload{ - Data: &app.WorkItem{ - Type: APIStringTypeWorkItem, - ID: &fxt.WorkItems[0].ID, - Attributes: map[string]interface{}{ - workitem.SystemTitle: fxt.WorkItems[0].Fields[workitem.SystemTitle], - fieldName: 4235, - workitem.SystemVersion: fxt.WorkItems[0].Version, - }, - Relationships: &app.WorkItemRelationships{ - Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), - }, - }, - } - test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) - res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) - safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") - require.NotEmpty(t, eventList) - require.Len(t, eventList.Data, 1) - compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-kindInt.res.payload.golden.json"), eventList) - compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-kindInt.res.headers.golden.json"), res.Header()) - }) + // s.T().Run("event list ok - Field Type Int", func(t *testing.T) { + // fieldName := "myIntType" + // fxt := tf.NewTestFixture(t, s.DB, + // tf.CreateWorkItemEnvironment(), + // tf.WorkItemTypes(1, func(fxt *tf.TestFixture, idx int) error { + // fxt.WorkItemTypes[idx].Fields = map[string]workitem.FieldDefinition{ + // fieldName: { + // Type: &workitem.SimpleType{Kind: workitem.KindInteger}, + // }, + // } + // return nil + // }), + // tf.WorkItems(1, func(fxt *tf.TestFixture, idx int) error { + // fxt.WorkItems[idx].Type = fxt.WorkItemTypes[idx].ID + // fxt.WorkItems[idx].Fields[fieldName] = 200 + // fxt.WorkItems[idx].Fields[workitem.SystemTitle] = "My workitem" + // return nil + // }), + // ) + // svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) + // eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) + // workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) + // spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) + // payload := app.UpdateWorkitemPayload{ + // Data: &app.WorkItem{ + // Type: APIStringTypeWorkItem, + // ID: &fxt.WorkItems[0].ID, + // Attributes: map[string]interface{}{ + // workitem.SystemTitle: fxt.WorkItems[0].Fields[workitem.SystemTitle], + // fieldName: 4235, + // workitem.SystemVersion: fxt.WorkItems[0].Version, + // }, + // Relationships: &app.WorkItemRelationships{ + // Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), + // }, + // }, + // } + // test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) + // res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) + // safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") + // require.NotEmpty(t, eventList) + // require.Len(t, eventList.Data, 1) + // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-kindInt.res.payload.golden.json"), eventList) + // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-kindInt.res.headers.golden.json"), res.Header()) + // }) - s.T().Run("event list ok - description", func(t *testing.T) { - fxt := tf.NewTestFixture(s.T(), s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1)) - svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) - eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) - workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) - spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) - payload := app.UpdateWorkitemPayload{ - Data: &app.WorkItem{ - Type: APIStringTypeWorkItem, - ID: &fxt.WorkItems[0].ID, - Attributes: map[string]interface{}{ - workitem.SystemDescription: "New Description", - workitem.SystemVersion: fxt.WorkItems[0].Version, - }, - Relationships: &app.WorkItemRelationships{ - Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), - }, - }, - } - test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) - res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) - safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") - require.NotEmpty(t, eventList) - require.Len(t, eventList.Data, 1) - compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-description.res.payload.golden.json"), eventList) - compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-description.res.headers.golden.json"), res.Header()) - }) + // s.T().Run("event list ok - description", func(t *testing.T) { + // fxt := tf.NewTestFixture(t, s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1)) + // svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) + // eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) + // workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) + // spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) - s.T().Run("event list ok - assigned", func(t *testing.T) { - fxt := tf.NewTestFixture(s.T(), s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1)) - svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) - eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) - assignee := []string{fxt.Identities[0].ID.String()} - workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) - spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) - payload := app.UpdateWorkitemPayload{ - Data: &app.WorkItem{ - Type: APIStringTypeWorkItem, - ID: &fxt.WorkItems[0].ID, - Attributes: map[string]interface{}{ - workitem.SystemAssignees: assignee, - workitem.SystemVersion: fxt.WorkItems[0].Version, - }, - Relationships: &app.WorkItemRelationships{ - Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), - }, - }, - } - test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) - res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) - safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") - require.NotEmpty(t, eventList) - require.Len(t, eventList.Data, 1) - compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-assignees.res.payload.golden.json"), eventList) - compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-assignees.res.headers.golden.json"), res.Header()) - }) + // modifiedDescription := "# Description is modified1" + // modifiedRenderedDescription := "

Description is modified1

\n" + // modifiedMarkup := rendering.SystemMarkupMarkdown - s.T().Run("event list ok - label", func(t *testing.T) { - fxt := tf.NewTestFixture(t, s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1), tf.Labels(2)) - svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) - eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) - wiCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) - - u := app.UpdateWorkitemPayload{ - Data: &app.WorkItem{ - ID: &fxt.WorkItems[0].ID, - Type: APIStringTypeWorkItem, - Attributes: map[string]interface{}{ - workitem.SystemVersion: fxt.WorkItems[0].Version, - }, - Relationships: &app.WorkItemRelationships{}, - }, - } - // attach 2 labels - apiLabelType := label.APIStringTypeLabels - lbl0 := fxt.Labels[0].ID.String() - lbl1 := fxt.Labels[1].ID.String() - u.Data.Relationships.Labels = &app.RelationGenericList{ - Data: []*app.GenericData{ - { - ID: &lbl0, - Type: &apiLabelType, - }, - { - ID: &lbl1, - Type: &apiLabelType, - }, - }, - } - _, updatedWI := test.UpdateWorkitemOK(t, svc.Context, svc, wiCtrl, fxt.WorkItems[0].ID, &u) - assert.NotNil(t, updatedWI) - require.NotNil(t, updatedWI.Data.Relationships.Labels.Links) - assert.Len(t, updatedWI.Data.Relationships.Labels.Data, 2) - - res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) - safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") - require.NotEmpty(t, eventList) - require.Len(t, eventList.Data, 1) - compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-labels.res.payload.golden.json"), eventList) - compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-labels.res.headers.golden.json"), res.Header()) - }) + // payload := app.UpdateWorkitemPayload{ + // Data: &app.WorkItem{ + // Type: APIStringTypeWorkItem, + // ID: &fxt.WorkItems[0].ID, + // Attributes: map[string]interface{}{ + // workitem.SystemDescription: modifiedDescription, + // workitem.SystemDescriptionRendered: modifiedRenderedDescription, + // workitem.SystemDescriptionMarkup: modifiedMarkup, + // workitem.SystemVersion: fxt.WorkItems[0].Version, + // }, + // Relationships: &app.WorkItemRelationships{ + // Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), + // }, + // }, + // } + // test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) + // res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) + // safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") + // require.NotEmpty(t, eventList) + // require.Len(t, eventList.Data, 1) + // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-description.res.payload.golden.json"), eventList) + // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-description.res.headers.golden.json"), res.Header()) + // }) - s.T().Run("event list ok - iteration", func(t *testing.T) { - fxt := tf.NewTestFixture(s.T(), s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1)) - svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) - eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) - workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) - spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) - payload := app.UpdateWorkitemPayload{ - Data: &app.WorkItem{ - Type: APIStringTypeWorkItem, - ID: &fxt.WorkItems[0].ID, - Attributes: map[string]interface{}{ - workitem.SystemIteration: fxt.Iterations[0].ID.String(), - workitem.SystemVersion: fxt.WorkItems[0].Version, - }, - Relationships: &app.WorkItemRelationships{ - Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), - }, - }, - } - test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) - res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) - safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") - require.NotEmpty(t, eventList) - require.Len(t, eventList.Data, 1) - compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-iteration.res.payload.golden.json"), eventList) - compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-iteration.res.headers.golden.json"), res.Header()) - }) + // s.T().Run("event list ok - assigned", func(t *testing.T) { + // fxt := tf.NewTestFixture(t, s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1)) + // svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) + // eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) + // assignee := []string{fxt.Identities[0].ID.String()} + // workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) + // spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) + // payload := app.UpdateWorkitemPayload{ + // Data: &app.WorkItem{ + // Type: APIStringTypeWorkItem, + // ID: &fxt.WorkItems[0].ID, + // Attributes: map[string]interface{}{ + // workitem.SystemAssignees: assignee, + // workitem.SystemVersion: fxt.WorkItems[0].Version, + // }, + // Relationships: &app.WorkItemRelationships{ + // Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), + // }, + // }, + // } + // test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) + // res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) + // safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") + // require.NotEmpty(t, eventList) + // require.Len(t, eventList.Data, 1) + // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-assignees.res.payload.golden.json"), eventList) + // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-assignees.res.headers.golden.json"), res.Header()) + // }) - s.T().Run("event list ok - area", func(t *testing.T) { - fxt := tf.NewTestFixture(s.T(), s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1)) - svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) - eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) - workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) - spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) - payload := app.UpdateWorkitemPayload{ - Data: &app.WorkItem{ - Type: APIStringTypeWorkItem, - ID: &fxt.WorkItems[0].ID, - Attributes: map[string]interface{}{ - workitem.SystemArea: fxt.Areas[0].ID.String(), - workitem.SystemVersion: fxt.WorkItems[0].Version, - }, - Relationships: &app.WorkItemRelationships{ - Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), - }, - }, - } - test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) - res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) - safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") - require.NotEmpty(t, eventList) - require.Len(t, eventList.Data, 1) - compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-area.res.payload.golden.json"), eventList) - compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-area.res.headers.golden.json"), res.Header()) - }) + // s.T().Run("event list ok - label", func(t *testing.T) { + // fxt := tf.NewTestFixture(t, s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1), tf.Labels(2)) + // svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) + // eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) + // wiCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) - s.T().Run("event list - empty", func(t *testing.T) { - fxt := tf.NewTestFixture(s.T(), s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1)) - svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) - eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) - res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) - safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") - compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-no-event.res.errors.payload.golden.json"), eventList) - compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-no-event.res.errors.headers.golden.json"), res.Header()) - }) + // u := app.UpdateWorkitemPayload{ + // Data: &app.WorkItem{ + // ID: &fxt.WorkItems[0].ID, + // Type: APIStringTypeWorkItem, + // Attributes: map[string]interface{}{ + // workitem.SystemVersion: fxt.WorkItems[0].Version, + // }, + // Relationships: &app.WorkItemRelationships{}, + // }, + // } + // // attach 2 labels + // apiLabelType := label.APIStringTypeLabels + // lbl0 := fxt.Labels[0].ID.String() + // lbl1 := fxt.Labels[1].ID.String() + // u.Data.Relationships.Labels = &app.RelationGenericList{ + // Data: []*app.GenericData{ + // { + // ID: &lbl0, + // Type: &apiLabelType, + // }, + // { + // ID: &lbl1, + // Type: &apiLabelType, + // }, + // }, + // } + // _, updatedWI := test.UpdateWorkitemOK(t, svc.Context, svc, wiCtrl, fxt.WorkItems[0].ID, &u) + // assert.NotNil(t, updatedWI) + // require.NotNil(t, updatedWI.Data.Relationships.Labels.Links) + // assert.Len(t, updatedWI.Data.Relationships.Labels.Data, 2) - s.T().Run("many events", func(t *testing.T) { - fxt := tf.NewTestFixture(s.T(), s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1), tf.Iterations(2)) - svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) - eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) - workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) - spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) - payload1 := app.UpdateWorkitemPayload{ - Data: &app.WorkItem{ - Type: APIStringTypeWorkItem, - ID: &fxt.WorkItems[0].ID, - Attributes: map[string]interface{}{ - workitem.SystemIteration: fxt.Iterations[0].ID.String(), - workitem.SystemVersion: fxt.WorkItems[0].Version, - }, - Relationships: &app.WorkItemRelationships{ - Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), - }, - }, - } - test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload1) // update iteration - res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) - safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") - require.NotEmpty(t, eventList) - require.Len(t, eventList.Data, 1) - - assignee := []string{fxt.Identities[0].ID.String()} - payload2 := app.UpdateWorkitemPayload{ - Data: &app.WorkItem{ - Type: APIStringTypeWorkItem, - ID: &fxt.WorkItems[0].ID, - Attributes: map[string]interface{}{ - workitem.SystemAssignees: assignee, - workitem.SystemVersion: fxt.WorkItems[0].Version + 1, - }, - Relationships: &app.WorkItemRelationships{ - Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), - }, - }, - } - test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload2) // update assignee - res, eventList = test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) - require.NotEmpty(t, eventList) - require.Len(t, eventList.Data, 2) - - payload3 := app.UpdateWorkitemPayload{ - Data: &app.WorkItem{ - Type: APIStringTypeWorkItem, - ID: &fxt.WorkItems[0].ID, - Attributes: map[string]interface{}{ - workitem.SystemIteration: fxt.Iterations[1].ID.String(), - workitem.SystemVersion: fxt.WorkItems[0].Version + 2, - }, - Relationships: &app.WorkItemRelationships{ - Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), - }, - }, + // res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) + // safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") + // require.NotEmpty(t, eventList) + // require.Len(t, eventList.Data, 1) + // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-labels.res.payload.golden.json"), eventList) + // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-labels.res.headers.golden.json"), res.Header()) + // }) + + // s.T().Run("event list ok - iteration", func(t *testing.T) { + // fxt := tf.NewTestFixture(t, s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1)) + // svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) + // eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) + // workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) + // spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) + // payload := app.UpdateWorkitemPayload{ + // Data: &app.WorkItem{ + // Type: APIStringTypeWorkItem, + // ID: &fxt.WorkItems[0].ID, + // Attributes: map[string]interface{}{ + // workitem.SystemIteration: fxt.Iterations[0].ID.String(), + // workitem.SystemVersion: fxt.WorkItems[0].Version, + // }, + // Relationships: &app.WorkItemRelationships{ + // Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), + // }, + // }, + // } + // test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) + // res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) + // safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") + // require.NotEmpty(t, eventList) + // require.Len(t, eventList.Data, 1) + // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-iteration.res.payload.golden.json"), eventList) + // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-iteration.res.headers.golden.json"), res.Header()) + // }) + + // s.T().Run("event list ok - area", func(t *testing.T) { + // fxt := tf.NewTestFixture(t, s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1)) + // svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) + // eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) + // workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) + // spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) + // payload := app.UpdateWorkitemPayload{ + // Data: &app.WorkItem{ + // Type: APIStringTypeWorkItem, + // ID: &fxt.WorkItems[0].ID, + // Attributes: map[string]interface{}{ + // workitem.SystemArea: fxt.Areas[0].ID.String(), + // workitem.SystemVersion: fxt.WorkItems[0].Version, + // }, + // Relationships: &app.WorkItemRelationships{ + // Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), + // }, + // }, + // } + // test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) + // res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) + // safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") + // require.NotEmpty(t, eventList) + // require.Len(t, eventList.Data, 1) + // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-area.res.payload.golden.json"), eventList) + // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-area.res.headers.golden.json"), res.Header()) + // }) + + // s.T().Run("event list - empty", func(t *testing.T) { + // fxt := tf.NewTestFixture(t, s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1)) + // svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) + // eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) + // res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) + // safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") + // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-no-event.res.errors.payload.golden.json"), eventList) + // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-no-event.res.errors.headers.golden.json"), res.Header()) + // }) + + // s.T().Run("many events", func(t *testing.T) { + // fxt := tf.NewTestFixture(t, s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1), tf.Iterations(2)) + // svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) + // eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) + // workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) + // spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) + // payload1 := app.UpdateWorkitemPayload{ + // Data: &app.WorkItem{ + // Type: APIStringTypeWorkItem, + // ID: &fxt.WorkItems[0].ID, + // Attributes: map[string]interface{}{ + // workitem.SystemIteration: fxt.Iterations[0].ID.String(), + // workitem.SystemVersion: fxt.WorkItems[0].Version, + // }, + // Relationships: &app.WorkItemRelationships{ + // Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), + // }, + // }, + // } + // test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload1) // update iteration + // res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) + // safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") + // require.NotEmpty(t, eventList) + // require.Len(t, eventList.Data, 1) + + // assignee := []string{fxt.Identities[0].ID.String()} + // payload2 := app.UpdateWorkitemPayload{ + // Data: &app.WorkItem{ + // Type: APIStringTypeWorkItem, + // ID: &fxt.WorkItems[0].ID, + // Attributes: map[string]interface{}{ + // workitem.SystemAssignees: assignee, + // workitem.SystemVersion: fxt.WorkItems[0].Version + 1, + // }, + // Relationships: &app.WorkItemRelationships{ + // Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), + // }, + // }, + // } + // test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload2) // update assignee + // res, eventList = test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) + // require.NotEmpty(t, eventList) + // require.Len(t, eventList.Data, 2) + + // payload3 := app.UpdateWorkitemPayload{ + // Data: &app.WorkItem{ + // Type: APIStringTypeWorkItem, + // ID: &fxt.WorkItems[0].ID, + // Attributes: map[string]interface{}{ + // workitem.SystemIteration: fxt.Iterations[1].ID.String(), + // workitem.SystemVersion: fxt.WorkItems[0].Version + 2, + // }, + // Relationships: &app.WorkItemRelationships{ + // Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), + // }, + // }, + // } + // test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload3) // update iteration + // res, eventList = test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) + // safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") + // require.NotEmpty(t, eventList) + // require.Len(t, eventList.Data, 3) + // }) + + s.T().Run("non-relational field kinds", func(t *testing.T) { + testData := workitem.GetFieldTypeTestData(t) + for _, kind := range testData.GetKinds() { + if !kind.IsSimpleType() || kind.IsRelational() { + continue + } + + // TODO(kwk): Once we got rid of the duration kind remove this skip + if kind == workitem.KindDuration { + continue + } + + // TODO(kwk): Once the new type system enhancements are in, also + // test instant fields + if kind == workitem.KindInstant { + continue + } + + fieldNameSingle := kind.String() + "_single" + fieldNameList := kind.String() + "_list" + // fieldNameEnum := kind.String() + "_enum" + + fxt := tf.NewTestFixture(t, s.DB, + tf.CreateWorkItemEnvironment(), + tf.WorkItems(1), + tf.WorkItemTypes(1, func(fxt *tf.TestFixture, idx int) error { + fxt.WorkItemTypes[idx].Fields[fieldNameSingle] = workitem.FieldDefinition{ + Label: fieldNameSingle, + Description: "A single value of a " + kind.String() + " object", + Type: workitem.SimpleType{Kind: kind}, + } + fxt.WorkItemTypes[idx].Fields[fieldNameList] = workitem.FieldDefinition{ + Label: fieldNameList, + Description: "An array of " + kind.String() + " objects", + Type: workitem.ListType{ + SimpleType: workitem.SimpleType{Kind: workitem.KindList}, + ComponentType: workitem.SimpleType{Kind: kind}, + }, + } + // fxt.WorkItemTypes[idx].Fields[fieldNameEnum] = workitem.FieldDefinition{ + // Label: fieldNameEnum, + // Description: "An enum value of a " + kind.String() + " object", + // Type: workitem.EnumType{ + // SimpleType: workitem.SimpleType{Kind: workitem.KindEnum}, + // BaseType: workitem.SimpleType{Kind: kind}, + // Values: []interface{}{ + // testData[kind].Valid[0], + // testData[kind].Valid[1], + // }, + // }, + // } + return nil + }), + ) + svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) + eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) + workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) + spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) + + t.Run(fieldNameSingle, func(t *testing.T) { + // NOTE(kwk): Leave this commented out until we have proper test data + // fieldDef := fxt.WorkItemTypes[0].Fields[fieldNameSingle] + // val, err := fieldDef.ConvertFromModel(fieldNameSingle, testData[kind].Valid[0]) + // require.NoError(t, err) + newValue := testData[kind].Valid[0] + payload := app.UpdateWorkitemPayload{ + Data: &app.WorkItem{ + Type: APIStringTypeWorkItem, + ID: &fxt.WorkItems[0].ID, + Attributes: map[string]interface{}{ + fieldNameSingle: newValue, + workitem.SystemVersion: fxt.WorkItems[0].Version, + }, + Relationships: &app.WorkItemRelationships{ + Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), + }, + }, + } + test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) + res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) + safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") + require.NotEmpty(t, eventList) + require.Len(t, eventList.Data, 1) + compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok."+fieldNameSingle+".res.payload.golden.json"), eventList) + // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok."+fieldNameSingle+".res.headers.golden.json"), res.Header()) + }) + t.Run(fieldNameList, func(t *testing.T) { + // NOTE(kwk): Leave this commented out until we have proper test data + // listDef := fxt.WorkItemTypes[0].Fields[fieldNameList] + // fieldDef, ok := listDef.Type.(workitem.ListType) + // require.True(t, ok, "failed to cast %+v (%[1]T) to workitem.ListType", listDef) + // vals, err := fieldDef.ConvertFromModel([]interface{}{testData[kind].Valid[0], testData[kind].Valid[1]}) + // require.NoError(t, err) + newValue := []interface{}{testData[kind].Valid[0], testData[kind].Valid[1]} + payload := app.UpdateWorkitemPayload{ + Data: &app.WorkItem{ + Type: APIStringTypeWorkItem, + ID: &fxt.WorkItems[0].ID, + Attributes: map[string]interface{}{ + fieldNameList: newValue, + workitem.SystemVersion: fxt.WorkItems[0].Version + 1, + }, + Relationships: &app.WorkItemRelationships{ + Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), + }, + }, + } + test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) + res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) + safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") + require.NotEmpty(t, eventList) + require.Len(t, eventList.Data, 2) + compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok."+fieldNameList+".res.payload.golden.json"), eventList) + // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok."+fieldNameList+".res.headers.golden.json"), res.Header()) + }) + + // TODO(kwk): Once the new type system enhancements are in, also + // test for enum fields here. + + // t.Run(fieldNameEnum, func(t *testing.T) { + // // NOTE(kwk): Leave this commented out until we have proper test data + // // listDef := fxt.WorkItemTypes[0].Fields[fieldNameEnum] + // // fieldDef, ok := listDef.Type.(workitem.EnumType) + // // require.True(t, ok, "failed to cast %+v (%[1]T) to workitem.EnumType", listDef) + // // val, err := fieldDef.ConvertFromModel(testData[kind].Valid[0]) + // // require.NoError(t, err) + + // // we have to use the second value because we default to the + // // first one upon creation of the work item. + // newValue := testData[kind].Valid[1] + // payload := app.UpdateWorkitemPayload{ + // Data: &app.WorkItem{ + // Type: APIStringTypeWorkItem, + // ID: &fxt.WorkItems[0].ID, + // Attributes: map[string]interface{}{ + // fieldNameEnum: newValue, + // workitem.SystemVersion: fxt.WorkItems[0].Version + 2, + // }, + // Relationships: &app.WorkItemRelationships{ + // Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), + // }, + // }, + // } + // test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) + // res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) + // safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") + // require.NotEmpty(t, eventList) + // require.Len(t, eventList.Data, 3) + // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok."+fieldNameEnum+".res.payload.golden.json"), eventList) + // // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok."+fieldNameEnum+".res.headers.golden.json"), res.Header()) + // }) } - test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload3) // update iteration - res, eventList = test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) - safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") - require.NotEmpty(t, eventList) - require.Len(t, eventList.Data, 3) }) } diff --git a/design/work_item_event.go b/design/work_item_event.go index 0cee367212..6d26bb4a2f 100644 --- a/design/work_item_event.go +++ b/design/work_item_event.go @@ -13,9 +13,7 @@ var event = a.Type("Event", func() { a.Attribute("id", d.UUID, "ID of event", func() { a.Example("40bbdd3d-8b5d-4fd6-ac90-7236b669af04") }) - a.Attribute("attributes", a.HashOf(d.String, d.Any), func() { - a.Example(map[string]interface{}{"version": "1", "system.state": "new", "system.title": "Example story"}) - }) + a.Attribute("attributes", eventAttributes) a.Attribute("relationships", eventRelationships) a.Attribute("links", genericLinks) a.Required("type") @@ -27,7 +25,10 @@ var eventAttributes = a.Type("EventAttributes", func() { a.Example("2016-11-29T23:18:14Z") }) a.Attribute("name", d.String, "The name of the event occured", func() { - a.Example("closed") + a.Example("system.title") + }) + a.Attribute("workItemTypeID", d.UUID, "The type ID of the work item at given point in history", func() { + a.Example("ae753d1a-4625-4c84-baf8-0fc99a189df9") }) a.Attribute("oldValue", d.Any, "The user who was assigned to (or unassigned from). Only for 'assigned' and 'unassigned' events.", func() { a.Example("813a456e-1c8a-48df-ac15-84065ee039f7") diff --git a/workitem/enum_type.go b/workitem/enum_type.go index ac995e01b1..525279e05f 100644 --- a/workitem/enum_type.go +++ b/workitem/enum_type.go @@ -63,7 +63,7 @@ func (t EnumType) ConvertToModel(value interface{}) (interface{}, error) { } if !contains(t.Values, converted) { - return nil, fmt.Errorf("not an enum value: %v", value) + return nil, fmt.Errorf("value: %+v (%[1]T) is not part of allowed enum values: %+v", value, t.Values) } return converted, nil } diff --git a/workitem/event/event.go b/workitem/event/event.go index 57bfee74d0..546f12fb0a 100644 --- a/workitem/event/event.go +++ b/workitem/event/event.go @@ -8,12 +8,13 @@ import ( // Event represents work item event type Event struct { - ID uuid.UUID - Name string - Timestamp time.Time - Modifier uuid.UUID - Old interface{} - New interface{} + ID uuid.UUID + Name string + WorkItemTypeID uuid.UUID + Timestamp time.Time + Modifier uuid.UUID + Old interface{} + New interface{} } // GetETagData returns the field values to use to generate the ETag diff --git a/workitem/event/event_repository.go b/workitem/event/event_repository.go index 8a857ea23a..b5996250b8 100644 --- a/workitem/event/event_repository.go +++ b/workitem/event/event_repository.go @@ -51,13 +51,8 @@ func (r *GormEventRepository) List(ctx context.Context, wiID uuid.UUID) ([]Event if revisionList == nil { return []Event{}, nil } - wi, err := r.workItemRepo.LoadByID(ctx, wiID) - if err != nil { - return nil, errs.Wrapf(err, "failed to load work item: %s", wiID) - } - wiType, err := r.workItemTypeRepo.Load(ctx, wi.Type) - if err != nil { - return nil, errs.Wrapf(err, "failed to load work item type: %s", wiType) + if err = r.workItemRepo.CheckExists(ctx, wiID); err != nil { + return nil, errs.Wrapf(err, "failed to find work item: %s", wiID) } eventList := []Event{} @@ -66,23 +61,38 @@ func (r *GormEventRepository) List(ctx context.Context, wiID uuid.UUID) ([]Event oldRev := revisionList[k-1] newRev := revisionList[k] + // If the new and old work item type are different, we're skipping this + // revision because it denotes the change of a work item type. + // + // TODO(kwk): make sure we have a proper "changed work item type" + // revision entry in one way or another. + if oldRev.WorkItemTypeID != newRev.WorkItemTypeID { + continue + } + + wit, err := r.workItemTypeRepo.Load(ctx, oldRev.WorkItemTypeID) + if err != nil { + return nil, errs.Wrapf(err, "failed to load old work item type: %s", oldRev.WorkItemTypeID) + } + modifierID, err := r.identityRepo.Load(ctx, newRev.ModifierIdentity) if err != nil { return nil, errs.Wrapf(err, "failed to load modifier identity %s", newRev.ModifierIdentity) } - for fieldName, fieldDef := range wiType.Fields { + for fieldName, fieldDef := range wit.Fields { oldVal := oldRev.WorkItemFields[fieldName] newVal := newRev.WorkItemFields[fieldName] event := Event{ - ID: revisionList[k].ID, - Name: fieldName, - Timestamp: revisionList[k].Time, - Modifier: modifierID.ID, - Old: oldVal, - New: newVal, + ID: newRev.ID, + Name: fieldName, + WorkItemTypeID: newRev.WorkItemTypeID, + Timestamp: newRev.Time, + Modifier: modifierID.ID, + Old: oldVal, + New: newVal, } // The enum type can be handled by the simple type since it's just a @@ -133,16 +143,7 @@ func (r *GormEventRepository) List(ctx context.Context, wiID uuid.UUID) ([]Event eventList = append(eventList, event) } case workitem.SimpleType: - switch fieldType.GetKind() { - case workitem.KindString, - workitem.KindFloat, - workitem.KindInteger, - workitem.KindIteration, - workitem.KindBoardColumn, - workitem.KindArea, - workitem.KindLabel, - workitem.KindMarkup: - + if !fieldType.GetKind().IsRelational() { // compensate conversion from storage if this really was an enum field converter := fieldType.ConvertFromModel if isEnumType { diff --git a/workitem/field_definition.go b/workitem/field_definition.go index 94576a9e63..413e2cc0b6 100644 --- a/workitem/field_definition.go +++ b/workitem/field_definition.go @@ -13,22 +13,25 @@ import ( // constants for describing possible field types const ( - KindString Kind = "string" - KindInteger Kind = "integer" - KindFloat Kind = "float" - KindBoolean Kind = "bool" - KindInstant Kind = "instant" - KindDuration Kind = "duration" - KindURL Kind = "url" + // non-relational + KindString Kind = "string" + KindInteger Kind = "integer" + KindFloat Kind = "float" + KindBoolean Kind = "bool" + KindInstant Kind = "instant" + KindDuration Kind = "duration" + KindURL Kind = "url" + KindMarkup Kind = "markup" + // relational KindIteration Kind = "iteration" KindUser Kind = "user" KindLabel Kind = "label" KindBoardColumn Kind = "boardcolumn" - KindEnum Kind = "enum" - KindList Kind = "list" - KindMarkup Kind = "markup" KindArea Kind = "area" KindCodebase Kind = "codebase" + // composite + KindEnum Kind = "enum" + KindList Kind = "list" ) // Kind is the kind of field type @@ -39,6 +42,21 @@ func (k Kind) IsSimpleType() bool { return k != KindEnum && k != KindList } +// IsRelational returns 'true' if the kind must be represented with a +// relationship. +func (k Kind) IsRelational() bool { + switch k { + case KindIteration, + KindUser, + KindLabel, + KindBoardColumn, + KindArea, + KindCodebase: + return true + } + return false +} + // String implements the Stringer interface and returns the kind as a string // object. func (k Kind) String() string { diff --git a/workitem/field_definition_blackbox_test.go b/workitem/field_definition_blackbox_test.go index 926736176b..b582c0e126 100644 --- a/workitem/field_definition_blackbox_test.go +++ b/workitem/field_definition_blackbox_test.go @@ -7,6 +7,8 @@ import ( "github.com/fabric8-services/fabric8-wit/resource" "github.com/fabric8-services/fabric8-wit/workitem" + uuid "github.com/satori/go.uuid" + "github.com/stretchr/testify/require" ) func testFieldDefinitionMarshalUnmarshal(t *testing.T, def workitem.FieldDefinition) { @@ -74,3 +76,24 @@ func TestFieldDefinition_Marshalling(t *testing.T) { testFieldDefinitionMarshalUnmarshal(t, def) }) } + +func TestFieldDefinition_IsRelational(t *testing.T) { + // relational kinds + require.True(t, workitem.KindLabel.IsRelational()) + require.True(t, workitem.KindArea.IsRelational()) + require.True(t, workitem.KindIteration.IsRelational()) + require.True(t, workitem.KindBoardColumn.IsRelational()) + require.True(t, workitem.KindUser.IsRelational()) + require.True(t, workitem.KindCodebase.IsRelational()) + // composite kinds + require.False(t, workitem.KindList.IsRelational()) + require.False(t, workitem.KindEnum.IsRelational()) + // non-relational kinds + require.False(t, workitem.KindString.IsRelational()) + require.False(t, workitem.KindInteger.IsRelational()) + require.False(t, workitem.KindInstant.IsRelational()) + require.False(t, workitem.KindFloat.IsRelational()) + require.False(t, workitem.KindBoolean.IsRelational()) + // random + require.False(t, workitem.Kind(uuid.NewV4().String()).IsRelational()) +} diff --git a/workitem/field_test_data.go b/workitem/field_test_data.go index 7d29dc278f..b0fb097ff7 100644 --- a/workitem/field_test_data.go +++ b/workitem/field_test_data.go @@ -161,7 +161,7 @@ func GetFieldTypeTestData(t *testing.T) FieldTypeTestDataMap { return int(v) }, Valid: []interface{}{ - 0, + int(0), 333, -100, }, diff --git a/workitem/simple_type.go b/workitem/simple_type.go index a7b45b2424..419a3ed321 100644 --- a/workitem/simple_type.go +++ b/workitem/simple_type.go @@ -55,34 +55,47 @@ func (t SimpleType) ConvertToModel(value interface{}) (interface{}, error) { switch t.GetKind() { case KindString, KindUser, KindIteration, KindArea, KindLabel, KindBoardColumn: if valueType.Kind() != reflect.String { - return nil, errs.Errorf("value %v should be %s, but is %s", value, "string", valueType.Name()) + return nil, errs.Errorf("value %v (%[1]T) should be %s, but is %s", value, "string", valueType.Name()) } return value, nil case KindURL: if valueType.Kind() == reflect.String && govalidator.IsURL(value.(string)) { return value, nil } - return nil, errs.Errorf("value %v should be %s, but is %s", value, "URL", valueType.Name()) + return nil, errs.Errorf("value %v (%[1]T) should be %s, but is \"%s\"", value, "URL", valueType.Name()) case KindFloat: if valueType.Kind() != reflect.Float64 { - return nil, errs.Errorf("value %v should be %s, but is %s", value, "float64", valueType.Name()) + return nil, errs.Errorf("value %v (%[1]T) should be %s, but is \"%s\"", value, "float64", valueType.Name()) } return value, nil case KindInteger, KindDuration: // NOTE: Duration is a typedef of int64 - if valueType.Kind() != reflect.Int && valueType.Kind() != reflect.Int64 { - return nil, errs.Errorf("value %v should be %s, but is %s", value, "int", valueType.Name()) + // NOTE(kwk): This will change soon to be more consistent. + switch valueType.Kind() { + case reflect.Int, + reflect.Int64: + return value, nil + case reflect.Float64: + fval, ok := value.(float64) + if !ok { + return nil, errs.Errorf("failed to cast value %+v (%[1]T) to float64", value) + } + if fval != math.Trunc(fval) { + return nil, errs.Errorf("float64 value %+v (%[1]T) has digits after the decimal point and therefore cannot be represented by an integer", value, valueType.Name()) + } + return int(fval), nil + default: + return nil, errs.Errorf("value %v (%[1]T) should be %s, but is %s ", value, "int", valueType.Name()) } - return value, nil case KindInstant: // instant == milliseconds // if !valueType.Implements(timeType) { if valueType.Kind() != timeType.Kind() { - return nil, errs.Errorf("value %v should be %s, but is %s", value, "time.Time", valueType.Name()) + return nil, errs.Errorf("value %v (%[1]T) should be %s, but is %s", value, "time.Time", valueType.Name()) } return value.(time.Time).UnixNano(), nil case KindList: if (valueType.Kind() != reflect.Array) && (valueType.Kind() != reflect.Slice) { - return nil, errs.Errorf("value %v should be %s, but is %s,", value, "array/slice", valueType.Kind()) + return nil, errs.Errorf("value %v (%[1]T) should be %s, but is %s,", value, "array/slice", valueType.Kind()) } return value, nil case KindEnum: @@ -95,26 +108,26 @@ func (t SimpleType) ConvertToModel(value interface{}) (interface{}, error) { case rendering.MarkupContent: markupContent := value.(rendering.MarkupContent) if !rendering.IsMarkupSupported(markupContent.Markup) { - return nil, errs.Errorf("value %v (type %s) has no valid markup type %s", value, "MarkupContent", markupContent.Markup) + return nil, errs.Errorf("value %v (%[1]T) has no valid markup type %s", value, markupContent.Markup) } return markupContent.ToMap(), nil default: - return nil, errs.Errorf("value %v should be %s, but is %s", value, "MarkupContent", valueType) + return nil, errs.Errorf("value %v (%[1]T) should be rendering.MarkupContent, but is %s", value, valueType) } case KindCodebase: switch value.(type) { case codebase.Content: cb := value.(codebase.Content) if err := cb.IsValid(); err != nil { - return nil, errs.Wrapf(err, "value %v (type %s) is invalid %s", value, "Codebase", cb) + return nil, errs.Wrapf(err, "value %v (%[1]T) is invalid %s", value, cb) } return cb.ToMap(), nil default: - return nil, errs.Errorf("value %v should be %s, but is %s", value, "CodebaseContent", valueType) + return nil, errs.Errorf("value %v (%[1]T) should be %s, but is %s", value, "CodebaseContent", valueType) } case KindBoolean: if valueType.Kind() != reflect.Bool { - return nil, errs.Errorf("value %v should be %s, but is %s", value, "boolean", valueType.Name()) + return nil, errs.Errorf("value %v (%[1]T) should be %s, but is %s", value, "boolean", valueType.Name()) } return value, nil default: From cdb7a3955e6d96711fceb892c31cfca92a4a0c23 Mon Sep 17 00:00:00 2001 From: Konrad Kleine Date: Mon, 30 Jul 2018 17:19:46 +0200 Subject: [PATCH 07/10] Fix golden files --- ..._null_show_after_update_work_item.golden.json | 12 ------------ ...er_assignee_null_update_work_item.golden.json | 12 ------------ ..._null_show_after_update_work_item.golden.json | 12 ------------ ...ilter_label_null_update_work_item.golden.json | 12 ------------ ..._not_include_children.res.payload.golden.json | 8 -------- .../include_children.res.payload.golden.json | 16 ---------------- .../A_with_tree-view=false.res.golden.json | 4 ---- .../A_with_tree-view=true.res.golden.json | 4 ---- .../B,C_with_tree-view=false.res.golden.json | 8 -------- .../B,C_with_tree-view=true.res.golden.json | 12 ------------ .../B_with_tree-view=false.res.golden.json | 4 ---- .../B_with_tree-view=true.res.golden.json | 8 -------- .../C_with_tree-view=false.res.golden.json | 4 ---- .../C_with_tree-view=true.res.golden.json | 12 ------------ .../D_with_tree-view=false.res.golden.json | 4 ---- .../D_with_tree-view=true.res.golden.json | 8 -------- .../E_with_tree-view=false.res.golden.json | 4 ---- .../E_with_tree-view=true.res.golden.json | 4 ---- .../list_children/ok.res.payload.golden.json | 8 -------- .../show/ok.has_children.res.payload.golden.json | 4 ---- .../ok.has_no_children.res.payload.golden.json | 4 ---- .../area/valid_sample_1.res.payload.golden.json | 4 ---- .../valid_sample_1.res.payload.golden.json | 4 ---- .../bool/valid_sample_1.res.payload.golden.json | 4 ---- .../valid_sample_1.res.payload.golden.json | 4 ---- .../valid_sample_1.res.payload.golden.json | 4 ---- .../valid_sample_2.res.payload.golden.json | 4 ---- .../float/valid_sample_1.res.payload.golden.json | 4 ---- .../float/valid_sample_2.res.payload.golden.json | 4 ---- .../valid_sample_1.res.payload.golden.json | 4 ---- .../valid_sample_1.res.payload.golden.json | 4 ---- .../valid_sample_2.res.payload.golden.json | 4 ---- .../valid_sample_1.res.payload.golden.json | 4 ---- .../valid_sample_2.res.payload.golden.json | 4 ---- .../label/valid_sample_1.res.payload.golden.json | 4 ---- .../label/valid_sample_2.res.payload.golden.json | 4 ---- .../valid_sample_1.res.payload.golden.json | 4 ---- .../valid_sample_2.res.payload.golden.json | 4 ---- .../valid_sample_1.res.payload.golden.json | 4 ---- .../url/valid_sample_1.res.payload.golden.json | 4 ---- .../url/valid_sample_2.res.payload.golden.json | 4 ---- .../url/valid_sample_3.res.payload.golden.json | 4 ---- .../user/valid_sample_1.res.payload.golden.json | 4 ---- .../user/valid_sample_2.res.payload.golden.json | 4 ---- .../create/ok.res.payload.golden.json | 8 -------- .../list/ok.res.paylpad.golden.json | 8 -------- .../show/ok.res.payload.golden.json | 8 -------- workitem/field_test_data.go | 2 +- 48 files changed, 1 insertion(+), 281 deletions(-) diff --git a/controller/test-files/search/show/filter_assignee_null_show_after_update_work_item.golden.json b/controller/test-files/search/show/filter_assignee_null_show_after_update_work_item.golden.json index c5c8cc4f58..0f94f28a11 100755 --- a/controller/test-files/search/show/filter_assignee_null_show_after_update_work_item.golden.json +++ b/controller/test-files/search/show/filter_assignee_null_show_after_update_work_item.golden.json @@ -20,10 +20,6 @@ "area": { "data": { "id": "00000000-0000-0000-0000-000000000002", - "links": { - "related": "http:///api/areas/00000000-0000-0000-0000-000000000002", - "self": "http:///api/areas/00000000-0000-0000-0000-000000000002" - }, "type": "areas" } }, @@ -54,10 +50,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000004", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000004", - "self": "http:///api/users/00000000-0000-0000-0000-000000000004" - }, "type": "users" } }, @@ -69,10 +61,6 @@ "iteration": { "data": { "id": "00000000-0000-0000-0000-000000000005", - "links": { - "related": "http:///api/iterations/00000000-0000-0000-0000-000000000005", - "self": "http:///api/iterations/00000000-0000-0000-0000-000000000005" - }, "type": "iterations" } }, diff --git a/controller/test-files/search/show/filter_assignee_null_update_work_item.golden.json b/controller/test-files/search/show/filter_assignee_null_update_work_item.golden.json index c5c8cc4f58..0f94f28a11 100755 --- a/controller/test-files/search/show/filter_assignee_null_update_work_item.golden.json +++ b/controller/test-files/search/show/filter_assignee_null_update_work_item.golden.json @@ -20,10 +20,6 @@ "area": { "data": { "id": "00000000-0000-0000-0000-000000000002", - "links": { - "related": "http:///api/areas/00000000-0000-0000-0000-000000000002", - "self": "http:///api/areas/00000000-0000-0000-0000-000000000002" - }, "type": "areas" } }, @@ -54,10 +50,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000004", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000004", - "self": "http:///api/users/00000000-0000-0000-0000-000000000004" - }, "type": "users" } }, @@ -69,10 +61,6 @@ "iteration": { "data": { "id": "00000000-0000-0000-0000-000000000005", - "links": { - "related": "http:///api/iterations/00000000-0000-0000-0000-000000000005", - "self": "http:///api/iterations/00000000-0000-0000-0000-000000000005" - }, "type": "iterations" } }, diff --git a/controller/test-files/search/show/filter_label_null_show_after_update_work_item.golden.json b/controller/test-files/search/show/filter_label_null_show_after_update_work_item.golden.json index c5c8cc4f58..0f94f28a11 100755 --- a/controller/test-files/search/show/filter_label_null_show_after_update_work_item.golden.json +++ b/controller/test-files/search/show/filter_label_null_show_after_update_work_item.golden.json @@ -20,10 +20,6 @@ "area": { "data": { "id": "00000000-0000-0000-0000-000000000002", - "links": { - "related": "http:///api/areas/00000000-0000-0000-0000-000000000002", - "self": "http:///api/areas/00000000-0000-0000-0000-000000000002" - }, "type": "areas" } }, @@ -54,10 +50,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000004", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000004", - "self": "http:///api/users/00000000-0000-0000-0000-000000000004" - }, "type": "users" } }, @@ -69,10 +61,6 @@ "iteration": { "data": { "id": "00000000-0000-0000-0000-000000000005", - "links": { - "related": "http:///api/iterations/00000000-0000-0000-0000-000000000005", - "self": "http:///api/iterations/00000000-0000-0000-0000-000000000005" - }, "type": "iterations" } }, diff --git a/controller/test-files/search/show/filter_label_null_update_work_item.golden.json b/controller/test-files/search/show/filter_label_null_update_work_item.golden.json index c5c8cc4f58..0f94f28a11 100755 --- a/controller/test-files/search/show/filter_label_null_update_work_item.golden.json +++ b/controller/test-files/search/show/filter_label_null_update_work_item.golden.json @@ -20,10 +20,6 @@ "area": { "data": { "id": "00000000-0000-0000-0000-000000000002", - "links": { - "related": "http:///api/areas/00000000-0000-0000-0000-000000000002", - "self": "http:///api/areas/00000000-0000-0000-0000-000000000002" - }, "type": "areas" } }, @@ -54,10 +50,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000004", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000004", - "self": "http:///api/users/00000000-0000-0000-0000-000000000004" - }, "type": "users" } }, @@ -69,10 +61,6 @@ "iteration": { "data": { "id": "00000000-0000-0000-0000-000000000005", - "links": { - "related": "http:///api/iterations/00000000-0000-0000-0000-000000000005", - "self": "http:///api/iterations/00000000-0000-0000-0000-000000000005" - }, "type": "iterations" } }, diff --git a/controller/test-files/search/show/in_topology_A-B-C-D_and_B-E_search_for_B_and_C/do_not_include_children.res.payload.golden.json b/controller/test-files/search/show/in_topology_A-B-C-D_and_B-E_search_for_B_and_C/do_not_include_children.res.payload.golden.json index 2231c61939..8ec5248822 100755 --- a/controller/test-files/search/show/in_topology_A-B-C-D_and_B-E_search_for_B_and_C/do_not_include_children.res.payload.golden.json +++ b/controller/test-files/search/show/in_topology_A-B-C-D_and_B-E_search_for_B_and_C/do_not_include_children.res.payload.golden.json @@ -46,10 +46,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, @@ -130,10 +126,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, diff --git a/controller/test-files/search/show/in_topology_A-B-C-D_and_B-E_search_for_B_and_C/include_children.res.payload.golden.json b/controller/test-files/search/show/in_topology_A-B-C-D_and_B-E_search_for_B_and_C/include_children.res.payload.golden.json index 2449c691d4..46cece02b3 100755 --- a/controller/test-files/search/show/in_topology_A-B-C-D_and_B-E_search_for_B_and_C/include_children.res.payload.golden.json +++ b/controller/test-files/search/show/in_topology_A-B-C-D_and_B-E_search_for_B_and_C/include_children.res.payload.golden.json @@ -46,10 +46,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, @@ -135,10 +131,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, @@ -226,10 +218,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, @@ -310,10 +298,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, diff --git a/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/A_with_tree-view=false.res.golden.json b/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/A_with_tree-view=false.res.golden.json index 6d891e9842..e140b7c066 100755 --- a/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/A_with_tree-view=false.res.golden.json +++ b/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/A_with_tree-view=false.res.golden.json @@ -46,10 +46,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, diff --git a/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/A_with_tree-view=true.res.golden.json b/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/A_with_tree-view=true.res.golden.json index beb788fd16..8a2adc382a 100755 --- a/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/A_with_tree-view=true.res.golden.json +++ b/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/A_with_tree-view=true.res.golden.json @@ -46,10 +46,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, diff --git a/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/B,C_with_tree-view=false.res.golden.json b/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/B,C_with_tree-view=false.res.golden.json index 97e2c3d255..b1e5dd3330 100755 --- a/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/B,C_with_tree-view=false.res.golden.json +++ b/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/B,C_with_tree-view=false.res.golden.json @@ -46,10 +46,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, @@ -130,10 +126,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, diff --git a/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/B,C_with_tree-view=true.res.golden.json b/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/B,C_with_tree-view=true.res.golden.json index 73dd5bfbed..28533c8ba5 100755 --- a/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/B,C_with_tree-view=true.res.golden.json +++ b/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/B,C_with_tree-view=true.res.golden.json @@ -46,10 +46,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, @@ -135,10 +131,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, @@ -226,10 +218,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, diff --git a/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/B_with_tree-view=false.res.golden.json b/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/B_with_tree-view=false.res.golden.json index 2262d2c3d7..31839b3228 100755 --- a/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/B_with_tree-view=false.res.golden.json +++ b/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/B_with_tree-view=false.res.golden.json @@ -46,10 +46,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, diff --git a/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/B_with_tree-view=true.res.golden.json b/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/B_with_tree-view=true.res.golden.json index 2123bd27d3..27913a9118 100755 --- a/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/B_with_tree-view=true.res.golden.json +++ b/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/B_with_tree-view=true.res.golden.json @@ -46,10 +46,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, @@ -137,10 +133,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, diff --git a/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/C_with_tree-view=false.res.golden.json b/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/C_with_tree-view=false.res.golden.json index 5d71c3ea1c..4d770db022 100755 --- a/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/C_with_tree-view=false.res.golden.json +++ b/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/C_with_tree-view=false.res.golden.json @@ -46,10 +46,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, diff --git a/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/C_with_tree-view=true.res.golden.json b/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/C_with_tree-view=true.res.golden.json index 95f5c53737..d08eee1899 100755 --- a/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/C_with_tree-view=true.res.golden.json +++ b/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/C_with_tree-view=true.res.golden.json @@ -46,10 +46,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, @@ -137,10 +133,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, @@ -221,10 +213,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, diff --git a/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/D_with_tree-view=false.res.golden.json b/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/D_with_tree-view=false.res.golden.json index 1f3adc34d6..4c9bd0b98d 100755 --- a/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/D_with_tree-view=false.res.golden.json +++ b/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/D_with_tree-view=false.res.golden.json @@ -46,10 +46,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, diff --git a/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/D_with_tree-view=true.res.golden.json b/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/D_with_tree-view=true.res.golden.json index ceb54d0a8c..906943c967 100755 --- a/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/D_with_tree-view=true.res.golden.json +++ b/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/D_with_tree-view=true.res.golden.json @@ -46,10 +46,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, @@ -137,10 +133,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, diff --git a/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/E_with_tree-view=false.res.golden.json b/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/E_with_tree-view=false.res.golden.json index cceea0a1e9..ed02e3695b 100755 --- a/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/E_with_tree-view=false.res.golden.json +++ b/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/E_with_tree-view=false.res.golden.json @@ -46,10 +46,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, diff --git a/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/E_with_tree-view=true.res.golden.json b/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/E_with_tree-view=true.res.golden.json index 66d9d5d055..02a2312f27 100755 --- a/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/E_with_tree-view=true.res.golden.json +++ b/controller/test-files/search/show/in_topology_A-B-C_and_A-D_search_for/E_with_tree-view=true.res.golden.json @@ -46,10 +46,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, diff --git a/controller/test-files/work_item/list_children/ok.res.payload.golden.json b/controller/test-files/work_item/list_children/ok.res.payload.golden.json index 243d093a30..0cef7ae91d 100755 --- a/controller/test-files/work_item/list_children/ok.res.payload.golden.json +++ b/controller/test-files/work_item/list_children/ok.res.payload.golden.json @@ -46,10 +46,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, @@ -129,10 +125,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, diff --git a/controller/test-files/work_item/show/ok.has_children.res.payload.golden.json b/controller/test-files/work_item/show/ok.has_children.res.payload.golden.json index 18458b9eb2..da824209cc 100755 --- a/controller/test-files/work_item/show/ok.has_children.res.payload.golden.json +++ b/controller/test-files/work_item/show/ok.has_children.res.payload.golden.json @@ -48,10 +48,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, diff --git a/controller/test-files/work_item/show/ok.has_no_children.res.payload.golden.json b/controller/test-files/work_item/show/ok.has_no_children.res.payload.golden.json index 6e11fc54d8..8c959af44d 100755 --- a/controller/test-files/work_item/show/ok.has_no_children.res.payload.golden.json +++ b/controller/test-files/work_item/show/ok.has_no_children.res.payload.golden.json @@ -48,10 +48,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, diff --git a/controller/test-files/work_item/update/area/valid_sample_1.res.payload.golden.json b/controller/test-files/work_item/update/area/valid_sample_1.res.payload.golden.json index 50e423484b..77254fe7db 100755 --- a/controller/test-files/work_item/update/area/valid_sample_1.res.payload.golden.json +++ b/controller/test-files/work_item/update/area/valid_sample_1.res.payload.golden.json @@ -46,10 +46,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000004", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000004", - "self": "http:///api/users/00000000-0000-0000-0000-000000000004" - }, "type": "users" } }, diff --git a/controller/test-files/work_item/update/boardcolumn/valid_sample_1.res.payload.golden.json b/controller/test-files/work_item/update/boardcolumn/valid_sample_1.res.payload.golden.json index ec020c6674..53ae8e706a 100755 --- a/controller/test-files/work_item/update/boardcolumn/valid_sample_1.res.payload.golden.json +++ b/controller/test-files/work_item/update/boardcolumn/valid_sample_1.res.payload.golden.json @@ -46,10 +46,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000004", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000004", - "self": "http:///api/users/00000000-0000-0000-0000-000000000004" - }, "type": "users" } }, diff --git a/controller/test-files/work_item/update/bool/valid_sample_1.res.payload.golden.json b/controller/test-files/work_item/update/bool/valid_sample_1.res.payload.golden.json index 640a6ff42a..90638bb4b4 100755 --- a/controller/test-files/work_item/update/bool/valid_sample_1.res.payload.golden.json +++ b/controller/test-files/work_item/update/bool/valid_sample_1.res.payload.golden.json @@ -46,10 +46,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, diff --git a/controller/test-files/work_item/update/codebase/valid_sample_1.res.payload.golden.json b/controller/test-files/work_item/update/codebase/valid_sample_1.res.payload.golden.json index 99ce748823..e6ea9c8bf6 100755 --- a/controller/test-files/work_item/update/codebase/valid_sample_1.res.payload.golden.json +++ b/controller/test-files/work_item/update/codebase/valid_sample_1.res.payload.golden.json @@ -52,10 +52,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, diff --git a/controller/test-files/work_item/update/duration/valid_sample_1.res.payload.golden.json b/controller/test-files/work_item/update/duration/valid_sample_1.res.payload.golden.json index 491547f8a6..a614020082 100755 --- a/controller/test-files/work_item/update/duration/valid_sample_1.res.payload.golden.json +++ b/controller/test-files/work_item/update/duration/valid_sample_1.res.payload.golden.json @@ -46,10 +46,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, diff --git a/controller/test-files/work_item/update/duration/valid_sample_2.res.payload.golden.json b/controller/test-files/work_item/update/duration/valid_sample_2.res.payload.golden.json index 5535613b6c..06fb957517 100755 --- a/controller/test-files/work_item/update/duration/valid_sample_2.res.payload.golden.json +++ b/controller/test-files/work_item/update/duration/valid_sample_2.res.payload.golden.json @@ -46,10 +46,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, diff --git a/controller/test-files/work_item/update/float/valid_sample_1.res.payload.golden.json b/controller/test-files/work_item/update/float/valid_sample_1.res.payload.golden.json index 625215376f..2e85e87f3e 100755 --- a/controller/test-files/work_item/update/float/valid_sample_1.res.payload.golden.json +++ b/controller/test-files/work_item/update/float/valid_sample_1.res.payload.golden.json @@ -46,10 +46,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, diff --git a/controller/test-files/work_item/update/float/valid_sample_2.res.payload.golden.json b/controller/test-files/work_item/update/float/valid_sample_2.res.payload.golden.json index 70ea7455b6..e5f1e1b42f 100755 --- a/controller/test-files/work_item/update/float/valid_sample_2.res.payload.golden.json +++ b/controller/test-files/work_item/update/float/valid_sample_2.res.payload.golden.json @@ -46,10 +46,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, diff --git a/controller/test-files/work_item/update/instant/valid_sample_1.res.payload.golden.json b/controller/test-files/work_item/update/instant/valid_sample_1.res.payload.golden.json index e332e9d240..23f82aecd8 100755 --- a/controller/test-files/work_item/update/instant/valid_sample_1.res.payload.golden.json +++ b/controller/test-files/work_item/update/instant/valid_sample_1.res.payload.golden.json @@ -46,10 +46,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, diff --git a/controller/test-files/work_item/update/integer/valid_sample_1.res.payload.golden.json b/controller/test-files/work_item/update/integer/valid_sample_1.res.payload.golden.json index ebc45a4655..b6fe90991f 100755 --- a/controller/test-files/work_item/update/integer/valid_sample_1.res.payload.golden.json +++ b/controller/test-files/work_item/update/integer/valid_sample_1.res.payload.golden.json @@ -46,10 +46,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, diff --git a/controller/test-files/work_item/update/integer/valid_sample_2.res.payload.golden.json b/controller/test-files/work_item/update/integer/valid_sample_2.res.payload.golden.json index 47839e12ea..b9374a319d 100755 --- a/controller/test-files/work_item/update/integer/valid_sample_2.res.payload.golden.json +++ b/controller/test-files/work_item/update/integer/valid_sample_2.res.payload.golden.json @@ -46,10 +46,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, diff --git a/controller/test-files/work_item/update/iteration/valid_sample_1.res.payload.golden.json b/controller/test-files/work_item/update/iteration/valid_sample_1.res.payload.golden.json index ac46b4639d..ba857ca233 100755 --- a/controller/test-files/work_item/update/iteration/valid_sample_1.res.payload.golden.json +++ b/controller/test-files/work_item/update/iteration/valid_sample_1.res.payload.golden.json @@ -46,10 +46,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000004", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000004", - "self": "http:///api/users/00000000-0000-0000-0000-000000000004" - }, "type": "users" } }, diff --git a/controller/test-files/work_item/update/iteration/valid_sample_2.res.payload.golden.json b/controller/test-files/work_item/update/iteration/valid_sample_2.res.payload.golden.json index c819498a62..15f895476f 100755 --- a/controller/test-files/work_item/update/iteration/valid_sample_2.res.payload.golden.json +++ b/controller/test-files/work_item/update/iteration/valid_sample_2.res.payload.golden.json @@ -46,10 +46,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, diff --git a/controller/test-files/work_item/update/label/valid_sample_1.res.payload.golden.json b/controller/test-files/work_item/update/label/valid_sample_1.res.payload.golden.json index 458a9fbb69..ee4d82b9a5 100755 --- a/controller/test-files/work_item/update/label/valid_sample_1.res.payload.golden.json +++ b/controller/test-files/work_item/update/label/valid_sample_1.res.payload.golden.json @@ -46,10 +46,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000004", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000004", - "self": "http:///api/users/00000000-0000-0000-0000-000000000004" - }, "type": "users" } }, diff --git a/controller/test-files/work_item/update/label/valid_sample_2.res.payload.golden.json b/controller/test-files/work_item/update/label/valid_sample_2.res.payload.golden.json index 44f0236156..6042a0412a 100755 --- a/controller/test-files/work_item/update/label/valid_sample_2.res.payload.golden.json +++ b/controller/test-files/work_item/update/label/valid_sample_2.res.payload.golden.json @@ -46,10 +46,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, diff --git a/controller/test-files/work_item/update/markup/valid_sample_1.res.payload.golden.json b/controller/test-files/work_item/update/markup/valid_sample_1.res.payload.golden.json index 9d2ff5f608..c834c656eb 100755 --- a/controller/test-files/work_item/update/markup/valid_sample_1.res.payload.golden.json +++ b/controller/test-files/work_item/update/markup/valid_sample_1.res.payload.golden.json @@ -49,10 +49,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, diff --git a/controller/test-files/work_item/update/markup/valid_sample_2.res.payload.golden.json b/controller/test-files/work_item/update/markup/valid_sample_2.res.payload.golden.json index ffd4d99b20..6a4f2cfdab 100755 --- a/controller/test-files/work_item/update/markup/valid_sample_2.res.payload.golden.json +++ b/controller/test-files/work_item/update/markup/valid_sample_2.res.payload.golden.json @@ -49,10 +49,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, diff --git a/controller/test-files/work_item/update/string/valid_sample_1.res.payload.golden.json b/controller/test-files/work_item/update/string/valid_sample_1.res.payload.golden.json index b427e66618..2822618238 100755 --- a/controller/test-files/work_item/update/string/valid_sample_1.res.payload.golden.json +++ b/controller/test-files/work_item/update/string/valid_sample_1.res.payload.golden.json @@ -46,10 +46,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, diff --git a/controller/test-files/work_item/update/url/valid_sample_1.res.payload.golden.json b/controller/test-files/work_item/update/url/valid_sample_1.res.payload.golden.json index 1722f304d0..5d0392a335 100755 --- a/controller/test-files/work_item/update/url/valid_sample_1.res.payload.golden.json +++ b/controller/test-files/work_item/update/url/valid_sample_1.res.payload.golden.json @@ -46,10 +46,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, diff --git a/controller/test-files/work_item/update/url/valid_sample_2.res.payload.golden.json b/controller/test-files/work_item/update/url/valid_sample_2.res.payload.golden.json index f4ce8e013e..f730f38699 100755 --- a/controller/test-files/work_item/update/url/valid_sample_2.res.payload.golden.json +++ b/controller/test-files/work_item/update/url/valid_sample_2.res.payload.golden.json @@ -46,10 +46,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, diff --git a/controller/test-files/work_item/update/url/valid_sample_3.res.payload.golden.json b/controller/test-files/work_item/update/url/valid_sample_3.res.payload.golden.json index 33df259738..4ed45ee49d 100755 --- a/controller/test-files/work_item/update/url/valid_sample_3.res.payload.golden.json +++ b/controller/test-files/work_item/update/url/valid_sample_3.res.payload.golden.json @@ -46,10 +46,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, diff --git a/controller/test-files/work_item/update/user/valid_sample_1.res.payload.golden.json b/controller/test-files/work_item/update/user/valid_sample_1.res.payload.golden.json index a1dc016191..d07fa5a25c 100755 --- a/controller/test-files/work_item/update/user/valid_sample_1.res.payload.golden.json +++ b/controller/test-files/work_item/update/user/valid_sample_1.res.payload.golden.json @@ -46,10 +46,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, diff --git a/controller/test-files/work_item/update/user/valid_sample_2.res.payload.golden.json b/controller/test-files/work_item/update/user/valid_sample_2.res.payload.golden.json index b4ce360a53..eb9d1c0665 100755 --- a/controller/test-files/work_item/update/user/valid_sample_2.res.payload.golden.json +++ b/controller/test-files/work_item/update/user/valid_sample_2.res.payload.golden.json @@ -46,10 +46,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000003", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000003", - "self": "http:///api/users/00000000-0000-0000-0000-000000000003" - }, "type": "users" } }, diff --git a/controller/test-files/work_item_link/create/ok.res.payload.golden.json b/controller/test-files/work_item_link/create/ok.res.payload.golden.json index 845bfb290b..fef736a94b 100755 --- a/controller/test-files/work_item_link/create/ok.res.payload.golden.json +++ b/controller/test-files/work_item_link/create/ok.res.payload.golden.json @@ -130,10 +130,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000011", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000011", - "self": "http:///api/users/00000000-0000-0000-0000-000000000011" - }, "type": "users" } }, @@ -210,10 +206,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000011", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000011", - "self": "http:///api/users/00000000-0000-0000-0000-000000000011" - }, "type": "users" } }, diff --git a/controller/test-files/work_item_link/list/ok.res.paylpad.golden.json b/controller/test-files/work_item_link/list/ok.res.paylpad.golden.json index ca0dbbc912..977c9880b5 100755 --- a/controller/test-files/work_item_link/list/ok.res.paylpad.golden.json +++ b/controller/test-files/work_item_link/list/ok.res.paylpad.golden.json @@ -132,10 +132,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000011", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000011", - "self": "http:///api/users/00000000-0000-0000-0000-000000000011" - }, "type": "users" } }, @@ -212,10 +208,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000011", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000011", - "self": "http:///api/users/00000000-0000-0000-0000-000000000011" - }, "type": "users" } }, diff --git a/controller/test-files/work_item_link/show/ok.res.payload.golden.json b/controller/test-files/work_item_link/show/ok.res.payload.golden.json index 845bfb290b..fef736a94b 100755 --- a/controller/test-files/work_item_link/show/ok.res.payload.golden.json +++ b/controller/test-files/work_item_link/show/ok.res.payload.golden.json @@ -130,10 +130,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000011", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000011", - "self": "http:///api/users/00000000-0000-0000-0000-000000000011" - }, "type": "users" } }, @@ -210,10 +206,6 @@ "creator": { "data": { "id": "00000000-0000-0000-0000-000000000011", - "links": { - "related": "http:///api/users/00000000-0000-0000-0000-000000000011", - "self": "http:///api/users/00000000-0000-0000-0000-000000000011" - }, "type": "users" } }, diff --git a/workitem/field_test_data.go b/workitem/field_test_data.go index b0fb097ff7..0102299e9f 100644 --- a/workitem/field_test_data.go +++ b/workitem/field_test_data.go @@ -166,7 +166,7 @@ func GetFieldTypeTestData(t *testing.T) FieldTypeTestDataMap { -100, }, Invalid: []interface{}{ - 1e2, + 100.2, nil, "", "foo", From 6020b734995ea164b14ef6089ccd749b18725892 Mon Sep 17 00:00:00 2001 From: Konrad Kleine Date: Tue, 31 Jul 2018 16:28:55 +0200 Subject: [PATCH 08/10] wit as relationship --- .../list/ok.bool_list.res.payload.golden.json | 22 +++++++++++++------ .../ok.bool_single.res.payload.golden.json | 12 ++++++---- .../ok.float_list.res.payload.golden.json | 22 +++++++++++++------ .../ok.float_single.res.payload.golden.json | 12 ++++++---- .../ok.integer_list.res.payload.golden.json | 22 +++++++++++++------ .../ok.integer_single.res.payload.golden.json | 12 ++++++---- .../ok.markup_list.res.payload.golden.json | 22 +++++++++++++------ .../ok.markup_single.res.payload.golden.json | 12 ++++++---- .../ok.string_list.res.payload.golden.json | 22 +++++++++++++------ .../ok.string_single.res.payload.golden.json | 12 ++++++---- .../list/ok.url_list.res.payload.golden.json | 22 +++++++++++++------ .../ok.url_single.res.payload.golden.json | 12 ++++++---- controller/work_item_events.go | 13 +++++++---- design/work_item_event.go | 8 +++---- 14 files changed, 151 insertions(+), 74 deletions(-) diff --git a/controller/test-files/event/list/ok.bool_list.res.payload.golden.json b/controller/test-files/event/list/ok.bool_list.res.payload.golden.json index a9d593c3b6..03f8911997 100755 --- a/controller/test-files/event/list/ok.bool_list.res.payload.golden.json +++ b/controller/test-files/event/list/ok.bool_list.res.payload.golden.json @@ -5,16 +5,20 @@ "name": "bool_single", "newValue": true, "oldValue": null, - "timestamp": "0001-01-01T00:00:00Z", - "workItemTypeID": "00000000-0000-0000-0000-000000000001" + "timestamp": "0001-01-01T00:00:00Z" }, - "id": "00000000-0000-0000-0000-000000000002", + "id": "00000000-0000-0000-0000-000000000001", "relationships": { "modifier": { "data": { - "id": "00000000-0000-0000-0000-000000000003", + "id": "00000000-0000-0000-0000-000000000002", "type": "identities" } + }, + "workItemType": { + "links": { + "self": "http:///api/workitemtypes/00000000-0000-0000-0000-000000000003" + } } }, "type": "events" @@ -26,16 +30,20 @@ true, false ], - "timestamp": "0001-01-01T00:00:00Z", - "workItemTypeID": "00000000-0000-0000-0000-000000000001" + "timestamp": "0001-01-01T00:00:00Z" }, "id": "00000000-0000-0000-0000-000000000004", "relationships": { "modifier": { "data": { - "id": "00000000-0000-0000-0000-000000000003", + "id": "00000000-0000-0000-0000-000000000002", "type": "identities" } + }, + "workItemType": { + "links": { + "self": "http:///api/workitemtypes/00000000-0000-0000-0000-000000000003" + } } }, "type": "events" diff --git a/controller/test-files/event/list/ok.bool_single.res.payload.golden.json b/controller/test-files/event/list/ok.bool_single.res.payload.golden.json index 561642756d..30592adf5e 100755 --- a/controller/test-files/event/list/ok.bool_single.res.payload.golden.json +++ b/controller/test-files/event/list/ok.bool_single.res.payload.golden.json @@ -5,16 +5,20 @@ "name": "bool_single", "newValue": true, "oldValue": null, - "timestamp": "0001-01-01T00:00:00Z", - "workItemTypeID": "00000000-0000-0000-0000-000000000001" + "timestamp": "0001-01-01T00:00:00Z" }, - "id": "00000000-0000-0000-0000-000000000002", + "id": "00000000-0000-0000-0000-000000000001", "relationships": { "modifier": { "data": { - "id": "00000000-0000-0000-0000-000000000003", + "id": "00000000-0000-0000-0000-000000000002", "type": "identities" } + }, + "workItemType": { + "links": { + "self": "http:///api/workitemtypes/00000000-0000-0000-0000-000000000003" + } } }, "type": "events" diff --git a/controller/test-files/event/list/ok.float_list.res.payload.golden.json b/controller/test-files/event/list/ok.float_list.res.payload.golden.json index 4687da7ead..339f2ff6b3 100755 --- a/controller/test-files/event/list/ok.float_list.res.payload.golden.json +++ b/controller/test-files/event/list/ok.float_list.res.payload.golden.json @@ -5,16 +5,20 @@ "name": "float_single", "newValue": 0.1, "oldValue": null, - "timestamp": "0001-01-01T00:00:00Z", - "workItemTypeID": "00000000-0000-0000-0000-000000000001" + "timestamp": "0001-01-01T00:00:00Z" }, - "id": "00000000-0000-0000-0000-000000000002", + "id": "00000000-0000-0000-0000-000000000001", "relationships": { "modifier": { "data": { - "id": "00000000-0000-0000-0000-000000000003", + "id": "00000000-0000-0000-0000-000000000002", "type": "identities" } + }, + "workItemType": { + "links": { + "self": "http:///api/workitemtypes/00000000-0000-0000-0000-000000000003" + } } }, "type": "events" @@ -26,16 +30,20 @@ 0.1, -1111.1 ], - "timestamp": "0001-01-01T00:00:00Z", - "workItemTypeID": "00000000-0000-0000-0000-000000000001" + "timestamp": "0001-01-01T00:00:00Z" }, "id": "00000000-0000-0000-0000-000000000004", "relationships": { "modifier": { "data": { - "id": "00000000-0000-0000-0000-000000000003", + "id": "00000000-0000-0000-0000-000000000002", "type": "identities" } + }, + "workItemType": { + "links": { + "self": "http:///api/workitemtypes/00000000-0000-0000-0000-000000000003" + } } }, "type": "events" diff --git a/controller/test-files/event/list/ok.float_single.res.payload.golden.json b/controller/test-files/event/list/ok.float_single.res.payload.golden.json index 629c9614ea..da107099cb 100755 --- a/controller/test-files/event/list/ok.float_single.res.payload.golden.json +++ b/controller/test-files/event/list/ok.float_single.res.payload.golden.json @@ -5,16 +5,20 @@ "name": "float_single", "newValue": 0.1, "oldValue": null, - "timestamp": "0001-01-01T00:00:00Z", - "workItemTypeID": "00000000-0000-0000-0000-000000000001" + "timestamp": "0001-01-01T00:00:00Z" }, - "id": "00000000-0000-0000-0000-000000000002", + "id": "00000000-0000-0000-0000-000000000001", "relationships": { "modifier": { "data": { - "id": "00000000-0000-0000-0000-000000000003", + "id": "00000000-0000-0000-0000-000000000002", "type": "identities" } + }, + "workItemType": { + "links": { + "self": "http:///api/workitemtypes/00000000-0000-0000-0000-000000000003" + } } }, "type": "events" diff --git a/controller/test-files/event/list/ok.integer_list.res.payload.golden.json b/controller/test-files/event/list/ok.integer_list.res.payload.golden.json index 12fc4bfcbe..f02ffaf052 100755 --- a/controller/test-files/event/list/ok.integer_list.res.payload.golden.json +++ b/controller/test-files/event/list/ok.integer_list.res.payload.golden.json @@ -5,16 +5,20 @@ "name": "integer_single", "newValue": 0, "oldValue": null, - "timestamp": "0001-01-01T00:00:00Z", - "workItemTypeID": "00000000-0000-0000-0000-000000000001" + "timestamp": "0001-01-01T00:00:00Z" }, - "id": "00000000-0000-0000-0000-000000000002", + "id": "00000000-0000-0000-0000-000000000001", "relationships": { "modifier": { "data": { - "id": "00000000-0000-0000-0000-000000000003", + "id": "00000000-0000-0000-0000-000000000002", "type": "identities" } + }, + "workItemType": { + "links": { + "self": "http:///api/workitemtypes/00000000-0000-0000-0000-000000000003" + } } }, "type": "events" @@ -26,16 +30,20 @@ 0, 333 ], - "timestamp": "0001-01-01T00:00:00Z", - "workItemTypeID": "00000000-0000-0000-0000-000000000001" + "timestamp": "0001-01-01T00:00:00Z" }, "id": "00000000-0000-0000-0000-000000000004", "relationships": { "modifier": { "data": { - "id": "00000000-0000-0000-0000-000000000003", + "id": "00000000-0000-0000-0000-000000000002", "type": "identities" } + }, + "workItemType": { + "links": { + "self": "http:///api/workitemtypes/00000000-0000-0000-0000-000000000003" + } } }, "type": "events" diff --git a/controller/test-files/event/list/ok.integer_single.res.payload.golden.json b/controller/test-files/event/list/ok.integer_single.res.payload.golden.json index beab8f40d4..b584501391 100755 --- a/controller/test-files/event/list/ok.integer_single.res.payload.golden.json +++ b/controller/test-files/event/list/ok.integer_single.res.payload.golden.json @@ -5,16 +5,20 @@ "name": "integer_single", "newValue": 0, "oldValue": null, - "timestamp": "0001-01-01T00:00:00Z", - "workItemTypeID": "00000000-0000-0000-0000-000000000001" + "timestamp": "0001-01-01T00:00:00Z" }, - "id": "00000000-0000-0000-0000-000000000002", + "id": "00000000-0000-0000-0000-000000000001", "relationships": { "modifier": { "data": { - "id": "00000000-0000-0000-0000-000000000003", + "id": "00000000-0000-0000-0000-000000000002", "type": "identities" } + }, + "workItemType": { + "links": { + "self": "http:///api/workitemtypes/00000000-0000-0000-0000-000000000003" + } } }, "type": "events" diff --git a/controller/test-files/event/list/ok.markup_list.res.payload.golden.json b/controller/test-files/event/list/ok.markup_list.res.payload.golden.json index a4e51fec65..0fee0d7cb3 100755 --- a/controller/test-files/event/list/ok.markup_list.res.payload.golden.json +++ b/controller/test-files/event/list/ok.markup_list.res.payload.golden.json @@ -8,16 +8,20 @@ "markup": "PlainText" }, "oldValue": null, - "timestamp": "0001-01-01T00:00:00Z", - "workItemTypeID": "00000000-0000-0000-0000-000000000001" + "timestamp": "0001-01-01T00:00:00Z" }, - "id": "00000000-0000-0000-0000-000000000002", + "id": "00000000-0000-0000-0000-000000000001", "relationships": { "modifier": { "data": { - "id": "00000000-0000-0000-0000-000000000003", + "id": "00000000-0000-0000-0000-000000000002", "type": "identities" } + }, + "workItemType": { + "links": { + "self": "http:///api/workitemtypes/00000000-0000-0000-0000-000000000003" + } } }, "type": "events" @@ -35,16 +39,20 @@ "markup": "PlainText" } ], - "timestamp": "0001-01-01T00:00:00Z", - "workItemTypeID": "00000000-0000-0000-0000-000000000001" + "timestamp": "0001-01-01T00:00:00Z" }, "id": "00000000-0000-0000-0000-000000000004", "relationships": { "modifier": { "data": { - "id": "00000000-0000-0000-0000-000000000003", + "id": "00000000-0000-0000-0000-000000000002", "type": "identities" } + }, + "workItemType": { + "links": { + "self": "http:///api/workitemtypes/00000000-0000-0000-0000-000000000003" + } } }, "type": "events" diff --git a/controller/test-files/event/list/ok.markup_single.res.payload.golden.json b/controller/test-files/event/list/ok.markup_single.res.payload.golden.json index d40bd4a34f..16d7ece928 100755 --- a/controller/test-files/event/list/ok.markup_single.res.payload.golden.json +++ b/controller/test-files/event/list/ok.markup_single.res.payload.golden.json @@ -8,16 +8,20 @@ "markup": "PlainText" }, "oldValue": null, - "timestamp": "0001-01-01T00:00:00Z", - "workItemTypeID": "00000000-0000-0000-0000-000000000001" + "timestamp": "0001-01-01T00:00:00Z" }, - "id": "00000000-0000-0000-0000-000000000002", + "id": "00000000-0000-0000-0000-000000000001", "relationships": { "modifier": { "data": { - "id": "00000000-0000-0000-0000-000000000003", + "id": "00000000-0000-0000-0000-000000000002", "type": "identities" } + }, + "workItemType": { + "links": { + "self": "http:///api/workitemtypes/00000000-0000-0000-0000-000000000003" + } } }, "type": "events" diff --git a/controller/test-files/event/list/ok.string_list.res.payload.golden.json b/controller/test-files/event/list/ok.string_list.res.payload.golden.json index 849a2e5e70..214ea8a8a5 100755 --- a/controller/test-files/event/list/ok.string_list.res.payload.golden.json +++ b/controller/test-files/event/list/ok.string_list.res.payload.golden.json @@ -5,16 +5,20 @@ "name": "string_single", "newValue": "foo", "oldValue": null, - "timestamp": "0001-01-01T00:00:00Z", - "workItemTypeID": "00000000-0000-0000-0000-000000000001" + "timestamp": "0001-01-01T00:00:00Z" }, - "id": "00000000-0000-0000-0000-000000000002", + "id": "00000000-0000-0000-0000-000000000001", "relationships": { "modifier": { "data": { - "id": "00000000-0000-0000-0000-000000000003", + "id": "00000000-0000-0000-0000-000000000002", "type": "identities" } + }, + "workItemType": { + "links": { + "self": "http:///api/workitemtypes/00000000-0000-0000-0000-000000000003" + } } }, "type": "events" @@ -26,16 +30,20 @@ "foo", "bar" ], - "timestamp": "0001-01-01T00:00:00Z", - "workItemTypeID": "00000000-0000-0000-0000-000000000001" + "timestamp": "0001-01-01T00:00:00Z" }, "id": "00000000-0000-0000-0000-000000000004", "relationships": { "modifier": { "data": { - "id": "00000000-0000-0000-0000-000000000003", + "id": "00000000-0000-0000-0000-000000000002", "type": "identities" } + }, + "workItemType": { + "links": { + "self": "http:///api/workitemtypes/00000000-0000-0000-0000-000000000003" + } } }, "type": "events" diff --git a/controller/test-files/event/list/ok.string_single.res.payload.golden.json b/controller/test-files/event/list/ok.string_single.res.payload.golden.json index e81283dbd9..d2a5327619 100755 --- a/controller/test-files/event/list/ok.string_single.res.payload.golden.json +++ b/controller/test-files/event/list/ok.string_single.res.payload.golden.json @@ -5,16 +5,20 @@ "name": "string_single", "newValue": "foo", "oldValue": null, - "timestamp": "0001-01-01T00:00:00Z", - "workItemTypeID": "00000000-0000-0000-0000-000000000001" + "timestamp": "0001-01-01T00:00:00Z" }, - "id": "00000000-0000-0000-0000-000000000002", + "id": "00000000-0000-0000-0000-000000000001", "relationships": { "modifier": { "data": { - "id": "00000000-0000-0000-0000-000000000003", + "id": "00000000-0000-0000-0000-000000000002", "type": "identities" } + }, + "workItemType": { + "links": { + "self": "http:///api/workitemtypes/00000000-0000-0000-0000-000000000003" + } } }, "type": "events" diff --git a/controller/test-files/event/list/ok.url_list.res.payload.golden.json b/controller/test-files/event/list/ok.url_list.res.payload.golden.json index afe208fd70..bdaca0d75a 100755 --- a/controller/test-files/event/list/ok.url_list.res.payload.golden.json +++ b/controller/test-files/event/list/ok.url_list.res.payload.golden.json @@ -5,16 +5,20 @@ "name": "url_single", "newValue": "127.0.0.1", "oldValue": null, - "timestamp": "0001-01-01T00:00:00Z", - "workItemTypeID": "00000000-0000-0000-0000-000000000001" + "timestamp": "0001-01-01T00:00:00Z" }, - "id": "00000000-0000-0000-0000-000000000002", + "id": "00000000-0000-0000-0000-000000000001", "relationships": { "modifier": { "data": { - "id": "00000000-0000-0000-0000-000000000003", + "id": "00000000-0000-0000-0000-000000000002", "type": "identities" } + }, + "workItemType": { + "links": { + "self": "http:///api/workitemtypes/00000000-0000-0000-0000-000000000003" + } } }, "type": "events" @@ -26,16 +30,20 @@ "127.0.0.1", "http://www.openshift.io" ], - "timestamp": "0001-01-01T00:00:00Z", - "workItemTypeID": "00000000-0000-0000-0000-000000000001" + "timestamp": "0001-01-01T00:00:00Z" }, "id": "00000000-0000-0000-0000-000000000004", "relationships": { "modifier": { "data": { - "id": "00000000-0000-0000-0000-000000000003", + "id": "00000000-0000-0000-0000-000000000002", "type": "identities" } + }, + "workItemType": { + "links": { + "self": "http:///api/workitemtypes/00000000-0000-0000-0000-000000000003" + } } }, "type": "events" diff --git a/controller/test-files/event/list/ok.url_single.res.payload.golden.json b/controller/test-files/event/list/ok.url_single.res.payload.golden.json index 870f27dca2..c764838c93 100755 --- a/controller/test-files/event/list/ok.url_single.res.payload.golden.json +++ b/controller/test-files/event/list/ok.url_single.res.payload.golden.json @@ -5,16 +5,20 @@ "name": "url_single", "newValue": "127.0.0.1", "oldValue": null, - "timestamp": "0001-01-01T00:00:00Z", - "workItemTypeID": "00000000-0000-0000-0000-000000000001" + "timestamp": "0001-01-01T00:00:00Z" }, - "id": "00000000-0000-0000-0000-000000000002", + "id": "00000000-0000-0000-0000-000000000001", "relationships": { "modifier": { "data": { - "id": "00000000-0000-0000-0000-000000000003", + "id": "00000000-0000-0000-0000-000000000002", "type": "identities" } + }, + "workItemType": { + "links": { + "self": "http:///api/workitemtypes/00000000-0000-0000-0000-000000000003" + } } }, "type": "events" diff --git a/controller/work_item_events.go b/controller/work_item_events.go index 3613ec4778..5cd949dd94 100644 --- a/controller/work_item_events.go +++ b/controller/work_item_events.go @@ -8,6 +8,7 @@ import ( "github.com/fabric8-services/fabric8-wit/application" "github.com/fabric8-services/fabric8-wit/jsonapi" "github.com/fabric8-services/fabric8-wit/ptr" + "github.com/fabric8-services/fabric8-wit/rest" "github.com/fabric8-services/fabric8-wit/workitem" "github.com/fabric8-services/fabric8-wit/workitem/event" "github.com/goadesign/goa" @@ -96,11 +97,10 @@ func ConvertEvent(ctx context.Context, appl application.Application, req *http.R e := app.Event{ Type: event.APIStringTypeEvents, - ID: &wiEvent.ID, + ID: wiEvent.ID, Attributes: &app.EventAttributes{ - Name: wiEvent.Name, - Timestamp: wiEvent.Timestamp, - WorkItemTypeID: &wiEvent.WorkItemTypeID, + Name: wiEvent.Name, + Timestamp: wiEvent.Timestamp, }, Relationships: &app.EventRelations{ Modifier: &app.RelationGeneric{ @@ -109,6 +109,11 @@ func ConvertEvent(ctx context.Context, appl application.Application, req *http.R ID: ptr.String(wiEvent.Modifier.String()), }, }, + WorkItemType: &app.RelationGeneric{ + Links: &app.GenericLinks{ + Self: ptr.String(rest.AbsoluteURL(req, app.WorkitemtypeHref(wit.ID))), + }, + }, }, } diff --git a/design/work_item_event.go b/design/work_item_event.go index 6d26bb4a2f..9c3c7a389a 100644 --- a/design/work_item_event.go +++ b/design/work_item_event.go @@ -16,7 +16,7 @@ var event = a.Type("Event", func() { a.Attribute("attributes", eventAttributes) a.Attribute("relationships", eventRelationships) a.Attribute("links", genericLinks) - a.Required("type") + a.Required("type", "relationships", "attributes", "id") }) var eventAttributes = a.Type("EventAttributes", func() { @@ -27,9 +27,6 @@ var eventAttributes = a.Type("EventAttributes", func() { a.Attribute("name", d.String, "The name of the event occured", func() { a.Example("system.title") }) - a.Attribute("workItemTypeID", d.UUID, "The type ID of the work item at given point in history", func() { - a.Example("ae753d1a-4625-4c84-baf8-0fc99a189df9") - }) a.Attribute("oldValue", d.Any, "The user who was assigned to (or unassigned from). Only for 'assigned' and 'unassigned' events.", func() { a.Example("813a456e-1c8a-48df-ac15-84065ee039f7") }) @@ -43,6 +40,9 @@ var eventRelationships = a.Type("EventRelations", func() { a.Attribute("modifier", relationGeneric, "This defines the modifier of the event") a.Attribute("oldValue", relationGenericList) a.Attribute("newValue", relationGenericList) + a.Attribute("workItemType", relationGeneric, "The type of the work item at the event's point in time") + + a.Required("workItemType", "modifier") }) var eventList = JSONList( From 09ae9adf8bb91ef7e10dd57e34eb442c216c7003 Mon Sep 17 00:00:00 2001 From: Konrad Kleine Date: Tue, 31 Jul 2018 17:26:16 +0200 Subject: [PATCH 09/10] Readded old tests --- .../list/ok-assignees.res.payload.golden.json | 14 +- .../ok-description.res.payload.golden.json | 12 +- .../list/ok-kindFloat.res.payload.golden.json | 12 +- .../list/ok-kindInt.res.payload.golden.json | 12 +- .../list/ok-labels.res.payload.golden.json | 16 +- .../list/ok-state.res.payload.golden.json | 12 +- .../list/ok-title.res.payload.golden.json | 12 +- controller/work_item_events.go | 1 - controller/work_item_events_test.go | 775 +++++++++--------- 9 files changed, 448 insertions(+), 418 deletions(-) diff --git a/controller/test-files/event/list/ok-assignees.res.payload.golden.json b/controller/test-files/event/list/ok-assignees.res.payload.golden.json index b8db0ce197..dd7b084969 100755 --- a/controller/test-files/event/list/ok-assignees.res.payload.golden.json +++ b/controller/test-files/event/list/ok-assignees.res.payload.golden.json @@ -3,24 +3,28 @@ { "attributes": { "name": "system.assignees", - "timestamp": "0001-01-01T00:00:00Z", - "workItemTypeID": "00000000-0000-0000-0000-000000000001" + "timestamp": "0001-01-01T00:00:00Z" }, - "id": "00000000-0000-0000-0000-000000000002", + "id": "00000000-0000-0000-0000-000000000001", "relationships": { "modifier": { "data": { - "id": "00000000-0000-0000-0000-000000000003", + "id": "00000000-0000-0000-0000-000000000002", "type": "identities" } }, "newValue": { "data": [ { - "id": "00000000-0000-0000-0000-000000000003", + "id": "00000000-0000-0000-0000-000000000002", "type": "users" } ] + }, + "workItemType": { + "links": { + "self": "http:///api/workitemtypes/00000000-0000-0000-0000-000000000003" + } } }, "type": "events" diff --git a/controller/test-files/event/list/ok-description.res.payload.golden.json b/controller/test-files/event/list/ok-description.res.payload.golden.json index e889d5917a..d56f7cbd11 100755 --- a/controller/test-files/event/list/ok-description.res.payload.golden.json +++ b/controller/test-files/event/list/ok-description.res.payload.golden.json @@ -8,16 +8,20 @@ "markup": "Markdown" }, "oldValue": null, - "timestamp": "0001-01-01T00:00:00Z", - "workItemTypeID": "00000000-0000-0000-0000-000000000001" + "timestamp": "0001-01-01T00:00:00Z" }, - "id": "00000000-0000-0000-0000-000000000002", + "id": "00000000-0000-0000-0000-000000000001", "relationships": { "modifier": { "data": { - "id": "00000000-0000-0000-0000-000000000003", + "id": "00000000-0000-0000-0000-000000000002", "type": "identities" } + }, + "workItemType": { + "links": { + "self": "http:///api/workitemtypes/00000000-0000-0000-0000-000000000003" + } } }, "type": "events" diff --git a/controller/test-files/event/list/ok-kindFloat.res.payload.golden.json b/controller/test-files/event/list/ok-kindFloat.res.payload.golden.json index 8ac03d28d2..61eb7e5000 100755 --- a/controller/test-files/event/list/ok-kindFloat.res.payload.golden.json +++ b/controller/test-files/event/list/ok-kindFloat.res.payload.golden.json @@ -5,16 +5,20 @@ "name": "myFloatType", "newValue": 2.99, "oldValue": 1.99, - "timestamp": "0001-01-01T00:00:00Z", - "workItemTypeID": "00000000-0000-0000-0000-000000000001" + "timestamp": "0001-01-01T00:00:00Z" }, - "id": "00000000-0000-0000-0000-000000000002", + "id": "00000000-0000-0000-0000-000000000001", "relationships": { "modifier": { "data": { - "id": "00000000-0000-0000-0000-000000000003", + "id": "00000000-0000-0000-0000-000000000002", "type": "identities" } + }, + "workItemType": { + "links": { + "self": "http:///api/workitemtypes/00000000-0000-0000-0000-000000000003" + } } }, "type": "events" diff --git a/controller/test-files/event/list/ok-kindInt.res.payload.golden.json b/controller/test-files/event/list/ok-kindInt.res.payload.golden.json index b967329ed3..7eb320a34b 100755 --- a/controller/test-files/event/list/ok-kindInt.res.payload.golden.json +++ b/controller/test-files/event/list/ok-kindInt.res.payload.golden.json @@ -5,16 +5,20 @@ "name": "myIntType", "newValue": 4235, "oldValue": 200, - "timestamp": "0001-01-01T00:00:00Z", - "workItemTypeID": "00000000-0000-0000-0000-000000000001" + "timestamp": "0001-01-01T00:00:00Z" }, - "id": "00000000-0000-0000-0000-000000000002", + "id": "00000000-0000-0000-0000-000000000001", "relationships": { "modifier": { "data": { - "id": "00000000-0000-0000-0000-000000000003", + "id": "00000000-0000-0000-0000-000000000002", "type": "identities" } + }, + "workItemType": { + "links": { + "self": "http:///api/workitemtypes/00000000-0000-0000-0000-000000000003" + } } }, "type": "events" diff --git a/controller/test-files/event/list/ok-labels.res.payload.golden.json b/controller/test-files/event/list/ok-labels.res.payload.golden.json index 9eb504ac3c..2ff36d715a 100755 --- a/controller/test-files/event/list/ok-labels.res.payload.golden.json +++ b/controller/test-files/event/list/ok-labels.res.payload.golden.json @@ -3,28 +3,32 @@ { "attributes": { "name": "system.labels", - "timestamp": "0001-01-01T00:00:00Z", - "workItemTypeID": "00000000-0000-0000-0000-000000000001" + "timestamp": "0001-01-01T00:00:00Z" }, - "id": "00000000-0000-0000-0000-000000000002", + "id": "00000000-0000-0000-0000-000000000001", "relationships": { "modifier": { "data": { - "id": "00000000-0000-0000-0000-000000000003", + "id": "00000000-0000-0000-0000-000000000002", "type": "identities" } }, "newValue": { "data": [ { - "id": "00000000-0000-0000-0000-000000000004", + "id": "00000000-0000-0000-0000-000000000003", "type": "labels" }, { - "id": "00000000-0000-0000-0000-000000000005", + "id": "00000000-0000-0000-0000-000000000004", "type": "labels" } ] + }, + "workItemType": { + "links": { + "self": "http:///api/workitemtypes/00000000-0000-0000-0000-000000000005" + } } }, "type": "events" diff --git a/controller/test-files/event/list/ok-state.res.payload.golden.json b/controller/test-files/event/list/ok-state.res.payload.golden.json index 1f90a2437c..853a898710 100755 --- a/controller/test-files/event/list/ok-state.res.payload.golden.json +++ b/controller/test-files/event/list/ok-state.res.payload.golden.json @@ -5,16 +5,20 @@ "name": "system.state", "newValue": "resolved", "oldValue": "new", - "timestamp": "0001-01-01T00:00:00Z", - "workItemTypeID": "00000000-0000-0000-0000-000000000001" + "timestamp": "0001-01-01T00:00:00Z" }, - "id": "00000000-0000-0000-0000-000000000002", + "id": "00000000-0000-0000-0000-000000000001", "relationships": { "modifier": { "data": { - "id": "00000000-0000-0000-0000-000000000003", + "id": "00000000-0000-0000-0000-000000000002", "type": "identities" } + }, + "workItemType": { + "links": { + "self": "http:///api/workitemtypes/00000000-0000-0000-0000-000000000003" + } } }, "type": "events" diff --git a/controller/test-files/event/list/ok-title.res.payload.golden.json b/controller/test-files/event/list/ok-title.res.payload.golden.json index 20edb6fdfc..d5f3d2bcaf 100755 --- a/controller/test-files/event/list/ok-title.res.payload.golden.json +++ b/controller/test-files/event/list/ok-title.res.payload.golden.json @@ -5,16 +5,20 @@ "name": "system.title", "newValue": "New Title", "oldValue": "work item 00000000-0000-0000-0000-000000000001", - "timestamp": "0001-01-01T00:00:00Z", - "workItemTypeID": "00000000-0000-0000-0000-000000000002" + "timestamp": "0001-01-01T00:00:00Z" }, - "id": "00000000-0000-0000-0000-000000000003", + "id": "00000000-0000-0000-0000-000000000002", "relationships": { "modifier": { "data": { - "id": "00000000-0000-0000-0000-000000000004", + "id": "00000000-0000-0000-0000-000000000003", "type": "identities" } + }, + "workItemType": { + "links": { + "self": "http:///api/workitemtypes/00000000-0000-0000-0000-000000000004" + } } }, "type": "events" diff --git a/controller/work_item_events.go b/controller/work_item_events.go index 5cd949dd94..0576f65723 100644 --- a/controller/work_item_events.go +++ b/controller/work_item_events.go @@ -227,6 +227,5 @@ func ConvertEvent(ctx context.Context, appl application.Application, req *http.R (*e.Attributes.NewValue).([]interface{})[i] = newVal } } - return &e, nil } diff --git a/controller/work_item_events_test.go b/controller/work_item_events_test.go index 82cd09290d..8cba31ebfb 100644 --- a/controller/work_item_events_test.go +++ b/controller/work_item_events_test.go @@ -9,11 +9,14 @@ import ( "github.com/fabric8-services/fabric8-wit/app/test" . "github.com/fabric8-services/fabric8-wit/controller" "github.com/fabric8-services/fabric8-wit/gormtestsupport" + "github.com/fabric8-services/fabric8-wit/label" + "github.com/fabric8-services/fabric8-wit/rendering" "github.com/fabric8-services/fabric8-wit/resource" "github.com/fabric8-services/fabric8-wit/rest" testsupport "github.com/fabric8-services/fabric8-wit/test" tf "github.com/fabric8-services/fabric8-wit/test/testfixture" "github.com/fabric8-services/fabric8-wit/workitem" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" ) @@ -35,392 +38,392 @@ func (s *TestEvent) SetupTest() { func (s *TestEvent) TestListEvent() { - // s.T().Run("event list ok - state", func(t *testing.T) { - // fxt := tf.NewTestFixture(t, s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1)) - // svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) - // eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) - // workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) - // spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) - // payload := app.UpdateWorkitemPayload{ - // Data: &app.WorkItem{ - // Type: APIStringTypeWorkItem, - // ID: &fxt.WorkItems[0].ID, - // Attributes: map[string]interface{}{ - // workitem.SystemState: "resolved", - // workitem.SystemVersion: fxt.WorkItems[0].Version, - // }, - // Relationships: &app.WorkItemRelationships{ - // Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), - // }, - // }, - // } - // test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) - // res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) - // safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") - // require.NotEmpty(t, eventList) - // require.Len(t, eventList.Data, 1) - // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-state.res.payload.golden.json"), eventList) - // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-state.res.headers.golden.json"), res.Header()) - // }) - - // s.T().Run("event list ok - title", func(t *testing.T) { - // fxt := tf.NewTestFixture(t, s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1)) - // svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) - // eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) - // workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) - // spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) - // payload := app.UpdateWorkitemPayload{ - // Data: &app.WorkItem{ - // Type: APIStringTypeWorkItem, - // ID: &fxt.WorkItems[0].ID, - // Attributes: map[string]interface{}{ - // workitem.SystemTitle: "New Title", - // workitem.SystemVersion: fxt.WorkItems[0].Version, - // }, - // Relationships: &app.WorkItemRelationships{ - // Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), - // }, - // }, - // } - // test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) - // res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) - // safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") - // require.NotEmpty(t, eventList) - // require.Len(t, eventList.Data, 1) - // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-title.res.payload.golden.json"), eventList) - // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-title.res.headers.golden.json"), res.Header()) - // }) - - // s.T().Run("event list ok - Field Type Float", func(t *testing.T) { - // fieldName := "myFloatType" - // fxt := tf.NewTestFixture(t, s.DB, - // tf.CreateWorkItemEnvironment(), - // tf.WorkItemTypes(1, func(fxt *tf.TestFixture, idx int) error { - // fxt.WorkItemTypes[idx].Fields = map[string]workitem.FieldDefinition{ - // fieldName: { - // Type: &workitem.SimpleType{Kind: workitem.KindFloat}, - // }, - // } - // return nil - // }), - // tf.WorkItems(1, func(fxt *tf.TestFixture, idx int) error { - // fxt.WorkItems[idx].Type = fxt.WorkItemTypes[idx].ID - // fxt.WorkItems[idx].Fields[fieldName] = 1.99 - // fxt.WorkItems[idx].Fields[workitem.SystemTitle] = "My workitem" - // return nil - // }), - // ) - // svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) - // eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) - // workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) - // spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) - // payload := app.UpdateWorkitemPayload{ - // Data: &app.WorkItem{ - // Type: APIStringTypeWorkItem, - // ID: &fxt.WorkItems[0].ID, - // Attributes: map[string]interface{}{ - // workitem.SystemTitle: fxt.WorkItems[0].Fields[workitem.SystemTitle], - // fieldName: 2.99, - // workitem.SystemVersion: fxt.WorkItems[0].Version, - // }, - // Relationships: &app.WorkItemRelationships{ - // Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), - // }, - // }, - // } - // test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) - // res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) - // safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") - // require.NotEmpty(t, eventList) - // require.Len(t, eventList.Data, 1) - // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-kindFloat.res.payload.golden.json"), eventList) - // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-kindFloat.res.headers.golden.json"), res.Header()) - // }) - - // s.T().Run("event list ok - Field Type Int", func(t *testing.T) { - // fieldName := "myIntType" - // fxt := tf.NewTestFixture(t, s.DB, - // tf.CreateWorkItemEnvironment(), - // tf.WorkItemTypes(1, func(fxt *tf.TestFixture, idx int) error { - // fxt.WorkItemTypes[idx].Fields = map[string]workitem.FieldDefinition{ - // fieldName: { - // Type: &workitem.SimpleType{Kind: workitem.KindInteger}, - // }, - // } - // return nil - // }), - // tf.WorkItems(1, func(fxt *tf.TestFixture, idx int) error { - // fxt.WorkItems[idx].Type = fxt.WorkItemTypes[idx].ID - // fxt.WorkItems[idx].Fields[fieldName] = 200 - // fxt.WorkItems[idx].Fields[workitem.SystemTitle] = "My workitem" - // return nil - // }), - // ) - // svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) - // eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) - // workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) - // spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) - // payload := app.UpdateWorkitemPayload{ - // Data: &app.WorkItem{ - // Type: APIStringTypeWorkItem, - // ID: &fxt.WorkItems[0].ID, - // Attributes: map[string]interface{}{ - // workitem.SystemTitle: fxt.WorkItems[0].Fields[workitem.SystemTitle], - // fieldName: 4235, - // workitem.SystemVersion: fxt.WorkItems[0].Version, - // }, - // Relationships: &app.WorkItemRelationships{ - // Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), - // }, - // }, - // } - // test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) - // res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) - // safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") - // require.NotEmpty(t, eventList) - // require.Len(t, eventList.Data, 1) - // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-kindInt.res.payload.golden.json"), eventList) - // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-kindInt.res.headers.golden.json"), res.Header()) - // }) - - // s.T().Run("event list ok - description", func(t *testing.T) { - // fxt := tf.NewTestFixture(t, s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1)) - // svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) - // eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) - // workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) - // spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) - - // modifiedDescription := "# Description is modified1" - // modifiedRenderedDescription := "

Description is modified1

\n" - // modifiedMarkup := rendering.SystemMarkupMarkdown - - // payload := app.UpdateWorkitemPayload{ - // Data: &app.WorkItem{ - // Type: APIStringTypeWorkItem, - // ID: &fxt.WorkItems[0].ID, - // Attributes: map[string]interface{}{ - // workitem.SystemDescription: modifiedDescription, - // workitem.SystemDescriptionRendered: modifiedRenderedDescription, - // workitem.SystemDescriptionMarkup: modifiedMarkup, - // workitem.SystemVersion: fxt.WorkItems[0].Version, - // }, - // Relationships: &app.WorkItemRelationships{ - // Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), - // }, - // }, - // } - // test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) - // res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) - // safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") - // require.NotEmpty(t, eventList) - // require.Len(t, eventList.Data, 1) - // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-description.res.payload.golden.json"), eventList) - // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-description.res.headers.golden.json"), res.Header()) - // }) - - // s.T().Run("event list ok - assigned", func(t *testing.T) { - // fxt := tf.NewTestFixture(t, s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1)) - // svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) - // eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) - // assignee := []string{fxt.Identities[0].ID.String()} - // workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) - // spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) - // payload := app.UpdateWorkitemPayload{ - // Data: &app.WorkItem{ - // Type: APIStringTypeWorkItem, - // ID: &fxt.WorkItems[0].ID, - // Attributes: map[string]interface{}{ - // workitem.SystemAssignees: assignee, - // workitem.SystemVersion: fxt.WorkItems[0].Version, - // }, - // Relationships: &app.WorkItemRelationships{ - // Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), - // }, - // }, - // } - // test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) - // res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) - // safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") - // require.NotEmpty(t, eventList) - // require.Len(t, eventList.Data, 1) - // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-assignees.res.payload.golden.json"), eventList) - // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-assignees.res.headers.golden.json"), res.Header()) - // }) - - // s.T().Run("event list ok - label", func(t *testing.T) { - // fxt := tf.NewTestFixture(t, s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1), tf.Labels(2)) - // svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) - // eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) - // wiCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) - - // u := app.UpdateWorkitemPayload{ - // Data: &app.WorkItem{ - // ID: &fxt.WorkItems[0].ID, - // Type: APIStringTypeWorkItem, - // Attributes: map[string]interface{}{ - // workitem.SystemVersion: fxt.WorkItems[0].Version, - // }, - // Relationships: &app.WorkItemRelationships{}, - // }, - // } - // // attach 2 labels - // apiLabelType := label.APIStringTypeLabels - // lbl0 := fxt.Labels[0].ID.String() - // lbl1 := fxt.Labels[1].ID.String() - // u.Data.Relationships.Labels = &app.RelationGenericList{ - // Data: []*app.GenericData{ - // { - // ID: &lbl0, - // Type: &apiLabelType, - // }, - // { - // ID: &lbl1, - // Type: &apiLabelType, - // }, - // }, - // } - // _, updatedWI := test.UpdateWorkitemOK(t, svc.Context, svc, wiCtrl, fxt.WorkItems[0].ID, &u) - // assert.NotNil(t, updatedWI) - // require.NotNil(t, updatedWI.Data.Relationships.Labels.Links) - // assert.Len(t, updatedWI.Data.Relationships.Labels.Data, 2) - - // res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) - // safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") - // require.NotEmpty(t, eventList) - // require.Len(t, eventList.Data, 1) - // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-labels.res.payload.golden.json"), eventList) - // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-labels.res.headers.golden.json"), res.Header()) - // }) - - // s.T().Run("event list ok - iteration", func(t *testing.T) { - // fxt := tf.NewTestFixture(t, s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1)) - // svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) - // eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) - // workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) - // spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) - // payload := app.UpdateWorkitemPayload{ - // Data: &app.WorkItem{ - // Type: APIStringTypeWorkItem, - // ID: &fxt.WorkItems[0].ID, - // Attributes: map[string]interface{}{ - // workitem.SystemIteration: fxt.Iterations[0].ID.String(), - // workitem.SystemVersion: fxt.WorkItems[0].Version, - // }, - // Relationships: &app.WorkItemRelationships{ - // Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), - // }, - // }, - // } - // test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) - // res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) - // safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") - // require.NotEmpty(t, eventList) - // require.Len(t, eventList.Data, 1) - // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-iteration.res.payload.golden.json"), eventList) - // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-iteration.res.headers.golden.json"), res.Header()) - // }) - - // s.T().Run("event list ok - area", func(t *testing.T) { - // fxt := tf.NewTestFixture(t, s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1)) - // svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) - // eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) - // workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) - // spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) - // payload := app.UpdateWorkitemPayload{ - // Data: &app.WorkItem{ - // Type: APIStringTypeWorkItem, - // ID: &fxt.WorkItems[0].ID, - // Attributes: map[string]interface{}{ - // workitem.SystemArea: fxt.Areas[0].ID.String(), - // workitem.SystemVersion: fxt.WorkItems[0].Version, - // }, - // Relationships: &app.WorkItemRelationships{ - // Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), - // }, - // }, - // } - // test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) - // res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) - // safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") - // require.NotEmpty(t, eventList) - // require.Len(t, eventList.Data, 1) - // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-area.res.payload.golden.json"), eventList) - // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-area.res.headers.golden.json"), res.Header()) - // }) - - // s.T().Run("event list - empty", func(t *testing.T) { - // fxt := tf.NewTestFixture(t, s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1)) - // svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) - // eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) - // res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) - // safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") - // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-no-event.res.errors.payload.golden.json"), eventList) - // compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-no-event.res.errors.headers.golden.json"), res.Header()) - // }) - - // s.T().Run("many events", func(t *testing.T) { - // fxt := tf.NewTestFixture(t, s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1), tf.Iterations(2)) - // svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) - // eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) - // workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) - // spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) - // payload1 := app.UpdateWorkitemPayload{ - // Data: &app.WorkItem{ - // Type: APIStringTypeWorkItem, - // ID: &fxt.WorkItems[0].ID, - // Attributes: map[string]interface{}{ - // workitem.SystemIteration: fxt.Iterations[0].ID.String(), - // workitem.SystemVersion: fxt.WorkItems[0].Version, - // }, - // Relationships: &app.WorkItemRelationships{ - // Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), - // }, - // }, - // } - // test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload1) // update iteration - // res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) - // safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") - // require.NotEmpty(t, eventList) - // require.Len(t, eventList.Data, 1) - - // assignee := []string{fxt.Identities[0].ID.String()} - // payload2 := app.UpdateWorkitemPayload{ - // Data: &app.WorkItem{ - // Type: APIStringTypeWorkItem, - // ID: &fxt.WorkItems[0].ID, - // Attributes: map[string]interface{}{ - // workitem.SystemAssignees: assignee, - // workitem.SystemVersion: fxt.WorkItems[0].Version + 1, - // }, - // Relationships: &app.WorkItemRelationships{ - // Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), - // }, - // }, - // } - // test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload2) // update assignee - // res, eventList = test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) - // require.NotEmpty(t, eventList) - // require.Len(t, eventList.Data, 2) - - // payload3 := app.UpdateWorkitemPayload{ - // Data: &app.WorkItem{ - // Type: APIStringTypeWorkItem, - // ID: &fxt.WorkItems[0].ID, - // Attributes: map[string]interface{}{ - // workitem.SystemIteration: fxt.Iterations[1].ID.String(), - // workitem.SystemVersion: fxt.WorkItems[0].Version + 2, - // }, - // Relationships: &app.WorkItemRelationships{ - // Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), - // }, - // }, - // } - // test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload3) // update iteration - // res, eventList = test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) - // safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") - // require.NotEmpty(t, eventList) - // require.Len(t, eventList.Data, 3) - // }) + s.T().Run("event list ok - state", func(t *testing.T) { + fxt := tf.NewTestFixture(t, s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1)) + svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) + eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) + workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) + spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) + payload := app.UpdateWorkitemPayload{ + Data: &app.WorkItem{ + Type: APIStringTypeWorkItem, + ID: &fxt.WorkItems[0].ID, + Attributes: map[string]interface{}{ + workitem.SystemState: "resolved", + workitem.SystemVersion: fxt.WorkItems[0].Version, + }, + Relationships: &app.WorkItemRelationships{ + Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), + }, + }, + } + test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) + res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) + safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") + require.NotEmpty(t, eventList) + require.Len(t, eventList.Data, 1) + compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-state.res.payload.golden.json"), eventList) + compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-state.res.headers.golden.json"), res.Header()) + }) + + s.T().Run("event list ok - title", func(t *testing.T) { + fxt := tf.NewTestFixture(t, s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1)) + svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) + eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) + workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) + spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) + payload := app.UpdateWorkitemPayload{ + Data: &app.WorkItem{ + Type: APIStringTypeWorkItem, + ID: &fxt.WorkItems[0].ID, + Attributes: map[string]interface{}{ + workitem.SystemTitle: "New Title", + workitem.SystemVersion: fxt.WorkItems[0].Version, + }, + Relationships: &app.WorkItemRelationships{ + Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), + }, + }, + } + test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) + res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) + safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") + require.NotEmpty(t, eventList) + require.Len(t, eventList.Data, 1) + compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-title.res.payload.golden.json"), eventList) + compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-title.res.headers.golden.json"), res.Header()) + }) + + s.T().Run("event list ok - Field Type Float", func(t *testing.T) { + fieldName := "myFloatType" + fxt := tf.NewTestFixture(t, s.DB, + tf.CreateWorkItemEnvironment(), + tf.WorkItemTypes(1, func(fxt *tf.TestFixture, idx int) error { + fxt.WorkItemTypes[idx].Fields = map[string]workitem.FieldDefinition{ + fieldName: { + Type: &workitem.SimpleType{Kind: workitem.KindFloat}, + }, + } + return nil + }), + tf.WorkItems(1, func(fxt *tf.TestFixture, idx int) error { + fxt.WorkItems[idx].Type = fxt.WorkItemTypes[idx].ID + fxt.WorkItems[idx].Fields[fieldName] = 1.99 + fxt.WorkItems[idx].Fields[workitem.SystemTitle] = "My workitem" + return nil + }), + ) + svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) + eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) + workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) + spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) + payload := app.UpdateWorkitemPayload{ + Data: &app.WorkItem{ + Type: APIStringTypeWorkItem, + ID: &fxt.WorkItems[0].ID, + Attributes: map[string]interface{}{ + workitem.SystemTitle: fxt.WorkItems[0].Fields[workitem.SystemTitle], + fieldName: 2.99, + workitem.SystemVersion: fxt.WorkItems[0].Version, + }, + Relationships: &app.WorkItemRelationships{ + Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), + }, + }, + } + test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) + res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) + safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") + require.NotEmpty(t, eventList) + require.Len(t, eventList.Data, 1) + compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-kindFloat.res.payload.golden.json"), eventList) + compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-kindFloat.res.headers.golden.json"), res.Header()) + }) + + s.T().Run("event list ok - Field Type Int", func(t *testing.T) { + fieldName := "myIntType" + fxt := tf.NewTestFixture(t, s.DB, + tf.CreateWorkItemEnvironment(), + tf.WorkItemTypes(1, func(fxt *tf.TestFixture, idx int) error { + fxt.WorkItemTypes[idx].Fields = map[string]workitem.FieldDefinition{ + fieldName: { + Type: &workitem.SimpleType{Kind: workitem.KindInteger}, + }, + } + return nil + }), + tf.WorkItems(1, func(fxt *tf.TestFixture, idx int) error { + fxt.WorkItems[idx].Type = fxt.WorkItemTypes[idx].ID + fxt.WorkItems[idx].Fields[fieldName] = 200 + fxt.WorkItems[idx].Fields[workitem.SystemTitle] = "My workitem" + return nil + }), + ) + svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) + eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) + workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) + spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) + payload := app.UpdateWorkitemPayload{ + Data: &app.WorkItem{ + Type: APIStringTypeWorkItem, + ID: &fxt.WorkItems[0].ID, + Attributes: map[string]interface{}{ + workitem.SystemTitle: fxt.WorkItems[0].Fields[workitem.SystemTitle], + fieldName: 4235, + workitem.SystemVersion: fxt.WorkItems[0].Version, + }, + Relationships: &app.WorkItemRelationships{ + Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), + }, + }, + } + test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) + res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) + safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") + require.NotEmpty(t, eventList) + require.Len(t, eventList.Data, 1) + compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-kindInt.res.payload.golden.json"), eventList) + compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-kindInt.res.headers.golden.json"), res.Header()) + }) + + s.T().Run("event list ok - description", func(t *testing.T) { + fxt := tf.NewTestFixture(t, s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1)) + svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) + eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) + workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) + spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) + + modifiedDescription := "# Description is modified1" + modifiedRenderedDescription := "

Description is modified1

\n" + modifiedMarkup := rendering.SystemMarkupMarkdown + + payload := app.UpdateWorkitemPayload{ + Data: &app.WorkItem{ + Type: APIStringTypeWorkItem, + ID: &fxt.WorkItems[0].ID, + Attributes: map[string]interface{}{ + workitem.SystemDescription: modifiedDescription, + workitem.SystemDescriptionRendered: modifiedRenderedDescription, + workitem.SystemDescriptionMarkup: modifiedMarkup, + workitem.SystemVersion: fxt.WorkItems[0].Version, + }, + Relationships: &app.WorkItemRelationships{ + Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), + }, + }, + } + test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) + res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) + safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") + require.NotEmpty(t, eventList) + require.Len(t, eventList.Data, 1) + compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-description.res.payload.golden.json"), eventList) + compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-description.res.headers.golden.json"), res.Header()) + }) + + s.T().Run("event list ok - assigned", func(t *testing.T) { + fxt := tf.NewTestFixture(t, s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1)) + svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) + eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) + assignee := []string{fxt.Identities[0].ID.String()} + workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) + spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) + payload := app.UpdateWorkitemPayload{ + Data: &app.WorkItem{ + Type: APIStringTypeWorkItem, + ID: &fxt.WorkItems[0].ID, + Attributes: map[string]interface{}{ + workitem.SystemAssignees: assignee, + workitem.SystemVersion: fxt.WorkItems[0].Version, + }, + Relationships: &app.WorkItemRelationships{ + Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), + }, + }, + } + test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) + res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) + safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") + require.NotEmpty(t, eventList) + require.Len(t, eventList.Data, 1) + compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-assignees.res.payload.golden.json"), eventList) + compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-assignees.res.headers.golden.json"), res.Header()) + }) + + s.T().Run("event list ok - label", func(t *testing.T) { + fxt := tf.NewTestFixture(t, s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1), tf.Labels(2)) + svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) + eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) + wiCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) + + u := app.UpdateWorkitemPayload{ + Data: &app.WorkItem{ + ID: &fxt.WorkItems[0].ID, + Type: APIStringTypeWorkItem, + Attributes: map[string]interface{}{ + workitem.SystemVersion: fxt.WorkItems[0].Version, + }, + Relationships: &app.WorkItemRelationships{}, + }, + } + // attach 2 labels + apiLabelType := label.APIStringTypeLabels + lbl0 := fxt.Labels[0].ID.String() + lbl1 := fxt.Labels[1].ID.String() + u.Data.Relationships.Labels = &app.RelationGenericList{ + Data: []*app.GenericData{ + { + ID: &lbl0, + Type: &apiLabelType, + }, + { + ID: &lbl1, + Type: &apiLabelType, + }, + }, + } + _, updatedWI := test.UpdateWorkitemOK(t, svc.Context, svc, wiCtrl, fxt.WorkItems[0].ID, &u) + assert.NotNil(t, updatedWI) + require.NotNil(t, updatedWI.Data.Relationships.Labels.Links) + assert.Len(t, updatedWI.Data.Relationships.Labels.Data, 2) + + res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) + safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") + require.NotEmpty(t, eventList) + require.Len(t, eventList.Data, 1) + compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-labels.res.payload.golden.json"), eventList) + compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-labels.res.headers.golden.json"), res.Header()) + }) + + s.T().Run("event list ok - iteration", func(t *testing.T) { + fxt := tf.NewTestFixture(t, s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1)) + svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) + eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) + workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) + spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) + payload := app.UpdateWorkitemPayload{ + Data: &app.WorkItem{ + Type: APIStringTypeWorkItem, + ID: &fxt.WorkItems[0].ID, + Attributes: map[string]interface{}{ + workitem.SystemIteration: fxt.Iterations[0].ID.String(), + workitem.SystemVersion: fxt.WorkItems[0].Version, + }, + Relationships: &app.WorkItemRelationships{ + Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), + }, + }, + } + test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) + res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) + safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") + require.NotEmpty(t, eventList) + require.Len(t, eventList.Data, 1) + compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-iteration.res.payload.golden.json"), eventList) + compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-iteration.res.headers.golden.json"), res.Header()) + }) + + s.T().Run("event list ok - area", func(t *testing.T) { + fxt := tf.NewTestFixture(t, s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1)) + svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) + eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) + workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) + spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) + payload := app.UpdateWorkitemPayload{ + Data: &app.WorkItem{ + Type: APIStringTypeWorkItem, + ID: &fxt.WorkItems[0].ID, + Attributes: map[string]interface{}{ + workitem.SystemArea: fxt.Areas[0].ID.String(), + workitem.SystemVersion: fxt.WorkItems[0].Version, + }, + Relationships: &app.WorkItemRelationships{ + Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), + }, + }, + } + test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload) + res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) + safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") + require.NotEmpty(t, eventList) + require.Len(t, eventList.Data, 1) + compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-area.res.payload.golden.json"), eventList) + compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-area.res.headers.golden.json"), res.Header()) + }) + + s.T().Run("event list - empty", func(t *testing.T) { + fxt := tf.NewTestFixture(t, s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1)) + svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) + eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) + res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) + safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") + compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-no-event.res.errors.payload.golden.json"), eventList) + compareWithGoldenAgnostic(t, filepath.Join(s.testDir, "list", "ok-no-event.res.errors.headers.golden.json"), res.Header()) + }) + + s.T().Run("many events", func(t *testing.T) { + fxt := tf.NewTestFixture(t, s.DB, tf.CreateWorkItemEnvironment(), tf.WorkItems(1), tf.Iterations(2)) + svc := testsupport.ServiceAsSpaceUser("Event-Service", *fxt.Identities[0], &TestSpaceAuthzService{*fxt.Identities[0], ""}) + eventCtrl := NewEventsController(svc, s.GormDB, s.Configuration) + workitemCtrl := NewWorkitemController(svc, s.GormDB, s.Configuration) + spaceSelfURL := rest.AbsoluteURL(&http.Request{Host: "api.service.domain.org"}, app.SpaceHref(fxt.Spaces[0].ID.String())) + payload1 := app.UpdateWorkitemPayload{ + Data: &app.WorkItem{ + Type: APIStringTypeWorkItem, + ID: &fxt.WorkItems[0].ID, + Attributes: map[string]interface{}{ + workitem.SystemIteration: fxt.Iterations[0].ID.String(), + workitem.SystemVersion: fxt.WorkItems[0].Version, + }, + Relationships: &app.WorkItemRelationships{ + Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), + }, + }, + } + test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload1) // update iteration + res, eventList := test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) + safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") + require.NotEmpty(t, eventList) + require.Len(t, eventList.Data, 1) + + assignee := []string{fxt.Identities[0].ID.String()} + payload2 := app.UpdateWorkitemPayload{ + Data: &app.WorkItem{ + Type: APIStringTypeWorkItem, + ID: &fxt.WorkItems[0].ID, + Attributes: map[string]interface{}{ + workitem.SystemAssignees: assignee, + workitem.SystemVersion: fxt.WorkItems[0].Version + 1, + }, + Relationships: &app.WorkItemRelationships{ + Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), + }, + }, + } + test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload2) // update assignee + res, eventList = test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) + require.NotEmpty(t, eventList) + require.Len(t, eventList.Data, 2) + + payload3 := app.UpdateWorkitemPayload{ + Data: &app.WorkItem{ + Type: APIStringTypeWorkItem, + ID: &fxt.WorkItems[0].ID, + Attributes: map[string]interface{}{ + workitem.SystemIteration: fxt.Iterations[1].ID.String(), + workitem.SystemVersion: fxt.WorkItems[0].Version + 2, + }, + Relationships: &app.WorkItemRelationships{ + Space: app.NewSpaceRelation(fxt.Spaces[0].ID, spaceSelfURL), + }, + }, + } + test.UpdateWorkitemOK(t, svc.Context, svc, workitemCtrl, fxt.WorkItems[0].ID, &payload3) // update iteration + res, eventList = test.ListWorkItemEventsOK(t, svc.Context, svc, eventCtrl, fxt.WorkItems[0].ID, nil, nil) + safeOverriteHeader(t, res, app.ETag, "1GmclFDDPcLR1ZWPZnykWw==") + require.NotEmpty(t, eventList) + require.Len(t, eventList.Data, 3) + }) s.T().Run("non-relational field kinds", func(t *testing.T) { testData := workitem.GetFieldTypeTestData(t) From 5038e34ac1e2a97f275847daef9dfad257808d05 Mon Sep 17 00:00:00 2001 From: Konrad Kleine Date: Wed, 1 Aug 2018 17:39:05 +0200 Subject: [PATCH 10/10] Fix tests --- .../list/ok-area.res.payload.golden.json | 14 ++++--- .../list/ok-iteration.res.payload.golden.json | 14 ++++--- workitem/event/event_repository.go | 37 +++++++++---------- 3 files changed, 35 insertions(+), 30 deletions(-) diff --git a/controller/test-files/event/list/ok-area.res.payload.golden.json b/controller/test-files/event/list/ok-area.res.payload.golden.json index a5a947adbd..9254dc7af0 100755 --- a/controller/test-files/event/list/ok-area.res.payload.golden.json +++ b/controller/test-files/event/list/ok-area.res.payload.golden.json @@ -3,21 +3,20 @@ { "attributes": { "name": "system.area", - "timestamp": "0001-01-01T00:00:00Z", - "workItemTypeID": "00000000-0000-0000-0000-000000000001" + "timestamp": "0001-01-01T00:00:00Z" }, - "id": "00000000-0000-0000-0000-000000000002", + "id": "00000000-0000-0000-0000-000000000001", "relationships": { "modifier": { "data": { - "id": "00000000-0000-0000-0000-000000000003", + "id": "00000000-0000-0000-0000-000000000002", "type": "identities" } }, "newValue": { "data": [ { - "id": "00000000-0000-0000-0000-000000000004", + "id": "00000000-0000-0000-0000-000000000003", "type": "areas" } ] @@ -29,6 +28,11 @@ "type": "areas" } ] + }, + "workItemType": { + "links": { + "self": "http:///api/workitemtypes/00000000-0000-0000-0000-000000000004" + } } }, "type": "events" diff --git a/controller/test-files/event/list/ok-iteration.res.payload.golden.json b/controller/test-files/event/list/ok-iteration.res.payload.golden.json index 6892f49e43..4a9651fde8 100755 --- a/controller/test-files/event/list/ok-iteration.res.payload.golden.json +++ b/controller/test-files/event/list/ok-iteration.res.payload.golden.json @@ -3,21 +3,20 @@ { "attributes": { "name": "system.iteration", - "timestamp": "0001-01-01T00:00:00Z", - "workItemTypeID": "00000000-0000-0000-0000-000000000001" + "timestamp": "0001-01-01T00:00:00Z" }, - "id": "00000000-0000-0000-0000-000000000002", + "id": "00000000-0000-0000-0000-000000000001", "relationships": { "modifier": { "data": { - "id": "00000000-0000-0000-0000-000000000003", + "id": "00000000-0000-0000-0000-000000000002", "type": "identities" } }, "newValue": { "data": [ { - "id": "00000000-0000-0000-0000-000000000004", + "id": "00000000-0000-0000-0000-000000000003", "type": "iterations" } ] @@ -29,6 +28,11 @@ "type": "iterations" } ] + }, + "workItemType": { + "links": { + "self": "http:///api/workitemtypes/00000000-0000-0000-0000-000000000004" + } } }, "type": "events" diff --git a/workitem/event/event_repository.go b/workitem/event/event_repository.go index b5996250b8..6adfab9255 100644 --- a/workitem/event/event_repository.go +++ b/workitem/event/event_repository.go @@ -143,27 +143,24 @@ func (r *GormEventRepository) List(ctx context.Context, wiID uuid.UUID) ([]Event eventList = append(eventList, event) } case workitem.SimpleType: - if !fieldType.GetKind().IsRelational() { - // compensate conversion from storage if this really was an enum field - converter := fieldType.ConvertFromModel - if isEnumType { - converter = enumType.ConvertFromModel - } - - p, err := converter(oldVal) - if err != nil { - return nil, errs.Wrapf(err, "failed to convert old value for field %s from storage representation: %+v", fieldName, oldVal) - } - n, err := converter(newVal) - if err != nil { - return nil, errs.Wrapf(err, "failed to convert new value for field %s from storage representation: %+v", fieldName, newVal) - } + // compensate conversion from storage if this really was an enum field + converter := fieldType.ConvertFromModel + if isEnumType { + converter = enumType.ConvertFromModel + } - if !reflect.DeepEqual(p, n) { - event.Old = p - event.New = n - eventList = append(eventList, event) - } + p, err := converter(oldVal) + if err != nil { + return nil, errs.Wrapf(err, "failed to convert old value for field %s from storage representation: %+v", fieldName, oldVal) + } + n, err := converter(newVal) + if err != nil { + return nil, errs.Wrapf(err, "failed to convert new value for field %s from storage representation: %+v", fieldName, newVal) + } + if !reflect.DeepEqual(p, n) { + event.Old = p + event.New = n + eventList = append(eventList, event) } default: return nil, errors.NewNotFoundError("unknown field type", fieldType.GetKind().String())