diff --git a/gooddata-java-model/src/main/java/com/gooddata/sdk/model/auditevent/AccessLog.java b/gooddata-java-model/src/main/java/com/gooddata/sdk/model/auditevent/AccessLog.java new file mode 100644 index 000000000..316629d86 --- /dev/null +++ b/gooddata-java-model/src/main/java/com/gooddata/sdk/model/auditevent/AccessLog.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2004-2021, GoodData(R) Corporation. All rights reserved. + * This source code is licensed under the BSD-style license found in the + * LICENSE.txt file in the root directory of this source tree. + */ +package com.gooddata.sdk.model.auditevent; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.gooddata.sdk.common.util.GoodDataToStringBuilder; +import com.gooddata.sdk.common.util.ISOZonedDateTime; + +import java.time.ZonedDateTime; + +/** + * Model class, used for special audit log events/access logs directly from haproxy, + * that represents access logs for particular hosts. + */ +@JsonTypeInfo(include = JsonTypeInfo.As.WRAPPER_OBJECT, use = JsonTypeInfo.Id.NAME) +@JsonTypeName("accessLog") +@JsonIgnoreProperties(ignoreUnknown = true) +public class AccessLog { + + public static final String RESOURCE_URI = "/gdc/domains/{domainId}/accessLogs"; + + private final String id; + private final String host; + private final String path; + private final String method; + private final String code; + private final String size; + private final String userIp; + @ISOZonedDateTime + private final ZonedDateTime occurred; + @ISOZonedDateTime + private final ZonedDateTime recorded; + + @JsonCreator + public AccessLog(@JsonProperty("id") String id, @JsonProperty("host") String host, @JsonProperty("path") String path, + @JsonProperty("method") String method, @JsonProperty("code") String code, @JsonProperty("size") String size, + @JsonProperty("userIp") String userIp, @JsonProperty("occurred") ZonedDateTime occurred, @JsonProperty("recorded") ZonedDateTime recorded) { + this.id = id; + this.host = host; + this.path = path; + this.method = method; + this.code = code; + this.size = size; + this.userIp = userIp; + this.occurred = occurred; + this.recorded = recorded; + } + + public String getId() { + return id; + } + + public String getHost() { + return host; + } + + public String getPath() { + return path; + } + + public String getMethod() { + return method; + } + + public String getCode() { + return code; + } + + public String getSize() { + return size; + } + + public String getUserIp() { + return userIp; + } + + public ZonedDateTime getOccurred() { + return occurred; + } + + public ZonedDateTime getRecorded() { + return recorded; + } + + @Override + public String toString() { + return GoodDataToStringBuilder.defaultToString(this); + } +} diff --git a/gooddata-java-model/src/main/java/com/gooddata/sdk/model/auditevent/AccessLogs.java b/gooddata-java-model/src/main/java/com/gooddata/sdk/model/auditevent/AccessLogs.java new file mode 100644 index 000000000..def336394 --- /dev/null +++ b/gooddata-java-model/src/main/java/com/gooddata/sdk/model/auditevent/AccessLogs.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2004-2021, GoodData(R) Corporation. All rights reserved. + * This source code is licensed under the BSD-style license found in the + * LICENSE.txt file in the root directory of this source tree. + */ +package com.gooddata.sdk.model.auditevent; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.gooddata.sdk.common.collections.Page; +import com.gooddata.sdk.common.collections.Paging; + +import java.util.List; +import java.util.Map; + +@JsonTypeInfo( + include = JsonTypeInfo.As.WRAPPER_OBJECT, + use = JsonTypeInfo.Id.NAME +) +@JsonTypeName("accessLogs") +@JsonIgnoreProperties( + ignoreUnknown = true +) +@JsonSerialize( + using = AccessLogsSerializer.class +) +@JsonDeserialize( + using = AccessLogsDeserializer.class +) +public class AccessLogs extends Page { + static final String ROOT_NODE = "accessLogs"; + + public AccessLogs(List items, Paging paging, Map links) { + super(items, paging, links); + } +} diff --git a/gooddata-java-model/src/main/java/com/gooddata/sdk/model/auditevent/AccessLogsDeserializer.java b/gooddata-java-model/src/main/java/com/gooddata/sdk/model/auditevent/AccessLogsDeserializer.java new file mode 100644 index 000000000..70f73ebaa --- /dev/null +++ b/gooddata-java-model/src/main/java/com/gooddata/sdk/model/auditevent/AccessLogsDeserializer.java @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2004-2021, GoodData(R) Corporation. All rights reserved. + * This source code is licensed under the BSD-style license found in the + * LICENSE.txt file in the root directory of this source tree. + */ +package com.gooddata.sdk.model.auditevent; + +import com.gooddata.sdk.common.collections.PageDeserializer; +import com.gooddata.sdk.common.collections.Paging; + +import java.util.List; +import java.util.Map; + +public class AccessLogsDeserializer extends PageDeserializer { + + public AccessLogsDeserializer() { super(AccessLog.class); } + + @Override + protected AccessLogs createPage(List items, Paging paging, Map links) { + return new AccessLogs(items, paging, links); + } +} diff --git a/gooddata-java-model/src/main/java/com/gooddata/sdk/model/auditevent/AccessLogsSerializer.java b/gooddata-java-model/src/main/java/com/gooddata/sdk/model/auditevent/AccessLogsSerializer.java new file mode 100644 index 000000000..3103b9490 --- /dev/null +++ b/gooddata-java-model/src/main/java/com/gooddata/sdk/model/auditevent/AccessLogsSerializer.java @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2004-2021, GoodData(R) Corporation. All rights reserved. + * This source code is licensed under the BSD-style license found in the + * LICENSE.txt file in the root directory of this source tree. + */ +package com.gooddata.sdk.model.auditevent; + +import com.gooddata.sdk.common.collections.PageSerializer; + +public class AccessLogsSerializer extends PageSerializer { + public AccessLogsSerializer() { + super(AccessLogs.ROOT_NODE); + } +} diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/auditevent/AccessLogTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/auditevent/AccessLogTest.java new file mode 100644 index 000000000..d9269afa5 --- /dev/null +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/auditevent/AccessLogTest.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2004-2021, GoodData(R) Corporation. All rights reserved. + * This source code is licensed under the BSD-style license found in the + * LICENSE.txt file in the root directory of this source tree. + */ +package com.gooddata.sdk.model.auditevent; + +import org.testng.annotations.Test; + +import java.time.LocalDate; +import java.time.ZonedDateTime; + +import static com.gooddata.sdk.common.util.ResourceUtils.readObjectFromResource; +import static java.time.ZoneOffset.UTC; +import static net.javacrumbs.jsonunit.JsonMatchers.jsonEquals; +import static net.javacrumbs.jsonunit.core.util.ResourceUtils.resource; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.MatcherAssert.assertThat; + +public class AccessLogTest { + + private static final ZonedDateTime DATE = ZonedDateTime.of(LocalDate.of(1993, 3, 9).atStartOfDay(), UTC); + + private final AccessLog ACCESS_LOG = new AccessLog("123", "visa.gooddata.com", "/gdc/ping", "GET", "200", "2231", "127.0.0.1", DATE, DATE); + + @Test + public void testSerialize() throws Exception { + assertThat(ACCESS_LOG, jsonEquals(resource("auditevents/accessLog.json"))); + } + + @Test + public void testDeserialize() throws Exception { + final AccessLog deserializedObject = readObjectFromResource("/auditevents/accessLog.json", AccessLog.class); + assertThat(deserializedObject, notNullValue()); + assertThat(deserializedObject.getId(), is(ACCESS_LOG.getId())); + assertThat(deserializedObject.getHost(), is(ACCESS_LOG.getHost())); + assertThat(deserializedObject.getPath(), is(ACCESS_LOG.getPath())); + assertThat(deserializedObject.getMethod(), is(ACCESS_LOG.getMethod())); + assertThat(deserializedObject.getCode(), is(ACCESS_LOG.getCode())); + assertThat(deserializedObject.getSize(), is(ACCESS_LOG.getSize())); + assertThat(deserializedObject.getUserIp(), is(ACCESS_LOG.getUserIp())); + assertThat(deserializedObject.getOccurred(), is(ACCESS_LOG.getOccurred())); + assertThat(deserializedObject.getRecorded(), is(ACCESS_LOG.getRecorded())); + } + +} diff --git a/gooddata-java-model/src/test/java/com/gooddata/sdk/model/auditevent/AccessLogsTest.java b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/auditevent/AccessLogsTest.java new file mode 100644 index 000000000..b5f75a042 --- /dev/null +++ b/gooddata-java-model/src/test/java/com/gooddata/sdk/model/auditevent/AccessLogsTest.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2004-2021, GoodData(R) Corporation. All rights reserved. + * This source code is licensed under the BSD-style license found in the + * LICENSE.txt file in the root directory of this source tree. + */ +package com.gooddata.sdk.model.auditevent; + +import com.gooddata.sdk.common.collections.Paging; +import org.springframework.web.util.UriTemplate; +import org.testng.annotations.Test; + +import java.time.LocalDate; +import java.time.ZonedDateTime; +import java.util.Collections; +import java.util.List; + +import static com.gooddata.sdk.common.util.ResourceUtils.readObjectFromResource; +import static java.time.ZoneOffset.UTC; +import static java.util.Arrays.asList; +import static java.util.Collections.singletonMap; +import static net.javacrumbs.jsonunit.JsonMatchers.jsonEquals; +import static net.javacrumbs.jsonunit.core.util.ResourceUtils.resource; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasSize; + +public class AccessLogsTest { + + private static final ZonedDateTime DATE = ZonedDateTime.of(LocalDate.of(1993, 3, 9).atStartOfDay(), UTC); + + private final AccessLog ACCESS_LOG_1 = new AccessLog("123", "visa.gooddata.com", "/gdc/ping", "GET", "200", "2231", "127.0.0.1", DATE, DATE); + private final AccessLog ACCESS_LOG_2 = new AccessLog("456", "mastercard.gooddata.com", "/gdc/ping", "GET", "200", "2231", "127.0.0.1", DATE, DATE); + + private static final String DOMAIN = "default"; + private static final String RESOURCE_URI = new UriTemplate(AccessLog.RESOURCE_URI).expand(DOMAIN).toString(); + private static final String RESOURCE_NEXT_URI = RESOURCE_URI + "?offset=456"; + + private final AccessLogs ACCESS_LOGS = new AccessLogs( + asList(ACCESS_LOG_1, ACCESS_LOG_2), + new Paging(RESOURCE_NEXT_URI), + singletonMap("self", RESOURCE_URI) + ); + + private final AccessLogs EMPTY_ACCESS_LOGS = new AccessLogs( + Collections.emptyList(), + new Paging(null), + singletonMap("self", RESOURCE_URI) + ); + + @Test + public void shouldSerialize() throws Exception { + assertThat(ACCESS_LOGS, jsonEquals(resource("auditevents/accessLogs.json"))); + } + + @Test + public void shouldDeserialize() throws Exception { + final AccessLogs deserialized = readObjectFromResource("/auditevents/accessLogs.json", AccessLogs.class); + assertThat(deserialized.getPaging().getNextUri(), is(RESOURCE_NEXT_URI)); + final List pageItems = deserialized.getPageItems(); + assertThat(pageItems, hasSize(2)); + assertThat(pageItems.get(0).getId(), is(ACCESS_LOG_1.getId())); + assertThat(pageItems.get(1).getId(), is(ACCESS_LOG_2.getId())); + } + + @Test + public void testSerializeEmptyAccessLogs() throws Exception { + assertThat(EMPTY_ACCESS_LOGS, jsonEquals(resource("auditevents/emptyAccessLogs.json"))); + } + + @Test + public void testDeserializeEmptyEvents() throws Exception { + final AccessLogs deserialized = readObjectFromResource("/auditevents/emptyAccessLogs.json", AccessLogs.class); + assertThat(deserialized.getPaging().getNextUri(), nullValue()); + assertThat(deserialized.getPageItems(), hasSize(0)); + } + +} diff --git a/gooddata-java-model/src/test/resources/auditevents/accessLog.json b/gooddata-java-model/src/test/resources/auditevents/accessLog.json new file mode 100644 index 000000000..118b2e965 --- /dev/null +++ b/gooddata-java-model/src/test/resources/auditevents/accessLog.json @@ -0,0 +1,13 @@ +{ + "accessLog": { + "id": "123", + "host": "visa.gooddata.com", + "path": "/gdc/ping", + "method": "GET", + "code": "200", + "size": "2231", + "userIp": "127.0.0.1", + "occurred": "1993-03-09T00:00:00.000Z", + "recorded": "1993-03-09T00:00:00.000Z" + } +} diff --git a/gooddata-java-model/src/test/resources/auditevents/accessLogs.json b/gooddata-java-model/src/test/resources/auditevents/accessLogs.json new file mode 100644 index 000000000..0c8d59ecd --- /dev/null +++ b/gooddata-java-model/src/test/resources/auditevents/accessLogs.json @@ -0,0 +1,38 @@ +{ + "accessLogs": { + "items": [ + { + "accessLog": { + "id": "123", + "host": "visa.gooddata.com", + "path": "/gdc/ping", + "method": "GET", + "code": "200", + "size": "2231", + "userIp": "127.0.0.1", + "occurred": "1993-03-09T00:00:00.000Z", + "recorded": "1993-03-09T00:00:00.000Z" + } + }, + { + "accessLog": { + "id": "456", + "host": "mastercard.gooddata.com", + "path": "/gdc/ping", + "method": "GET", + "code": "200", + "size": "2231", + "userIp": "127.0.0.1", + "occurred": "1993-03-09T00:00:00.000Z", + "recorded": "1993-03-09T00:00:00.000Z" + } + } + ], + "paging": { + "next": "/gdc/domains/default/accessLogs?offset=456" + }, + "links": { + "self": "/gdc/domains/default/accessLogs" + } + } +} diff --git a/gooddata-java-model/src/test/resources/auditevents/emptyAccessLogs.json b/gooddata-java-model/src/test/resources/auditevents/emptyAccessLogs.json new file mode 100644 index 000000000..a2f22f479 --- /dev/null +++ b/gooddata-java-model/src/test/resources/auditevents/emptyAccessLogs.json @@ -0,0 +1,11 @@ +{ + "accessLogs": { + "items": [ + ], + "paging": { + }, + "links": { + "self": "/gdc/domains/default/accessLogs" + } + } +} \ No newline at end of file diff --git a/gooddata-java/src/main/java/com/gooddata/sdk/service/auditevent/AuditEventPageRequest.java b/gooddata-java/src/main/java/com/gooddata/sdk/service/auditevent/AuditEventPageRequest.java index 1e5d3e26e..4b13de613 100644 --- a/gooddata-java/src/main/java/com/gooddata/sdk/service/auditevent/AuditEventPageRequest.java +++ b/gooddata-java/src/main/java/com/gooddata/sdk/service/auditevent/AuditEventPageRequest.java @@ -1,57 +1,26 @@ /* - * Copyright (C) 2004-2019, GoodData(R) Corporation. All rights reserved. + * Copyright (C) 2004-2021, GoodData(R) Corporation. All rights reserved. * This source code is licensed under the BSD-style license found in the * LICENSE.txt file in the root directory of this source tree. */ package com.gooddata.sdk.service.auditevent; -import com.gooddata.sdk.common.collections.CustomPageRequest; import com.gooddata.sdk.common.util.GoodDataToStringBuilder; -import com.gooddata.sdk.common.util.ISOZonedDateTime; import com.gooddata.sdk.common.util.MutableUri; import org.springframework.beans.BeanUtils; -import java.time.ZonedDateTime; - -import static java.time.ZoneOffset.UTC; import static org.apache.commons.lang3.Validate.notNull; /** * Class to encapsulate time filtering and paging parameters */ -public final class AuditEventPageRequest extends CustomPageRequest { - - private ZonedDateTime from; - - private ZonedDateTime to; +public final class AuditEventPageRequest extends TimeFilterPageRequest { private String type; public AuditEventPageRequest() { } - public ZonedDateTime getFrom() { - return from; - } - - /** - * Specify lower bound of interval - */ - public void setFrom(final ZonedDateTime from) { - this.from = from; - } - - public ZonedDateTime getTo() { - return to; - } - - /** - * Specify upper bound of interval - */ - public void setTo(final ZonedDateTime to) { - this.to = to; - } - public String getType() { return type; } @@ -95,12 +64,7 @@ public AuditEventPageRequest withIncrementedLimit() { @Override public MutableUri updateWithPageParams(final MutableUri builder) { MutableUri builderWithPaging = super.updateWithPageParams(builder); - if (from != null) { - builderWithPaging.replaceQueryParam("from", ISOZonedDateTime.FORMATTER.format(from.withZoneSameInstant(UTC))); - } - if (to != null) { - builderWithPaging.replaceQueryParam("to", ISOZonedDateTime.FORMATTER.format(to.withZoneSameInstant(UTC))); - } + if (type != null) { builderWithPaging.replaceQueryParam("type", type); } diff --git a/gooddata-java/src/main/java/com/gooddata/sdk/service/auditevent/TimeFilterPageRequest.java b/gooddata-java/src/main/java/com/gooddata/sdk/service/auditevent/TimeFilterPageRequest.java new file mode 100644 index 000000000..721f5d69c --- /dev/null +++ b/gooddata-java/src/main/java/com/gooddata/sdk/service/auditevent/TimeFilterPageRequest.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2004-2021, GoodData(R) Corporation. All rights reserved. + * This source code is licensed under the BSD-style license found in the + * LICENSE.txt file in the root directory of this source tree. + */ +package com.gooddata.sdk.service.auditevent; + +import com.gooddata.sdk.common.collections.CustomPageRequest; +import com.gooddata.sdk.common.util.GoodDataToStringBuilder; +import com.gooddata.sdk.common.util.ISOZonedDateTime; +import com.gooddata.sdk.common.util.MutableUri; +import com.gooddata.sdk.common.util.Validate; +import org.springframework.beans.BeanUtils; + +import java.time.ZoneOffset; +import java.time.ZonedDateTime; + +/** + * Class to encapsulate time filtering + */ +public class TimeFilterPageRequest extends CustomPageRequest { + protected ZonedDateTime from; + protected ZonedDateTime to; + + public TimeFilterPageRequest() { + } + + public ZonedDateTime getFrom() { + return this.from; + } + + public void setFrom(ZonedDateTime from) { + this.from = from; + } + + public ZonedDateTime getTo() { + return this.to; + } + + public void setTo(ZonedDateTime to) { + this.to = to; + } + + public static TimeFilterPageRequest copy(TimeFilterPageRequest source) { + Validate.notNull(source, "source cannot be null"); + TimeFilterPageRequest copy = new TimeFilterPageRequest(); + BeanUtils.copyProperties(source, copy); + return copy; + } + + public TimeFilterPageRequest withIncrementedLimit() { + TimeFilterPageRequest copy = copy(this); + copy.setLimit(this.getSanitizedLimit() + 1); + return copy; + } + + @Override + public MutableUri updateWithPageParams(MutableUri builder) { + MutableUri builderWithPaging = super.updateWithPageParams(builder); + if (this.from != null) { + builderWithPaging.replaceQueryParam("from", new Object[]{ISOZonedDateTime.FORMATTER.format(this.from.withZoneSameInstant(ZoneOffset.UTC))}); + } + + if (this.to != null) { + builderWithPaging.replaceQueryParam("to", new Object[]{ISOZonedDateTime.FORMATTER.format(this.to.withZoneSameInstant(ZoneOffset.UTC))}); + } + + return builderWithPaging; + } + + @Override + protected boolean canEqual(Object o) { + return o instanceof TimeFilterPageRequest; + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (!(o instanceof TimeFilterPageRequest)) return false; + if (!super.equals(o)) return false; + + final TimeFilterPageRequest that = (TimeFilterPageRequest) o; + if (!that.canEqual(this)) return false; + + if (from != null ? !from.equals(that.from) : that.from != null) return false; + if (to != null ? !to.equals(that.to) : that.to != null) return false; + return true; + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + (this.from != null ? this.from.hashCode() : 0); + result = 31 * result + (this.to != null ? this.to.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return GoodDataToStringBuilder.defaultToString(this, new String[0]); + } + +} + diff --git a/gooddata-java/src/test/java/com/gooddata/sdk/service/auditevent/TimeFilterPageRequestTest.java b/gooddata-java/src/test/java/com/gooddata/sdk/service/auditevent/TimeFilterPageRequestTest.java new file mode 100644 index 000000000..5e76a401c --- /dev/null +++ b/gooddata-java/src/test/java/com/gooddata/sdk/service/auditevent/TimeFilterPageRequestTest.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2004-2021, GoodData(R) Corporation. All rights reserved. + * This source code is licensed under the BSD-style license found in the + * LICENSE.txt file in the root directory of this source tree. + */ +package com.gooddata.sdk.service.auditevent; + +import com.gooddata.sdk.common.util.ISOZonedDateTime; +import com.gooddata.sdk.common.util.MutableUri; +import com.gooddata.sdk.common.util.SpringMutableUri; +import nl.jqno.equalsverifier.EqualsVerifier; +import nl.jqno.equalsverifier.Warning; +import org.testng.annotations.Test; + +import java.time.ZonedDateTime; + +import static com.gooddata.sdk.common.collections.CustomPageRequest.DEFAULT_LIMIT; +import static com.shazam.shazamcrest.matcher.Matchers.sameBeanAs; +import static java.time.ZoneOffset.UTC; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; + +public class TimeFilterPageRequestTest { + + private static final ZonedDateTime FROM = ZonedDateTime.of(2019, 10, 28, 15, 30, 12, 0, UTC); + private static final ZonedDateTime TO = ZonedDateTime.of(2019, 11, 25, 8, 5, 58, 125000000, UTC); + private static final Integer LIMIT = 10; + private static final String OFFSET = "foo"; + + @Test + public void testCopy() { + TimeFilterPageRequest request = new TimeFilterPageRequest(); + request.setFrom(FROM); + request.setTo(TO); + request.setLimit(LIMIT); + request.setOffset(OFFSET); + + TimeFilterPageRequest copy = TimeFilterPageRequest.copy(request); + + assertThat(request, is(sameBeanAs(copy))); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testCopyNull() { + TimeFilterPageRequest.copy(null); + } + + @Test + public void testWithIncrementedLimit() { + TimeFilterPageRequest request = new TimeFilterPageRequest(); + request.setFrom(FROM); + request.setTo(TO); + request.setLimit(LIMIT); + request.setOffset(OFFSET); + TimeFilterPageRequest result = request.withIncrementedLimit(); + + assertThat(result.getFrom(), is(FROM)); + assertThat(result.getTo(), is(TO)); + assertThat(result.getSanitizedLimit(), is(LIMIT + 1)); + assertThat(result.getOffset(), is(OFFSET)); + } + + @Test + public void testUpdateWithAllFields() { + TimeFilterPageRequest request = new TimeFilterPageRequest(); + request.setFrom(FROM); + request.setTo(TO); + request.setLimit(LIMIT); + request.setOffset(OFFSET); + + MutableUri result = request.updateWithPageParams(new SpringMutableUri("")); + + assertThat(result.toUriString(), is(String.format("?offset=%s&limit=%d&from=%s&to=%s", + OFFSET, LIMIT, ISOZonedDateTime.FORMATTER.format(FROM.withZoneSameInstant(UTC)), + ISOZonedDateTime.FORMATTER.format(TO.withZoneSameInstant(UTC))))); + } + + @Test + public void testUpdateWithOnlyPagingFields() { + TimeFilterPageRequest request = new TimeFilterPageRequest(); + request.setLimit(LIMIT); + request.setOffset(OFFSET); + + MutableUri result = request.updateWithPageParams(new SpringMutableUri("")); + + assertThat(result.toUriString(), is("?offset=" + OFFSET + "&limit=" + LIMIT)); + } + + @Test + public void testUpdateWithOnlyTimeIntervalFields() { + TimeFilterPageRequest request = new TimeFilterPageRequest(); + request.setFrom(FROM); + request.setTo(TO); + + MutableUri result = request.updateWithPageParams(new SpringMutableUri("")); + + assertThat(result.toUriString(), is("?limit=" + DEFAULT_LIMIT + + "&from=2019-10-28T15:30:12.000Z&to=2019-11-25T08:05:58.125Z")); + } + + @Test + public void shouldVerifyEquals() { + EqualsVerifier.simple().forClass(TimeFilterPageRequest.class) + .withRedefinedSuperclass() + .suppress(Warning.NONFINAL_FIELDS) + .verify(); + } + +}