From c1a55bf79b9c3148927f2cd10a0d06fd585febd5 Mon Sep 17 00:00:00 2001 From: Jj! Date: Thu, 23 May 2019 12:50:43 -0500 Subject: [PATCH] [SHIBUI-1253] use file writing service for metadata providers refactor tests --- .../CoreShibUiConfiguration.java | 2 +- .../MetadataProvidersScheduledTasks.java | 5 +- .../FileCheckingFileWritingService.java | 52 ++++++++++---- .../admin/ui/service/FileWritingService.java | 13 +++- ...FileCheckingFileWritingServiceTests.groovy | 71 +++++++++++++++---- 5 files changed, 112 insertions(+), 31 deletions(-) diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/CoreShibUiConfiguration.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/CoreShibUiConfiguration.java index a339e90ee..da33c53f8 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/CoreShibUiConfiguration.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/CoreShibUiConfiguration.java @@ -106,7 +106,7 @@ public EntityDescriptorFilesScheduledTasks entityDescriptorFilesScheduledTasks(E @Bean @ConditionalOnProperty(name = "shibui.metadataProviders.target") public MetadataProvidersScheduledTasks metadataProvidersScheduledTasks(@Value("${shibui.metadataProviders.target}") final Resource resource, final MetadataResolverService metadataResolverService) { - return new MetadataProvidersScheduledTasks(resource, metadataResolverService); + return new MetadataProvidersScheduledTasks(resource, metadataResolverService, fileWritingService()); } @Bean diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/scheduled/MetadataProvidersScheduledTasks.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/scheduled/MetadataProvidersScheduledTasks.java index 49048f39b..1f6ce7e69 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/scheduled/MetadataProvidersScheduledTasks.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/scheduled/MetadataProvidersScheduledTasks.java @@ -1,5 +1,6 @@ package edu.internet2.tier.shibboleth.admin.ui.scheduled; +import edu.internet2.tier.shibboleth.admin.ui.service.FileWritingService; import edu.internet2.tier.shibboleth.admin.ui.service.MetadataResolverService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -26,10 +27,12 @@ public class MetadataProvidersScheduledTasks { private final Resource target; private final MetadataResolverService metadataResolverService; + private final FileWritingService fileWritingService; - public MetadataProvidersScheduledTasks(Resource target, MetadataResolverService metadataResolverService) { + public MetadataProvidersScheduledTasks(Resource target, MetadataResolverService metadataResolverService, FileWritingService fileWritingService) { this.target = target; this.metadataResolverService = metadataResolverService; + this.fileWritingService = fileWritingService; } @Scheduled(fixedRateString = "${shibui.metadataProviders.taskRunRate:30000}") diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/FileCheckingFileWritingService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/FileCheckingFileWritingService.java index a520be60a..6c05fa987 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/FileCheckingFileWritingService.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/FileCheckingFileWritingService.java @@ -1,7 +1,10 @@ package edu.internet2.tier.shibboleth.admin.ui.service; +import org.springframework.core.io.WritableResource; + import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; import java.security.DigestInputStream; @@ -24,28 +27,49 @@ public FileCheckingFileWritingService(String algorithm) { @Override public void write(Path path, String content) throws IOException { if (Files.exists(path)) { - try { - MessageDigest md = MessageDigest.getInstance(this.algorithm); - try ( - InputStream is = Files.newInputStream(path); - DigestInputStream dis = new DigestInputStream(is, md) - ) { - byte[] buf = new byte[4096]; - while (dis.read(buf) > -1){} + try (InputStream is = Files.newInputStream(path)) { + if (checkContentMatches(is, content)) { + return; } - byte[] fileDigest = md.digest(); - byte[] contentDigest = md.digest(content.getBytes()); - if (Arrays.equals(fileDigest, contentDigest)) { + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + } + writeContent(path, content); + } + + @Override + public void write(WritableResource resource, String content) throws IOException { + if (resource.exists()) { + try (InputStream is = resource.getInputStream()) { + if (checkContentMatches(is, content)) { return; } } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } } - writeContent(path, content.getBytes()); + writeContent(resource, content); + } + + private boolean checkContentMatches(InputStream inputStream, String content) throws NoSuchAlgorithmException, IOException { + MessageDigest md = MessageDigest.getInstance(this.algorithm); + try (DigestInputStream dis = new DigestInputStream(inputStream, md)) { + byte[] buf = new byte[4096]; + while (dis.read(buf) > -1) {} + } + byte[] fileDigest = md.digest(); + byte[] contentDigest = md.digest(content.getBytes()); + return Arrays.equals(fileDigest, contentDigest); } - void writeContent(Path path, byte[] bytes) throws IOException { - Files.write(path, bytes); + void writeContent(Path path, String content) throws IOException { + Files.write(path, content.getBytes()); + } + + void writeContent(WritableResource resource, String content) throws IOException { + try (OutputStream os = resource.getOutputStream()) { + os.write(content.getBytes()); + } } } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/FileWritingService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/FileWritingService.java index 93de34da6..80493c4c0 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/FileWritingService.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/FileWritingService.java @@ -1,5 +1,7 @@ package edu.internet2.tier.shibboleth.admin.ui.service; +import org.springframework.core.io.WritableResource; + import java.io.IOException; import java.nio.file.Path; @@ -9,11 +11,20 @@ */ public interface FileWritingService { /** - * write the file + * Write content to a file * * @param path target file Path * @param content content to write * @throws IOException */ void write(Path path, String content) throws IOException; + + /** + * Write content to a writeable resource + * + * @param resource + * @param content + * @throws IOException + */ + void write(WritableResource resource, String content) throws IOException; } diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/FileCheckingFileWritingServiceTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/FileCheckingFileWritingServiceTests.groovy index 3d88836d7..45465475a 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/FileCheckingFileWritingServiceTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/FileCheckingFileWritingServiceTests.groovy @@ -1,17 +1,26 @@ package edu.internet2.tier.shibboleth.admin.ui.service +import org.springframework.core.io.PathResource +import org.springframework.core.io.WritableResource import spock.lang.Specification import java.nio.file.Files +import java.nio.file.Path import java.security.NoSuchAlgorithmException class FileCheckingFileWritingServiceTests extends Specification { def writer = Spy(FileCheckingFileWritingService) - def file1 = Files.createTempFile('test1', '.txt') - def file2 = Files.createTempFile('test2', '.txt') + Path file - def "test bad algorithm"() { + WritableResource resource + + def setup() { + file = Files.createTempFile('test1', '.txt') + resource = new PathResource(file) + } + + def 'test bad algorithm'() { setup: def badWriter = new FileCheckingFileWritingService('badAlGoreRhythm') @@ -23,31 +32,65 @@ class FileCheckingFileWritingServiceTests extends Specification { assert ex.cause instanceof NoSuchAlgorithmException } - def "test a single write"() { + def 'test a single write to a Path'() { + when: + writer.write(file, 'testme') + + then: + 1 * writer.writeContent(file, 'testme') + assert file.text == 'testme' + } + + def 'test writes with changed content to a Path'() { + when: + writer.write(file, 'testme') + writer.write(file, 'anothertest') + + then: + 1 * writer.writeContent(file, 'testme') + 1 * writer.writeContent(file, 'anothertest') + assert file.text == 'anothertest' + } + + def 'test writes with unchanged content, should only write once to a Path'() { + when: + (1..5).each { + writer.write(file, 'testme2') + } + + then: + 1 * writer.writeContent(file, 'testme2') + assert file.text == 'testme2' + } + + def 'test a single write to a WriteableResource'() { when: - writer.write(file1, 'testme') + writer.write(resource, 'testme') then: - 1 * writer.writeContent(file1, 'testme'.bytes) + 1 * writer.writeContent(resource, 'testme') + assert resource.getFile().text == 'testme' } - def "test writes with changed content"() { + def 'test write with changed content to a WritableResource'() { when: - writer.write(file2, 'testme') - writer.write(file2, 'anothertest') + writer.write(resource, 'testme') + writer.write(resource, 'anothertest') then: - 1 * writer.writeContent(file2, 'testme'.bytes) - 1 * writer.writeContent(file2, 'anothertest'.bytes) + 1 * writer.writeContent(resource, 'testme') + 1 * writer.writeContent(resource, 'anothertest') + assert resource.getFile().text == 'anothertest' } - def "test writes with unchanged content, should only write once"() { + def 'test writes with unchanged content, should only write once to a WriteableResource'() { when: (1..5).each { - writer.write(file1, 'testme') + writer.write(resource, 'testme2') } then: - 1 * writer.writeContent(file1, 'testme'.bytes) + 1 * writer.writeContent(resource, 'testme2') + assert resource.getFile().text == 'testme2' } }