From 099dd4bd0fb4bd82ffe195bfda466ff080cca394 Mon Sep 17 00:00:00 2001 From: Guilherme Branco Date: Fri, 6 Sep 2024 15:59:46 -0300 Subject: [PATCH 1/3] OCM-10939 | feat: include timestamp to error --- pkg/generators/golang/errors_generator.go | 43 +++++++++++++++++++++++ tests/go/marshal_test.go | 29 +++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/pkg/generators/golang/errors_generator.go b/pkg/generators/golang/errors_generator.go index 6696ee1..8155e61 100644 --- a/pkg/generators/golang/errors_generator.go +++ b/pkg/generators/golang/errors_generator.go @@ -175,6 +175,7 @@ func (g *ErrorsGenerator) generateCommonErrors() error { g.buffer.Import("fmt", "") g.buffer.Import("io", "") g.buffer.Import("strings", "") + g.buffer.Import("time", "") g.buffer.Import("github.com/golang/glog", "") g.buffer.Import("github.com/openshift-online/ocm-api-metamodel/pkg/runtime", "") g.buffer.Import(g.packages.HelpersImport(), "") @@ -195,6 +196,7 @@ func (g *ErrorsGenerator) generateCommonErrors() error { reason string details interface{} operationID string + timestamp *time.Time } // Error represents errors. @@ -207,6 +209,7 @@ func (g *ErrorsGenerator) generateCommonErrors() error { reason string details interface{} operationID string + timestamp *time.Time } // NewError creates a new builder that can then be used to create error objects. @@ -263,6 +266,13 @@ func (g *ErrorsGenerator) generateCommonErrors() error { return b } + // Timestamp sets the moment when it happened. + func (b *ErrorBuilder) Timestamp(value *time.Time) *ErrorBuilder { + b.timestamp = value + b.bitmap_ |= 128 + return b + } + // Copy copies the attributes of the given error into this // builder, discarding any previous values. func (b *ErrorBuilder) Copy(object *Error) *ErrorBuilder { @@ -277,6 +287,7 @@ func (g *ErrorsGenerator) generateCommonErrors() error { b.reason = object.reason b.details = object.details b.operationID = object.operationID + b.timestamp = object.timestamp return b } @@ -290,6 +301,7 @@ func (g *ErrorsGenerator) generateCommonErrors() error { reason: b.reason, details: b.details, operationID: b.operationID, + timestamp: b.timestamp, bitmap_: b.bitmap_, } return @@ -429,6 +441,24 @@ func (g *ErrorsGenerator) generateCommonErrors() error { return } + // Timestamp sets the moment when it happened + func (e *Error) Timestamp() *time.Time { + if e != nil && e.bitmap_&128 != 0 { + return e.timestamp + } + return nil + } + + // GetTimestamp returns the timestamp of the error and a flag + // indicating if the timestamp have a value. + func (e *Error) GetTimestamp() (value *time.Time, ok bool) { + ok = e != nil && e.bitmap_&128 != 0 + if ok { + value = e.timestamp + } + return + } + // Error is the implementation of the error interface. func (e *Error) Error() string { chunks := make([]string, 0, 3) @@ -521,6 +551,14 @@ func (g *ErrorsGenerator) generateCommonErrors() error { case "details": object.details = iterator.ReadAny().GetInterface() object.bitmap_ |= 64 + case "timestamp": + text := iterator.ReadString() + value, err := time.Parse(time.RFC3339, text) + if err != nil { + iterator.ReportError("", err.Error()) + } + object.timestamp = &value + object.bitmap_ |= 128 default: iterator.ReadAny() } @@ -578,6 +616,11 @@ func (g *ErrorsGenerator) generateCommonErrors() error { stream.WriteObjectField("details") stream.WriteVal(e.details) } + if e.bitmap_&128 != 0 { + stream.WriteMore() + stream.WriteObjectField("timestamp") + stream.WriteVal(e.timestamp) + } stream.WriteObjectEnd() } diff --git a/tests/go/marshal_test.go b/tests/go/marshal_test.go index bcd12ca..682fa91 100644 --- a/tests/go/marshal_test.go +++ b/tests/go/marshal_test.go @@ -20,6 +20,7 @@ package tests import ( "bytes" + "fmt" "time" . "github.com/onsi/ginkgo/v2" @@ -172,6 +173,34 @@ var _ = Describe("Marshal", func() { }) It("Can write an error", func() { + now := time.Now().UTC() + object, err := errors.NewError(). + ID("401"). + HREF("/api/clusters_mgmt/v1/errors/401"). + Code("CLUSTERS-MGMT-401"). + Reason("My reason"). + OperationID("456"). + Details(map[string]interface{}{ + "kind": "cluster error"}). + Timestamp(&now). + Build() + Expect(err).ToNot(HaveOccurred()) + buffer := new(bytes.Buffer) + err = errors.MarshalError(object, buffer) + Expect(err).ToNot(HaveOccurred()) + Expect(buffer).To(MatchJSON(fmt.Sprintf(`{ + "kind": "Error", + "id": "401", + "href": "/api/clusters_mgmt/v1/errors/401", + "code": "CLUSTERS-MGMT-401", + "reason": "My reason", + "operation_id": "456", + "details": {"kind" : "cluster error"}, + "timestamp": "%v" + }`, now.Format(time.RFC3339Nano)))) + }) + + It("Can write an error without timestamp", func() { object, err := errors.NewError(). ID("401"). HREF("/api/clusters_mgmt/v1/errors/401"). From 02987f1a0b6d572f8859eef99508608c0b16657b Mon Sep 17 00:00:00 2001 From: Guilherme Branco Date: Fri, 6 Sep 2024 16:08:51 -0300 Subject: [PATCH 2/3] OCM-10939 | fix: adjust error message to include timestamp --- pkg/generators/golang/errors_generator.go | 4 ++++ tests/go/marshal_test.go | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/pkg/generators/golang/errors_generator.go b/pkg/generators/golang/errors_generator.go index 8155e61..a88ecaf 100644 --- a/pkg/generators/golang/errors_generator.go +++ b/pkg/generators/golang/errors_generator.go @@ -460,6 +460,7 @@ func (g *ErrorsGenerator) generateCommonErrors() error { } // Error is the implementation of the error interface. + // Details are intentionally left out as there is no guarantee of their type func (e *Error) Error() string { chunks := make([]string, 0, 3) if e.bitmap_&1 != 0 { @@ -471,6 +472,9 @@ func (g *ErrorsGenerator) generateCommonErrors() error { if e.bitmap_&8 != 0 { chunks = append(chunks, fmt.Sprintf("code is '%s'", e.code)) } + if e.bitmap_&128 != 0 { + chunks = append(chunks, fmt.Sprintf("at '%v'", e.timestamp.Format(time.RFC3339))) + } if e.bitmap_&32 != 0 { chunks = append(chunks, fmt.Sprintf("operation identifier is '%s'", e.operationID)) } diff --git a/tests/go/marshal_test.go b/tests/go/marshal_test.go index 682fa91..06f9e79 100644 --- a/tests/go/marshal_test.go +++ b/tests/go/marshal_test.go @@ -198,6 +198,10 @@ var _ = Describe("Marshal", func() { "details": {"kind" : "cluster error"}, "timestamp": "%v" }`, now.Format(time.RFC3339Nano)))) + Expect(object.Error()).To(Equal( + fmt.Sprintf( + "identifier is '401', code is 'CLUSTERS-MGMT-401', at '%v' and operation identifier is '456': My reason", + now.Format(time.RFC3339)))) }) It("Can write an error without timestamp", func() { @@ -223,6 +227,8 @@ var _ = Describe("Marshal", func() { "operation_id": "456", "details": {"kind" : "cluster error"} }`)) + Expect(object.Error()).To(Equal( + "identifier is '401', code is 'CLUSTERS-MGMT-401' and operation identifier is '456': My reason")) }) It("Can write empty list of booleans", func() { From e42e002ea54f54c736a0318c5ed531e2f5424980 Mon Sep 17 00:00:00 2001 From: Guilherme Branco Date: Fri, 6 Sep 2024 16:41:30 -0300 Subject: [PATCH 3/3] OCM-10939 | chore: add release changes for v0.0.61 --- CHANGES.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index fe65e4a..f613af2 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,6 +3,10 @@ This document describes the relevant changes between releases of the API metamodel. +## 0.0.61 Sep 06 2024 + +- Add timestamp to error generator + ## 0.0.60 Apr 03 2024 - Add capability of list resource with a scalar items.