From 1bdfade93c80b3f1d86b8499ad7b76c304e4f478 Mon Sep 17 00:00:00 2001 From: David Goss Date: Wed, 2 Jul 2025 18:51:19 +0100 Subject: [PATCH 1/4] Add timestamp to Attachment --- .../messages/cucumber/messages/attachment.hpp | 2 ++ .../messages/cucumber/messages/attachment.cpp | 2 ++ .../Cucumber.Messages/generated/Attachment.cs | 14 ++++++++++++-- go/messages.go | 1 + .../cucumber/messages/types/Attachment.java | 19 ++++++++++++++++--- javascript/src/messages.ts | 3 +++ jsonschema/Attachment.json | 4 ++++ messages.md | 1 + perl/lib/Cucumber/Messages.pm | 11 +++++++++++ php/src-generated/Attachment.php | 17 +++++++++++++++++ python/src/cucumber_messages/_messages.py | 1 + ruby/lib/cucumber/messages/attachment.rb | 12 ++++++++++-- 12 files changed, 80 insertions(+), 7 deletions(-) diff --git a/cpp/include/messages/cucumber/messages/attachment.hpp b/cpp/include/messages/cucumber/messages/attachment.hpp index 7c984c08..d5716f0a 100644 --- a/cpp/include/messages/cucumber/messages/attachment.hpp +++ b/cpp/include/messages/cucumber/messages/attachment.hpp @@ -8,6 +8,7 @@ #include #include +#include namespace cucumber::messages { @@ -43,6 +44,7 @@ struct attachment std::optional url; std::optional test_run_started_id; std::optional test_run_hook_started_id; + std::optional timestamp; std::string to_string() const; diff --git a/cpp/src/lib/messages/cucumber/messages/attachment.cpp b/cpp/src/lib/messages/cucumber/messages/attachment.cpp index fb84b07c..3d3ed085 100644 --- a/cpp/src/lib/messages/cucumber/messages/attachment.cpp +++ b/cpp/src/lib/messages/cucumber/messages/attachment.cpp @@ -20,6 +20,7 @@ attachment::to_string() const cucumber::messages::to_string(oss, ", url=", url); cucumber::messages::to_string(oss, ", test_run_started_id=", test_run_started_id); cucumber::messages::to_string(oss, ", test_run_hook_started_id=", test_run_hook_started_id); + cucumber::messages::to_string(oss, ", timestamp=", timestamp); return oss.str(); } @@ -37,6 +38,7 @@ attachment::to_json(json& j) const cucumber::messages::to_json(j, camelize("url"), url); cucumber::messages::to_json(j, camelize("test_run_started_id"), test_run_started_id); cucumber::messages::to_json(j, camelize("test_run_hook_started_id"), test_run_hook_started_id); + cucumber::messages::to_json(j, camelize("timestamp"), timestamp); } std::string diff --git a/dotnet/Cucumber.Messages/generated/Attachment.cs b/dotnet/Cucumber.Messages/generated/Attachment.cs index 8a51b318..60ca0f23 100644 --- a/dotnet/Cucumber.Messages/generated/Attachment.cs +++ b/dotnet/Cucumber.Messages/generated/Attachment.cs @@ -87,6 +87,10 @@ public sealed class Attachment * The identifier of the test run hook execution if the attachment was created during the execution of a test run hook */ public string TestRunHookStartedId { get; private set; } + /** + * When the attachment was created + */ + public Timestamp Timestamp { get; private set; } public Attachment( @@ -99,7 +103,8 @@ public Attachment( string testStepId, string url, string testRunStartedId, - string testRunHookStartedId + string testRunHookStartedId, + Timestamp timestamp ) { RequireNonNull(body, "Body", "Attachment.Body cannot be null"); @@ -115,6 +120,7 @@ string testRunHookStartedId this.Url = url; this.TestRunStartedId = testRunStartedId; this.TestRunHookStartedId = testRunHookStartedId; + this.Timestamp = timestamp; } public override bool Equals(Object o) @@ -132,7 +138,8 @@ public override bool Equals(Object o) Object.Equals(TestStepId, that.TestStepId) && Object.Equals(Url, that.Url) && Object.Equals(TestRunStartedId, that.TestRunStartedId) && - Object.Equals(TestRunHookStartedId, that.TestRunHookStartedId); + Object.Equals(TestRunHookStartedId, that.TestRunHookStartedId) && + Object.Equals(Timestamp, that.Timestamp); } public override int GetHashCode() @@ -157,6 +164,8 @@ public override int GetHashCode() hash = hash * 31 + TestRunStartedId.GetHashCode(); if (TestRunHookStartedId != null) hash = hash * 31 + TestRunHookStartedId.GetHashCode(); + if (Timestamp != null) + hash = hash * 31 + Timestamp.GetHashCode(); return hash; } @@ -173,6 +182,7 @@ public override string ToString() ", url=" + Url + ", testRunStartedId=" + TestRunStartedId + ", testRunHookStartedId=" + TestRunHookStartedId + + ", timestamp=" + Timestamp + '}'; } diff --git a/go/messages.go b/go/messages.go index f244ff5e..7fb60c88 100644 --- a/go/messages.go +++ b/go/messages.go @@ -11,6 +11,7 @@ type Attachment struct { Url string `json:"url,omitempty"` TestRunStartedId string `json:"testRunStartedId,omitempty"` TestRunHookStartedId string `json:"testRunHookStartedId,omitempty"` + Timestamp *Timestamp `json:"timestamp,omitempty"` } type Duration struct { diff --git a/java/src/generated/java/io/cucumber/messages/types/Attachment.java b/java/src/generated/java/io/cucumber/messages/types/Attachment.java index a1ec6529..3947cb73 100644 --- a/java/src/generated/java/io/cucumber/messages/types/Attachment.java +++ b/java/src/generated/java/io/cucumber/messages/types/Attachment.java @@ -36,6 +36,7 @@ public final class Attachment { private final String url; private final String testRunStartedId; private final String testRunHookStartedId; + private final Timestamp timestamp; public Attachment( String body, @@ -47,7 +48,8 @@ public Attachment( String testStepId, String url, String testRunStartedId, - String testRunHookStartedId + String testRunHookStartedId, + Timestamp timestamp ) { this.body = requireNonNull(body, "Attachment.body cannot be null"); this.contentEncoding = requireNonNull(contentEncoding, "Attachment.contentEncoding cannot be null"); @@ -59,6 +61,7 @@ public Attachment( this.url = url; this.testRunStartedId = testRunStartedId; this.testRunHookStartedId = testRunHookStartedId; + this.timestamp = timestamp; } /** @@ -150,6 +153,13 @@ public Optional getTestRunHookStartedId() { return Optional.ofNullable(testRunHookStartedId); } + /** + * When the attachment was created + */ + public Optional getTimestamp() { + return Optional.ofNullable(timestamp); + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -165,7 +175,8 @@ public boolean equals(Object o) { Objects.equals(testStepId, that.testStepId) && Objects.equals(url, that.url) && Objects.equals(testRunStartedId, that.testRunStartedId) && - Objects.equals(testRunHookStartedId, that.testRunHookStartedId); + Objects.equals(testRunHookStartedId, that.testRunHookStartedId) && + Objects.equals(timestamp, that.timestamp); } @Override @@ -180,7 +191,8 @@ public int hashCode() { testStepId, url, testRunStartedId, - testRunHookStartedId + testRunHookStartedId, + timestamp ); } @@ -197,6 +209,7 @@ public String toString() { ", url=" + url + ", testRunStartedId=" + testRunStartedId + ", testRunHookStartedId=" + testRunHookStartedId + + ", timestamp=" + timestamp + '}'; } } diff --git a/javascript/src/messages.ts b/javascript/src/messages.ts index 8e6ff7d8..e79c3a98 100644 --- a/javascript/src/messages.ts +++ b/javascript/src/messages.ts @@ -23,6 +23,9 @@ export class Attachment { testRunStartedId?: string testRunHookStartedId?: string + + @Type(() => Timestamp) + timestamp?: Timestamp } export class Duration { diff --git a/jsonschema/Attachment.json b/jsonschema/Attachment.json index abbbc572..5ba885e5 100644 --- a/jsonschema/Attachment.json +++ b/jsonschema/Attachment.json @@ -52,6 +52,10 @@ "testRunHookStartedId": { "description": "The identifier of the test run hook execution if the attachment was created during the execution of a test run hook", "type": "string" + }, + "timestamp": { + "description": "When the attachment was created", + "$ref": "./Timestamp.json" } }, "type": "object" diff --git a/messages.md b/messages.md index d90dbe6b..2a455533 100644 --- a/messages.md +++ b/messages.md @@ -17,6 +17,7 @@ will only have one of its fields set, which indicates the payload of the message | `url` | string | no | | | `testRunStartedId` | string | no | | | `testRunHookStartedId` | string | no | | +| `timestamp` | [Timestamp](#timestamp) | no | | ## Duration diff --git a/perl/lib/Cucumber/Messages.pm b/perl/lib/Cucumber/Messages.pm index 6ed52b58..8b6ca712 100644 --- a/perl/lib/Cucumber/Messages.pm +++ b/perl/lib/Cucumber/Messages.pm @@ -88,6 +88,7 @@ my %types = ( url => 'string', test_run_started_id => 'string', test_run_hook_started_id => 'string', + timestamp => 'Cucumber::Messages::Timestamp', ); # This is a work-around for the fact that Moo doesn't have introspection @@ -248,6 +249,16 @@ has test_run_hook_started_id => ); +=head4 timestamp + +When the attachment was created +=cut + +has timestamp => + (is => 'ro', + ); + + } package Cucumber::Messages::Duration { diff --git a/php/src-generated/Attachment.php b/php/src-generated/Attachment.php index bf34254e..8aee9fcd 100644 --- a/php/src-generated/Attachment.php +++ b/php/src-generated/Attachment.php @@ -103,6 +103,11 @@ public function __construct( * The identifier of the test run hook execution if the attachment was created during the execution of a test run hook */ public readonly ?string $testRunHookStartedId = null, + + /** + * When the attachment was created + */ + public readonly ?Timestamp $timestamp = null, ) { } @@ -123,6 +128,7 @@ public static function fromArray(array $arr): self self::ensureUrl($arr); self::ensureTestRunStartedId($arr); self::ensureTestRunHookStartedId($arr); + self::ensureTimestamp($arr); return new self( (string) $arr['body'], @@ -135,6 +141,7 @@ public static function fromArray(array $arr): self isset($arr['url']) ? (string) $arr['url'] : null, isset($arr['testRunStartedId']) ? (string) $arr['testRunStartedId'] : null, isset($arr['testRunHookStartedId']) ? (string) $arr['testRunHookStartedId'] : null, + isset($arr['timestamp']) ? Timestamp::fromArray($arr['timestamp']) : null, ); } @@ -246,4 +253,14 @@ private static function ensureTestRunHookStartedId(array $arr): void throw new SchemaViolationException('Property \'testRunHookStartedId\' was array'); } } + + /** + * @psalm-assert array{timestamp?: array} $arr + */ + private static function ensureTimestamp(array $arr): void + { + if (array_key_exists('timestamp', $arr) && !is_array($arr['timestamp'])) { + throw new SchemaViolationException('Property \'timestamp\' was not array'); + } + } } diff --git a/python/src/cucumber_messages/_messages.py b/python/src/cucumber_messages/_messages.py index 4439dd27..1e2ad28c 100644 --- a/python/src/cucumber_messages/_messages.py +++ b/python/src/cucumber_messages/_messages.py @@ -65,6 +65,7 @@ class Attachment: test_run_hook_started_id: Optional[str] = None # The identifier of the test run hook execution if the attachment was created during the execution of a test run hook test_run_started_id: Optional[str] = None # Not used; implementers should instead populate `testRunHookStartedId` if an attachment was created during the execution of a test run hook test_step_id: Optional[str] = None # The identifier of the test step if the attachment was created during the execution of a test step + timestamp: Optional[Timestamp] = None # When the attachment was created url: Optional[str] = None """ * diff --git a/ruby/lib/cucumber/messages/attachment.rb b/ruby/lib/cucumber/messages/attachment.rb index c56bf2ab..e81cae40 100644 --- a/ruby/lib/cucumber/messages/attachment.rb +++ b/ruby/lib/cucumber/messages/attachment.rb @@ -95,6 +95,11 @@ class Attachment < Message ## attr_reader :test_run_hook_started_id + ## + # When the attachment was created + ## + attr_reader :timestamp + def initialize( body: '', content_encoding: AttachmentContentEncoding::IDENTITY, @@ -105,7 +110,8 @@ def initialize( test_step_id: nil, url: nil, test_run_started_id: nil, - test_run_hook_started_id: nil + test_run_hook_started_id: nil, + timestamp: nil ) @body = body @content_encoding = content_encoding @@ -117,6 +123,7 @@ def initialize( @url = url @test_run_started_id = test_run_started_id @test_run_hook_started_id = test_run_hook_started_id + @timestamp = timestamp super() end @@ -140,7 +147,8 @@ def self.from_h(hash) test_step_id: hash[:testStepId], url: hash[:url], test_run_started_id: hash[:testRunStartedId], - test_run_hook_started_id: hash[:testRunHookStartedId] + test_run_hook_started_id: hash[:testRunHookStartedId], + timestamp: Timestamp.from_h(hash[:timestamp]) ) end end From a058c1f66d6ed0d8dc3a56781b430c8881bb3429 Mon Sep 17 00:00:00 2001 From: David Goss Date: Wed, 2 Jul 2025 18:59:01 +0100 Subject: [PATCH 2/4] fix ordering for codegen --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index cf95cf24..f1a62a9d 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,6 @@ # The order is significant - ajv needs referenced schemas to be preceded by referencing schemas schemas = \ ./jsonschema/Source.json \ - ./jsonschema/Attachment.json \ ./jsonschema/Location.json \ ./jsonschema/Exception.json \ ./jsonschema/SourceReference.json \ @@ -14,6 +13,7 @@ schemas = \ ./jsonschema/StepDefinition.json \ ./jsonschema/TestCase.json \ ./jsonschema/Timestamp.json \ + ./jsonschema/Attachment.json \ ./jsonschema/TestCaseFinished.json \ ./jsonschema/TestCaseStarted.json \ ./jsonschema/TestRunFinished.json \ From 9eaafccaa2be521cd2ebdf560f1f56f46f4be9b6 Mon Sep 17 00:00:00 2001 From: David Goss Date: Wed, 2 Jul 2025 19:01:18 +0100 Subject: [PATCH 3/4] fix java test --- java/src/test/java/io/cucumber/messages/MessagesTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/src/test/java/io/cucumber/messages/MessagesTest.java b/java/src/test/java/io/cucumber/messages/MessagesTest.java index 1be32c32..d3c9d028 100644 --- a/java/src/test/java/io/cucumber/messages/MessagesTest.java +++ b/java/src/test/java/io/cucumber/messages/MessagesTest.java @@ -10,7 +10,7 @@ public class MessagesTest { @Test void is_invalid_when_required_fields_are_missing() { assertThrows(NullPointerException.class, () -> { - new Attachment(null, null, null, null, null, null, null, null, null, null); + new Attachment(null, null, null, null, null, null, null, null, null, null, null); }, "Attachment.body cannot be null"); } From 676981409339909d472862d15a33812149c63461 Mon Sep 17 00:00:00 2001 From: David Goss Date: Wed, 2 Jul 2025 19:06:39 +0100 Subject: [PATCH 4/4] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ff663feb..931df384 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] ### Added - Add `Attachment.testRunHookStartedId` for traceability of attachments to test run hooks ([#301](https://github.com/cucumber/messages/pull/301)) +- Add `Attachment.timestamp` ([#305](https://github.com/cucumber/messages/pull/305)) ### Fixed - [python] Add a LICENSE file for Python ([#278](https://github.com/cucumber/messages/pull/278))