JAMES-2530 [FILTERS] Complete POJOs, add tests and first draft of DTO Based on Gautier work
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/4d8e807e Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/4d8e807e Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/4d8e807e Branch: refs/heads/master Commit: 4d8e807e5414d26fd912aae7017760e32fe7c38e Parents: 3b648e9 Author: Gautier DI FOLCO <gdifo...@linagora.com> Authored: Thu Aug 23 10:18:01 2018 +0200 Committer: Benoit Tellier <btell...@linagora.com> Committed: Tue Aug 28 12:48:15 2018 +0700 ---------------------------------------------------------------------- server/data/data-jmap-cassandra/pom.xml | 5 + .../FilteringRuleSetDefineDTOModules.java | 4 +- .../filtering/FilteringRuleSetDefinedDTO.java | 4 + .../james/jmap/cassandra/filtering/RuleDTO.java | 68 ++++- .../james/jmap/cassandra/filtering/DTOTest.java | 114 ++++++++ .../src/test/resources/json/event.json | 23 ++ .../src/test/resources/json/eventComplex.json | 39 +++ .../src/test/resources/json/eventEmpty.json | 6 + .../jmap/api/filtering/FilteringManagement.java | 11 + .../apache/james/jmap/api/filtering/Rule.java | 287 ++++++++++++++++++- .../filtering/FilteringManagementContract.java | 78 +++-- .../james/jmap/api/filtering/RuleFixture.java | 71 +++++ .../james/jmap/api/filtering/RuleTest.java | 133 ++++++++- .../filtering/impl/DefineRulesCommandTest.java | 5 +- 14 files changed, 799 insertions(+), 49 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/james-project/blob/4d8e807e/server/data/data-jmap-cassandra/pom.xml ---------------------------------------------------------------------- diff --git a/server/data/data-jmap-cassandra/pom.xml b/server/data/data-jmap-cassandra/pom.xml index e9f4e85..67a479a 100644 --- a/server/data/data-jmap-cassandra/pom.xml +++ b/server/data/data-jmap-cassandra/pom.xml @@ -78,6 +78,11 @@ <artifactId>javax.inject</artifactId> </dependency> <dependency> + <groupId>net.javacrumbs.json-unit</groupId> + <artifactId>json-unit-assertj</artifactId> + <scope>test</scope> + </dependency> + <dependency> <groupId>org.assertj</groupId> <artifactId>assertj-core</artifactId> <scope>test</scope> http://git-wip-us.apache.org/repos/asf/james-project/blob/4d8e807e/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/filtering/FilteringRuleSetDefineDTOModules.java ---------------------------------------------------------------------- diff --git a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/filtering/FilteringRuleSetDefineDTOModules.java b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/filtering/FilteringRuleSetDefineDTOModules.java index 0c56b1c..2248eec 100644 --- a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/filtering/FilteringRuleSetDefineDTOModules.java +++ b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/filtering/FilteringRuleSetDefineDTOModules.java @@ -24,11 +24,13 @@ import org.apache.james.jmap.api.filtering.impl.RuleSetDefined; public interface FilteringRuleSetDefineDTOModules { + String TYPE = "filtering-rule-set-defined"; + EventDTOModule<RuleSetDefined, FilteringRuleSetDefinedDTO> FILTERING_RULE_SET_DEFINED = EventDTOModule .forEvent(RuleSetDefined.class) .convertToDTO(FilteringRuleSetDefinedDTO.class) .convertWith(FilteringRuleSetDefinedDTO::from) - .typeName("filtering-rule-set-defined"); + .typeName(TYPE); } http://git-wip-us.apache.org/repos/asf/james-project/blob/4d8e807e/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/filtering/FilteringRuleSetDefinedDTO.java ---------------------------------------------------------------------- diff --git a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/filtering/FilteringRuleSetDefinedDTO.java b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/filtering/FilteringRuleSetDefinedDTO.java index 5a0de2c..0aa5bf6 100644 --- a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/filtering/FilteringRuleSetDefinedDTO.java +++ b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/filtering/FilteringRuleSetDefinedDTO.java @@ -41,6 +41,10 @@ public class FilteringRuleSetDefinedDTO implements EventDTO { RuleDTO.from(event.getRules())); } + public static FilteringRuleSetDefinedDTO from(RuleSetDefined event) { + return from(event, FilteringRuleSetDefineDTOModules.TYPE); + } + private final String type; private final int eventId; private final String aggregateId; http://git-wip-us.apache.org/repos/asf/james-project/blob/4d8e807e/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/filtering/RuleDTO.java ---------------------------------------------------------------------- diff --git a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/filtering/RuleDTO.java b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/filtering/RuleDTO.java index a361465..c72eb39 100644 --- a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/filtering/RuleDTO.java +++ b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/filtering/RuleDTO.java @@ -35,7 +35,7 @@ public class RuleDTO { public static ImmutableList<Rule> toRules(List<RuleDTO> ruleDTOList) { Preconditions.checkNotNull(ruleDTOList); return ruleDTOList.stream() - .map(dto -> Rule.of(dto.getId())) + .map(RuleDTO::toRule) .collect(ImmutableList.toImmutableList()); } @@ -47,13 +47,33 @@ public class RuleDTO { } public static RuleDTO from(Rule rule) { - return new RuleDTO(rule.getId()); + return new RuleDTO(rule.getId().asString(), + rule.getName(), + rule.getCondition().getField().asString(), + rule.getCondition().getComparator().asString(), + rule.getCondition().getValue(), + rule.getAction().getMailboxIds()); } private final String id; + private final String name; + private final String field; + private final String comparator; + private final String value; + private final List<String> mailboxIds; @JsonCreator - public RuleDTO(@JsonProperty("id") String id) { + public RuleDTO(@JsonProperty("id") String id, + @JsonProperty("name") String name, + @JsonProperty("field") String field, + @JsonProperty("comparator") String comparator, + @JsonProperty("value") String value, + @JsonProperty("mailboxIds") List<String> mailboxIds) { + this.name = name; + this.field = field; + this.comparator = comparator; + this.value = value; + this.mailboxIds = ImmutableList.copyOf(mailboxIds); Preconditions.checkNotNull(id); this.id = id; @@ -63,19 +83,57 @@ public class RuleDTO { return id; } + public String getName() { + return name; + } + + public String getField() { + return field; + } + + public String getComparator() { + return comparator; + } + + public String getValue() { + return value; + } + + public List<String> getMailboxIds() { + return mailboxIds; + } + + public Rule toRule() { + return Rule.builder() + .id(Rule.Id.of(id)) + .name(name) + .condition(Rule.Condition.of( + Rule.Condition.Field.valueOf(field), + Rule.Condition.Comparator.of(comparator), + value)) + .name(name) + .action(Rule.Action.ofMailboxIds(mailboxIds)) + .build(); + } + @Override public final boolean equals(Object o) { if (o instanceof RuleDTO) { RuleDTO ruleDTO = (RuleDTO) o; - return Objects.equals(this.id, ruleDTO.id); + return Objects.equals(this.id, ruleDTO.id) + && Objects.equals(this.name, ruleDTO.name) + && Objects.equals(this.field, ruleDTO.field) + && Objects.equals(this.comparator, ruleDTO.comparator) + && Objects.equals(this.value, ruleDTO.value) + && Objects.equals(this.mailboxIds, ruleDTO.mailboxIds); } return false; } @Override public final int hashCode() { - return Objects.hash(id); + return Objects.hash(id, name, field, comparator, value, mailboxIds); } @Override http://git-wip-us.apache.org/repos/asf/james-project/blob/4d8e807e/server/data/data-jmap-cassandra/src/test/java/org/apache/james/jmap/cassandra/filtering/DTOTest.java ---------------------------------------------------------------------- diff --git a/server/data/data-jmap-cassandra/src/test/java/org/apache/james/jmap/cassandra/filtering/DTOTest.java b/server/data/data-jmap-cassandra/src/test/java/org/apache/james/jmap/cassandra/filtering/DTOTest.java new file mode 100644 index 0000000..08f5685 --- /dev/null +++ b/server/data/data-jmap-cassandra/src/test/java/org/apache/james/jmap/cassandra/filtering/DTOTest.java @@ -0,0 +1,114 @@ +/**************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one * + * or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information * + * regarding copyright ownership. The ASF licenses this file * + * to you 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 org.apache.james.jmap.cassandra.filtering; + +import static org.apache.james.jmap.api.filtering.RuleFixture.RULE_1; +import static org.apache.james.jmap.api.filtering.RuleFixture.RULE_2; +import static org.apache.james.jmap.api.filtering.RuleFixture.RULE_FROM; +import static org.apache.james.jmap.api.filtering.RuleFixture.RULE_RECIPIENT; +import static org.apache.james.jmap.api.filtering.RuleFixture.RULE_SUBJECT; +import static org.apache.james.jmap.api.filtering.RuleFixture.RULE_TO; +import static org.assertj.core.api.Assertions.assertThat; +import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson; + +import org.apache.james.core.User; +import org.apache.james.eventsourcing.EventId; +import org.apache.james.jmap.api.filtering.impl.FilteringAggregateId; +import org.apache.james.jmap.api.filtering.impl.RuleSetDefined; +import org.apache.james.util.ClassLoaderUtils; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.guava.GuavaModule; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; +import com.google.common.collect.ImmutableList; + +public class DTOTest { + static final String EVENT_JSON = ClassLoaderUtils.getSystemResourceAsString("json/event.json"); + static final String EVENT_EMPTY_JSON = ClassLoaderUtils.getSystemResourceAsString("json/eventEmpty.json"); + static final String EVENT_COMPLEX_JSON = ClassLoaderUtils.getSystemResourceAsString("json/eventComplex.json"); + static final FilteringRuleSetDefinedDTO SIMPLE_DTO = FilteringRuleSetDefinedDTO.from( + new RuleSetDefined( + new FilteringAggregateId(User.fromUsername("Bart")), + EventId.first(), + ImmutableList.of(RULE_1, RULE_2))); + static final FilteringRuleSetDefinedDTO EMPTY_DTO = FilteringRuleSetDefinedDTO.from( + new RuleSetDefined( + new FilteringAggregateId(User.fromUsername("Bart")), + EventId.first(), + ImmutableList.of())); + static final FilteringRuleSetDefinedDTO COMPLEX_DTO = FilteringRuleSetDefinedDTO.from( + new RuleSetDefined( + new FilteringAggregateId(User.fromUsername("Bart")), + EventId.first(), + ImmutableList.of(RULE_FROM, RULE_RECIPIENT, RULE_SUBJECT, RULE_TO))); + + private ObjectMapper objectMapper; + + @BeforeEach + void setUp() { + objectMapper = new ObjectMapper(); + objectMapper.registerModule(new Jdk8Module()); + objectMapper.registerModule(new GuavaModule()); + } + + @Test + void shouldSerializeDTO() throws Exception { + String serializedEvent = objectMapper.writeValueAsString(SIMPLE_DTO); + + assertThatJson(serializedEvent).isEqualTo(EVENT_JSON); + } + + @Test + void shouldDeserializeDTO() throws Exception { + FilteringRuleSetDefinedDTO dto = objectMapper.readValue(EVENT_JSON, FilteringRuleSetDefinedDTO.class); + + assertThat(dto).isEqualTo(SIMPLE_DTO); + } + + @Test + void shouldSerializeEmptyDTO() throws Exception { + String serializedEvent = objectMapper.writeValueAsString(EMPTY_DTO); + + assertThatJson(serializedEvent).isEqualTo(EVENT_EMPTY_JSON); + } + + @Test + void shouldDeserializeEmptyDTO() throws Exception { + FilteringRuleSetDefinedDTO dto = objectMapper.readValue(EVENT_EMPTY_JSON, FilteringRuleSetDefinedDTO.class); + + assertThat(dto).isEqualTo(EMPTY_DTO); + } + + @Test + void shouldSerializeComplexDTO() throws Exception { + String serializedEvent = objectMapper.writeValueAsString(COMPLEX_DTO); + + assertThatJson(serializedEvent).isEqualTo(EVENT_COMPLEX_JSON); + } + + @Test + void shouldDeserializeComplexDTO() throws Exception { + FilteringRuleSetDefinedDTO dto = objectMapper.readValue(EVENT_COMPLEX_JSON, FilteringRuleSetDefinedDTO.class); + + assertThat(dto).isEqualTo(COMPLEX_DTO); + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/4d8e807e/server/data/data-jmap-cassandra/src/test/resources/json/event.json ---------------------------------------------------------------------- diff --git a/server/data/data-jmap-cassandra/src/test/resources/json/event.json b/server/data/data-jmap-cassandra/src/test/resources/json/event.json new file mode 100644 index 0000000..b77e46a --- /dev/null +++ b/server/data/data-jmap-cassandra/src/test/resources/json/event.json @@ -0,0 +1,23 @@ +{ + "type":"filtering-rule-set-defined", + "eventId":0, + "aggregateId":"FilteringRule/Bart", + "rules":[ + { + "id":"1", + "name":"a name", + "field":"cc", + "comparator":"contains", + "value":"something", + "mailboxIds":["id-01"] + }, + { + "id":"2", + "name":"a name", + "field":"cc", + "comparator":"contains", + "value":"something", + "mailboxIds":["id-01"] + } + ] +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/james-project/blob/4d8e807e/server/data/data-jmap-cassandra/src/test/resources/json/eventComplex.json ---------------------------------------------------------------------- diff --git a/server/data/data-jmap-cassandra/src/test/resources/json/eventComplex.json b/server/data/data-jmap-cassandra/src/test/resources/json/eventComplex.json new file mode 100644 index 0000000..a08e2d1 --- /dev/null +++ b/server/data/data-jmap-cassandra/src/test/resources/json/eventComplex.json @@ -0,0 +1,39 @@ +{ + "type":"filtering-rule-set-defined", + "eventId":0, + "aggregateId":"FilteringRule/Bart", + "rules":[ + { + "id":"id-from", + "name":"a name", + "field":"from", + "comparator":"contains", + "value":"A value to match 4", + "mailboxIds":["mbx1"] + }, + { + "id":"id-rcpt", + "name":"a name", + "field":"recipient", + "comparator":"not-exactly-equals", + "value":"A value to match 3", + "mailboxIds":["mbx1"] + }, + { + "id":"id-subject", + "name":"a name", + "field":"subject", + "comparator":"not-contains", + "value":"A value to match 2", + "mailboxIds":["mbx1"] + }, + { + "id":"id-to", + "name":"a name", + "field":"to", + "comparator":"exactly-equals", + "value":"A value to match 1", + "mailboxIds":["mbx1"] + } + ] +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/james-project/blob/4d8e807e/server/data/data-jmap-cassandra/src/test/resources/json/eventEmpty.json ---------------------------------------------------------------------- diff --git a/server/data/data-jmap-cassandra/src/test/resources/json/eventEmpty.json b/server/data/data-jmap-cassandra/src/test/resources/json/eventEmpty.json new file mode 100644 index 0000000..f7fbaee --- /dev/null +++ b/server/data/data-jmap-cassandra/src/test/resources/json/eventEmpty.json @@ -0,0 +1,6 @@ +{ + "type":"filtering-rule-set-defined", + "eventId":0, + "aggregateId":"FilteringRule/Bart", + "rules":[] +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/james-project/blob/4d8e807e/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/FilteringManagement.java ---------------------------------------------------------------------- diff --git a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/FilteringManagement.java b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/FilteringManagement.java index a8b1c4b..b39f691 100644 --- a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/FilteringManagement.java +++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/FilteringManagement.java @@ -19,14 +19,25 @@ package org.apache.james.jmap.api.filtering; +import java.util.Arrays; import java.util.List; import org.apache.james.core.User; +import com.google.common.collect.ImmutableList; + public interface FilteringManagement { void defineRulesForUser(User user, List<Rule> rules); + default void defineRulesForUser(User user, Rule... rules) { + defineRulesForUser(user, Arrays.asList(rules)); + } + + default void clearRulesForUser(User user) { + defineRulesForUser(user, ImmutableList.of()); + } + List<Rule> listRulesForUser(User user); } http://git-wip-us.apache.org/repos/asf/james-project/blob/4d8e807e/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/Rule.java ---------------------------------------------------------------------- diff --git a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/Rule.java b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/Rule.java index 8bca30a..0da600d 100644 --- a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/Rule.java +++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/Rule.java @@ -19,49 +19,318 @@ package org.apache.james.jmap.api.filtering; +import java.util.Arrays; +import java.util.List; import java.util.Objects; +import java.util.Optional; + +import org.apache.commons.lang3.StringUtils; import com.google.common.base.MoreObjects; import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; public class Rule { - private final String id; + public static class Id { + + public static Id of(String id) { + Preconditions.checkNotNull(id, "id should no be null"); + Preconditions.checkArgument(StringUtils.isNotBlank(id), "id should no be empty"); + return new Id(id); + } + + private final String value; + + private Id(String value) { + this.value = value; + } + + public String asString() { + return value; + } + + @Override + public final boolean equals(Object o) { + if (o instanceof Id) { + Id id = (Id) o; + return Objects.equals(value, id.value); + } + return false; + } + + @Override + public final int hashCode() { + return Objects.hash(value); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("value", value) + .toString(); + } + } + + public static class Condition { + + public enum Field { + FROM("from"), + TO("to"), + CC("cc"), + SUBJECT("subject"), + RECIPIENT("recipient"); + + public static Optional<Field> find(String fieldName) { + return Arrays.stream(values()) + .filter(value -> value.fieldName.equalsIgnoreCase(fieldName)) + .findAny(); + } + + public static Field of(String fieldName) { + return find(fieldName).orElseThrow(() -> new IllegalStateException("'" + fieldName + "' is not a valid field name")); + } + + private final String fieldName; + + private Field(String fieldName) { + this.fieldName = fieldName; + } + + public String asString() { + return fieldName; + } + } + + public enum Comparator { + CONTAINS("contains"), + NOT_CONTAINS("not-contains"), + EXACTLY_EQUALS("exactly-equals"), + NOT_EXACTLY_EQUALS("not-exactly-equals"); + + public static Optional<Comparator> find(String comparatorName) { + return Arrays.stream(values()) + .filter(value -> value.comparatorName.equalsIgnoreCase(comparatorName)) + .findAny(); + } + + public static Comparator of(String comparatorName) { + return find(comparatorName).orElseThrow(() -> new IllegalStateException("'" + comparatorName + "' is not a valid comparator name")); + } + + private final String comparatorName; + + private Comparator(String comparator) { + this.comparatorName = comparator; + } + + public String asString() { + return comparatorName; + } + } + + public static Condition of(Field field, Comparator comparator, String value) { + Preconditions.checkNotNull(field, "field should no be null"); + Preconditions.checkNotNull(comparator, "comparator should no be null"); + Preconditions.checkNotNull(value, "value should no be null"); + Preconditions.checkArgument(StringUtils.isNotBlank(value), "value should no be empty"); + return new Condition(field, comparator, value); + } + + private final Field field; + private final Comparator comparator; + private final String value; + + private Condition(Field field, Comparator comparator, String value) { + this.field = field; + this.comparator = comparator; + this.value = value; + } + + public Field getField() { + return field; + } + + public Comparator getComparator() { + return comparator; + } + + public String getValue() { + return value; + } + + @Override + public final boolean equals(Object o) { + if (o instanceof Condition) { + Condition condition = (Condition) o; + return Objects.equals(field, condition.field) + && Objects.equals(comparator, condition.comparator) + && Objects.equals(value, condition.value); + } + return false; + } - public static Rule of(String id) { - return new Rule(id); + @Override + public final int hashCode() { + return Objects.hash(field, comparator, value); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("field", field) + .add("comparator", comparator) + .add("value", value) + .toString(); + } } - public Rule(String id) { - Preconditions.checkNotNull(id); + public static class Action { + + public static Action ofMailboxIds(List<String> mailboxIds) { + Preconditions.checkNotNull(mailboxIds, "mailboxIds should no be null"); + return new Action(mailboxIds); + } + + public static Action ofMailboxIds(String... mailboxIds) { + return ofMailboxIds(Arrays.asList(mailboxIds)); + } + + private final ImmutableList<String> mailboxIds; + + private Action(List<String> mailboxIds) { + this.mailboxIds = ImmutableList.copyOf(mailboxIds); + } + + public ImmutableList<String> getMailboxIds() { + return mailboxIds; + } + + @Override + public final boolean equals(Object o) { + if (o instanceof Action) { + Action action = (Action) o; + return Objects.equals(mailboxIds, action.mailboxIds); + } + return false; + } + + @Override + public final int hashCode() { + return Objects.hash(mailboxIds); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("mailboxIds", mailboxIds) + .toString(); + } + } + + public static class Builder { + + private Optional<Id> id; + private Optional<String> name; + private Optional<Condition> condition; + private Optional<Action> action; + + public Builder() { + this.id = Optional.empty(); + this.name = Optional.empty(); + this.condition = Optional.empty(); + this.action = Optional.empty(); + } + + public Builder id(Id id) { + this.id = Optional.of(id); + return this; + } + + public Builder name(String name) { + this.name = Optional.of(name); + return this; + } + + public Builder condition(Condition condition) { + this.condition = Optional.of(condition); + return this; + } + + public Builder action(Action action) { + this.action = Optional.of(action); + return this; + } + + public Rule build() { + Preconditions.checkState(id.isPresent(), "`id` is mandatory"); + Preconditions.checkState(name.isPresent(), "`name` is mandatory"); + Preconditions.checkState(condition.isPresent(), "`condition` is mandatory"); + Preconditions.checkState(action.isPresent(), "`action` is mandatory"); + + return new Rule(id.get(), name.get(), condition.get(), action.get()); + } + + } + + public static Builder builder() { + return new Builder(); + } + + private final Id id; + private final String name; + private final Condition condition; + private final Action action; + + public Rule(Id id, String name, Condition condition, Action action) { this.id = id; + this.name = name; + this.condition = condition; + this.action = action; } - public String getId() { + public Id getId() { return id; } + public String getName() { + return name; + } + + public Condition getCondition() { + return condition; + } + + public Action getAction() { + return action; + } + @Override public final boolean equals(Object o) { if (o instanceof Rule) { Rule rule = (Rule) o; - return Objects.equals(this.id, rule.id); + return Objects.equals(this.id, rule.id) + && Objects.equals(this.name, rule.name) + && Objects.equals(this.condition, rule.condition) + && Objects.equals(this.action, rule.action); } return false; } @Override public final int hashCode() { - return Objects.hash(id); + return Objects.hash(id, name, condition, action); } @Override public String toString() { return MoreObjects.toStringHelper(this) .add("id", id) + .add("name", name) + .add("condition", condition) + .add("action", action) .toString(); } - } http://git-wip-us.apache.org/repos/asf/james-project/blob/4d8e807e/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/FilteringManagementContract.java ---------------------------------------------------------------------- diff --git a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/FilteringManagementContract.java b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/FilteringManagementContract.java index dd2f773..a28cbff 100644 --- a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/FilteringManagementContract.java +++ b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/FilteringManagementContract.java @@ -18,22 +18,27 @@ ****************************************************************/ package org.apache.james.jmap.api.filtering; +import static org.apache.james.jmap.api.filtering.RuleFixture.RULE_1; +import static org.apache.james.jmap.api.filtering.RuleFixture.RULE_2; +import static org.apache.james.jmap.api.filtering.RuleFixture.RULE_3; +import static org.apache.james.jmap.api.filtering.RuleFixture.RULE_FROM; +import static org.apache.james.jmap.api.filtering.RuleFixture.RULE_RECIPIENT; +import static org.apache.james.jmap.api.filtering.RuleFixture.RULE_SUBJECT; +import static org.apache.james.jmap.api.filtering.RuleFixture.RULE_TO; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import java.util.List; + import org.apache.james.core.User; import org.apache.james.eventsourcing.eventstore.EventStore; import org.apache.james.jmap.api.filtering.impl.EventSourcingFilteringManagement; import org.junit.jupiter.api.Test; -import com.google.common.collect.ImmutableList; - public interface FilteringManagementContract { String BART_SIMPSON_CARTOON = "bart@simpson.cartoon"; - Rule RULE_1 = Rule.of("1"); - Rule RULE_2 = Rule.of("2"); - Rule RULE_3 = Rule.of("3"); + User USER = User.fromUsername(BART_SIMPSON_CARTOON); default FilteringManagement instanciateFilteringManagement(EventStore eventStore) { return new EventSourcingFilteringManagement(eventStore); @@ -41,71 +46,90 @@ public interface FilteringManagementContract { @Test default void listingRulesForUnknownUserShouldReturnEmptyList(EventStore eventStore) { - User user = User.fromUsername(BART_SIMPSON_CARTOON); - assertThat(instanciateFilteringManagement(eventStore).listRulesForUser(user)).isEmpty(); + assertThat(instanciateFilteringManagement(eventStore).listRulesForUser(USER)) + .isEmpty(); } @Test default void listingRulesShouldThrowWhenNullUser(EventStore eventStore) { User user = null; - assertThatThrownBy(() -> instanciateFilteringManagement(eventStore).listRulesForUser(user)).isInstanceOf(NullPointerException.class); + assertThatThrownBy(() -> instanciateFilteringManagement(eventStore).listRulesForUser(user)) + .isInstanceOf(NullPointerException.class); } @Test default void listingRulesShouldReturnDefinedRules(EventStore eventStore) { - User user = User.fromUsername(BART_SIMPSON_CARTOON); FilteringManagement testee = instanciateFilteringManagement(eventStore); - testee.defineRulesForUser(user, ImmutableList.of(RULE_1, RULE_2)); - assertThat(testee.listRulesForUser(user)).containsExactly(RULE_1, RULE_2); + + testee.defineRulesForUser(USER, RULE_1, RULE_2); + + assertThat(testee.listRulesForUser(USER)) + .containsExactly(RULE_1, RULE_2); } @Test default void listingRulesShouldReturnLastDefinedRules(EventStore eventStore) { - User user = User.fromUsername(BART_SIMPSON_CARTOON); FilteringManagement testee = instanciateFilteringManagement(eventStore); - testee.defineRulesForUser(user, ImmutableList.of(RULE_1, RULE_2)); - testee.defineRulesForUser(user, ImmutableList.of(RULE_2, RULE_1)); - assertThat(testee.listRulesForUser(user)).containsExactly(RULE_2, RULE_1); + + testee.defineRulesForUser(USER, RULE_1, RULE_2); + testee.defineRulesForUser(USER, RULE_2, RULE_1); + + assertThat(testee.listRulesForUser(USER)) + .containsExactly(RULE_2, RULE_1); } @Test default void definingRulesShouldThrowWhenDuplicateRules(EventStore eventStore) { - User user = User.fromUsername(BART_SIMPSON_CARTOON); FilteringManagement testee = instanciateFilteringManagement(eventStore); - assertThatThrownBy(() -> testee.defineRulesForUser(user, ImmutableList.of(RULE_1, RULE_1))) + + assertThatThrownBy(() -> testee.defineRulesForUser(USER, RULE_1, RULE_1)) .isInstanceOf(IllegalArgumentException.class); } @Test default void definingRulesShouldThrowWhenNullUser(EventStore eventStore) { FilteringManagement testee = instanciateFilteringManagement(eventStore); - assertThatThrownBy(() -> testee.defineRulesForUser(null, ImmutableList.of(RULE_1, RULE_1))) + + assertThatThrownBy(() -> testee.defineRulesForUser(null, RULE_1, RULE_1)) .isInstanceOf(NullPointerException.class); } @Test default void definingRulesShouldThrowWhenNullRuleList(EventStore eventStore) { - User user = User.fromUsername(BART_SIMPSON_CARTOON); FilteringManagement testee = instanciateFilteringManagement(eventStore); - assertThatThrownBy(() -> testee.defineRulesForUser(user, null)) + + List<Rule> rules = null; + assertThatThrownBy(() -> testee.defineRulesForUser(USER, rules)) .isInstanceOf(NullPointerException.class); } @Test default void definingRulesShouldKeepOrdering(EventStore eventStore) { - User user = User.fromUsername(BART_SIMPSON_CARTOON); FilteringManagement testee = instanciateFilteringManagement(eventStore); - testee.defineRulesForUser(user, ImmutableList.of(RULE_3, RULE_2, RULE_1)); - assertThat(testee.listRulesForUser(user)).containsExactly(RULE_3, RULE_2, RULE_1); + testee.defineRulesForUser(USER, RULE_3, RULE_2, RULE_1); + + assertThat(testee.listRulesForUser(USER)) + .containsExactly(RULE_3, RULE_2, RULE_1); } @Test default void definingEmptyRuleListShouldRemoveExistingRules(EventStore eventStore) { - User user = User.fromUsername(BART_SIMPSON_CARTOON); FilteringManagement testee = instanciateFilteringManagement(eventStore); - testee.defineRulesForUser(user, ImmutableList.of(RULE_3, RULE_2, RULE_1)); - testee.defineRulesForUser(user, ImmutableList.of()); - assertThat(testee.listRulesForUser(user)).isEmpty(); + + testee.defineRulesForUser(USER, RULE_3, RULE_2, RULE_1); + testee.clearRulesForUser(USER); + + assertThat(testee.listRulesForUser(USER)).isEmpty(); + } + + @Test + default void allFieldsAndComparatorShouldWellBeStored(EventStore eventStore) { + FilteringManagement testee = instanciateFilteringManagement(eventStore); + + testee.defineRulesForUser(USER, RULE_FROM, RULE_RECIPIENT, RULE_SUBJECT, RULE_TO, RULE_1); + + assertThat(testee.listRulesForUser(USER)) + .containsExactly(RULE_FROM, RULE_RECIPIENT, RULE_SUBJECT, RULE_TO, RULE_1); } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/james-project/blob/4d8e807e/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/RuleFixture.java ---------------------------------------------------------------------- diff --git a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/RuleFixture.java b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/RuleFixture.java new file mode 100644 index 0000000..5d17d03 --- /dev/null +++ b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/RuleFixture.java @@ -0,0 +1,71 @@ +/**************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one * + * or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information * + * regarding copyright ownership. The ASF licenses this file * + * to you 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 org.apache.james.jmap.api.filtering; + +public interface RuleFixture { + String NAME = "a name"; + Rule.Condition CONDITION = Rule.Condition.of(Rule.Condition.Field.CC, Rule.Condition.Comparator.CONTAINS, "something"); + Rule.Action ACTION = Rule.Action.ofMailboxIds("id-01"); + Rule.Builder RULE_BUILER = Rule.builder().name(NAME).condition(CONDITION).action(ACTION); + Rule RULE_1 = RULE_BUILER.id(Rule.Id.of("1")).build(); + Rule RULE_2 = RULE_BUILER.id(Rule.Id.of("2")).build(); + Rule RULE_3 = RULE_BUILER.id(Rule.Id.of("3")).build(); + + Rule RULE_TO = Rule.builder() + .id(Rule.Id.of("id-to")) + .name(NAME) + .action(Rule.Action.ofMailboxIds("mbx1")) + .condition(Rule.Condition.of( + Rule.Condition.Field.TO, + Rule.Condition.Comparator.EXACTLY_EQUALS, + "A value to match 1")) + .build(); + + Rule RULE_SUBJECT = Rule.builder() + .id(Rule.Id.of("id-subject")) + .name(NAME) + .action(Rule.Action.ofMailboxIds("mbx1")) + .condition(Rule.Condition.of( + Rule.Condition.Field.SUBJECT, + Rule.Condition.Comparator.NOT_CONTAINS, + "A value to match 2")) + .build(); + + Rule RULE_RECIPIENT = Rule.builder() + .id(Rule.Id.of("id-rcpt")) + .name(NAME) + .action(Rule.Action.ofMailboxIds("mbx1")) + .condition(Rule.Condition.of( + Rule.Condition.Field.RECIPIENT, + Rule.Condition.Comparator.NOT_EXACTLY_EQUALS, + "A value to match 3")) + .build(); + + Rule RULE_FROM = Rule.builder() + .id(Rule.Id.of("id-from")) + .name(NAME) + .action(Rule.Action.ofMailboxIds("mbx1")) + .condition(Rule.Condition.of( + Rule.Condition.Field.FROM, + Rule.Condition.Comparator.CONTAINS, + "A value to match 4")) + .build(); + +} http://git-wip-us.apache.org/repos/asf/james-project/blob/4d8e807e/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/RuleTest.java ---------------------------------------------------------------------- diff --git a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/RuleTest.java b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/RuleTest.java index fc10f6a..2e3e760 100644 --- a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/RuleTest.java +++ b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/RuleTest.java @@ -19,13 +19,25 @@ package org.apache.james.jmap.api.filtering; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import java.util.Arrays; +import java.util.List; + import org.junit.jupiter.api.Test; import nl.jqno.equalsverifier.EqualsVerifier; -class RuleTest { +public class RuleTest { + + private static final List<String> ACTION_MAILBOXIDS = Arrays.asList("id-01"); + private static final String CONDITION_COMPARATOR = "contains"; + private static final String CONDITION_FIELD = "cc"; + private static final String NAME = "a name"; + public static final Rule.Condition CONDITION = Rule.Condition.of(Rule.Condition.Field.of(CONDITION_FIELD), Rule.Condition.Comparator.of(CONDITION_COMPARATOR), "something"); + public static final Rule.Action ACTION = Rule.Action.ofMailboxIds(ACTION_MAILBOXIDS); + public static final Rule.Id UNIQUE_ID = Rule.Id.of("uniqueId"); @Test void shouldMatchBeanContract() { @@ -34,8 +46,119 @@ class RuleTest { } @Test - void constructorShouldThrowWhenNullId() { - assertThatThrownBy(() -> new Rule(null)) - .isInstanceOf(NullPointerException.class); + void innerClassConditionShouldMatchBeanContract() { + EqualsVerifier.forClass(Rule.Condition.class) + .verify(); + } + + @Test + void innerClassActionShouldMatchBeanContract() { + EqualsVerifier.forClass(Rule.Action.class) + .verify(); + } + + @Test + void innerClassIdShouldMatchBeanContract() { + EqualsVerifier.forClass(Rule.Id.class) + .verify(); + } + + @Test + void idShouldThrowOnNull() { + assertThatThrownBy(() -> Rule.Id.of(null)).isInstanceOf(NullPointerException.class); + } + + @Test + void idShouldThrowOnEmpty() { + assertThatThrownBy(() -> Rule.Id.of("")).isInstanceOf(IllegalArgumentException.class); + } + + @Test + void idShouldThrowOnBlank() { + assertThatThrownBy(() -> Rule.Id.of(" ")).isInstanceOf(IllegalArgumentException.class); + } + + @Test + void idShouldBeMandatory() { + assertThatThrownBy(() -> + Rule.builder() + .name(NAME) + .condition(CONDITION) + .action(ACTION) + .build()) + .isInstanceOf(IllegalStateException.class); + } + + @Test + void nameShouldBeMandatory() { + assertThatThrownBy(() -> + Rule.builder() + .id(UNIQUE_ID) + .condition(CONDITION) + .action(ACTION) + .build()) + .isInstanceOf(IllegalStateException.class); + } + + @Test + void conditionShouldBeMandatory() { + assertThatThrownBy(() -> + Rule.builder() + .id(UNIQUE_ID) + .name(NAME) + .action(ACTION) + .build()) + .isInstanceOf(IllegalStateException.class); + } + + @Test + void actionShouldBeMandatory() { + assertThatThrownBy(() -> + Rule.builder() + .id(UNIQUE_ID) + .name(NAME) + .condition(CONDITION) + .build()) + .isInstanceOf(IllegalStateException.class); } -} \ No newline at end of file + + @Test + void builderShouldPreserveCondition() { + Rule rule = Rule.builder() + .id(UNIQUE_ID) + .name(NAME) + .condition(CONDITION) + .action(ACTION) + .build(); + + assertThat(rule.getCondition()).isEqualTo(CONDITION); + } + + @Test + void builderShouldPreserveAction() { + Rule rule = Rule.builder() + .id(UNIQUE_ID) + .name(NAME) + .condition(CONDITION) + .action(ACTION) + .build(); + + assertThat(rule.getAction()).isEqualTo(ACTION); + } + + @Test + void buildConditionShouldConserveField() { + assertThat(CONDITION.getField().asString()).isEqualTo(CONDITION_FIELD); + } + + @Test + void buildConditionShouldConserveComparator() { + assertThat(CONDITION.getComparator().asString()).isEqualTo(CONDITION_COMPARATOR); + } + + @Test + void buildActionShouldConserveMailboxIdsList() { + assertThat(ACTION.getMailboxIds()).isEqualTo(ACTION_MAILBOXIDS); + } + +} http://git-wip-us.apache.org/repos/asf/james-project/blob/4d8e807e/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/impl/DefineRulesCommandTest.java ---------------------------------------------------------------------- diff --git a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/impl/DefineRulesCommandTest.java b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/impl/DefineRulesCommandTest.java index a917fdd..2fa75c0 100644 --- a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/impl/DefineRulesCommandTest.java +++ b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/impl/DefineRulesCommandTest.java @@ -19,10 +19,11 @@ package org.apache.james.jmap.api.filtering.impl; +import static org.apache.james.jmap.api.filtering.RuleFixture.RULE_1; +import static org.apache.james.jmap.api.filtering.RuleFixture.RULE_2; import static org.assertj.core.api.Assertions.assertThatThrownBy; import org.apache.james.core.User; -import org.apache.james.jmap.api.filtering.Rule; import org.junit.jupiter.api.Test; import com.google.common.collect.ImmutableList; @@ -39,7 +40,7 @@ class DefineRulesCommandTest { @Test void constructorShouldThrowWhenNullUser() { - assertThatThrownBy(() -> new DefineRulesCommand(null, ImmutableList.of(Rule.of("1"), Rule.of("2")))) + assertThatThrownBy(() -> new DefineRulesCommand(null, ImmutableList.of(RULE_1, RULE_2))) .isInstanceOf(NullPointerException.class); } --------------------------------------------------------------------- To unsubscribe, e-mail: server-dev-unsubscr...@james.apache.org For additional commands, e-mail: server-dev-h...@james.apache.org