Skip to content

Commit 378e89a

Browse files
committed
handle dataschema (optional attribute)
1 parent f2f88f9 commit 378e89a

File tree

2 files changed

+86
-39
lines changed

2 files changed

+86
-39
lines changed

v1/util/cloud_events_util.cc

+38-24
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,26 @@
22

33
#include <google/protobuf/util/time_util.h>
44

5+
#include <regex>
6+
57
namespace cloudevents {
68
namespace cloudevents_util {
79

810
using ::io::cloudevents::v1::CloudEvent;
9-
using ::io::cloudevents::v1::CloudEvent_CloudEventAttribute;
1011
using ::google::protobuf::Timestamp;
1112
using ::google::protobuf::util::TimeUtil;
1213

14+
// Taken from https://tools.ietf.org/html/rfc3986#appendix-B
15+
// Adapted to only accept absolute URIs
16+
constexpr char kAbsUriRegex[] = R"(^(([^:/?#]+):)(//([^/?#]*))?([^?#]*)(\?([^#]*))?)";
17+
1318
constexpr char kErrCeInvalid[] = "Given Cloud Event is missing required attributes.";
1419
constexpr char kErrTimeInvalid[] = "Given time is invalid because it does not comply to RFC 3339.";
1520
constexpr char kErrAttrNotSet[] = "Given Cloud Event attribute is not set.";
1621
constexpr char kErrAttrNotHandled[] = "A Cloud Event type is not handled.";
22+
constexpr char kErrInvalidDataschema[] = "The given value for Dataschema is not a valid absolute URI.";
23+
24+
typedef ::io::cloudevents::v1::CloudEvent_CloudEventAttribute CeAttr;
1725

1826
absl::Status CloudEventsUtil::IsValid(const CloudEvent& cloud_event) {
1927
if (cloud_event.id().empty() ||
@@ -26,14 +34,14 @@ absl::Status CloudEventsUtil::IsValid(const CloudEvent& cloud_event) {
2634
}
2735

2836
cloudevents_absl::StatusOr<
29-
absl::flat_hash_map<std::string, CloudEvent_CloudEventAttribute>>
37+
absl::flat_hash_map<std::string, CeAttr>>
3038
CloudEventsUtil::GetMetadata(const CloudEvent& cloud_event) {
3139
if (auto is_valid = CloudEventsUtil::IsValid(cloud_event); !is_valid.ok()) {
3240
return is_valid;
3341
}
3442

3543
// create absl::flat_hash_map from protobuf map of optional/ extensionattrs
36-
absl::flat_hash_map<std::string, CloudEvent_CloudEventAttribute> attrs(
44+
absl::flat_hash_map<std::string, CeAttr> attrs(
3745
(cloud_event.attributes()).begin(),
3846
cloud_event.attributes().end());
3947

@@ -51,31 +59,37 @@ cloudevents_absl::StatusOr<
5159

5260
absl::Status CloudEventsUtil::SetMetadata(const std::string& key,
5361
const std::string& val, CloudEvent& cloud_event) {
54-
// TODO (#39): Recognize URI and URI Reference types
5562
// CE Spec defines attribute as "specversion" while
5663
// proprietary proto defines it as "spec_version"
5764
// https://github.com/cloudevents/spec/blob/master/spec.md#specversion
58-
if (key == "id") {
65+
if (key == "id") { // required attributes
5966
cloud_event.set_id(val);
6067
} else if (key == "source") {
6168
cloud_event.set_source(val);
6269
} else if (key == "specversion") {
6370
cloud_event.set_spec_version(val);
6471
} else if (key == "type") {
6572
cloud_event.set_type(val);
73+
} else if (key == "dataschema") { // optional attributes
74+
// TODO (#60): Use external library to validate URIs.
75+
std::regex uri_regex (kAbsUriRegex, std::regex::extended);
76+
77+
if (!std::regex_match(val, uri_regex)) {
78+
return absl::InvalidArgumentError(kErrInvalidDataschema);
79+
}
80+
CeAttr abs_uri;
81+
abs_uri.set_ce_uri(val);
82+
(*cloud_event.mutable_attributes())[key] = abs_uri;
6683
} else if (key == "time") {
67-
CloudEvent_CloudEventAttribute attr;
84+
CeAttr time_str;
6885
Timestamp timestamp;
6986
if (!TimeUtil::FromString(val, &timestamp)) {
7087
return absl::InvalidArgumentError(kErrTimeInvalid);
7188
}
72-
*attr.mutable_ce_timestamp() = timestamp;
73-
(*cloud_event.mutable_attributes())[key] = attr;
74-
} else {
75-
// default assumes unrecognized attributes to be of type string
76-
CloudEvent_CloudEventAttribute attr;
77-
attr.set_ce_string(val);
78-
(*cloud_event.mutable_attributes())[key] = attr;
89+
*time_str.mutable_ce_timestamp() = timestamp;
90+
(*cloud_event.mutable_attributes())[key] = time_str;
91+
} else { // default assumes type ce string
92+
(*cloud_event.mutable_attributes())[key] = ToCeString(val);
7993
}
8094
return absl::OkStatus();
8195
}
@@ -86,34 +100,34 @@ absl::Status CloudEventsUtil::SetContentType(const std::string& val,
86100
}
87101

88102
cloudevents_absl::StatusOr<std::string> CloudEventsUtil::ToString(
89-
const CloudEvent_CloudEventAttribute& attr){
103+
const CeAttr& attr){
90104
switch (attr.attr_oneof_case()) {
91-
case CloudEvent_CloudEventAttribute::AttrOneofCase::kCeBoolean:
105+
case CeAttr::AttrOneofCase::kCeBoolean:
92106
// StatusOr requires explicit conversion
93107
return std::string(attr.ce_boolean() ? "true" : "false");
94-
case CloudEvent_CloudEventAttribute::AttrOneofCase::kCeInteger:
108+
case CeAttr::AttrOneofCase::kCeInteger:
95109
// skipping validity checks as protobuf generates int32 for sfixed32
96110
return std::to_string(attr.ce_integer());
97-
case CloudEvent_CloudEventAttribute::AttrOneofCase::kCeString:
111+
case CeAttr::AttrOneofCase::kCeString:
98112
return attr.ce_string();
99-
case CloudEvent_CloudEventAttribute::AttrOneofCase::kCeBinary:
113+
case CeAttr::AttrOneofCase::kCeBinary:
100114
return cloudevents_base64::base64_encode(attr.ce_binary());
101-
case CloudEvent_CloudEventAttribute::AttrOneofCase::kCeUri:
115+
case CeAttr::AttrOneofCase::kCeUri:
102116
return attr.ce_uri();
103-
case CloudEvent_CloudEventAttribute::AttrOneofCase::kCeUriReference:
117+
case CeAttr::AttrOneofCase::kCeUriReference:
104118
return attr.ce_uri_reference();
105-
case CloudEvent_CloudEventAttribute::AttrOneofCase::kCeTimestamp:
119+
case CeAttr::AttrOneofCase::kCeTimestamp:
106120
// protobuf also uses RFC3339 representation
107121
return TimeUtil::ToString(attr.ce_timestamp());
108-
case CloudEvent_CloudEventAttribute::AttrOneofCase::ATTR_ONEOF_NOT_SET:
122+
case CeAttr::AttrOneofCase::ATTR_ONEOF_NOT_SET:
109123
return absl::InvalidArgumentError(kErrAttrNotSet);
110124
}
111125
return absl::InternalError(kErrAttrNotHandled);
112126
}
113127

114-
CloudEvent_CloudEventAttribute CloudEventsUtil::ToCeString(
128+
CeAttr CloudEventsUtil::ToCeString(
115129
const std::string& val) {
116-
CloudEvent_CloudEventAttribute ce_str;
130+
CeAttr ce_str;
117131
ce_str.set_ce_string(val);
118132
return ce_str;
119133
}

v1/util/cloud_events_util_test.cc

+48-15
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,11 @@ namespace cloudevents {
88
namespace cloudevents_util {
99

1010
using ::io::cloudevents::v1::CloudEvent;
11-
using ::io::cloudevents::v1::CloudEvent_CloudEventAttribute;
1211
using ::google::protobuf::Timestamp;
1312
using ::google::protobuf::util::TimeUtil;
1413

15-
typedef absl::flat_hash_map<std::string, CloudEvent_CloudEventAttribute>
16-
CeAttrMap;
14+
typedef io::cloudevents::v1::CloudEvent_CloudEventAttribute CeAttr;
15+
typedef absl::flat_hash_map<std::string, CeAttr> CeAttrMap;
1716

1817
TEST(CloudEventsUtilTest, IsValid_NoSource) {
1918
CloudEvent cloud_event;
@@ -100,7 +99,7 @@ TEST(CloudEventsUtilTest, GetMetadata_OneOptional) {
10099
cloud_event.set_source("/test");
101100
cloud_event.set_spec_version("1.0");
102101
cloud_event.set_type("test");
103-
CloudEvent_CloudEventAttribute attr;
102+
CeAttr attr;
104103
attr.set_ce_string("test_val");
105104
(*cloud_event.mutable_attributes())["test_key"] = attr;
106105

@@ -121,7 +120,7 @@ TEST(CloudEventsUtilTest, GetMetadata_TwoOptional) {
121120
cloud_event.set_source("/test");
122121
cloud_event.set_spec_version("1.0");
123122
cloud_event.set_type("test");
124-
CloudEvent_CloudEventAttribute attr;
123+
CeAttr attr;
125124
attr.set_ce_string("test_val1");
126125
(*cloud_event.mutable_attributes())["test_key1"] = attr;
127126
attr.set_ce_string("test_val2");
@@ -185,7 +184,7 @@ TEST(CloudEventsUtilTest, SetMetadata_Optional) {
185184
absl::Status set_meta = CloudEventsUtil::SetMetadata("opt", "arbitrary",
186185
cloud_event);
187186

188-
CloudEvent_CloudEventAttribute attr = cloud_event.attributes().at("opt");
187+
CeAttr attr = cloud_event.attributes().at("opt");
189188

190189
ASSERT_TRUE(set_meta.ok());
191190
ASSERT_EQ(attr.ce_string(), "arbitrary");
@@ -198,12 +197,46 @@ TEST(CloudEventsUtilTest, SetMetadata_Time) {
198197

199198
absl::Status set_meta = CloudEventsUtil::SetMetadata("time", timestamp_str,
200199
cloud_event);
201-
CloudEvent_CloudEventAttribute attr = cloud_event.attributes().at("time");
200+
CeAttr attr = cloud_event.attributes().at("time");
202201

203202
ASSERT_TRUE(set_meta.ok());
204203
ASSERT_EQ(TimeUtil::ToString(attr.ce_timestamp()), timestamp_str);
205204
}
206205

206+
TEST(CloudEventsUtilTest, SetMetadata_DataschemaValid) {
207+
std::string valid_dataschema = "http:www/test.com?query";
208+
CloudEvent cloud_event;
209+
210+
absl::Status set_meta = CloudEventsUtil::SetMetadata("dataschema",
211+
valid_dataschema, cloud_event);
212+
213+
ASSERT_TRUE(set_meta.ok());
214+
ASSERT_EQ(cloud_event.attributes().at("dataschema").ce_uri(),
215+
valid_dataschema);
216+
}
217+
218+
TEST(CloudEventsUtilTest, SetMetadata_DataschemaFragment) {
219+
std::string valid_dataschema = "http:www/test.com?query#fragment";
220+
CloudEvent cloud_event;
221+
222+
absl::Status set_meta = CloudEventsUtil::SetMetadata("dataschema",
223+
valid_dataschema, cloud_event);
224+
225+
ASSERT_FALSE(set_meta.ok());
226+
ASSERT_TRUE(absl::IsInvalidArgument(set_meta));
227+
}
228+
229+
TEST(CloudEventsUtilTest, SetMetadata_DataschemaNoScheme) {
230+
std::string valid_dataschema = "www/test.com?query";
231+
CloudEvent cloud_event;
232+
233+
absl::Status set_meta = CloudEventsUtil::SetMetadata("dataschema",
234+
valid_dataschema, cloud_event);
235+
236+
ASSERT_FALSE(set_meta.ok());
237+
ASSERT_TRUE(absl::IsInvalidArgument(set_meta));
238+
}
239+
207240
TEST(CloudEventsUtilTest, SetContentType) {
208241
std::string type = "test";
209242
CloudEvent cloud_event;
@@ -216,7 +249,7 @@ TEST(CloudEventsUtilTest, SetContentType) {
216249
}
217250

218251
TEST(CloudEventsUtilTest, ToString_BoolFalse) {
219-
CloudEvent_CloudEventAttribute attr;
252+
CeAttr attr;
220253
attr.set_ce_boolean(false);
221254

222255
cloudevents_absl::StatusOr<std::string> stringify_ce_type =
@@ -227,7 +260,7 @@ TEST(CloudEventsUtilTest, ToString_BoolFalse) {
227260
}
228261

229262
TEST(CloudEventsUtilTest, ToString_BoolTrue) {
230-
CloudEvent_CloudEventAttribute attr;
263+
CeAttr attr;
231264
attr.set_ce_boolean(true);
232265

233266
cloudevents_absl::StatusOr<std::string> stringify_ce_type =
@@ -238,7 +271,7 @@ TEST(CloudEventsUtilTest, ToString_BoolTrue) {
238271
}
239272

240273
TEST(CloudEventsUtilTest, ToString_Integer) {
241-
CloudEvent_CloudEventAttribute attr;
274+
CeAttr attr;
242275
attr.set_ce_integer(88);
243276

244277
cloudevents_absl::StatusOr<std::string> stringify_ce_type =
@@ -249,7 +282,7 @@ TEST(CloudEventsUtilTest, ToString_Integer) {
249282
}
250283

251284
TEST(CloudEventsUtilTest, ToString_String) {
252-
CloudEvent_CloudEventAttribute attr;
285+
CeAttr attr;
253286
attr.set_ce_string("test");
254287

255288
cloudevents_absl::StatusOr<std::string> stringify_ce_type =
@@ -260,7 +293,7 @@ TEST(CloudEventsUtilTest, ToString_String) {
260293
}
261294

262295
TEST(CloudEventsUtilTest, ToString_URI) {
263-
CloudEvent_CloudEventAttribute attr;
296+
CeAttr attr;
264297
attr.set_ce_uri("https://google.com");
265298

266299
cloudevents_absl::StatusOr<std::string> stringify_ce_type =
@@ -271,7 +304,7 @@ TEST(CloudEventsUtilTest, ToString_URI) {
271304
}
272305

273306
TEST(CloudEventsUtilTest, ToString_URIRef) {
274-
CloudEvent_CloudEventAttribute attr;
307+
CeAttr attr;
275308
attr.set_ce_uri_reference("https://www.google.com/#fragment");
276309

277310
cloudevents_absl::StatusOr<std::string> stringify_ce_type =
@@ -284,7 +317,7 @@ TEST(CloudEventsUtilTest, ToString_URIRef) {
284317
TEST(CloudEventsUtilTest, ToString_Timestamp) {
285318
Timestamp timestamp = TimeUtil::GetCurrentTime();
286319
std::string timestamp_str = TimeUtil::ToString(timestamp);
287-
CloudEvent_CloudEventAttribute attr;
320+
CeAttr attr;
288321
attr.mutable_ce_timestamp()-> MergeFrom(timestamp);
289322

290323
cloudevents_absl::StatusOr<std::string> stringify_ce_type =
@@ -294,7 +327,7 @@ TEST(CloudEventsUtilTest, ToString_Timestamp) {
294327
}
295328

296329
TEST(CloudEventsUtilTest, ToString_NotSet) {
297-
CloudEvent_CloudEventAttribute attr;
330+
CeAttr attr;
298331

299332
cloudevents_absl::StatusOr<std::string> stringify_ce_type =
300333
CloudEventsUtil::ToString(attr);

0 commit comments

Comments
 (0)