jkevan commented on a change in pull request #268: URL: https://github.com/apache/unomi/pull/268#discussion_r600356723
########## File path: itests/src/test/java/org/apache/unomi/itests/CopyPropertiesActionIT.java ########## @@ -0,0 +1,312 @@ +/* + * 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.unomi.itests; + +import org.apache.unomi.api.Event; +import org.apache.unomi.api.Metadata; +import org.apache.unomi.api.Profile; +import org.apache.unomi.api.PropertyType; +import org.apache.unomi.api.rules.Rule; +import org.apache.unomi.api.services.EventService; +import org.apache.unomi.api.services.ProfileService; +import org.apache.unomi.api.services.RulesService; +import org.apache.unomi.persistence.spi.CustomObjectMapper; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.ops4j.pax.exam.junit.PaxExam; +import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy; +import org.ops4j.pax.exam.spi.reactors.PerSuite; +import org.ops4j.pax.exam.util.Filter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.inject.Inject; +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Date; + +/** + * Created by amidani on 12/10/2017. + */ + +@RunWith(PaxExam.class) +@ExamReactorStrategy(PerSuite.class) +public class CopyPropertiesActionIT extends BaseIT { + private final static Logger LOGGER = LoggerFactory.getLogger(CopyPropertiesActionIT.class); + + private final static String PROFILE_TARGET_TEST_ID = "profile-target-event"; + private final static String PROFILE_TEST_ID = "profile-to-update-by-event"; + + @Inject + @Filter(timeout = 600000) + protected RulesService rulesService; + @Inject + @Filter(timeout = 600000) + protected ProfileService profileService; + @Inject + @Filter(timeout = 600000) + protected EventService eventService; + + @Before + public void setUp() throws IOException, InterruptedException { + Profile profile = new Profile(); + profile.setItemId(PROFILE_TEST_ID); + profile.setProperties(new HashMap<>()); + profile.setProperty("lastName", "Jose"); // property that have a propertyType registered in the system + profile.setProperty("prop4", "New property 4"); // property that do not have a propertyType registered in the system + profileService.save(profile); + LOGGER.info("Profile saved with ID [{}].", profile.getItemId()); + + Profile profileTarget = new Profile(); + profileTarget.setItemId(PROFILE_TARGET_TEST_ID); + profileService.save(profileTarget); + LOGGER.info("Profile saved with ID [{}].", profileTarget.getItemId()); + + refreshPersistence(); + } + + @Test + public void testCopyProperties_copyMultipleValueWithExistingPropertyType() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); + + Profile profile = profileService.load(PROFILE_TARGET_TEST_ID); + Assert.assertNull(profile.getProperty("firstName")); + + Event event = new Event("copyProperties", null, profile, null, null, profile, new Date()); + event.setPersistent(false); + + Map<String, Object> properties = new HashMap<>(); + properties.put("param1", Arrays.asList("value")); + properties.put("param2", Arrays.asList("valueA", "valueB")); + + event.setProperty("urlParameters", properties); + + Metadata metadata = new Metadata(); + metadata.setSystemTags(new HashSet<>(Arrays.asList("urlParameters"))); + metadata.setId("param1"); + metadata.setName("Url parameters"); + + PropertyType propertyType1 = new PropertyType(); + propertyType1.setItemId("param1"); + propertyType1.setMetadata(metadata); + propertyType1.setTarget("profiles"); + propertyType1.setValueTypeId("string"); + propertyType1.setMultivalued(true); + + profileService.setPropertyType(propertyType1); + + Metadata metadata2 = new Metadata(); + metadata2.setSystemTags(new HashSet<>(Arrays.asList("urlParameters"))); + metadata2.setId("param2"); + metadata2.setName("Url parameters"); + + PropertyType propertyType2 = new PropertyType(); + propertyType2.setItemId("param2"); + propertyType2.setMetadata(metadata2); + propertyType2.setTarget("profiles"); + propertyType2.setValueTypeId("string"); + propertyType2.setMultivalued(true); + + profileService.setPropertyType(propertyType2); + + int changes = eventService.send(event); + + LOGGER.info("Changes of the event : {}", changes); + + Assert.assertTrue(changes > 0); + } + + @Test + public void testCopyProperties_copyMultipleValueWithoutExistingPropertyType() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); + + Profile profile = profileService.load(PROFILE_TARGET_TEST_ID); + Assert.assertNull(profile.getProperty("firstName")); + + Event event = new Event("copyProperties", null, profile, null, null, profile, new Date()); + event.setPersistent(false); + + Map<String, Object> properties = new HashMap<>(); + properties.put("param1WithoutPropertyType", Arrays.asList("value")); + properties.put("param2WithoutPropertyType", Arrays.asList("valueA", "valueB")); + + event.setProperty("urlParameters", properties); + + int changes = eventService.send(event); + + LOGGER.info("Changes of the event : {}", changes); + + Assert.assertTrue(changes > 0); Review comment: Check the properties of the profiles are the expected one. ########## File path: itests/src/test/java/org/apache/unomi/itests/CopyPropertiesActionIT.java ########## @@ -0,0 +1,312 @@ +/* + * 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.unomi.itests; + +import org.apache.unomi.api.Event; +import org.apache.unomi.api.Metadata; +import org.apache.unomi.api.Profile; +import org.apache.unomi.api.PropertyType; +import org.apache.unomi.api.rules.Rule; +import org.apache.unomi.api.services.EventService; +import org.apache.unomi.api.services.ProfileService; +import org.apache.unomi.api.services.RulesService; +import org.apache.unomi.persistence.spi.CustomObjectMapper; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.ops4j.pax.exam.junit.PaxExam; +import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy; +import org.ops4j.pax.exam.spi.reactors.PerSuite; +import org.ops4j.pax.exam.util.Filter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.inject.Inject; +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Date; + +/** + * Created by amidani on 12/10/2017. + */ + +@RunWith(PaxExam.class) +@ExamReactorStrategy(PerSuite.class) +public class CopyPropertiesActionIT extends BaseIT { + private final static Logger LOGGER = LoggerFactory.getLogger(CopyPropertiesActionIT.class); + + private final static String PROFILE_TARGET_TEST_ID = "profile-target-event"; + private final static String PROFILE_TEST_ID = "profile-to-update-by-event"; + + @Inject + @Filter(timeout = 600000) + protected RulesService rulesService; + @Inject + @Filter(timeout = 600000) + protected ProfileService profileService; + @Inject + @Filter(timeout = 600000) + protected EventService eventService; + + @Before + public void setUp() throws IOException, InterruptedException { + Profile profile = new Profile(); + profile.setItemId(PROFILE_TEST_ID); + profile.setProperties(new HashMap<>()); + profile.setProperty("lastName", "Jose"); // property that have a propertyType registered in the system + profile.setProperty("prop4", "New property 4"); // property that do not have a propertyType registered in the system + profileService.save(profile); + LOGGER.info("Profile saved with ID [{}].", profile.getItemId()); + + Profile profileTarget = new Profile(); + profileTarget.setItemId(PROFILE_TARGET_TEST_ID); + profileService.save(profileTarget); + LOGGER.info("Profile saved with ID [{}].", profileTarget.getItemId()); + + refreshPersistence(); + } + + @Test + public void testCopyProperties_copyMultipleValueWithExistingPropertyType() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); + + Profile profile = profileService.load(PROFILE_TARGET_TEST_ID); + Assert.assertNull(profile.getProperty("firstName")); + + Event event = new Event("copyProperties", null, profile, null, null, profile, new Date()); + event.setPersistent(false); + + Map<String, Object> properties = new HashMap<>(); + properties.put("param1", Arrays.asList("value")); + properties.put("param2", Arrays.asList("valueA", "valueB")); + + event.setProperty("urlParameters", properties); + + Metadata metadata = new Metadata(); + metadata.setSystemTags(new HashSet<>(Arrays.asList("urlParameters"))); + metadata.setId("param1"); + metadata.setName("Url parameters"); + + PropertyType propertyType1 = new PropertyType(); + propertyType1.setItemId("param1"); + propertyType1.setMetadata(metadata); + propertyType1.setTarget("profiles"); + propertyType1.setValueTypeId("string"); + propertyType1.setMultivalued(true); + + profileService.setPropertyType(propertyType1); + + Metadata metadata2 = new Metadata(); + metadata2.setSystemTags(new HashSet<>(Arrays.asList("urlParameters"))); + metadata2.setId("param2"); + metadata2.setName("Url parameters"); + + PropertyType propertyType2 = new PropertyType(); + propertyType2.setItemId("param2"); + propertyType2.setMetadata(metadata2); + propertyType2.setTarget("profiles"); + propertyType2.setValueTypeId("string"); + propertyType2.setMultivalued(true); + + profileService.setPropertyType(propertyType2); + + int changes = eventService.send(event); + + LOGGER.info("Changes of the event : {}", changes); + + Assert.assertTrue(changes > 0); + } + + @Test + public void testCopyProperties_copyMultipleValueWithoutExistingPropertyType() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); + + Profile profile = profileService.load(PROFILE_TARGET_TEST_ID); + Assert.assertNull(profile.getProperty("firstName")); + + Event event = new Event("copyProperties", null, profile, null, null, profile, new Date()); + event.setPersistent(false); + + Map<String, Object> properties = new HashMap<>(); + properties.put("param1WithoutPropertyType", Arrays.asList("value")); + properties.put("param2WithoutPropertyType", Arrays.asList("valueA", "valueB")); + + event.setProperty("urlParameters", properties); + + int changes = eventService.send(event); + + LOGGER.info("Changes of the event : {}", changes); + + Assert.assertTrue(changes > 0); + } + + @Test + public void testCopyProperties_copySingleValueWithoutPropertyType() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); + + Profile profile = profileService.load(PROFILE_TARGET_TEST_ID); + Assert.assertNull(profile.getProperty("firstName")); + + Event event = new Event("copyProperties", null, profile, null, null, profile, new Date()); + event.setPersistent(false); + + Map<String, Object> properties = new HashMap<>(); + properties.put("param1SingleValue", "SingleValue"); + + event.setProperty("urlParameters", properties); + + int changes = eventService.send(event); + + LOGGER.info("Changes of the event : {}", changes); + + Assert.assertTrue(changes > 0); + } + + @Test + public void testCopyProperties_copySingleValueWithExistingPropertyType() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); + + Profile profile = profileService.load(PROFILE_TARGET_TEST_ID); + Assert.assertNull(profile.getProperty("firstName")); + + Event event = new Event("copyProperties", null, profile, null, null, profile, new Date()); + event.setPersistent(false); + + Map<String, Object> properties = new HashMap<>(); + properties.put("param1SingleWithPropertyType", "SingleValue"); + + event.setProperty("urlParameters", properties); + + Metadata metadata = new Metadata(); + metadata.setSystemTags(new HashSet<>(Arrays.asList("urlParameters"))); + metadata.setId("param1SingleWithPropertyType"); + metadata.setName("Url parameters"); + + PropertyType propertyType1 = new PropertyType(); + propertyType1.setItemId("param1SingleWithPropertyType"); + propertyType1.setMetadata(metadata); + propertyType1.setTarget("profiles"); + propertyType1.setValueTypeId("string"); + propertyType1.setMultivalued(false); + + profileService.setPropertyType(propertyType1); + + int changes = eventService.send(event); + + LOGGER.info("Changes of the event : {}", changes); + + Assert.assertTrue(changes > 0); Review comment: Check the properties of the profiles are the expected ones. ########## File path: plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/CopyPropertiesAction.java ########## @@ -0,0 +1,109 @@ +/* + * 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.unomi.plugins.baseplugin.actions; + +import org.apache.commons.beanutils.BeanUtilsBean; +import org.apache.commons.lang3.StringUtils; +import org.apache.unomi.api.Event; +import org.apache.unomi.api.PropertyType; +import org.apache.unomi.api.actions.Action; +import org.apache.unomi.api.actions.ActionExecutor; +import org.apache.unomi.api.services.EventService; +import org.apache.unomi.api.services.ProfileService; +import org.apache.unomi.persistence.spi.PropertyHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class CopyPropertiesAction implements ActionExecutor { + + private static final Logger logger = LoggerFactory.getLogger(CopyPropertiesAction.class); + private ProfileService profileService; + + public void setProfileService(ProfileService profileService) { + this.profileService = profileService; + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public int execute(Action action, Event event) { + boolean changed = false; + + for (Map.Entry<String, Object> entry : getEventPropsToCopy(action, event).entrySet()) { + // propType Check + PropertyType propertyType = profileService.getPropertyType(entry.getKey()); + String propertyName = "properties." + entry.getKey(); + if (propertyType != null && propertyType.isMultivalued()) { Review comment: I would suggest to handle also the case where propertyType != null && !propertyPe.isMultivalued(). because we also need some control here (check next comments that explain why) ########## File path: itests/src/test/java/org/apache/unomi/itests/CopyPropertiesActionIT.java ########## @@ -0,0 +1,312 @@ +/* + * 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.unomi.itests; + +import org.apache.unomi.api.Event; +import org.apache.unomi.api.Metadata; +import org.apache.unomi.api.Profile; +import org.apache.unomi.api.PropertyType; +import org.apache.unomi.api.rules.Rule; +import org.apache.unomi.api.services.EventService; +import org.apache.unomi.api.services.ProfileService; +import org.apache.unomi.api.services.RulesService; +import org.apache.unomi.persistence.spi.CustomObjectMapper; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.ops4j.pax.exam.junit.PaxExam; +import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy; +import org.ops4j.pax.exam.spi.reactors.PerSuite; +import org.ops4j.pax.exam.util.Filter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.inject.Inject; +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Date; + +/** + * Created by amidani on 12/10/2017. + */ + +@RunWith(PaxExam.class) +@ExamReactorStrategy(PerSuite.class) +public class CopyPropertiesActionIT extends BaseIT { + private final static Logger LOGGER = LoggerFactory.getLogger(CopyPropertiesActionIT.class); + + private final static String PROFILE_TARGET_TEST_ID = "profile-target-event"; + private final static String PROFILE_TEST_ID = "profile-to-update-by-event"; + + @Inject + @Filter(timeout = 600000) + protected RulesService rulesService; + @Inject + @Filter(timeout = 600000) + protected ProfileService profileService; + @Inject + @Filter(timeout = 600000) + protected EventService eventService; + + @Before + public void setUp() throws IOException, InterruptedException { + Profile profile = new Profile(); + profile.setItemId(PROFILE_TEST_ID); + profile.setProperties(new HashMap<>()); + profile.setProperty("lastName", "Jose"); // property that have a propertyType registered in the system + profile.setProperty("prop4", "New property 4"); // property that do not have a propertyType registered in the system + profileService.save(profile); + LOGGER.info("Profile saved with ID [{}].", profile.getItemId()); + + Profile profileTarget = new Profile(); + profileTarget.setItemId(PROFILE_TARGET_TEST_ID); + profileService.save(profileTarget); + LOGGER.info("Profile saved with ID [{}].", profileTarget.getItemId()); + + refreshPersistence(); + } + + @Test + public void testCopyProperties_copyMultipleValueWithExistingPropertyType() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); + + Profile profile = profileService.load(PROFILE_TARGET_TEST_ID); + Assert.assertNull(profile.getProperty("firstName")); + + Event event = new Event("copyProperties", null, profile, null, null, profile, new Date()); + event.setPersistent(false); + + Map<String, Object> properties = new HashMap<>(); + properties.put("param1", Arrays.asList("value")); + properties.put("param2", Arrays.asList("valueA", "valueB")); + + event.setProperty("urlParameters", properties); + + Metadata metadata = new Metadata(); + metadata.setSystemTags(new HashSet<>(Arrays.asList("urlParameters"))); + metadata.setId("param1"); + metadata.setName("Url parameters"); + + PropertyType propertyType1 = new PropertyType(); + propertyType1.setItemId("param1"); + propertyType1.setMetadata(metadata); + propertyType1.setTarget("profiles"); + propertyType1.setValueTypeId("string"); + propertyType1.setMultivalued(true); + + profileService.setPropertyType(propertyType1); + + Metadata metadata2 = new Metadata(); + metadata2.setSystemTags(new HashSet<>(Arrays.asList("urlParameters"))); + metadata2.setId("param2"); + metadata2.setName("Url parameters"); + + PropertyType propertyType2 = new PropertyType(); + propertyType2.setItemId("param2"); + propertyType2.setMetadata(metadata2); + propertyType2.setTarget("profiles"); + propertyType2.setValueTypeId("string"); + propertyType2.setMultivalued(true); + + profileService.setPropertyType(propertyType2); + + int changes = eventService.send(event); + + LOGGER.info("Changes of the event : {}", changes); + + Assert.assertTrue(changes > 0); + } + + @Test + public void testCopyProperties_copyMultipleValueWithoutExistingPropertyType() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); + + Profile profile = profileService.load(PROFILE_TARGET_TEST_ID); + Assert.assertNull(profile.getProperty("firstName")); + + Event event = new Event("copyProperties", null, profile, null, null, profile, new Date()); + event.setPersistent(false); + + Map<String, Object> properties = new HashMap<>(); + properties.put("param1WithoutPropertyType", Arrays.asList("value")); + properties.put("param2WithoutPropertyType", Arrays.asList("valueA", "valueB")); + + event.setProperty("urlParameters", properties); + + int changes = eventService.send(event); + + LOGGER.info("Changes of the event : {}", changes); + + Assert.assertTrue(changes > 0); + } + + @Test + public void testCopyProperties_copySingleValueWithoutPropertyType() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); + + Profile profile = profileService.load(PROFILE_TARGET_TEST_ID); + Assert.assertNull(profile.getProperty("firstName")); + + Event event = new Event("copyProperties", null, profile, null, null, profile, new Date()); + event.setPersistent(false); + + Map<String, Object> properties = new HashMap<>(); + properties.put("param1SingleValue", "SingleValue"); + + event.setProperty("urlParameters", properties); + + int changes = eventService.send(event); + + LOGGER.info("Changes of the event : {}", changes); + + Assert.assertTrue(changes > 0); + } + + @Test + public void testCopyProperties_copySingleValueWithExistingPropertyType() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); + + Profile profile = profileService.load(PROFILE_TARGET_TEST_ID); + Assert.assertNull(profile.getProperty("firstName")); + + Event event = new Event("copyProperties", null, profile, null, null, profile, new Date()); + event.setPersistent(false); + + Map<String, Object> properties = new HashMap<>(); + properties.put("param1SingleWithPropertyType", "SingleValue"); + + event.setProperty("urlParameters", properties); + + Metadata metadata = new Metadata(); + metadata.setSystemTags(new HashSet<>(Arrays.asList("urlParameters"))); + metadata.setId("param1SingleWithPropertyType"); + metadata.setName("Url parameters"); + + PropertyType propertyType1 = new PropertyType(); + propertyType1.setItemId("param1SingleWithPropertyType"); + propertyType1.setMetadata(metadata); + propertyType1.setTarget("profiles"); + propertyType1.setValueTypeId("string"); + propertyType1.setMultivalued(false); + + profileService.setPropertyType(propertyType1); + + int changes = eventService.send(event); + + LOGGER.info("Changes of the event : {}", changes); + + Assert.assertTrue(changes > 0); + } + + + @Test + public void testCopyProperties_copySingleValueWithExistingPropertyOnProfile() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); + + Profile profile = profileService.load(PROFILE_TARGET_TEST_ID); + profile.setProperty("param1Existing", "existing"); + profile.setProperty("param2Existing", Arrays.asList("existingArray")); + Assert.assertNull(profile.getProperty("firstName")); + + Event event = new Event("copyProperties", null, profile, null, null, profile, new Date()); + event.setPersistent(false); + + Map<String, Object> properties = new HashMap<>(); + properties.put("param1Existing", "SingleValue"); + + event.setProperty("urlParameters", properties); + + int changes = eventService.send(event); + + LOGGER.info("Changes of the event : {}", changes); + + Assert.assertTrue(changes > 0); + } + + @Test + public void testCopyProperties_copySingleValueWithExistingArray() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); + + Profile profile = profileService.load(PROFILE_TARGET_TEST_ID); + profile.setProperty("paramExistingArray", Arrays.asList("existingArray")); + Assert.assertNull(profile.getProperty("firstName")); + + Event event = new Event("copyProperties", null, profile, null, null, profile, new Date()); + event.setPersistent(false); + + Map<String, Object> properties = new HashMap<>(); + properties.put("paramExistingArray", "SingleValue"); + + event.setProperty("urlParameters", properties); + + int changes = eventService.send(event); + + LOGGER.info("Changes of the event : {}", changes); + + Assert.assertTrue(changes > 0); Review comment: Check the properties of the profiles are the expected ones. ########## File path: itests/src/test/java/org/apache/unomi/itests/CopyPropertiesActionIT.java ########## @@ -0,0 +1,312 @@ +/* + * 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.unomi.itests; + +import org.apache.unomi.api.Event; +import org.apache.unomi.api.Metadata; +import org.apache.unomi.api.Profile; +import org.apache.unomi.api.PropertyType; +import org.apache.unomi.api.rules.Rule; +import org.apache.unomi.api.services.EventService; +import org.apache.unomi.api.services.ProfileService; +import org.apache.unomi.api.services.RulesService; +import org.apache.unomi.persistence.spi.CustomObjectMapper; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.ops4j.pax.exam.junit.PaxExam; +import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy; +import org.ops4j.pax.exam.spi.reactors.PerSuite; +import org.ops4j.pax.exam.util.Filter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.inject.Inject; +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Date; + +/** + * Created by amidani on 12/10/2017. + */ + +@RunWith(PaxExam.class) +@ExamReactorStrategy(PerSuite.class) +public class CopyPropertiesActionIT extends BaseIT { + private final static Logger LOGGER = LoggerFactory.getLogger(CopyPropertiesActionIT.class); + + private final static String PROFILE_TARGET_TEST_ID = "profile-target-event"; + private final static String PROFILE_TEST_ID = "profile-to-update-by-event"; + + @Inject + @Filter(timeout = 600000) + protected RulesService rulesService; + @Inject + @Filter(timeout = 600000) + protected ProfileService profileService; + @Inject + @Filter(timeout = 600000) + protected EventService eventService; + + @Before + public void setUp() throws IOException, InterruptedException { + Profile profile = new Profile(); + profile.setItemId(PROFILE_TEST_ID); + profile.setProperties(new HashMap<>()); + profile.setProperty("lastName", "Jose"); // property that have a propertyType registered in the system + profile.setProperty("prop4", "New property 4"); // property that do not have a propertyType registered in the system + profileService.save(profile); + LOGGER.info("Profile saved with ID [{}].", profile.getItemId()); + + Profile profileTarget = new Profile(); + profileTarget.setItemId(PROFILE_TARGET_TEST_ID); + profileService.save(profileTarget); + LOGGER.info("Profile saved with ID [{}].", profileTarget.getItemId()); Review comment: This profile seem's to be used and reused by multiple tests We need an @After function to cleanup and remove the 2 profiles that have been created for the tests. ########## File path: itests/src/test/java/org/apache/unomi/itests/CopyPropertiesActionIT.java ########## @@ -0,0 +1,312 @@ +/* + * 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.unomi.itests; + +import org.apache.unomi.api.Event; +import org.apache.unomi.api.Metadata; +import org.apache.unomi.api.Profile; +import org.apache.unomi.api.PropertyType; +import org.apache.unomi.api.rules.Rule; +import org.apache.unomi.api.services.EventService; +import org.apache.unomi.api.services.ProfileService; +import org.apache.unomi.api.services.RulesService; +import org.apache.unomi.persistence.spi.CustomObjectMapper; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.ops4j.pax.exam.junit.PaxExam; +import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy; +import org.ops4j.pax.exam.spi.reactors.PerSuite; +import org.ops4j.pax.exam.util.Filter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.inject.Inject; +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Date; + +/** + * Created by amidani on 12/10/2017. + */ + +@RunWith(PaxExam.class) +@ExamReactorStrategy(PerSuite.class) +public class CopyPropertiesActionIT extends BaseIT { + private final static Logger LOGGER = LoggerFactory.getLogger(CopyPropertiesActionIT.class); + + private final static String PROFILE_TARGET_TEST_ID = "profile-target-event"; + private final static String PROFILE_TEST_ID = "profile-to-update-by-event"; + + @Inject + @Filter(timeout = 600000) + protected RulesService rulesService; + @Inject + @Filter(timeout = 600000) + protected ProfileService profileService; + @Inject + @Filter(timeout = 600000) + protected EventService eventService; + + @Before + public void setUp() throws IOException, InterruptedException { + Profile profile = new Profile(); + profile.setItemId(PROFILE_TEST_ID); + profile.setProperties(new HashMap<>()); + profile.setProperty("lastName", "Jose"); // property that have a propertyType registered in the system + profile.setProperty("prop4", "New property 4"); // property that do not have a propertyType registered in the system + profileService.save(profile); + LOGGER.info("Profile saved with ID [{}].", profile.getItemId()); + + Profile profileTarget = new Profile(); + profileTarget.setItemId(PROFILE_TARGET_TEST_ID); + profileService.save(profileTarget); + LOGGER.info("Profile saved with ID [{}].", profileTarget.getItemId()); + + refreshPersistence(); + } + + @Test + public void testCopyProperties_copyMultipleValueWithExistingPropertyType() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); Review comment: This rule is still registered in the system at the end of the test, we need to cleanup the test data after each tests, either in a @After function, or in a try{} finally{} block in the the test it self. All the tests should clean the data they used: Rules, PropTypes, Profiles ########## File path: itests/src/test/resources/testCopyProperties.json ########## @@ -0,0 +1,23 @@ +{ Review comment: we could provide other rules with the other parameters to be able to also test them. And each test case will load the appropriate rule depending on what it should test. ########## File path: itests/src/test/java/org/apache/unomi/itests/CopyPropertiesActionIT.java ########## @@ -0,0 +1,312 @@ +/* + * 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.unomi.itests; + +import org.apache.unomi.api.Event; +import org.apache.unomi.api.Metadata; +import org.apache.unomi.api.Profile; +import org.apache.unomi.api.PropertyType; +import org.apache.unomi.api.rules.Rule; +import org.apache.unomi.api.services.EventService; +import org.apache.unomi.api.services.ProfileService; +import org.apache.unomi.api.services.RulesService; +import org.apache.unomi.persistence.spi.CustomObjectMapper; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.ops4j.pax.exam.junit.PaxExam; +import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy; +import org.ops4j.pax.exam.spi.reactors.PerSuite; +import org.ops4j.pax.exam.util.Filter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.inject.Inject; +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Date; + +/** + * Created by amidani on 12/10/2017. + */ + +@RunWith(PaxExam.class) +@ExamReactorStrategy(PerSuite.class) +public class CopyPropertiesActionIT extends BaseIT { + private final static Logger LOGGER = LoggerFactory.getLogger(CopyPropertiesActionIT.class); + + private final static String PROFILE_TARGET_TEST_ID = "profile-target-event"; + private final static String PROFILE_TEST_ID = "profile-to-update-by-event"; + + @Inject + @Filter(timeout = 600000) + protected RulesService rulesService; + @Inject + @Filter(timeout = 600000) + protected ProfileService profileService; + @Inject + @Filter(timeout = 600000) + protected EventService eventService; + + @Before + public void setUp() throws IOException, InterruptedException { + Profile profile = new Profile(); + profile.setItemId(PROFILE_TEST_ID); + profile.setProperties(new HashMap<>()); + profile.setProperty("lastName", "Jose"); // property that have a propertyType registered in the system + profile.setProperty("prop4", "New property 4"); // property that do not have a propertyType registered in the system + profileService.save(profile); + LOGGER.info("Profile saved with ID [{}].", profile.getItemId()); + + Profile profileTarget = new Profile(); + profileTarget.setItemId(PROFILE_TARGET_TEST_ID); + profileService.save(profileTarget); + LOGGER.info("Profile saved with ID [{}].", profileTarget.getItemId()); + + refreshPersistence(); + } + + @Test + public void testCopyProperties_copyMultipleValueWithExistingPropertyType() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); + + Profile profile = profileService.load(PROFILE_TARGET_TEST_ID); + Assert.assertNull(profile.getProperty("firstName")); + + Event event = new Event("copyProperties", null, profile, null, null, profile, new Date()); + event.setPersistent(false); + + Map<String, Object> properties = new HashMap<>(); + properties.put("param1", Arrays.asList("value")); + properties.put("param2", Arrays.asList("valueA", "valueB")); + + event.setProperty("urlParameters", properties); + + Metadata metadata = new Metadata(); + metadata.setSystemTags(new HashSet<>(Arrays.asList("urlParameters"))); + metadata.setId("param1"); + metadata.setName("Url parameters"); + + PropertyType propertyType1 = new PropertyType(); + propertyType1.setItemId("param1"); + propertyType1.setMetadata(metadata); + propertyType1.setTarget("profiles"); + propertyType1.setValueTypeId("string"); + propertyType1.setMultivalued(true); + + profileService.setPropertyType(propertyType1); + + Metadata metadata2 = new Metadata(); + metadata2.setSystemTags(new HashSet<>(Arrays.asList("urlParameters"))); + metadata2.setId("param2"); + metadata2.setName("Url parameters"); + + PropertyType propertyType2 = new PropertyType(); + propertyType2.setItemId("param2"); + propertyType2.setMetadata(metadata2); + propertyType2.setTarget("profiles"); + propertyType2.setValueTypeId("string"); + propertyType2.setMultivalued(true); + + profileService.setPropertyType(propertyType2); + + int changes = eventService.send(event); + + LOGGER.info("Changes of the event : {}", changes); + + Assert.assertTrue(changes > 0); Review comment: Could be great to check that the profile have been updated correctly by checking the profile in the event: event.getProfile() and check that the props are correct. ########## File path: itests/src/test/java/org/apache/unomi/itests/CopyPropertiesActionIT.java ########## @@ -0,0 +1,312 @@ +/* + * 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.unomi.itests; + +import org.apache.unomi.api.Event; +import org.apache.unomi.api.Metadata; +import org.apache.unomi.api.Profile; +import org.apache.unomi.api.PropertyType; +import org.apache.unomi.api.rules.Rule; +import org.apache.unomi.api.services.EventService; +import org.apache.unomi.api.services.ProfileService; +import org.apache.unomi.api.services.RulesService; +import org.apache.unomi.persistence.spi.CustomObjectMapper; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.ops4j.pax.exam.junit.PaxExam; +import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy; +import org.ops4j.pax.exam.spi.reactors.PerSuite; +import org.ops4j.pax.exam.util.Filter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.inject.Inject; +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Date; + +/** + * Created by amidani on 12/10/2017. + */ + +@RunWith(PaxExam.class) +@ExamReactorStrategy(PerSuite.class) +public class CopyPropertiesActionIT extends BaseIT { + private final static Logger LOGGER = LoggerFactory.getLogger(CopyPropertiesActionIT.class); + + private final static String PROFILE_TARGET_TEST_ID = "profile-target-event"; + private final static String PROFILE_TEST_ID = "profile-to-update-by-event"; + + @Inject + @Filter(timeout = 600000) + protected RulesService rulesService; + @Inject + @Filter(timeout = 600000) + protected ProfileService profileService; + @Inject + @Filter(timeout = 600000) + protected EventService eventService; + + @Before + public void setUp() throws IOException, InterruptedException { + Profile profile = new Profile(); + profile.setItemId(PROFILE_TEST_ID); + profile.setProperties(new HashMap<>()); + profile.setProperty("lastName", "Jose"); // property that have a propertyType registered in the system + profile.setProperty("prop4", "New property 4"); // property that do not have a propertyType registered in the system + profileService.save(profile); + LOGGER.info("Profile saved with ID [{}].", profile.getItemId()); + + Profile profileTarget = new Profile(); + profileTarget.setItemId(PROFILE_TARGET_TEST_ID); + profileService.save(profileTarget); + LOGGER.info("Profile saved with ID [{}].", profileTarget.getItemId()); + + refreshPersistence(); + } + + @Test + public void testCopyProperties_copyMultipleValueWithExistingPropertyType() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); + + Profile profile = profileService.load(PROFILE_TARGET_TEST_ID); + Assert.assertNull(profile.getProperty("firstName")); + + Event event = new Event("copyProperties", null, profile, null, null, profile, new Date()); + event.setPersistent(false); + + Map<String, Object> properties = new HashMap<>(); + properties.put("param1", Arrays.asList("value")); + properties.put("param2", Arrays.asList("valueA", "valueB")); + + event.setProperty("urlParameters", properties); + + Metadata metadata = new Metadata(); + metadata.setSystemTags(new HashSet<>(Arrays.asList("urlParameters"))); + metadata.setId("param1"); + metadata.setName("Url parameters"); + + PropertyType propertyType1 = new PropertyType(); + propertyType1.setItemId("param1"); + propertyType1.setMetadata(metadata); + propertyType1.setTarget("profiles"); + propertyType1.setValueTypeId("string"); + propertyType1.setMultivalued(true); + + profileService.setPropertyType(propertyType1); + + Metadata metadata2 = new Metadata(); + metadata2.setSystemTags(new HashSet<>(Arrays.asList("urlParameters"))); + metadata2.setId("param2"); + metadata2.setName("Url parameters"); + + PropertyType propertyType2 = new PropertyType(); + propertyType2.setItemId("param2"); + propertyType2.setMetadata(metadata2); + propertyType2.setTarget("profiles"); + propertyType2.setValueTypeId("string"); + propertyType2.setMultivalued(true); + + profileService.setPropertyType(propertyType2); + + int changes = eventService.send(event); + + LOGGER.info("Changes of the event : {}", changes); + + Assert.assertTrue(changes > 0); + } + + @Test + public void testCopyProperties_copyMultipleValueWithoutExistingPropertyType() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); + + Profile profile = profileService.load(PROFILE_TARGET_TEST_ID); + Assert.assertNull(profile.getProperty("firstName")); + + Event event = new Event("copyProperties", null, profile, null, null, profile, new Date()); + event.setPersistent(false); + + Map<String, Object> properties = new HashMap<>(); + properties.put("param1WithoutPropertyType", Arrays.asList("value")); + properties.put("param2WithoutPropertyType", Arrays.asList("valueA", "valueB")); + + event.setProperty("urlParameters", properties); + + int changes = eventService.send(event); + + LOGGER.info("Changes of the event : {}", changes); + + Assert.assertTrue(changes > 0); + } + + @Test + public void testCopyProperties_copySingleValueWithoutPropertyType() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); + + Profile profile = profileService.load(PROFILE_TARGET_TEST_ID); + Assert.assertNull(profile.getProperty("firstName")); + + Event event = new Event("copyProperties", null, profile, null, null, profile, new Date()); + event.setPersistent(false); + + Map<String, Object> properties = new HashMap<>(); + properties.put("param1SingleValue", "SingleValue"); + + event.setProperty("urlParameters", properties); + + int changes = eventService.send(event); + + LOGGER.info("Changes of the event : {}", changes); + + Assert.assertTrue(changes > 0); Review comment: Check the properties of the profiles are the expected ones. ########## File path: itests/src/test/java/org/apache/unomi/itests/CopyPropertiesActionIT.java ########## @@ -0,0 +1,312 @@ +/* + * 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.unomi.itests; + +import org.apache.unomi.api.Event; +import org.apache.unomi.api.Metadata; +import org.apache.unomi.api.Profile; +import org.apache.unomi.api.PropertyType; +import org.apache.unomi.api.rules.Rule; +import org.apache.unomi.api.services.EventService; +import org.apache.unomi.api.services.ProfileService; +import org.apache.unomi.api.services.RulesService; +import org.apache.unomi.persistence.spi.CustomObjectMapper; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.ops4j.pax.exam.junit.PaxExam; +import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy; +import org.ops4j.pax.exam.spi.reactors.PerSuite; +import org.ops4j.pax.exam.util.Filter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.inject.Inject; +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Date; + +/** + * Created by amidani on 12/10/2017. + */ + +@RunWith(PaxExam.class) +@ExamReactorStrategy(PerSuite.class) +public class CopyPropertiesActionIT extends BaseIT { + private final static Logger LOGGER = LoggerFactory.getLogger(CopyPropertiesActionIT.class); + + private final static String PROFILE_TARGET_TEST_ID = "profile-target-event"; + private final static String PROFILE_TEST_ID = "profile-to-update-by-event"; + + @Inject + @Filter(timeout = 600000) + protected RulesService rulesService; + @Inject + @Filter(timeout = 600000) + protected ProfileService profileService; + @Inject + @Filter(timeout = 600000) + protected EventService eventService; + + @Before + public void setUp() throws IOException, InterruptedException { + Profile profile = new Profile(); + profile.setItemId(PROFILE_TEST_ID); + profile.setProperties(new HashMap<>()); + profile.setProperty("lastName", "Jose"); // property that have a propertyType registered in the system + profile.setProperty("prop4", "New property 4"); // property that do not have a propertyType registered in the system + profileService.save(profile); + LOGGER.info("Profile saved with ID [{}].", profile.getItemId()); + + Profile profileTarget = new Profile(); + profileTarget.setItemId(PROFILE_TARGET_TEST_ID); + profileService.save(profileTarget); + LOGGER.info("Profile saved with ID [{}].", profileTarget.getItemId()); + + refreshPersistence(); + } + + @Test + public void testCopyProperties_copyMultipleValueWithExistingPropertyType() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); + + Profile profile = profileService.load(PROFILE_TARGET_TEST_ID); + Assert.assertNull(profile.getProperty("firstName")); + + Event event = new Event("copyProperties", null, profile, null, null, profile, new Date()); + event.setPersistent(false); + + Map<String, Object> properties = new HashMap<>(); + properties.put("param1", Arrays.asList("value")); + properties.put("param2", Arrays.asList("valueA", "valueB")); + + event.setProperty("urlParameters", properties); + + Metadata metadata = new Metadata(); + metadata.setSystemTags(new HashSet<>(Arrays.asList("urlParameters"))); + metadata.setId("param1"); + metadata.setName("Url parameters"); + + PropertyType propertyType1 = new PropertyType(); + propertyType1.setItemId("param1"); + propertyType1.setMetadata(metadata); + propertyType1.setTarget("profiles"); + propertyType1.setValueTypeId("string"); + propertyType1.setMultivalued(true); + + profileService.setPropertyType(propertyType1); + + Metadata metadata2 = new Metadata(); + metadata2.setSystemTags(new HashSet<>(Arrays.asList("urlParameters"))); + metadata2.setId("param2"); + metadata2.setName("Url parameters"); + + PropertyType propertyType2 = new PropertyType(); + propertyType2.setItemId("param2"); + propertyType2.setMetadata(metadata2); + propertyType2.setTarget("profiles"); + propertyType2.setValueTypeId("string"); + propertyType2.setMultivalued(true); Review comment: Could be extract to a function in the test for easing the test readability. ########## File path: itests/src/test/java/org/apache/unomi/itests/CopyPropertiesActionIT.java ########## @@ -0,0 +1,312 @@ +/* + * 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.unomi.itests; + +import org.apache.unomi.api.Event; +import org.apache.unomi.api.Metadata; +import org.apache.unomi.api.Profile; +import org.apache.unomi.api.PropertyType; +import org.apache.unomi.api.rules.Rule; +import org.apache.unomi.api.services.EventService; +import org.apache.unomi.api.services.ProfileService; +import org.apache.unomi.api.services.RulesService; +import org.apache.unomi.persistence.spi.CustomObjectMapper; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.ops4j.pax.exam.junit.PaxExam; +import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy; +import org.ops4j.pax.exam.spi.reactors.PerSuite; +import org.ops4j.pax.exam.util.Filter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.inject.Inject; +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Date; + +/** + * Created by amidani on 12/10/2017. + */ + +@RunWith(PaxExam.class) +@ExamReactorStrategy(PerSuite.class) +public class CopyPropertiesActionIT extends BaseIT { + private final static Logger LOGGER = LoggerFactory.getLogger(CopyPropertiesActionIT.class); + + private final static String PROFILE_TARGET_TEST_ID = "profile-target-event"; + private final static String PROFILE_TEST_ID = "profile-to-update-by-event"; + + @Inject + @Filter(timeout = 600000) + protected RulesService rulesService; + @Inject + @Filter(timeout = 600000) + protected ProfileService profileService; + @Inject + @Filter(timeout = 600000) + protected EventService eventService; + + @Before + public void setUp() throws IOException, InterruptedException { + Profile profile = new Profile(); + profile.setItemId(PROFILE_TEST_ID); + profile.setProperties(new HashMap<>()); + profile.setProperty("lastName", "Jose"); // property that have a propertyType registered in the system + profile.setProperty("prop4", "New property 4"); // property that do not have a propertyType registered in the system + profileService.save(profile); + LOGGER.info("Profile saved with ID [{}].", profile.getItemId()); + + Profile profileTarget = new Profile(); + profileTarget.setItemId(PROFILE_TARGET_TEST_ID); + profileService.save(profileTarget); + LOGGER.info("Profile saved with ID [{}].", profileTarget.getItemId()); + + refreshPersistence(); + } + + @Test + public void testCopyProperties_copyMultipleValueWithExistingPropertyType() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); + + Profile profile = profileService.load(PROFILE_TARGET_TEST_ID); + Assert.assertNull(profile.getProperty("firstName")); + + Event event = new Event("copyProperties", null, profile, null, null, profile, new Date()); + event.setPersistent(false); + + Map<String, Object> properties = new HashMap<>(); + properties.put("param1", Arrays.asList("value")); + properties.put("param2", Arrays.asList("valueA", "valueB")); + + event.setProperty("urlParameters", properties); + + Metadata metadata = new Metadata(); + metadata.setSystemTags(new HashSet<>(Arrays.asList("urlParameters"))); + metadata.setId("param1"); + metadata.setName("Url parameters"); + + PropertyType propertyType1 = new PropertyType(); + propertyType1.setItemId("param1"); + propertyType1.setMetadata(metadata); + propertyType1.setTarget("profiles"); + propertyType1.setValueTypeId("string"); + propertyType1.setMultivalued(true); + + profileService.setPropertyType(propertyType1); + + Metadata metadata2 = new Metadata(); + metadata2.setSystemTags(new HashSet<>(Arrays.asList("urlParameters"))); + metadata2.setId("param2"); + metadata2.setName("Url parameters"); + + PropertyType propertyType2 = new PropertyType(); + propertyType2.setItemId("param2"); + propertyType2.setMetadata(metadata2); + propertyType2.setTarget("profiles"); + propertyType2.setValueTypeId("string"); + propertyType2.setMultivalued(true); + + profileService.setPropertyType(propertyType2); + + int changes = eventService.send(event); + + LOGGER.info("Changes of the event : {}", changes); + + Assert.assertTrue(changes > 0); + } + + @Test + public void testCopyProperties_copyMultipleValueWithoutExistingPropertyType() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); + + Profile profile = profileService.load(PROFILE_TARGET_TEST_ID); + Assert.assertNull(profile.getProperty("firstName")); + + Event event = new Event("copyProperties", null, profile, null, null, profile, new Date()); + event.setPersistent(false); + + Map<String, Object> properties = new HashMap<>(); + properties.put("param1WithoutPropertyType", Arrays.asList("value")); + properties.put("param2WithoutPropertyType", Arrays.asList("valueA", "valueB")); + + event.setProperty("urlParameters", properties); + + int changes = eventService.send(event); + + LOGGER.info("Changes of the event : {}", changes); + + Assert.assertTrue(changes > 0); + } + + @Test + public void testCopyProperties_copySingleValueWithoutPropertyType() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); + + Profile profile = profileService.load(PROFILE_TARGET_TEST_ID); + Assert.assertNull(profile.getProperty("firstName")); + + Event event = new Event("copyProperties", null, profile, null, null, profile, new Date()); + event.setPersistent(false); + + Map<String, Object> properties = new HashMap<>(); + properties.put("param1SingleValue", "SingleValue"); + + event.setProperty("urlParameters", properties); + + int changes = eventService.send(event); + + LOGGER.info("Changes of the event : {}", changes); + + Assert.assertTrue(changes > 0); + } + + @Test + public void testCopyProperties_copySingleValueWithExistingPropertyType() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); + + Profile profile = profileService.load(PROFILE_TARGET_TEST_ID); + Assert.assertNull(profile.getProperty("firstName")); + + Event event = new Event("copyProperties", null, profile, null, null, profile, new Date()); + event.setPersistent(false); + + Map<String, Object> properties = new HashMap<>(); + properties.put("param1SingleWithPropertyType", "SingleValue"); + + event.setProperty("urlParameters", properties); + + Metadata metadata = new Metadata(); + metadata.setSystemTags(new HashSet<>(Arrays.asList("urlParameters"))); + metadata.setId("param1SingleWithPropertyType"); + metadata.setName("Url parameters"); + + PropertyType propertyType1 = new PropertyType(); + propertyType1.setItemId("param1SingleWithPropertyType"); + propertyType1.setMetadata(metadata); + propertyType1.setTarget("profiles"); + propertyType1.setValueTypeId("string"); + propertyType1.setMultivalued(false); + + profileService.setPropertyType(propertyType1); + + int changes = eventService.send(event); + + LOGGER.info("Changes of the event : {}", changes); + + Assert.assertTrue(changes > 0); + } + + + @Test + public void testCopyProperties_copySingleValueWithExistingPropertyOnProfile() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); + + Profile profile = profileService.load(PROFILE_TARGET_TEST_ID); + profile.setProperty("param1Existing", "existing"); + profile.setProperty("param2Existing", Arrays.asList("existingArray")); + Assert.assertNull(profile.getProperty("firstName")); + + Event event = new Event("copyProperties", null, profile, null, null, profile, new Date()); + event.setPersistent(false); + + Map<String, Object> properties = new HashMap<>(); + properties.put("param1Existing", "SingleValue"); + + event.setProperty("urlParameters", properties); + + int changes = eventService.send(event); + + LOGGER.info("Changes of the event : {}", changes); + + Assert.assertTrue(changes > 0); + } + + @Test + public void testCopyProperties_copySingleValueWithExistingArray() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); + + Profile profile = profileService.load(PROFILE_TARGET_TEST_ID); + profile.setProperty("paramExistingArray", Arrays.asList("existingArray")); + Assert.assertNull(profile.getProperty("firstName")); + + Event event = new Event("copyProperties", null, profile, null, null, profile, new Date()); + event.setPersistent(false); + + Map<String, Object> properties = new HashMap<>(); + properties.put("paramExistingArray", "SingleValue"); + + event.setProperty("urlParameters", properties); + + int changes = eventService.send(event); + + LOGGER.info("Changes of the event : {}", changes); + + Assert.assertTrue(changes > 0); + } + + @Test + public void testCopyProperties_copyArrayOnSingleValueShouldNotCopy() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); + + Profile profile = profileService.load(PROFILE_TARGET_TEST_ID); + profile.setProperty("paramToNotReplace", "existingSingleValue"); + Assert.assertNull(profile.getProperty("firstName")); + + Event event = new Event("copyProperties", null, profile, null, null, profile, new Date()); + event.setPersistent(false); + + Map<String, Object> properties = new HashMap<>(); + properties.put("paramToNotReplace", Arrays.asList("newArray")); + + event.setProperty("urlParameters", properties); + + int changes = eventService.send(event); + + LOGGER.info("Changes of the event : {}", changes); + + Assert.assertTrue(changes == 0); + } +} Review comment: Missing test scenario with: mandatoryPropTypeSystemTag missing test scenario with: setPropertyStrategy Also the code of the tests are quiet the same in all the cases, - creating the rule - sending the event - checking the result I think a big part of all the test scenarios can be exctract to a single function with parameters and reuse it in test cases. it will simplify the test and avoid code duplication, event if code duplication is kind of allowed in Itest code, I think it could help developing scenarios to centralize the test logic. ########## File path: itests/src/test/java/org/apache/unomi/itests/CopyPropertiesActionIT.java ########## @@ -0,0 +1,312 @@ +/* + * 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.unomi.itests; + +import org.apache.unomi.api.Event; +import org.apache.unomi.api.Metadata; +import org.apache.unomi.api.Profile; +import org.apache.unomi.api.PropertyType; +import org.apache.unomi.api.rules.Rule; +import org.apache.unomi.api.services.EventService; +import org.apache.unomi.api.services.ProfileService; +import org.apache.unomi.api.services.RulesService; +import org.apache.unomi.persistence.spi.CustomObjectMapper; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.ops4j.pax.exam.junit.PaxExam; +import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy; +import org.ops4j.pax.exam.spi.reactors.PerSuite; +import org.ops4j.pax.exam.util.Filter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.inject.Inject; +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Date; + +/** + * Created by amidani on 12/10/2017. + */ + +@RunWith(PaxExam.class) +@ExamReactorStrategy(PerSuite.class) +public class CopyPropertiesActionIT extends BaseIT { + private final static Logger LOGGER = LoggerFactory.getLogger(CopyPropertiesActionIT.class); + + private final static String PROFILE_TARGET_TEST_ID = "profile-target-event"; + private final static String PROFILE_TEST_ID = "profile-to-update-by-event"; + + @Inject + @Filter(timeout = 600000) + protected RulesService rulesService; + @Inject + @Filter(timeout = 600000) + protected ProfileService profileService; + @Inject + @Filter(timeout = 600000) + protected EventService eventService; + + @Before + public void setUp() throws IOException, InterruptedException { + Profile profile = new Profile(); + profile.setItemId(PROFILE_TEST_ID); + profile.setProperties(new HashMap<>()); + profile.setProperty("lastName", "Jose"); // property that have a propertyType registered in the system + profile.setProperty("prop4", "New property 4"); // property that do not have a propertyType registered in the system + profileService.save(profile); + LOGGER.info("Profile saved with ID [{}].", profile.getItemId()); + + Profile profileTarget = new Profile(); + profileTarget.setItemId(PROFILE_TARGET_TEST_ID); + profileService.save(profileTarget); + LOGGER.info("Profile saved with ID [{}].", profileTarget.getItemId()); + + refreshPersistence(); + } + + @Test + public void testCopyProperties_copyMultipleValueWithExistingPropertyType() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); + + Profile profile = profileService.load(PROFILE_TARGET_TEST_ID); + Assert.assertNull(profile.getProperty("firstName")); + + Event event = new Event("copyProperties", null, profile, null, null, profile, new Date()); + event.setPersistent(false); + + Map<String, Object> properties = new HashMap<>(); + properties.put("param1", Arrays.asList("value")); + properties.put("param2", Arrays.asList("valueA", "valueB")); + + event.setProperty("urlParameters", properties); + + Metadata metadata = new Metadata(); + metadata.setSystemTags(new HashSet<>(Arrays.asList("urlParameters"))); + metadata.setId("param1"); + metadata.setName("Url parameters"); + + PropertyType propertyType1 = new PropertyType(); + propertyType1.setItemId("param1"); + propertyType1.setMetadata(metadata); + propertyType1.setTarget("profiles"); + propertyType1.setValueTypeId("string"); + propertyType1.setMultivalued(true); + + profileService.setPropertyType(propertyType1); + + Metadata metadata2 = new Metadata(); + metadata2.setSystemTags(new HashSet<>(Arrays.asList("urlParameters"))); + metadata2.setId("param2"); + metadata2.setName("Url parameters"); + + PropertyType propertyType2 = new PropertyType(); + propertyType2.setItemId("param2"); + propertyType2.setMetadata(metadata2); + propertyType2.setTarget("profiles"); + propertyType2.setValueTypeId("string"); + propertyType2.setMultivalued(true); + + profileService.setPropertyType(propertyType2); + + int changes = eventService.send(event); + + LOGGER.info("Changes of the event : {}", changes); + + Assert.assertTrue(changes > 0); + } + + @Test + public void testCopyProperties_copyMultipleValueWithoutExistingPropertyType() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); + + Profile profile = profileService.load(PROFILE_TARGET_TEST_ID); + Assert.assertNull(profile.getProperty("firstName")); + + Event event = new Event("copyProperties", null, profile, null, null, profile, new Date()); + event.setPersistent(false); + + Map<String, Object> properties = new HashMap<>(); + properties.put("param1WithoutPropertyType", Arrays.asList("value")); + properties.put("param2WithoutPropertyType", Arrays.asList("valueA", "valueB")); + + event.setProperty("urlParameters", properties); + + int changes = eventService.send(event); + + LOGGER.info("Changes of the event : {}", changes); + + Assert.assertTrue(changes > 0); + } + + @Test + public void testCopyProperties_copySingleValueWithoutPropertyType() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); + + Profile profile = profileService.load(PROFILE_TARGET_TEST_ID); + Assert.assertNull(profile.getProperty("firstName")); + + Event event = new Event("copyProperties", null, profile, null, null, profile, new Date()); + event.setPersistent(false); + + Map<String, Object> properties = new HashMap<>(); + properties.put("param1SingleValue", "SingleValue"); + + event.setProperty("urlParameters", properties); + + int changes = eventService.send(event); + + LOGGER.info("Changes of the event : {}", changes); + + Assert.assertTrue(changes > 0); + } + + @Test + public void testCopyProperties_copySingleValueWithExistingPropertyType() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); + + Profile profile = profileService.load(PROFILE_TARGET_TEST_ID); + Assert.assertNull(profile.getProperty("firstName")); + + Event event = new Event("copyProperties", null, profile, null, null, profile, new Date()); + event.setPersistent(false); + + Map<String, Object> properties = new HashMap<>(); + properties.put("param1SingleWithPropertyType", "SingleValue"); + + event.setProperty("urlParameters", properties); + + Metadata metadata = new Metadata(); + metadata.setSystemTags(new HashSet<>(Arrays.asList("urlParameters"))); + metadata.setId("param1SingleWithPropertyType"); + metadata.setName("Url parameters"); + + PropertyType propertyType1 = new PropertyType(); + propertyType1.setItemId("param1SingleWithPropertyType"); + propertyType1.setMetadata(metadata); + propertyType1.setTarget("profiles"); + propertyType1.setValueTypeId("string"); + propertyType1.setMultivalued(false); + + profileService.setPropertyType(propertyType1); + + int changes = eventService.send(event); + + LOGGER.info("Changes of the event : {}", changes); + + Assert.assertTrue(changes > 0); + } + + + @Test + public void testCopyProperties_copySingleValueWithExistingPropertyOnProfile() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); + + Profile profile = profileService.load(PROFILE_TARGET_TEST_ID); + profile.setProperty("param1Existing", "existing"); + profile.setProperty("param2Existing", Arrays.asList("existingArray")); + Assert.assertNull(profile.getProperty("firstName")); + + Event event = new Event("copyProperties", null, profile, null, null, profile, new Date()); + event.setPersistent(false); + + Map<String, Object> properties = new HashMap<>(); + properties.put("param1Existing", "SingleValue"); + + event.setProperty("urlParameters", properties); + + int changes = eventService.send(event); + + LOGGER.info("Changes of the event : {}", changes); + + Assert.assertTrue(changes > 0); + } + + @Test + public void testCopyProperties_copySingleValueWithExistingArray() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); + + Profile profile = profileService.load(PROFILE_TARGET_TEST_ID); + profile.setProperty("paramExistingArray", Arrays.asList("existingArray")); + Assert.assertNull(profile.getProperty("firstName")); + + Event event = new Event("copyProperties", null, profile, null, null, profile, new Date()); + event.setPersistent(false); + + Map<String, Object> properties = new HashMap<>(); + properties.put("paramExistingArray", "SingleValue"); + + event.setProperty("urlParameters", properties); + + int changes = eventService.send(event); + + LOGGER.info("Changes of the event : {}", changes); + + Assert.assertTrue(changes > 0); + } + + @Test + public void testCopyProperties_copyArrayOnSingleValueShouldNotCopy() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); + + Profile profile = profileService.load(PROFILE_TARGET_TEST_ID); + profile.setProperty("paramToNotReplace", "existingSingleValue"); + Assert.assertNull(profile.getProperty("firstName")); + + Event event = new Event("copyProperties", null, profile, null, null, profile, new Date()); + event.setPersistent(false); + + Map<String, Object> properties = new HashMap<>(); + properties.put("paramToNotReplace", Arrays.asList("newArray")); + + event.setProperty("urlParameters", properties); + + int changes = eventService.send(event); + + LOGGER.info("Changes of the event : {}", changes); + + Assert.assertTrue(changes == 0); Review comment: Check the properties of the profiles are the expected ones. ########## File path: plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/CopyPropertiesAction.java ########## @@ -0,0 +1,109 @@ +/* + * 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.unomi.plugins.baseplugin.actions; + +import org.apache.commons.beanutils.BeanUtilsBean; +import org.apache.commons.lang3.StringUtils; +import org.apache.unomi.api.Event; +import org.apache.unomi.api.PropertyType; +import org.apache.unomi.api.actions.Action; +import org.apache.unomi.api.actions.ActionExecutor; +import org.apache.unomi.api.services.EventService; +import org.apache.unomi.api.services.ProfileService; +import org.apache.unomi.persistence.spi.PropertyHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class CopyPropertiesAction implements ActionExecutor { + + private static final Logger logger = LoggerFactory.getLogger(CopyPropertiesAction.class); + private ProfileService profileService; + + public void setProfileService(ProfileService profileService) { + this.profileService = profileService; + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public int execute(Action action, Event event) { + boolean changed = false; + + for (Map.Entry<String, Object> entry : getEventPropsToCopy(action, event).entrySet()) { + // propType Check + PropertyType propertyType = profileService.getPropertyType(entry.getKey()); + String propertyName = "properties." + entry.getKey(); Review comment: Here we should check if propertyType have the mandatorySystemTag from action config, if the mandatorySystemTag is provided, then it's also mean that that a propertyType is mandatory for doing the copy. ########## File path: plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/CopyPropertiesAction.java ########## @@ -0,0 +1,109 @@ +/* + * 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.unomi.plugins.baseplugin.actions; + +import org.apache.commons.beanutils.BeanUtilsBean; +import org.apache.commons.lang3.StringUtils; +import org.apache.unomi.api.Event; +import org.apache.unomi.api.PropertyType; +import org.apache.unomi.api.actions.Action; +import org.apache.unomi.api.actions.ActionExecutor; +import org.apache.unomi.api.services.EventService; +import org.apache.unomi.api.services.ProfileService; +import org.apache.unomi.persistence.spi.PropertyHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class CopyPropertiesAction implements ActionExecutor { + + private static final Logger logger = LoggerFactory.getLogger(CopyPropertiesAction.class); + private ProfileService profileService; + + public void setProfileService(ProfileService profileService) { + this.profileService = profileService; + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public int execute(Action action, Event event) { + boolean changed = false; + + for (Map.Entry<String, Object> entry : getEventPropsToCopy(action, event).entrySet()) { + // propType Check + PropertyType propertyType = profileService.getPropertyType(entry.getKey()); + String propertyName = "properties." + entry.getKey(); + if (propertyType != null && propertyType.isMultivalued()) { + changed = changed || PropertyHelper.setProperty(event.getProfile(), propertyName, entry.getValue(), "addValue"); + } else { + Object profileProperty = event.getProfile().getProperty(entry.getKey()); + if (profileProperty == null) { + if (entry.getValue() instanceof List) { + changed = changed || PropertyHelper.setProperty(event.getProfile(), propertyName, entry.getValue(), "addValues"); + } else { + changed = changed || PropertyHelper.setProperty(event.getProfile(), propertyName, entry.getValue(), "alwaysSet"); + } Review comment: This Should depends on the propType, in case the propType exist but is not multivalued you have an issue here: Input: - event input prop: toto = ["newValue"] - propType: singleValue - profile.properties.toto = null Output: -profile.properties.toto = ["newValue"] Should be: - FAIL: cannot copy a multiValue from event to a propType that is not multi valued ########## File path: itests/src/test/java/org/apache/unomi/itests/CopyPropertiesActionIT.java ########## @@ -0,0 +1,312 @@ +/* + * 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.unomi.itests; + +import org.apache.unomi.api.Event; +import org.apache.unomi.api.Metadata; +import org.apache.unomi.api.Profile; +import org.apache.unomi.api.PropertyType; +import org.apache.unomi.api.rules.Rule; +import org.apache.unomi.api.services.EventService; +import org.apache.unomi.api.services.ProfileService; +import org.apache.unomi.api.services.RulesService; +import org.apache.unomi.persistence.spi.CustomObjectMapper; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.ops4j.pax.exam.junit.PaxExam; +import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy; +import org.ops4j.pax.exam.spi.reactors.PerSuite; +import org.ops4j.pax.exam.util.Filter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.inject.Inject; +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Date; + +/** + * Created by amidani on 12/10/2017. + */ + +@RunWith(PaxExam.class) +@ExamReactorStrategy(PerSuite.class) +public class CopyPropertiesActionIT extends BaseIT { + private final static Logger LOGGER = LoggerFactory.getLogger(CopyPropertiesActionIT.class); + + private final static String PROFILE_TARGET_TEST_ID = "profile-target-event"; + private final static String PROFILE_TEST_ID = "profile-to-update-by-event"; + + @Inject + @Filter(timeout = 600000) + protected RulesService rulesService; + @Inject + @Filter(timeout = 600000) + protected ProfileService profileService; + @Inject + @Filter(timeout = 600000) + protected EventService eventService; + + @Before + public void setUp() throws IOException, InterruptedException { + Profile profile = new Profile(); + profile.setItemId(PROFILE_TEST_ID); + profile.setProperties(new HashMap<>()); + profile.setProperty("lastName", "Jose"); // property that have a propertyType registered in the system + profile.setProperty("prop4", "New property 4"); // property that do not have a propertyType registered in the system + profileService.save(profile); + LOGGER.info("Profile saved with ID [{}].", profile.getItemId()); + + Profile profileTarget = new Profile(); + profileTarget.setItemId(PROFILE_TARGET_TEST_ID); + profileService.save(profileTarget); + LOGGER.info("Profile saved with ID [{}].", profileTarget.getItemId()); + + refreshPersistence(); + } + + @Test + public void testCopyProperties_copyMultipleValueWithExistingPropertyType() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); + + Profile profile = profileService.load(PROFILE_TARGET_TEST_ID); + Assert.assertNull(profile.getProperty("firstName")); + + Event event = new Event("copyProperties", null, profile, null, null, profile, new Date()); + event.setPersistent(false); + + Map<String, Object> properties = new HashMap<>(); + properties.put("param1", Arrays.asList("value")); + properties.put("param2", Arrays.asList("valueA", "valueB")); + + event.setProperty("urlParameters", properties); + + Metadata metadata = new Metadata(); + metadata.setSystemTags(new HashSet<>(Arrays.asList("urlParameters"))); + metadata.setId("param1"); + metadata.setName("Url parameters"); + + PropertyType propertyType1 = new PropertyType(); + propertyType1.setItemId("param1"); + propertyType1.setMetadata(metadata); + propertyType1.setTarget("profiles"); + propertyType1.setValueTypeId("string"); + propertyType1.setMultivalued(true); + + profileService.setPropertyType(propertyType1); + + Metadata metadata2 = new Metadata(); + metadata2.setSystemTags(new HashSet<>(Arrays.asList("urlParameters"))); + metadata2.setId("param2"); + metadata2.setName("Url parameters"); + + PropertyType propertyType2 = new PropertyType(); + propertyType2.setItemId("param2"); + propertyType2.setMetadata(metadata2); + propertyType2.setTarget("profiles"); + propertyType2.setValueTypeId("string"); + propertyType2.setMultivalued(true); + + profileService.setPropertyType(propertyType2); + + int changes = eventService.send(event); + + LOGGER.info("Changes of the event : {}", changes); + + Assert.assertTrue(changes > 0); + } + + @Test + public void testCopyProperties_copyMultipleValueWithoutExistingPropertyType() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); + + Profile profile = profileService.load(PROFILE_TARGET_TEST_ID); + Assert.assertNull(profile.getProperty("firstName")); + + Event event = new Event("copyProperties", null, profile, null, null, profile, new Date()); + event.setPersistent(false); + + Map<String, Object> properties = new HashMap<>(); + properties.put("param1WithoutPropertyType", Arrays.asList("value")); + properties.put("param2WithoutPropertyType", Arrays.asList("valueA", "valueB")); + + event.setProperty("urlParameters", properties); + + int changes = eventService.send(event); + + LOGGER.info("Changes of the event : {}", changes); + + Assert.assertTrue(changes > 0); + } + + @Test + public void testCopyProperties_copySingleValueWithoutPropertyType() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); + + Profile profile = profileService.load(PROFILE_TARGET_TEST_ID); + Assert.assertNull(profile.getProperty("firstName")); + + Event event = new Event("copyProperties", null, profile, null, null, profile, new Date()); + event.setPersistent(false); + + Map<String, Object> properties = new HashMap<>(); + properties.put("param1SingleValue", "SingleValue"); + + event.setProperty("urlParameters", properties); + + int changes = eventService.send(event); + + LOGGER.info("Changes of the event : {}", changes); + + Assert.assertTrue(changes > 0); + } + + @Test + public void testCopyProperties_copySingleValueWithExistingPropertyType() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); + + Profile profile = profileService.load(PROFILE_TARGET_TEST_ID); + Assert.assertNull(profile.getProperty("firstName")); + + Event event = new Event("copyProperties", null, profile, null, null, profile, new Date()); + event.setPersistent(false); + + Map<String, Object> properties = new HashMap<>(); + properties.put("param1SingleWithPropertyType", "SingleValue"); + + event.setProperty("urlParameters", properties); + + Metadata metadata = new Metadata(); + metadata.setSystemTags(new HashSet<>(Arrays.asList("urlParameters"))); + metadata.setId("param1SingleWithPropertyType"); + metadata.setName("Url parameters"); + + PropertyType propertyType1 = new PropertyType(); + propertyType1.setItemId("param1SingleWithPropertyType"); + propertyType1.setMetadata(metadata); + propertyType1.setTarget("profiles"); + propertyType1.setValueTypeId("string"); + propertyType1.setMultivalued(false); + + profileService.setPropertyType(propertyType1); Review comment: exctract in a function ########## File path: plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/CopyPropertiesAction.java ########## @@ -0,0 +1,109 @@ +/* + * 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.unomi.plugins.baseplugin.actions; + +import org.apache.commons.beanutils.BeanUtilsBean; +import org.apache.commons.lang3.StringUtils; +import org.apache.unomi.api.Event; +import org.apache.unomi.api.PropertyType; +import org.apache.unomi.api.actions.Action; +import org.apache.unomi.api.actions.ActionExecutor; +import org.apache.unomi.api.services.EventService; +import org.apache.unomi.api.services.ProfileService; +import org.apache.unomi.persistence.spi.PropertyHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class CopyPropertiesAction implements ActionExecutor { + + private static final Logger logger = LoggerFactory.getLogger(CopyPropertiesAction.class); + private ProfileService profileService; + + public void setProfileService(ProfileService profileService) { + this.profileService = profileService; + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public int execute(Action action, Event event) { + boolean changed = false; + + for (Map.Entry<String, Object> entry : getEventPropsToCopy(action, event).entrySet()) { + // propType Check + PropertyType propertyType = profileService.getPropertyType(entry.getKey()); + String propertyName = "properties." + entry.getKey(); + if (propertyType != null && propertyType.isMultivalued()) { + changed = changed || PropertyHelper.setProperty(event.getProfile(), propertyName, entry.getValue(), "addValue"); Review comment: Doesnt seem's right, in case the event contains an array this will add the array as a value to the existing property. may should use "addValues" instead of "addValue" Input: - event input prop: toto = ["newValue"] - propType: multiple - profile.properties.toto = ["existingValue"] Output: - profile.properties.toto = ["existingValue", ["newValue"]] Should be: - profile.properties.toto = ["existingValue", "newValue"] ########## File path: plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/CopyPropertiesAction.java ########## @@ -0,0 +1,109 @@ +/* + * 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.unomi.plugins.baseplugin.actions; + +import org.apache.commons.beanutils.BeanUtilsBean; +import org.apache.commons.lang3.StringUtils; +import org.apache.unomi.api.Event; +import org.apache.unomi.api.PropertyType; +import org.apache.unomi.api.actions.Action; +import org.apache.unomi.api.actions.ActionExecutor; +import org.apache.unomi.api.services.EventService; +import org.apache.unomi.api.services.ProfileService; +import org.apache.unomi.persistence.spi.PropertyHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class CopyPropertiesAction implements ActionExecutor { + + private static final Logger logger = LoggerFactory.getLogger(CopyPropertiesAction.class); + private ProfileService profileService; + + public void setProfileService(ProfileService profileService) { + this.profileService = profileService; + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public int execute(Action action, Event event) { + boolean changed = false; + + for (Map.Entry<String, Object> entry : getEventPropsToCopy(action, event).entrySet()) { + // propType Check + PropertyType propertyType = profileService.getPropertyType(entry.getKey()); + String propertyName = "properties." + entry.getKey(); + if (propertyType != null && propertyType.isMultivalued()) { + changed = changed || PropertyHelper.setProperty(event.getProfile(), propertyName, entry.getValue(), "addValue"); + } else { + Object profileProperty = event.getProfile().getProperty(entry.getKey()); + if (profileProperty == null) { + if (entry.getValue() instanceof List) { + changed = changed || PropertyHelper.setProperty(event.getProfile(), propertyName, entry.getValue(), "addValues"); + } else { + changed = changed || PropertyHelper.setProperty(event.getProfile(), propertyName, entry.getValue(), "alwaysSet"); + } + } else if (profileProperty instanceof List) { + if (entry.getValue() instanceof List) { + changed = changed || PropertyHelper.setProperty(event.getProfile(), propertyName, entry.getValue(), "addValues"); + } else { + changed = changed || PropertyHelper.setProperty(event.getProfile(), propertyName, entry.getValue(), "addValue"); + } + } else { + if (entry.getValue() instanceof List) { + logger.warn("A single property named {} is already set on the profile.", entry.getKey()); + } else { + changed = changed || PropertyHelper.setProperty(event.getProfile(), propertyName, entry.getValue(), "alwaysSet"); + } + } + } + } + return changed ? EventService.PROFILE_UPDATED : EventService.NO_CHANGE; + } + + private Map<String, Object> getEventPropsToCopy(Action action, Event event) { + Map<String, Object> propsToCopy = new HashMap<String, Object>(); + + String rootProperty = (String) action.getParameterValues().get("rootProperty"); + boolean copyEventProps = false; + + if (StringUtils.isEmpty(rootProperty)) { + copyEventProps = true; + rootProperty = "target.properties"; + } + + // copy props from the event.properties + if (copyEventProps && event.getProperties() != null) { + propsToCopy.putAll(event.getProperties()); + } + + // copy props from the specified level (default is: target.properties) + try { + Object targetProperties = BeanUtilsBean.getInstance().getPropertyUtils().getProperty(event, rootProperty); + if (targetProperties instanceof Map) { + propsToCopy.putAll((Map) targetProperties); + } + } catch (Exception e) { + // Ignore Review comment: could be cool to log something like: "Unable to extract properties to be copied from the event to the profile using root property: {}" ########## File path: itests/src/test/java/org/apache/unomi/itests/CopyPropertiesActionIT.java ########## @@ -0,0 +1,312 @@ +/* + * 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.unomi.itests; + +import org.apache.unomi.api.Event; +import org.apache.unomi.api.Metadata; +import org.apache.unomi.api.Profile; +import org.apache.unomi.api.PropertyType; +import org.apache.unomi.api.rules.Rule; +import org.apache.unomi.api.services.EventService; +import org.apache.unomi.api.services.ProfileService; +import org.apache.unomi.api.services.RulesService; +import org.apache.unomi.persistence.spi.CustomObjectMapper; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.ops4j.pax.exam.junit.PaxExam; +import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy; +import org.ops4j.pax.exam.spi.reactors.PerSuite; +import org.ops4j.pax.exam.util.Filter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.inject.Inject; +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Date; + +/** + * Created by amidani on 12/10/2017. + */ + +@RunWith(PaxExam.class) +@ExamReactorStrategy(PerSuite.class) +public class CopyPropertiesActionIT extends BaseIT { + private final static Logger LOGGER = LoggerFactory.getLogger(CopyPropertiesActionIT.class); + + private final static String PROFILE_TARGET_TEST_ID = "profile-target-event"; + private final static String PROFILE_TEST_ID = "profile-to-update-by-event"; + + @Inject + @Filter(timeout = 600000) + protected RulesService rulesService; + @Inject + @Filter(timeout = 600000) + protected ProfileService profileService; + @Inject + @Filter(timeout = 600000) + protected EventService eventService; + + @Before + public void setUp() throws IOException, InterruptedException { + Profile profile = new Profile(); + profile.setItemId(PROFILE_TEST_ID); + profile.setProperties(new HashMap<>()); + profile.setProperty("lastName", "Jose"); // property that have a propertyType registered in the system + profile.setProperty("prop4", "New property 4"); // property that do not have a propertyType registered in the system + profileService.save(profile); + LOGGER.info("Profile saved with ID [{}].", profile.getItemId()); + + Profile profileTarget = new Profile(); + profileTarget.setItemId(PROFILE_TARGET_TEST_ID); + profileService.save(profileTarget); + LOGGER.info("Profile saved with ID [{}].", profileTarget.getItemId()); + + refreshPersistence(); + } + + @Test + public void testCopyProperties_copyMultipleValueWithExistingPropertyType() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); + + Profile profile = profileService.load(PROFILE_TARGET_TEST_ID); + Assert.assertNull(profile.getProperty("firstName")); + + Event event = new Event("copyProperties", null, profile, null, null, profile, new Date()); + event.setPersistent(false); + + Map<String, Object> properties = new HashMap<>(); + properties.put("param1", Arrays.asList("value")); + properties.put("param2", Arrays.asList("valueA", "valueB")); + + event.setProperty("urlParameters", properties); + + Metadata metadata = new Metadata(); + metadata.setSystemTags(new HashSet<>(Arrays.asList("urlParameters"))); + metadata.setId("param1"); + metadata.setName("Url parameters"); + + PropertyType propertyType1 = new PropertyType(); + propertyType1.setItemId("param1"); + propertyType1.setMetadata(metadata); + propertyType1.setTarget("profiles"); + propertyType1.setValueTypeId("string"); + propertyType1.setMultivalued(true); + + profileService.setPropertyType(propertyType1); + + Metadata metadata2 = new Metadata(); + metadata2.setSystemTags(new HashSet<>(Arrays.asList("urlParameters"))); + metadata2.setId("param2"); + metadata2.setName("Url parameters"); + + PropertyType propertyType2 = new PropertyType(); + propertyType2.setItemId("param2"); + propertyType2.setMetadata(metadata2); + propertyType2.setTarget("profiles"); + propertyType2.setValueTypeId("string"); + propertyType2.setMultivalued(true); + + profileService.setPropertyType(propertyType2); + + int changes = eventService.send(event); + + LOGGER.info("Changes of the event : {}", changes); + + Assert.assertTrue(changes > 0); + } + + @Test + public void testCopyProperties_copyMultipleValueWithoutExistingPropertyType() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); + + Profile profile = profileService.load(PROFILE_TARGET_TEST_ID); + Assert.assertNull(profile.getProperty("firstName")); + + Event event = new Event("copyProperties", null, profile, null, null, profile, new Date()); + event.setPersistent(false); + + Map<String, Object> properties = new HashMap<>(); + properties.put("param1WithoutPropertyType", Arrays.asList("value")); + properties.put("param2WithoutPropertyType", Arrays.asList("valueA", "valueB")); + + event.setProperty("urlParameters", properties); + + int changes = eventService.send(event); + + LOGGER.info("Changes of the event : {}", changes); + + Assert.assertTrue(changes > 0); + } + + @Test + public void testCopyProperties_copySingleValueWithoutPropertyType() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); + + Profile profile = profileService.load(PROFILE_TARGET_TEST_ID); + Assert.assertNull(profile.getProperty("firstName")); + + Event event = new Event("copyProperties", null, profile, null, null, profile, new Date()); + event.setPersistent(false); + + Map<String, Object> properties = new HashMap<>(); + properties.put("param1SingleValue", "SingleValue"); + + event.setProperty("urlParameters", properties); + + int changes = eventService.send(event); + + LOGGER.info("Changes of the event : {}", changes); + + Assert.assertTrue(changes > 0); + } + + @Test + public void testCopyProperties_copySingleValueWithExistingPropertyType() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); + + Profile profile = profileService.load(PROFILE_TARGET_TEST_ID); + Assert.assertNull(profile.getProperty("firstName")); + + Event event = new Event("copyProperties", null, profile, null, null, profile, new Date()); + event.setPersistent(false); + + Map<String, Object> properties = new HashMap<>(); + properties.put("param1SingleWithPropertyType", "SingleValue"); + + event.setProperty("urlParameters", properties); + + Metadata metadata = new Metadata(); + metadata.setSystemTags(new HashSet<>(Arrays.asList("urlParameters"))); + metadata.setId("param1SingleWithPropertyType"); + metadata.setName("Url parameters"); + + PropertyType propertyType1 = new PropertyType(); + propertyType1.setItemId("param1SingleWithPropertyType"); + propertyType1.setMetadata(metadata); + propertyType1.setTarget("profiles"); + propertyType1.setValueTypeId("string"); + propertyType1.setMultivalued(false); + + profileService.setPropertyType(propertyType1); + + int changes = eventService.send(event); + + LOGGER.info("Changes of the event : {}", changes); + + Assert.assertTrue(changes > 0); + } + + + @Test + public void testCopyProperties_copySingleValueWithExistingPropertyOnProfile() throws IOException, InterruptedException { + Rule rule = CustomObjectMapper.getObjectMapper() + .readValue(new File("data/tmp/testCopyProperties.json").toURI().toURL(), Rule.class); + rulesService.setRule(rule); + Thread.sleep(2000); + + Profile profile = profileService.load(PROFILE_TARGET_TEST_ID); + profile.setProperty("param1Existing", "existing"); + profile.setProperty("param2Existing", Arrays.asList("existingArray")); + Assert.assertNull(profile.getProperty("firstName")); + + Event event = new Event("copyProperties", null, profile, null, null, profile, new Date()); + event.setPersistent(false); + + Map<String, Object> properties = new HashMap<>(); + properties.put("param1Existing", "SingleValue"); + + event.setProperty("urlParameters", properties); + + int changes = eventService.send(event); + + LOGGER.info("Changes of the event : {}", changes); + + Assert.assertTrue(changes > 0); Review comment: Check the properties of the profiles are the expected ones. ########## File path: plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/CopyPropertiesAction.java ########## @@ -0,0 +1,109 @@ +/* + * 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.unomi.plugins.baseplugin.actions; + +import org.apache.commons.beanutils.BeanUtilsBean; +import org.apache.commons.lang3.StringUtils; +import org.apache.unomi.api.Event; +import org.apache.unomi.api.PropertyType; +import org.apache.unomi.api.actions.Action; +import org.apache.unomi.api.actions.ActionExecutor; +import org.apache.unomi.api.services.EventService; +import org.apache.unomi.api.services.ProfileService; +import org.apache.unomi.persistence.spi.PropertyHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class CopyPropertiesAction implements ActionExecutor { + + private static final Logger logger = LoggerFactory.getLogger(CopyPropertiesAction.class); + private ProfileService profileService; + + public void setProfileService(ProfileService profileService) { + this.profileService = profileService; + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public int execute(Action action, Event event) { + boolean changed = false; + + for (Map.Entry<String, Object> entry : getEventPropsToCopy(action, event).entrySet()) { + // propType Check + PropertyType propertyType = profileService.getPropertyType(entry.getKey()); + String propertyName = "properties." + entry.getKey(); + if (propertyType != null && propertyType.isMultivalued()) { + changed = changed || PropertyHelper.setProperty(event.getProfile(), propertyName, entry.getValue(), "addValue"); + } else { + Object profileProperty = event.getProfile().getProperty(entry.getKey()); + if (profileProperty == null) { + if (entry.getValue() instanceof List) { + changed = changed || PropertyHelper.setProperty(event.getProfile(), propertyName, entry.getValue(), "addValues"); + } else { + changed = changed || PropertyHelper.setProperty(event.getProfile(), propertyName, entry.getValue(), "alwaysSet"); + } + } else if (profileProperty instanceof List) { + if (entry.getValue() instanceof List) { + changed = changed || PropertyHelper.setProperty(event.getProfile(), propertyName, entry.getValue(), "addValues"); + } else { + changed = changed || PropertyHelper.setProperty(event.getProfile(), propertyName, entry.getValue(), "addValue"); + } + } else { + if (entry.getValue() instanceof List) { + logger.warn("A single property named {} is already set on the profile.", entry.getKey()); + } else { + changed = changed || PropertyHelper.setProperty(event.getProfile(), propertyName, entry.getValue(), "alwaysSet"); Review comment: We should consider the strategy from action config here. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: [email protected]
