Spec v1 support
Signed-off-by: Fabio José <fabiojose@gmail.com>
This commit is contained in:
parent
50508ba4b3
commit
698a3d1131
|
@ -0,0 +1,44 @@
|
|||
package io.cloudevents.v1;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
|
||||
import io.cloudevents.Attributes;
|
||||
import io.cloudevents.CloudEvent;
|
||||
import io.cloudevents.extensions.ExtensionFormat;
|
||||
import io.cloudevents.fun.ExtensionFormatAccessor;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author fabiojose
|
||||
* @version 1.0
|
||||
*/
|
||||
public class Accessor {
|
||||
|
||||
/**
|
||||
* To get access the set of {@link ExtensionFormat} inside the
|
||||
* event.
|
||||
*
|
||||
* <br>
|
||||
* <br>
|
||||
* This method follow the signature of
|
||||
* {@link ExtensionFormatAccessor#extensionsOf(CloudEvent)}
|
||||
*
|
||||
* @param cloudEvent
|
||||
* @throws IllegalArgumentException When argument is not an instance
|
||||
* of {@link CloudEventImpl}
|
||||
*/
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public static <A extends Attributes, T> Collection<ExtensionFormat>
|
||||
extensionsOf(CloudEvent<A, T> cloudEvent) {
|
||||
Objects.requireNonNull(cloudEvent);
|
||||
|
||||
if(cloudEvent instanceof CloudEventImpl) {
|
||||
CloudEventImpl impl = (CloudEventImpl)cloudEvent;
|
||||
return impl.getExtensionsFormats();
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Invalid instance type: "
|
||||
+ cloudEvent.getClass());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,183 @@
|
|||
/**
|
||||
* Copyright 2019 The CloudEvents Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.cloudevents.v1;
|
||||
|
||||
import java.net.URI;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Pattern;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
|
||||
import io.cloudevents.Attributes;
|
||||
import io.cloudevents.json.ZonedDateTimeDeserializer;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author fabiojose
|
||||
* @version 1.0
|
||||
*/
|
||||
public class AttributesImpl implements Attributes {
|
||||
|
||||
@NotBlank
|
||||
private final String id;
|
||||
|
||||
@NotNull
|
||||
private final URI source;
|
||||
|
||||
@NotBlank
|
||||
@Pattern(regexp = "1\\.0")
|
||||
private final String specversion;
|
||||
|
||||
@NotBlank
|
||||
private final String type;
|
||||
|
||||
private final String datacontenttype;
|
||||
|
||||
private final URI dataschema;
|
||||
|
||||
@Size(min = 1)
|
||||
private final String subject;
|
||||
|
||||
@JsonDeserialize(using = ZonedDateTimeDeserializer.class)
|
||||
private final ZonedDateTime time;
|
||||
|
||||
public AttributesImpl(String id, URI source, String specversion,
|
||||
String type, String datacontenttype,
|
||||
URI dataschema, String subject, ZonedDateTime time) {
|
||||
|
||||
this.id = id;
|
||||
this.source = source;
|
||||
this.specversion = specversion;
|
||||
this.type = type;
|
||||
this.datacontenttype = datacontenttype;
|
||||
this.dataschema = dataschema;
|
||||
this.subject = subject;
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<String> getMediaType() {
|
||||
return getDatacontenttype();
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public URI getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
public String getSpecversion() {
|
||||
return specversion;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public Optional<String> getDatacontenttype() {
|
||||
return Optional.ofNullable(datacontenttype);
|
||||
}
|
||||
|
||||
public Optional<URI> getDataschema() {
|
||||
return Optional.ofNullable(dataschema);
|
||||
}
|
||||
|
||||
public Optional<String> getSubject() {
|
||||
return Optional.ofNullable(subject);
|
||||
}
|
||||
|
||||
public Optional<ZonedDateTime> getTime() {
|
||||
return Optional.ofNullable(time);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AttibutesImpl [id=" + id + ", source=" + source
|
||||
+ ", specversion=" + specversion + ", type=" + type
|
||||
+ ", datacontenttype=" + datacontenttype + ", dataschema="
|
||||
+ dataschema + ", subject=" + subject
|
||||
+ ", time=" + time + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by the Jackson framework to unmarshall.
|
||||
*/
|
||||
@JsonCreator
|
||||
public static AttributesImpl build(
|
||||
@JsonProperty("id") String id,
|
||||
@JsonProperty("source") URI source,
|
||||
@JsonProperty("specversion") String specversion,
|
||||
@JsonProperty("type") String type,
|
||||
@JsonProperty("datacontenttype") String datacontenttype,
|
||||
@JsonProperty("dataschema") URI dataschema,
|
||||
@JsonProperty("subject") String subject,
|
||||
@JsonProperty("time") ZonedDateTime time) {
|
||||
|
||||
return new AttributesImpl(id, source, specversion, type,
|
||||
datacontenttype, dataschema, subject, time);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the marshaller instance to marshall {@link AttributesImpl} as
|
||||
* a {@link Map} of strings
|
||||
*/
|
||||
public static Map<String, String> marshal(AttributesImpl attributes) {
|
||||
Objects.requireNonNull(attributes);
|
||||
Map<String, String> result = new HashMap<>();
|
||||
|
||||
result.put(ContextAttributes.id.name(),
|
||||
attributes.getId());
|
||||
result.put(ContextAttributes.source.name(),
|
||||
attributes.getSource().toString());
|
||||
result.put(ContextAttributes.specversion.name(),
|
||||
attributes.getSpecversion());
|
||||
result.put(ContextAttributes.type.name(),
|
||||
attributes.getType());
|
||||
|
||||
attributes.getDatacontenttype().ifPresent(dct -> {
|
||||
result.put(ContextAttributes.datacontenttype.name(), dct);
|
||||
});
|
||||
|
||||
attributes.getDataschema().ifPresent(dataschema -> {
|
||||
result.put(ContextAttributes.dataschema.name(),
|
||||
dataschema.toString());
|
||||
});
|
||||
|
||||
attributes.getSubject().ifPresent(subject -> {
|
||||
result.put(ContextAttributes.subject.name(), subject);
|
||||
});
|
||||
|
||||
attributes.getTime().ifPresent(time -> {
|
||||
result.put(ContextAttributes.time.name(),
|
||||
time.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,202 @@
|
|||
package io.cloudevents.v1;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
import java.net.URI;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.validation.ConstraintViolation;
|
||||
import javax.validation.Validation;
|
||||
import javax.validation.Validator;
|
||||
|
||||
import io.cloudevents.CloudEvent;
|
||||
import io.cloudevents.extensions.ExtensionFormat;
|
||||
import io.cloudevents.fun.EventBuilder;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author fabiojose
|
||||
* @version 1.0
|
||||
*/
|
||||
public class CloudEventBuilder<T> implements
|
||||
EventBuilder<T, AttributesImpl> {
|
||||
|
||||
private CloudEventBuilder() {}
|
||||
|
||||
private static Validator VALIDATOR;
|
||||
|
||||
public static final String SPEC_VERSION = "1.0";
|
||||
private static final String MESSAGE_SEPARATOR = ", ";
|
||||
private static final String MESSAGE = "'%s' %s";
|
||||
private static final String ERR_MESSAGE = "invalid payload: %s";
|
||||
|
||||
private String id;
|
||||
private URI source;
|
||||
|
||||
private String type;
|
||||
private String datacontenttype;
|
||||
private URI dataschema;
|
||||
private String subject;
|
||||
private ZonedDateTime time;
|
||||
|
||||
private T data;
|
||||
|
||||
private final Set<ExtensionFormat> extensions = new HashSet<>();
|
||||
|
||||
private static Validator getValidator() {
|
||||
if(null== VALIDATOR) {
|
||||
VALIDATOR = Validation.buildDefaultValidatorFactory().getValidator();
|
||||
}
|
||||
return VALIDATOR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a brand new builder instance
|
||||
* @param <T> The 'data' type
|
||||
*/
|
||||
public static <T> CloudEventBuilder<T> builder() {
|
||||
return new CloudEventBuilder<T>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder with base event to copy attributes
|
||||
* @param <T> The 'data' type
|
||||
* @param base The base event to copy attributes
|
||||
*/
|
||||
public static <T> CloudEventBuilder<T> builder(
|
||||
CloudEvent<AttributesImpl, T> base) {
|
||||
Objects.requireNonNull(base);
|
||||
|
||||
CloudEventBuilder<T> result = new CloudEventBuilder<>();
|
||||
|
||||
AttributesImpl attributes = base.getAttributes();
|
||||
|
||||
result
|
||||
.withId(attributes.getId())
|
||||
.withSource(attributes.getSource())
|
||||
.withType(attributes.getType());
|
||||
|
||||
attributes.getDataschema().ifPresent((schema) -> {
|
||||
result.withDataschema(schema);
|
||||
});
|
||||
|
||||
attributes.getDatacontenttype().ifPresent(dc -> {
|
||||
result.withDatacontenttype(dc);
|
||||
});
|
||||
|
||||
attributes.getSubject().ifPresent(subject -> {
|
||||
result.withSubject(subject);
|
||||
});
|
||||
|
||||
attributes.getTime().ifPresent(time -> {
|
||||
result.withTime(time);
|
||||
});
|
||||
|
||||
Accessor.extensionsOf(base)
|
||||
.forEach(extension -> {
|
||||
result.withExtension(extension);
|
||||
});
|
||||
|
||||
base.getData().ifPresent(data -> {
|
||||
result.withData(data);
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CloudEvent<AttributesImpl, T> build(T data,
|
||||
AttributesImpl attributes,
|
||||
Collection<ExtensionFormat> extensions) {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return An new {@link CloudEvent} immutable instance
|
||||
* @throws IllegalStateException When there are specification constraints
|
||||
* violations
|
||||
*/
|
||||
public CloudEventImpl<T> build() {
|
||||
|
||||
AttributesImpl attributes = new AttributesImpl(id, source, SPEC_VERSION, type,
|
||||
datacontenttype, dataschema, subject, time);
|
||||
|
||||
CloudEventImpl<T> cloudEvent =
|
||||
new CloudEventImpl<T>(attributes, data, extensions);
|
||||
|
||||
Set<ConstraintViolation<Object>> violations =
|
||||
getValidator().validate(cloudEvent);
|
||||
|
||||
violations.addAll(getValidator().validate(cloudEvent.getAttributes()));
|
||||
|
||||
final String errs =
|
||||
violations.stream()
|
||||
.map(v -> format(MESSAGE, v.getPropertyPath(), v.getMessage()))
|
||||
.collect(Collectors.joining(MESSAGE_SEPARATOR));
|
||||
|
||||
Optional.ofNullable(
|
||||
"".equals(errs) ? null : errs
|
||||
|
||||
).ifPresent((e) -> {
|
||||
throw new IllegalStateException(format(ERR_MESSAGE, e));
|
||||
});
|
||||
|
||||
return cloudEvent;
|
||||
}
|
||||
|
||||
|
||||
public CloudEventBuilder<T> withId(String id) {
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CloudEventBuilder<T> withSource(URI source) {
|
||||
this.source = source;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CloudEventBuilder<T> withType(String type) {
|
||||
this.type = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CloudEventBuilder<T> withDataschema(URI dataschema) {
|
||||
this.dataschema = dataschema;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CloudEventBuilder<T> withDatacontenttype(
|
||||
String datacontenttype) {
|
||||
this.datacontenttype = datacontenttype;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CloudEventBuilder<T> withSubject(
|
||||
String subject) {
|
||||
this.subject = subject;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CloudEventBuilder<T> withTime(ZonedDateTime time) {
|
||||
this.time = time;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CloudEventBuilder<T> withData(T data) {
|
||||
this.data = data;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CloudEventBuilder<T> withExtension(ExtensionFormat extension) {
|
||||
this.extensions.add(extension);
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
/**
|
||||
* Copyright 2019 The CloudEvents Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.cloudevents.v1;
|
||||
|
||||
import java.net.URI;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAnyGetter;
|
||||
import com.fasterxml.jackson.annotation.JsonAnySetter;
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonUnwrapped;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
|
||||
import io.cloudevents.CloudEvent;
|
||||
import io.cloudevents.extensions.ExtensionFormat;
|
||||
import io.cloudevents.extensions.InMemoryFormat;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author fabiojose
|
||||
* @version 1.0
|
||||
*/
|
||||
@JsonInclude(value = Include.NON_ABSENT)
|
||||
public class CloudEventImpl<T> implements CloudEvent<AttributesImpl, T> {
|
||||
|
||||
@JsonIgnore
|
||||
@NotNull
|
||||
private final AttributesImpl attributes;
|
||||
|
||||
private final T data;
|
||||
|
||||
@NotNull
|
||||
private final Map<String, Object> extensions;
|
||||
|
||||
private final Set<ExtensionFormat> extensionsFormats;
|
||||
|
||||
CloudEventImpl(AttributesImpl attributes, T data,
|
||||
Set<ExtensionFormat> extensions){
|
||||
this.attributes = attributes;
|
||||
this.data = data;
|
||||
|
||||
this.extensions = extensions.stream()
|
||||
.map(ExtensionFormat::memory)
|
||||
.collect(Collectors.toMap(InMemoryFormat::getKey,
|
||||
InMemoryFormat::getValue));
|
||||
|
||||
this.extensionsFormats = extensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by the {@link Accessor} to access the set of {@link ExtensionFormat}
|
||||
*/
|
||||
Set<ExtensionFormat> getExtensionsFormats() {
|
||||
return extensionsFormats;
|
||||
}
|
||||
|
||||
@JsonUnwrapped
|
||||
@Override
|
||||
public AttributesImpl getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<T> getData() {
|
||||
return Optional.ofNullable(data);
|
||||
}
|
||||
|
||||
@JsonAnyGetter
|
||||
@Override
|
||||
public Map<String, Object> getExtensions() {
|
||||
return Collections.unmodifiableMap(extensions);
|
||||
}
|
||||
|
||||
/**
|
||||
* The unique method that allows mutation. Used by
|
||||
* Jackson Framework to inject the extensions.
|
||||
*
|
||||
* @param name Extension name
|
||||
* @param value Extension value
|
||||
*/
|
||||
@JsonAnySetter
|
||||
void addExtension(String name, Object value) {
|
||||
extensions.put(name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by the Jackson Framework to unmarshall.
|
||||
*/
|
||||
@JsonCreator
|
||||
public static <T> CloudEventImpl<T> build(
|
||||
@JsonProperty("id") String id,
|
||||
@JsonProperty("source") URI source,
|
||||
@JsonProperty("specversion") String specversion,
|
||||
@JsonProperty("type") String type,
|
||||
@JsonProperty("datacontenttype") String datacontenttype,
|
||||
@JsonProperty("dataschema") URI dataschema,
|
||||
@JsonProperty("subject") String subject,
|
||||
@JsonProperty("time") ZonedDateTime time,
|
||||
@JsonProperty("data") T data){
|
||||
|
||||
return CloudEventBuilder.<T>builder()
|
||||
.withId(id)
|
||||
.withSource(source)
|
||||
.withType(type)
|
||||
.withTime(time)
|
||||
.withDataschema(dataschema)
|
||||
.withDatacontenttype(datacontenttype)
|
||||
.withData(data)
|
||||
.withSubject(subject)
|
||||
.build();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/**
|
||||
* Copyright 2019 The CloudEvents Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.cloudevents.v1;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author fabiojose
|
||||
* @version 1.0
|
||||
*/
|
||||
public enum ContextAttributes {
|
||||
|
||||
id,
|
||||
source,
|
||||
specversion,
|
||||
type,
|
||||
datacontenttype,
|
||||
dataschema,
|
||||
subject,
|
||||
time;
|
||||
|
||||
public static final List<String> VALUES =
|
||||
Arrays.asList(ContextAttributes.values())
|
||||
.stream()
|
||||
.map(Enum::name)
|
||||
.collect(Collectors.toList());
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
/**
|
||||
* Copyright 2019 The CloudEvents Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.cloudevents.v1;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import io.cloudevents.extensions.DistributedTracingExtension;
|
||||
import io.cloudevents.extensions.ExtensionFormat;
|
||||
import io.cloudevents.extensions.InMemoryFormat;
|
||||
import io.cloudevents.v1.Accessor;
|
||||
import io.cloudevents.v1.CloudEventBuilder;
|
||||
import io.cloudevents.v1.CloudEventImpl;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author fabiojose
|
||||
*
|
||||
*/
|
||||
public class AccessorTest {
|
||||
@Test
|
||||
public void should_empty_collection_when_no_extensions() {
|
||||
// setup
|
||||
CloudEventImpl<Object> ce =
|
||||
CloudEventBuilder.<Object>builder()
|
||||
.withId("x10")
|
||||
.withSource(URI.create("/source"))
|
||||
.withType("event-type")
|
||||
.withDataschema(URI.create("/schema"))
|
||||
.withDatacontenttype("text/plain")
|
||||
.withData("my-data")
|
||||
.build();
|
||||
|
||||
// act
|
||||
Collection<ExtensionFormat> actual = Accessor.extensionsOf(ce);
|
||||
|
||||
// assert
|
||||
assertTrue(actual.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_return_the_tracing_extension() {
|
||||
// setup
|
||||
final DistributedTracingExtension dt = new DistributedTracingExtension();
|
||||
dt.setTraceparent("0");
|
||||
dt.setTracestate("congo=4");
|
||||
|
||||
final ExtensionFormat expected = new DistributedTracingExtension.Format(dt);
|
||||
|
||||
CloudEventImpl<Object> ce =
|
||||
CloudEventBuilder.<Object>builder()
|
||||
.withId("x10")
|
||||
.withSource(URI.create("/source"))
|
||||
.withType("event-type")
|
||||
.withDataschema(URI.create("/schema"))
|
||||
.withDatacontenttype("text/plain")
|
||||
.withData("my-data")
|
||||
.withExtension(expected)
|
||||
.build();
|
||||
|
||||
// act
|
||||
Collection<ExtensionFormat> extensions =
|
||||
Accessor.extensionsOf(ce);
|
||||
|
||||
// assert
|
||||
assertFalse(extensions.isEmpty());
|
||||
ExtensionFormat actual = extensions.iterator().next();
|
||||
|
||||
assertEquals("0", actual.transport().get("traceparent"));
|
||||
assertEquals("congo=4", actual.transport().get("tracestate"));
|
||||
|
||||
assertEquals("0",
|
||||
((DistributedTracingExtension)actual.memory().getValue()).getTraceparent());
|
||||
|
||||
assertEquals("congo=4",
|
||||
((DistributedTracingExtension)actual.memory().getValue()).getTracestate());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_return_the_custom_extension() {
|
||||
// setup
|
||||
String customExt = "comexampleextension1";
|
||||
String customVal = "my-ext-val";
|
||||
InMemoryFormat inMemory =
|
||||
InMemoryFormat.of(customExt, customVal, String.class);
|
||||
|
||||
ExtensionFormat expected =
|
||||
ExtensionFormat.of(inMemory, customExt, customVal);
|
||||
|
||||
CloudEventImpl<Object> ce =
|
||||
CloudEventBuilder.<Object>builder()
|
||||
.withId("x10")
|
||||
.withSource(URI.create("/source"))
|
||||
.withType("event-type")
|
||||
.withDataschema(URI.create("/schema"))
|
||||
.withDatacontenttype("text/plain")
|
||||
.withData("my-data")
|
||||
.withExtension(expected)
|
||||
.build();
|
||||
|
||||
// act
|
||||
Collection<ExtensionFormat> extensions =
|
||||
Accessor.extensionsOf(ce);
|
||||
|
||||
// assert
|
||||
assertFalse(extensions.isEmpty());
|
||||
ExtensionFormat actual = extensions.iterator().next();
|
||||
|
||||
assertEquals(customVal, actual.transport().get(customExt));
|
||||
|
||||
assertEquals(String.class, actual.memory().getValueType());
|
||||
|
||||
assertEquals(customExt, actual.memory().getKey());
|
||||
|
||||
assertEquals(customVal, actual.memory().getValue());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,194 @@
|
|||
/**
|
||||
* Copyright 2019 The CloudEvents Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.cloudevents.v1;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import io.cloudevents.CloudEvent;
|
||||
import io.cloudevents.extensions.DistributedTracingExtension;
|
||||
import io.cloudevents.extensions.ExtensionFormat;
|
||||
import io.cloudevents.extensions.InMemoryFormat;
|
||||
import io.cloudevents.v1.AttributesImpl;
|
||||
import io.cloudevents.v1.CloudEventBuilder;
|
||||
import io.cloudevents.v1.CloudEventImpl;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author fabiojose
|
||||
*
|
||||
*/
|
||||
public class CloudEventBuilderTest {
|
||||
|
||||
@Rule
|
||||
public ExpectedException expectedEx = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void error_when_null_id() {
|
||||
// setup
|
||||
expectedEx.expect(IllegalStateException.class);
|
||||
expectedEx.expectMessage("invalid payload: 'id' must not be blank");
|
||||
|
||||
// act
|
||||
CloudEventBuilder.builder()
|
||||
.withSource(URI.create("/test"))
|
||||
.withType("type")
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void error_when_empty_id() {
|
||||
// setup
|
||||
expectedEx.expect(IllegalStateException.class);
|
||||
expectedEx.expectMessage("invalid payload: 'id' must not be blank");
|
||||
|
||||
// act
|
||||
CloudEventBuilder.builder()
|
||||
.withId("")
|
||||
.withSource(URI.create("/test"))
|
||||
.withType("type")
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void error_when_null_type() {
|
||||
// setup
|
||||
expectedEx.expect(IllegalStateException.class);
|
||||
expectedEx.expectMessage("invalid payload: 'type' must not be blank");
|
||||
|
||||
// act
|
||||
CloudEventBuilder.builder()
|
||||
.withId("id")
|
||||
.withSource(URI.create("/test"))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void error_when_empty_type() {
|
||||
// setup
|
||||
expectedEx.expect(IllegalStateException.class);
|
||||
expectedEx.expectMessage("invalid payload: 'type' must not be blank");
|
||||
|
||||
// act
|
||||
CloudEventBuilder.builder()
|
||||
.withId("id")
|
||||
.withSource(URI.create("/test"))
|
||||
.withType("")
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void error_when_null_source() {
|
||||
// setup
|
||||
expectedEx.expect(IllegalStateException.class);
|
||||
expectedEx.expectMessage("invalid payload: 'source' must not be null");
|
||||
|
||||
// act
|
||||
CloudEventBuilder.builder()
|
||||
.withId("id")
|
||||
.withType("type")
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void error_when_empty_subject() {
|
||||
// setup
|
||||
expectedEx.expect(IllegalStateException.class);
|
||||
expectedEx.expectMessage("invalid payload: 'subject' size must be between 1 and 2147483647");
|
||||
|
||||
// act
|
||||
CloudEventBuilder.<Object>builder()
|
||||
.withId("id")
|
||||
.withType("type")
|
||||
.withSource(URI.create("/source"))
|
||||
.withSubject("")
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_have_subject() {
|
||||
// act
|
||||
CloudEvent<AttributesImpl, Object> ce =
|
||||
CloudEventBuilder.<Object>builder()
|
||||
.withId("id")
|
||||
.withSource(URI.create("/source"))
|
||||
.withType("type")
|
||||
.withSubject("subject")
|
||||
.build();
|
||||
|
||||
// assert
|
||||
assertTrue(ce.getAttributes().getSubject().isPresent());
|
||||
assertEquals("subject", ce.getAttributes().getSubject().get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_have_dte() {
|
||||
// setup
|
||||
final DistributedTracingExtension dt = new DistributedTracingExtension();
|
||||
dt.setTraceparent("0");
|
||||
dt.setTracestate("congo=4");
|
||||
|
||||
final ExtensionFormat tracing = new DistributedTracingExtension.Format(dt);
|
||||
|
||||
// act
|
||||
CloudEventImpl<Object> ce =
|
||||
CloudEventBuilder.builder()
|
||||
.withId("id")
|
||||
.withSource(URI.create("/source"))
|
||||
.withType("type")
|
||||
.withExtension(tracing)
|
||||
.build();
|
||||
|
||||
Object actual = ce.getExtensions()
|
||||
.get(DistributedTracingExtension.Format.IN_MEMORY_KEY);
|
||||
|
||||
// assert
|
||||
assertNotNull(actual);
|
||||
assertTrue(actual instanceof DistributedTracingExtension);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_have_custom_extension() {
|
||||
String myExtKey = "comexampleextension1";
|
||||
String myExtVal = "value";
|
||||
|
||||
ExtensionFormat custom = ExtensionFormat
|
||||
.of(InMemoryFormat.of(myExtKey, myExtKey, String.class),
|
||||
myExtKey, myExtVal);
|
||||
|
||||
// act
|
||||
CloudEventImpl<Object> ce =
|
||||
CloudEventBuilder.builder()
|
||||
.withId("id")
|
||||
.withSource(URI.create("/source"))
|
||||
.withType("type")
|
||||
.withExtension(custom)
|
||||
.build();
|
||||
|
||||
Object actual = ce.getExtensions()
|
||||
.get(myExtKey);
|
||||
|
||||
assertNotNull(actual);
|
||||
assertTrue(actual instanceof String);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue