From d670d3a8308db338100c2099c61373303005c6ce Mon Sep 17 00:00:00 2001 From: chasegawa Date: Tue, 8 Jun 2021 11:46:50 -0700 Subject: [PATCH] SHIBUI-1788 Adding testing to validate callback to the configuration is updated properly when the definitions are changed --- .../CustomPropertiesConfiguration.java | 61 +++++++----- ...stomEntityAttributesDefinitionService.java | 2 + ...EntityAttributesDefinitionServiceImpl.java | 27 +++++- ...tomEntityAttributesDefinitionListener.java | 5 + .../CustomPropertiesConfigurationTests.groovy | 93 +++++++++++++++++++ .../ui/configuration/TestConfiguration.groovy | 3 + 6 files changed, 163 insertions(+), 28 deletions(-) create mode 100644 backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ICustomEntityAttributesDefinitionListener.java create mode 100644 backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/configuration/CustomPropertiesConfigurationTests.groovy diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/CustomPropertiesConfiguration.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/CustomPropertiesConfiguration.java index b1bce979f..a1835932d 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/CustomPropertiesConfiguration.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/CustomPropertiesConfiguration.java @@ -3,10 +3,10 @@ import edu.internet2.tier.shibboleth.admin.ui.domain.IRelyingPartyOverrideProperty; import edu.internet2.tier.shibboleth.admin.ui.domain.RelyingPartyOverrideProperty; import edu.internet2.tier.shibboleth.admin.ui.service.CustomEntityAttributesDefinitionService; +import edu.internet2.tier.shibboleth.admin.ui.service.ICustomEntityAttributesDefinitionListener; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.ArrayList; @@ -18,7 +18,7 @@ @Configuration @ConfigurationProperties(prefix = "custom") -public class CustomPropertiesConfiguration { +public class CustomPropertiesConfiguration implements ICustomEntityAttributesDefinitionListener { private List> attributes = new ArrayList<>(); private CustomEntityAttributesDefinitionService ceadService; @@ -27,22 +27,53 @@ public class CustomPropertiesConfiguration { private List overridesFromConfigFile = new ArrayList<>(); - public List> getAttributes() { - return attributes; + private void buildRelyingPartyOverrides() { + // Start over with a clean map and get the CustomEntityAttributesDefinitions from the DB + overrides = new HashMap<>(); + ceadService.getAllDefinitions().forEach(def -> overrides.put(def.getName(), def)); + + // We only want to add to an override from the config file if the incoming override (by name) isn't already in + // the list of overrides (ie DB > file config) + for(RelyingPartyOverrideProperty rpop : this.overridesFromConfigFile) { + if (!this.overrides.containsKey(rpop.getName())) { + this.overrides.put(rpop.getName(), rpop); + } + } + } + + /** + * We don't know what change occurred, so the easiest thing to do is just rebuild our map of overrides. + * (especially since the small occurrence of this and number of items makes doing this ok perf-wise). + */ + @Override + public void customEntityAttributesDefinitionChangeOccurred() { + buildRelyingPartyOverrides(); } + public List> getAttributes() { + return attributes; + } + public List getOverrides() { return new ArrayList<>(overrides.values()); } + @PostConstruct + public void postConstruct() { + // Register with service to get the updates when changes are made to the DB definitions + ceadService.addCustomEntityAttributesDefinitionListener(this); + + // Make sure we have the right data + buildRelyingPartyOverrides(); + } + public void setAttributes(List> attributes) { this.attributes = attributes; - } - + } + @Autowired public void setCeadService(CustomEntityAttributesDefinitionService ceadService) { this.ceadService = ceadService; - } /** @@ -51,20 +82,4 @@ public void setCeadService(CustomEntityAttributesDefinitionService ceadService) public void setOverrides(List overridesFromConfigFile) { this.overridesFromConfigFile = overridesFromConfigFile; } - - @PostConstruct - public void postConstruct() { - // Register with service to get the updates when changes are made to the DB definitions - // ceadService.setCustomPropertiesConfiguration(this); - buildRelyingPartyOverrides(); - } - - private void buildRelyingPartyOverrides() { - // We only want to add to an override if the incoming override (by name) isn't already in the list of overrides - for(RelyingPartyOverrideProperty rpop : this.overridesFromConfigFile) { - if (!this.overrides.containsKey(rpop.getName())) { - this.overrides.put(rpop.getName(), rpop); - } - } - } } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/CustomEntityAttributesDefinitionService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/CustomEntityAttributesDefinitionService.java index 4087ad221..1ec6d772d 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/CustomEntityAttributesDefinitionService.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/CustomEntityAttributesDefinitionService.java @@ -6,6 +6,8 @@ public interface CustomEntityAttributesDefinitionService { + void addCustomEntityAttributesDefinitionListener(ICustomEntityAttributesDefinitionListener listener); + CustomEntityAttributeDefinition createOrUpdateDefinition(CustomEntityAttributeDefinition definition); void deleteDefinition(CustomEntityAttributeDefinition definition); diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/CustomEntityAttributesDefinitionServiceImpl.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/CustomEntityAttributesDefinitionServiceImpl.java index c164c7f01..dd1000736 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/CustomEntityAttributesDefinitionServiceImpl.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/CustomEntityAttributesDefinitionServiceImpl.java @@ -1,5 +1,6 @@ package edu.internet2.tier.shibboleth.admin.ui.service; +import java.util.ArrayList; import java.util.List; import javax.persistence.EntityManager; @@ -7,6 +8,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import edu.internet2.tier.shibboleth.admin.ui.domain.CustomEntityAttributeDefinition; import edu.internet2.tier.shibboleth.admin.ui.domain.filters.CustomEntityAttributeFilterValue; @@ -16,21 +18,32 @@ @Service @Primary public class CustomEntityAttributesDefinitionServiceImpl implements CustomEntityAttributesDefinitionService { - @Autowired - private CustomEntityAttributeDefinitionRepository repository; - @Autowired CustomEntityAttributeFilterValueRepository customEntityAttributeFilterValueRepository; @Autowired EntityManager entityManager; + + private List listeners = new ArrayList<>(); + @Autowired + private CustomEntityAttributeDefinitionRepository repository; + @Override - public CustomEntityAttributeDefinition createOrUpdateDefinition(CustomEntityAttributeDefinition definition) { - return repository.save(definition); + public void addCustomEntityAttributesDefinitionListener(ICustomEntityAttributesDefinitionListener listener) { + listeners.add(listener); } @Override + @Transactional + public CustomEntityAttributeDefinition createOrUpdateDefinition(CustomEntityAttributeDefinition definition) { + CustomEntityAttributeDefinition result = repository.save(definition); + notifyListeners(); + return result; + } + + @Override + @Transactional public void deleteDefinition(CustomEntityAttributeDefinition definition) { // must remove any CustomEntityAttributeFilterValues first to avoid integrity constraint issues List customEntityValues = customEntityAttributeFilterValueRepository.findAllByCustomEntityAttributeDefinition(definition); @@ -41,6 +54,7 @@ public void deleteDefinition(CustomEntityAttributeDefinition definition) { }); CustomEntityAttributeDefinition entityToRemove = repository.findByName(definition.getName()); repository.delete(entityToRemove); + notifyListeners(); } @Override @@ -53,4 +67,7 @@ public List getAllDefinitions() { return repository.findAll(); } + private void notifyListeners() { + listeners.forEach(l -> l.customEntityAttributesDefinitionChangeOccurred()); + } } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ICustomEntityAttributesDefinitionListener.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ICustomEntityAttributesDefinitionListener.java new file mode 100644 index 000000000..4ae2d2f27 --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ICustomEntityAttributesDefinitionListener.java @@ -0,0 +1,5 @@ +package edu.internet2.tier.shibboleth.admin.ui.service; + +public interface ICustomEntityAttributesDefinitionListener { + void customEntityAttributesDefinitionChangeOccurred(); +} diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/configuration/CustomPropertiesConfigurationTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/configuration/CustomPropertiesConfigurationTests.groovy new file mode 100644 index 000000000..e90e7974e --- /dev/null +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/configuration/CustomPropertiesConfigurationTests.groovy @@ -0,0 +1,93 @@ +package edu.internet2.tier.shibboleth.admin.ui.configuration + +import edu.internet2.tier.shibboleth.admin.ui.configuration.CoreShibUiConfiguration +import edu.internet2.tier.shibboleth.admin.ui.configuration.InternationalizationConfiguration +import edu.internet2.tier.shibboleth.admin.ui.configuration.SearchConfiguration +import edu.internet2.tier.shibboleth.admin.ui.domain.CustomEntityAttributeDefinition +import edu.internet2.tier.shibboleth.admin.ui.opensaml.OpenSamlObjects +import edu.internet2.tier.shibboleth.admin.ui.repository.CustomEntityAttributeDefinitionRepository +import edu.internet2.tier.shibboleth.admin.ui.repository.CustomEntityAttributeFilterValueRepository +import edu.internet2.tier.shibboleth.admin.ui.security.repository.RoleRepository +import edu.internet2.tier.shibboleth.admin.ui.security.repository.UserRepository +import edu.internet2.tier.shibboleth.admin.ui.service.CustomEntityAttributesDefinitionService +import edu.internet2.tier.shibboleth.admin.ui.service.CustomEntityAttributesDefinitionServiceImpl + +import javax.persistence.EntityManager + +import org.opensaml.saml.metadata.resolver.MetadataResolver +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Qualifier +import org.springframework.boot.autoconfigure.domain.EntityScan +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.boot.test.context.TestConfiguration +import org.springframework.context.annotation.Bean +import org.springframework.data.jpa.repository.config.EnableJpaRepositories +import org.springframework.security.core.userdetails.UsernameNotFoundException +import org.springframework.test.context.ActiveProfiles +import org.springframework.test.context.ContextConfiguration + +import spock.lang.Specification + +/** + * Tests for edu.internet2.tier.shibboleth.admin.ui.configuration.CustomPropertiesConfiguration + */ +@DataJpaTest +@ContextConfiguration(classes=[CoreShibUiConfiguration, InternationalizationConfiguration, SearchConfiguration, edu.internet2.tier.shibboleth.admin.ui.configuration.TestConfiguration]) +@EnableJpaRepositories(basePackages = ["edu.internet2.tier.shibboleth.admin.ui"]) +@EntityScan("edu.internet2.tier.shibboleth.admin.ui") +class CustomPropertiesConfigurationTests extends Specification { + + @Autowired + @Qualifier(value="customPropertiesConfiguration") + CustomPropertiesConfiguration configUnderTest + + @Autowired + CustomEntityAttributesDefinitionService ceadService + + @Autowired + CustomEntityAttributeDefinitionRepository repository; + + @Autowired + EntityManager entityManager + + def "Updating Custom Entity Attribute Definitions will update the CustomPropertiesConfiguration automatically"() { + given: 'Test defaults loaded (ie no CEADs in DB)' + + expect: + ceadService.getAllDefinitions().size() == 0 + configUnderTest.getOverrides().size() == 10 + + def ca = new CustomEntityAttributeDefinition().with { + it.name = "newDefName" + it.attributeType = "STRING" + it.defaultValue = "foobar" + it + } + + ceadService.createOrUpdateDefinition(ca) + entityManager.flush() + + ceadService.getAllDefinitions().size() == 1 + configUnderTest.getOverrides().size() == 11 + + def ca2 = new CustomEntityAttributeDefinition().with { + it.name = "newDefName2" + it.attributeType = "STRING" + it.defaultValue = "foobar2" + it + } + + ceadService.createOrUpdateDefinition(ca2) + entityManager.flush() + + ceadService.getAllDefinitions().size() == 2 + configUnderTest.getOverrides().size() == 12 + + ceadService.deleteDefinition(ca) + entityManager.flush() + + ceadService.getAllDefinitions().size() == 1 + configUnderTest.getOverrides().size() == 11 + } +} diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/configuration/TestConfiguration.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/configuration/TestConfiguration.groovy index 4a6e492de..4e6e78db8 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/configuration/TestConfiguration.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/configuration/TestConfiguration.groovy @@ -32,6 +32,9 @@ import org.springframework.data.domain.AuditorAware import org.springframework.mail.javamail.JavaMailSender import org.springframework.mail.javamail.JavaMailSenderImpl +/** + * NOT A TEST - this is configuration FOR tests + */ @Configuration class TestConfiguration { @Autowired