diff --git a/README.md b/README.md index 3cbaa3b..db84b4c 100644 --- a/README.md +++ b/README.md @@ -158,6 +158,7 @@ Sample skips: | persisted | The updated resource should be persisted and reachable with Get. | Generated only if all are true: | | preserve create_time | The field create_time should be preserved when a '\*'-update mask is used. | Generated only if all are true: | | etag mismatch | Method should fail with Aborted if the supplied etag doesnt match the current etag value. | Generated only if all are true: | +| etag updated | Field etag should have a new value when the resource is successfully updated. | Generated only if all are true: | | not found | Method should fail with NotFound if the resource does not exist. | Generated only if all are true: | | invalid update mask | The method should fail with InvalidArgument if the update_mask is invalid. | Generated only if all are true: | | required fields | Method should fail with InvalidArgument if any required field is missing when called with '\*' update_mask. | Generated only if all are true: | diff --git a/internal/aiptest/update/etag.go b/internal/aiptest/update/etag.go index 2c9e7b5..a0fef71 100644 --- a/internal/aiptest/update/etag.go +++ b/internal/aiptest/update/etag.go @@ -39,3 +39,35 @@ var etagMismatch = suite.Test{ return nil }, } + +//nolint:gochecknoglobals +var etagUpdated = suite.Test{ + Name: "etag updated", + Doc: []string{ + "Field etag should have a new value when the resource is successfully updated.", + }, + OnlyIf: suite.OnlyIfs( + onlyif.HasMethod(aipreflect.MethodTypeUpdate), + onlyif.HasRequestEtag(aipreflect.MethodTypeUpdate), + onlyif.HasField("etag"), + ), + Generate: func(f *protogen.GeneratedFile, scope suite.Scope) error { + if util.HasParent(scope.Resource) { + f.P("parent := ", ident.FixtureNextParent, "(t, false)") + f.P("created := fx.create(t, parent)") + } else { + f.P("created := fx.create(t)") + } + updateMethod, _ := util.StandardMethod(scope.Service, scope.Resource, aipreflect.MethodTypeUpdate) + util.MethodUpdate{ + Resource: scope.Resource, + Method: updateMethod, + Parent: "parent", + Name: "created.Name", + Etag: "created.Etag", + }.Generate(f, "updated", "err", ":=") + f.P(ident.AssertNilError, "(t, err)") + f.P(ident.AssertCheck, "(t, updated.Etag != created.Etag)") + return nil + }, +} diff --git a/internal/aiptest/update/update.go b/internal/aiptest/update/update.go index a311478..c7aceac 100644 --- a/internal/aiptest/update/update.go +++ b/internal/aiptest/update/update.go @@ -19,6 +19,7 @@ var Suite = suite.Suite{ persisted, preserveCreateTime, etagMismatch, + etagUpdated, }, TestGroups: []suite.TestGroup{ withResourceGroup, @@ -41,6 +42,5 @@ var withResourceGroup = suite.TestGroup{ invalidUpdateMask, requiredFields, // TODO: add test for supplying wildcard as name - // TODO: add test for etags }, } diff --git a/proto/gen/einride/example/freight/v1/freight_service_aiptest.pb.go b/proto/gen/einride/example/freight/v1/freight_service_aiptest.pb.go index 0cee5c1..79f6804 100644 --- a/proto/gen/einride/example/freight/v1/freight_service_aiptest.pb.go +++ b/proto/gen/einride/example/freight/v1/freight_service_aiptest.pb.go @@ -349,6 +349,20 @@ func (fx *FreightServiceShipperTestSuiteConfig) testUpdate(t *testing.T) { assert.Equal(t, codes.Aborted, status.Code(err), err) }) + // Field etag should have a new value when the resource is successfully updated. + t.Run("etag updated", func(t *testing.T) { + fx.maybeSkip(t) + created := fx.create(t) + msg := fx.Update() + msg.Name = created.Name + updated, err := fx.service.UpdateShipper(fx.ctx, &UpdateShipperRequest{ + Shipper: msg, + Etag: created.Etag, + }) + assert.NilError(t, err) + assert.Check(t, updated.Etag != created.Etag) + }) + created := fx.create(t) // Method should fail with NotFound if the resource does not exist. t.Run("not found", func(t *testing.T) { @@ -993,6 +1007,21 @@ func (fx *FreightServiceSiteTestSuiteConfig) testUpdate(t *testing.T) { assert.Equal(t, codes.Aborted, status.Code(err), err) }) + // Field etag should have a new value when the resource is successfully updated. + t.Run("etag updated", func(t *testing.T) { + fx.maybeSkip(t) + parent := fx.nextParent(t, false) + created := fx.create(t, parent) + msg := fx.Update(parent) + msg.Name = created.Name + updated, err := fx.service.UpdateSite(fx.ctx, &UpdateSiteRequest{ + Site: msg, + Etag: created.Etag, + }) + assert.NilError(t, err) + assert.Check(t, updated.Etag != created.Etag) + }) + parent := fx.nextParent(t, false) created := fx.create(t, parent) // Method should fail with NotFound if the resource does not exist.