/******************************************************************************* * Copyright (c) 2014 IBM Corp. * * Licensed 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 com.ibm.ws.repository.test; import static com.ibm.ws.lars.testutils.BasicChecks.populateResource; import static com.ibm.ws.lars.testutils.BasicChecks.simpleUpload; import static com.ibm.ws.repository.common.enums.State.PUBLISHED; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.junit.Assume.assumeThat; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URISyntaxException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.logging.Level; import java.util.logging.Logger; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; import com.ibm.ws.lars.testutils.FatUtils; import com.ibm.ws.lars.testutils.fixtures.FileRepositoryFixture; import com.ibm.ws.lars.testutils.fixtures.RepositoryFixture; import com.ibm.ws.repository.common.enums.AttachmentLinkType; import com.ibm.ws.repository.common.enums.AttachmentType; import com.ibm.ws.repository.common.enums.DisplayPolicy; import com.ibm.ws.repository.common.enums.ResourceType; import com.ibm.ws.repository.common.enums.State; import com.ibm.ws.repository.common.enums.Visibility; import com.ibm.ws.repository.common.utils.internal.HashUtils; import com.ibm.ws.repository.connections.RepositoryConnection; import com.ibm.ws.repository.connections.RepositoryConnectionList; import com.ibm.ws.repository.exceptions.RepositoryBackendException; import com.ibm.ws.repository.exceptions.RepositoryBackendIOException; import com.ibm.ws.repository.exceptions.RepositoryBackendRequestFailureException; import com.ibm.ws.repository.exceptions.RepositoryException; import com.ibm.ws.repository.exceptions.RepositoryResourceCreationException; import com.ibm.ws.repository.exceptions.RepositoryResourceException; import com.ibm.ws.repository.resources.AttachmentResource; import com.ibm.ws.repository.resources.RepositoryResource; import com.ibm.ws.repository.resources.internal.EsaResourceImpl; import com.ibm.ws.repository.resources.internal.IfixResourceImpl; import com.ibm.ws.repository.resources.internal.ProductResourceImpl; import com.ibm.ws.repository.resources.internal.RepositoryResourceImpl; import com.ibm.ws.repository.resources.internal.RepositoryResourceImpl.AttachmentResourceImpl; import com.ibm.ws.repository.resources.internal.ResourceFactory; import com.ibm.ws.repository.resources.internal.SampleResourceImpl; import com.ibm.ws.repository.resources.internal.UpdateType; import com.ibm.ws.repository.resources.writeable.EsaResourceWritable; import com.ibm.ws.repository.resources.writeable.RepositoryResourceWritable; import com.ibm.ws.repository.strategies.writeable.AddThenDeleteStrategy; import com.ibm.ws.repository.strategies.writeable.AddThenHideOldStrategy; import com.ibm.ws.repository.strategies.writeable.UpdateInPlaceStrategy; import com.ibm.ws.repository.transport.model.Asset; import com.ibm.ws.repository.transport.model.WlpInformation; @RunWith(Parameterized.class) public class ResourceTest { private static final String PROVIDER_NAME = "Test Provider"; private static final Logger logger = Logger.getLogger(ResourceTest.class.getName()); private final static File resourceDir = new File("resources"); private TestResource _testRes; private final RepositoryConnection repoConnection; @Rule public final RepositoryFixture fixture; //Used for multi-repo tests @Rule public final FileRepositoryFixture fixture2 = FileRepositoryFixture.createFixture(new File("repo2")); @Parameters(name = "{0}") public static Object[][] getParameters() { return FatUtils.getRestFixtureParameters(); } public ResourceTest(RepositoryFixture fixture) { this.fixture = fixture; this.repoConnection = fixture.getAdminConnection(); } @Before public void beforeTest() throws IOException { _testRes = new TestResource(repoConnection); } private SampleResourceImpl createSampleResource() { SampleResourceImpl sampleRes = new SampleResourceImpl(repoConnection); sampleRes.setType(ResourceType.PRODUCTSAMPLE); populateResource(sampleRes); return sampleRes; } private void uploadResource(RepositoryResourceWritable res) throws RepositoryBackendException, RepositoryResourceException { res.uploadToMassive(new AddThenDeleteStrategy()); } /** * This test checks that a resource can be added to massive and that * the asset inside the resource is equivalent before and after the * upload (equivalent doesn't compare things like ID, uploadedOn etc). * It also makes sure that the number of resources in massive inceases * by one once we have done the add. */ @Test public void testCreateResource() throws SecurityException, NoSuchFieldException, RepositoryException, URISyntaxException { populateResource(_testRes); Asset beforeAss = _testRes.getAsset(); int numAssets = new RepositoryConnectionList(repoConnection).getAllResources().size(); _testRes.uploadToMassive(new UpdateInPlaceStrategy()); Asset afterAss = _testRes.getAsset(); assertTrue("The asset was changed after uploading before=<" + beforeAss + "> after=<" + afterAss + ">", beforeAss.equivalent(afterAss)); assertNull( "The original asset was updated with an ID when only the returned one should have an id ", beforeAss.get_id()); assertNotNull("An ID was not assigned to the asset after uploading ", afterAss.get_id()); int newNumAssets = new RepositoryConnectionList(repoConnection).getAllResources().size(); assertEquals("Unexpected number of assets found after adding an asset", numAssets + 1, newNumAssets); } /** * This test will check that the creation of resources from the * MassiveResource.Type enum creates a resource of the correct type * * @throws RepositoryBackendIOException */ @Test public void testCreateType() throws RepositoryBackendIOException { // Null would fail an instanceof check so this checks for null as well assertTrue(ResourceFactory.getInstance().createResource(ResourceType.ADDON, repoConnection, null) instanceof ProductResourceImpl); assertTrue(ResourceFactory.getInstance().createResource(ResourceType.FEATURE, repoConnection, null) instanceof EsaResourceImpl); assertTrue(ResourceFactory.getInstance().createResource(ResourceType.IFIX, repoConnection, null) instanceof IfixResourceImpl); assertTrue(ResourceFactory.getInstance().createResource(ResourceType.INSTALL, repoConnection, null) instanceof ProductResourceImpl); assertTrue(ResourceFactory.getInstance().createResource(ResourceType.OPENSOURCE, repoConnection, null) instanceof SampleResourceImpl); assertTrue(ResourceFactory.getInstance().createResource(ResourceType.PRODUCTSAMPLE, repoConnection, null) instanceof SampleResourceImpl); } /** * This method checks that we can upload then read back an asset from massive and * that the resource read from massive is equivalent to the one we uploaded */ @Test public void testGetAssetBackFromMassive() throws RepositoryException, SecurityException, IllegalArgumentException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, URISyntaxException { SampleResourceImpl sampleRes = createSampleResource(); uploadResource(sampleRes); RepositoryResourceImpl readBack = (RepositoryResourceImpl) repoConnection.getResource(sampleRes.getId()); assertTrue("Resource was different from the one uploaded", sampleRes.equivalent(readBack)); } /** * Checks that we equivalent method says that resources are equivalent that * have different fields that we are not interested in. This is achieved by creating * a resource (which has fields we care about in) then uploading the resource. * We then get the resource back from massive which will now contain fields * that we don't care about and should not effect the equivalent method. * * We then make an update to a field we do care about. We then ensure that this * resource is not equivalent to the one we read back from massive. We then * upload this resource and re-check this hasn't changed the fact that this resource * should not be equivalent to the one we read back from massive. * * We then read back the resource from massive again and at this point the two * resources should be equivalent again. */ @Test public void testResourceEquivalent() throws URISyntaxException, RepositoryException { SampleResourceImpl sampleRes = createSampleResource(); File attachment1 = new File(resourceDir, "TestAttachment.txt"); sampleRes.addContent(attachment1); File attachment2 = new File(resourceDir, "license_enus.txt"); sampleRes.addLicense(attachment2, Locale.US); uploadResource(sampleRes); RepositoryResourceImpl readBack = (RepositoryResourceImpl) repoConnection.getResource(sampleRes.getId()); assertTrue("The resource uploaded is not equivalent to the one extracted from massive", sampleRes.equivalent(readBack)); sampleRes.moveToState(PUBLISHED); assertTrue("The resource is not equivalent after being published", sampleRes.equivalent(readBack)); sampleRes.setDescription("new description"); assertFalse("The resource has been updated and shouldn't be equivalent to the one obtained from massive", sampleRes.equivalent(readBack)); uploadResource(sampleRes); assertFalse("The resource has been updated and shouldn't be equivalent to the one obtained from massive", sampleRes.equivalent(readBack)); readBack = (RepositoryResourceImpl) repoConnection.getResource(sampleRes.getId()); assertTrue("The resource uploaded is not equivalent to the one extracted from massive", sampleRes.equivalent(readBack)); } /** * Tests that we can upload a resource into massive and that the find matching resource returns a * matching one when it should * * @throws IOException * @throws URISyntaxException */ @Test public void testFindMatchingResource() throws SecurityException, IllegalArgumentException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, RepositoryException, IOException, URISyntaxException { // Add a resource SampleResourceImpl sampleRes = createSampleResource(); List<RepositoryResourceImpl> resFromMassive = sampleRes.findMatchingResource(); assertTrue("A matching resource was found when there should not have been one", resFromMassive.isEmpty()); uploadResource(sampleRes); resFromMassive = sampleRes.findMatchingResource(); assertEquals("No matching resource was found when we expected to find one", 1, resFromMassive.size()); assertTrue("The matching resource was not as expected", sampleRes.equivalent(resFromMassive.get(0))); } /** * Tests that we can upload a resource, then using the same resource object * we can update the fields in the resource and update it in massive. * Check that the resource we get back is equivalent to the updated resource we * uploaded. */ @Test public void testUpdateResource() throws IOException, RepositoryException, SecurityException, IllegalArgumentException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, URISyntaxException { assumeThat(fixture.isUpdateSupported(), is(true)); SampleResourceImpl sampleRes = createSampleResource(); uploadResource(sampleRes); sampleRes.setDescription("Updated description"); sampleRes.uploadToMassive(new UpdateInPlaceStrategy()); // Read the resource back from massive String id = sampleRes.getId(); RepositoryResourceImpl readBack = (RepositoryResourceImpl) repoConnection.getResource(id); assertTrue("The updated resource was not the same as the one found in massive", sampleRes.equivalent(readBack)); } /** * This tests is similiar to testUpdateResource but this time we update fields * inside the wlpinfo inner fields. */ @Test public void testUpdateWlpInfoInResource() throws IOException, RepositoryException, SecurityException, IllegalArgumentException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, URISyntaxException { assumeThat(fixture.isUpdateSupported(), is(true)); SampleResourceImpl sampleRes = createSampleResource(); sampleRes.setAppliesTo("old applies to"); uploadResource(sampleRes); sampleRes.setAppliesTo("new applies to"); sampleRes.uploadToMassive(new UpdateInPlaceStrategy()); // Read the resource back from massive String id = sampleRes.getId(); RepositoryResourceImpl readBack = (RepositoryResourceImpl) repoConnection.getResource(id); assertTrue("The updated resource was not the same as the one found in massive", sampleRes.equivalent(readBack)); } /** * This test is like testUpdateWlpInfoInResource except that we create a brand new * resource object to update with instead of re-using the resource object we used for * doing the initial add. This checks that we don't hit any partial-update problems */ @Test public void testUpdateWlpInfo() throws IOException, RepositoryException, SecurityException, IllegalArgumentException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, URISyntaxException { assumeThat(fixture.isUpdateSupported(), is(true)); SampleResourceImpl res1 = new SampleResourceImpl(repoConnection); res1.setType(ResourceType.OPENSOURCE); res1.setAppliesTo("testAppliesTo1"); populateResource(res1); uploadResource(res1); String id1 = res1.getId(); SampleResourceImpl res2 = new SampleResourceImpl(repoConnection); populateResource(res2); res2.setType(ResourceType.OPENSOURCE); res2.setDescription("desc changed"); res2.setAppliesTo("testAppliesTo1"); res2.uploadToMassive(new UpdateInPlaceStrategy()); // Read the resource back from massive String id2 = res2.getId(); assertEquals("This was an update, the ids should be the same", id1, id2); RepositoryResourceImpl readBack = (RepositoryResourceImpl) repoConnection.getResource(id1); assertFalse("The updated resource was the same as the one found in massive", res1.equivalent(readBack)); assertTrue("The updated resource was not the same as the one found in massive", res2.equivalent(readBack)); } /** * This test tests the refreshFromMassive call. A resource is uploaded and read back. * The resource is then updated, we check that the updated resource is not equivalent to * the updated resource. We then refresh the resource we read back - this should make * the resource equivalent to the updated one. */ @Test public void testRefreshData() throws IOException, RepositoryException, SecurityException, IllegalArgumentException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, URISyntaxException { assumeThat(fixture.isUpdateSupported(), is(true)); // Add a resource SampleResourceImpl sampleRes = createSampleResource(); uploadResource(sampleRes); // Read the resource back from massive String id = sampleRes.getId(); RepositoryResourceImpl readBack = (RepositoryResourceImpl) repoConnection.getResource(id); // Update resource sampleRes.setDescription("Updated description"); sampleRes.uploadToMassive(new UpdateInPlaceStrategy()); // Check that the original resource has not been updated assertFalse("The resource found in massive was equal to the pre-updated resource " + " when it should have been updated", sampleRes.equivalent(readBack)); // refresh to get latest data readBack.refreshFromMassive(); // Now confirm the 2 resources match assertTrue("The resource found in massive was not the same as the updated resource " + " when it should have been updated", sampleRes.equivalent(readBack)); } /** * Tests * - What happens when we delete something that doesn't exist * - Add resource * - delete resource * - ensure the resource is no longer in massive * * @throws URISyntaxException */ @Test public void testDelete() throws IOException, RepositoryException, URISyntaxException { populateResource(_testRes); uploadResource(_testRes); String id = _testRes.getId(); _testRes.delete(); try { repoConnection.getResource(id); fail("Should not of been able to get an asset that did not exist"); } catch (RepositoryException e) { // pass } } /** * Add an attachment and ensure we can get an input stream to it. The attachment * is added to the resource before the resource is uploaded * * @throws URISyntaxException */ @Test public void testAddAttachmentBeforeUploading() throws IOException, RepositoryException, URISyntaxException { SampleResourceImpl sampleRes = createSampleResource(); File attachment = new File(resourceDir, "TestAttachment.txt"); sampleRes.addContent(attachment); uploadResource(sampleRes); String id = sampleRes.getId(); RepositoryResourceImpl readBack = (RepositoryResourceImpl) repoConnection.getResource(id); assertEquals("We only expected 1 attachment", 1, readBack.getAttachmentCount()); assertNotNull("No attachment was found", readBack.getAttachment(attachment.getName())); } /** * Add an attachment and ensure we can get an input stream to it. The resource is created * is created then the attachment is added to the resource and re-uploaded to massive, this * should update the asset in massive to include the attachment. We make sure we can get * an input stream to the attachment and that there is exactly one attachment associated * with the resource. * * @throws URISyntaxException */ @Test public void testAddAttachmentAfterUploading() throws IOException, RepositoryException, URISyntaxException { SampleResourceImpl sampleRes = createSampleResource(); uploadResource(sampleRes); File attachment = new File(resourceDir, "TestAttachment.txt"); sampleRes.addContent(attachment); sampleRes.uploadToMassive(new AddThenDeleteStrategy()); String id = sampleRes.getId(); RepositoryResourceImpl readBack = (RepositoryResourceImpl) repoConnection.getResource(id); assertEquals("We only expected 1 attachment", 1, readBack.getAttachmentCount()); assertNotNull("No input stream to the attachment was found", readBack.getAttachment(attachment.getName())); } @Test public void testWeCanHostAttachmentsOutsideMassive() throws Exception { SampleResourceImpl sampleRes = createSampleResource(); String testFile = "testfile.txt"; String sampleUrl = fixture.getHostedFileRoot() + "/testfile.txt"; sampleRes.addAttachment(new File(resourceDir, testFile), AttachmentType.CONTENT, testFile, sampleUrl, null); uploadResource(sampleRes); String id = sampleRes.getId(); RepositoryResourceImpl readBack = (RepositoryResourceImpl) repoConnection.getResource(id); assertEquals("We expected 1 attachment", 1, readBack.getAttachmentCount()); assertNotNull("No input stream to the attachment was found", readBack.getAttachment(testFile)); AttachmentResource att = readBack.getAttachment(testFile); InputStream is = att.getInputStream(); InputStreamReader isr = new InputStreamReader(is, "UTF-8"); char[] buffer = new char[1024]; StringBuilder sb = new StringBuilder(); while ((isr.read(buffer)) != -1) { sb.append(buffer); } assertTrue(sb.toString().contains("This is a test file")); assertEquals("The link type should default to direct", AttachmentLinkType.DIRECT, ((AttachmentResourceImpl) att).getLinkType()); } /** * This test checks that we the updateRequired methods return the correct values. * A resource is created, we confirm that updateRequired returns ADD at this point. * We then upload the resource into massive and add an attachment. At this point * the asset itself should not need updating (returns NOTHING), but the attachment * itself should return ADD when asked if an update is required. * Next we modify the resource to use a different attachment (using the same attachment * name as the original name). This should cause the asset to say that NOTHING needs updating * but the attachment should say that an UPDATE is required. * Lastly we upload the resource and ensure that, with no further changes to the resource, * that both the asset and the attachment say that nothing needs updating */ @Test public void testUpdateAttachmentRequired() throws RepositoryException, IOException, URISyntaxException { SampleResourceImpl sampleRes = createSampleResource(); List<RepositoryResourceImpl> matching = sampleRes.findMatchingResource(); assertEquals("Attachment had been uploaded, isUpdateRequired should have returned ADD", UpdateType.ADD, sampleRes.updateRequired(getFirst(matching))); uploadResource(sampleRes); File attachment = new File(resourceDir, "TestAttachment.txt"); matching = sampleRes.findMatchingResource(); assertEquals("Nothing has changed on the resource so isUpdateRequired should have returned type NOTHING", UpdateType.NOTHING, sampleRes.updateRequired(getFirst(matching))); sampleRes.addAttachment(attachment, AttachmentType.DOCUMENTATION, "documentationAttachment"); matching = sampleRes.findMatchingResource(); AttachmentResourceImpl sampleAtt; // The resource should not need updating after an attachment is added assertEquals("Attachment was added, isUpdateRequired should have returned type NOTHING", UpdateType.NOTHING, sampleRes.updateRequired(getFirst(matching))); // ... but the attachment does need adding sampleAtt = (AttachmentResourceImpl) sampleRes.getAttachment("documentationAttachment"); assertEquals("Attachment was added, isUpdateRequired should have returned type ADD", UpdateType.ADD, sampleAtt.updateRequired(getFirst(matching))); sampleRes.uploadToMassive(new AddThenDeleteStrategy()); sampleRes.addContent(attachment); matching = sampleRes.findMatchingResource(); // The resource will need updating when content is added assertEquals("Content was added so the file size should have changed and isUpdateRequired should have returned type UPDATE", UpdateType.UPDATE, sampleRes.updateRequired(getFirst(matching))); // ... and the attachment does need adding sampleAtt = (AttachmentResourceImpl) sampleRes.getAttachment("TestAttachment.txt"); assertEquals("Attachment was added, isUpdateRequired should have returned type ADD", UpdateType.ADD, sampleAtt.updateRequired(getFirst(matching))); sampleRes.uploadToMassive(new AddThenDeleteStrategy()); attachment = new File(resourceDir, "TestAttachment2.txt"); sampleRes.addAttachment(attachment, AttachmentType.CONTENT, "TestAttachment.txt"); matching = sampleRes.findMatchingResource(); // The resource should not need updating assertEquals("Attachment was changed, isUpdateRequired should have returned type NOTHING", UpdateType.NOTHING, sampleRes.updateRequired(getFirst(matching))); // ... but the attachment does need updating sampleAtt = (AttachmentResourceImpl) sampleRes.getAttachment("TestAttachment.txt"); assertEquals("Attachment was added, isUpdateRequired should have returned type UPDATE", UpdateType.UPDATE, sampleAtt.updateRequired(getFirst(matching))); sampleRes.uploadToMassive(new AddThenDeleteStrategy()); matching = sampleRes.findMatchingResource(); assertEquals("nothing has changed, isUpdateRequired should have returned type NOTHING", UpdateType.NOTHING, sampleRes.updateRequired(getFirst(matching))); sampleAtt = (AttachmentResourceImpl) sampleRes.getAttachment("TestAttachment.txt"); assertEquals("nothing has changed, isUpdateRequired should have returned type NOTHING", UpdateType.NOTHING, sampleAtt.updateRequired(getFirst(matching))); } private RepositoryResourceImpl getFirst(List<RepositoryResourceImpl> list) { return (list == null || list.isEmpty()) ? null : list.get(0); } @Test public void testUpdateURLInAttachment() throws RepositoryException, IOException, URISyntaxException { SampleResourceImpl sampleRes = createSampleResource(); File attachment = new File(resourceDir, "TestAttachment.txt"); AttachmentResourceImpl sampleAtt; // No url specified yet sampleRes.addAttachment(attachment, AttachmentType.DOCUMENTATION, "useDefaultURL"); List<RepositoryResourceImpl> matching = sampleRes.findMatchingResource(); assertEquals("Asset has not been uploaded, isUpdateRequired should have returned ADD", UpdateType.ADD, sampleRes.updateRequired(getFirst(matching))); sampleAtt = (AttachmentResourceImpl) sampleRes.getAttachment("useDefaultURL"); assertEquals("Attachment was added, isUpdateRequired should have returned type ADD", UpdateType.ADD, sampleAtt.updateRequired(getFirst(matching))); uploadResource(sampleRes); // Still no url specified yet - so this should match - we aren't changing the attachment at all sampleRes.addAttachment(attachment, AttachmentType.DOCUMENTATION, "useDefaultURL"); matching = sampleRes.findMatchingResource(); assertEquals("Asset has not changed, isUpdateRequired should have returned NOTHING", UpdateType.NOTHING, sampleRes.updateRequired(getFirst(matching))); sampleAtt = (AttachmentResourceImpl) sampleRes.getAttachment("useDefaultURL"); assertEquals("Attachment has not changed, isUpdateRequired should have returned type NOTHING", UpdateType.NOTHING, sampleAtt.updateRequired(getFirst(matching))); uploadResource(sampleRes); // Now create a new attachment and use the internal URL, should add a new attachment sampleRes.addAttachment(attachment, AttachmentType.DOCUMENTATION, "specifyURL"); matching = sampleRes.findMatchingResource(); assertEquals("Asset not changed, isUpdateRequired should have returned NOTHING", UpdateType.NOTHING, sampleRes.updateRequired(getFirst(matching))); sampleAtt = (AttachmentResourceImpl) sampleRes.getAttachment("specifyURL"); assertEquals("Attachment was added, isUpdateRequired should have returned type ADD", UpdateType.ADD, sampleAtt.updateRequired(getFirst(matching))); uploadResource(sampleRes); // Now use an internal URL, should add a new attachment sampleRes.addAttachment(attachment, AttachmentType.DOCUMENTATION, "specifyURL", "http://blah", AttachmentLinkType.DIRECT); matching = sampleRes.findMatchingResource(); assertEquals("Asset not changed, isUpdateRequired should have returned NOTHING", UpdateType.NOTHING, sampleRes.updateRequired(getFirst(matching))); sampleAtt = (AttachmentResourceImpl) sampleRes.getAttachment("specifyURL"); assertEquals("Attachment URL was set to external, isUpdateRequired should have returned type UPDATE", UpdateType.UPDATE, sampleAtt.updateRequired(getFirst(matching))); uploadResource(sampleRes); // Now change the URL, this should cause an update on attachment sampleRes.addAttachment(attachment, AttachmentType.DOCUMENTATION, "specifyURL", "http://differentblah", AttachmentLinkType.DIRECT); matching = sampleRes.findMatchingResource(); assertEquals("Asset not changed, isUpdateRequired should have returned NOTHING", UpdateType.NOTHING, sampleRes.updateRequired(getFirst(matching))); sampleAtt = (AttachmentResourceImpl) sampleRes.getAttachment("specifyURL"); assertEquals("Attachment URL was changed, isUpdateRequired should have returned type UPDATE", UpdateType.UPDATE, sampleAtt.updateRequired(getFirst(matching))); uploadResource(sampleRes); } /** * Check CRC of attachment, upload it then verify CRC matches the input stream * from massive for the asset */ @Test public void testCRC() throws Exception { File attachment = new File(resourceDir, "TestAttachment.txt"); Method getCRCMethod = RepositoryResourceImpl.class.getDeclaredMethod("getCRC", InputStream.class); getCRCMethod.setAccessible(true); long localFileCRC = (Long) getCRCMethod.invoke(null, new FileInputStream(attachment)); SampleResourceImpl sampleRes = createSampleResource(); sampleRes.addContent(attachment); uploadResource(sampleRes); long massiveFileCRC = sampleRes.getAttachment(attachment.getName()).getCRC(); assertEquals("CRC of file before adding to massive is different from the one in massive", localFileCRC, massiveFileCRC); } @Test public void testFeaturedWeight() throws URISyntaxException, RepositoryBackendException, RepositoryResourceException { SampleResourceImpl sampleRes = createSampleResource(); uploadResource(sampleRes); RepositoryResourceImpl readBack = (RepositoryResourceImpl) repoConnection.getResource(sampleRes.getId()); assertNull("The resource should not have a featuredWeight", readBack.getFeaturedWeight()); sampleRes.setFeaturedWeight("5"); uploadResource(sampleRes); readBack = (RepositoryResourceImpl) repoConnection.getResource(sampleRes.getId()); assertEquals("The resource should not have a featuredWeight", "5", readBack.getFeaturedWeight()); sampleRes.setFeaturedWeight("4"); uploadResource(sampleRes); readBack = (RepositoryResourceImpl) repoConnection.getResource(sampleRes.getId()); assertEquals("The resource should not have a featuredWeight", "4", readBack.getFeaturedWeight()); sampleRes.setFeaturedWeight(null); uploadResource(sampleRes); readBack = (RepositoryResourceImpl) repoConnection.getResource(sampleRes.getId()); assertNull("The resource should not have a featuredWeight", readBack.getFeaturedWeight()); } /** * Checks that the resource should get updated if the CRC changes * * @throws URISyntaxException * @throws RepositoryException */ @Test public void testCRCChangeCausesUpdate() throws URISyntaxException, RepositoryException { SampleResourceImpl sampleRes = createSampleResource(); List<RepositoryResourceImpl> matching = sampleRes.findMatchingResource(); assertEquals("Attachment had been uploaded, isUpdateRequired should have returned ADD", UpdateType.ADD, sampleRes.updateRequired(getFirst(matching))); uploadResource(sampleRes); AttachmentResourceImpl sampleAtt; File attachment1 = new File(resourceDir, "crc1.txt"); sampleRes.addAttachment(attachment1, AttachmentType.DOCUMENTATION, "documentationAttachment"); matching = sampleRes.findMatchingResource(); // The resource should not need updating after an attachment is added assertEquals("Attachment was added, isUpdateRequired should have returned type NOTHING", UpdateType.NOTHING, sampleRes.updateRequired(getFirst(matching))); // ... but the attachment does need adding sampleAtt = (AttachmentResourceImpl) sampleRes.getAttachment("documentationAttachment"); assertEquals("Attachment was added, isUpdateRequired should have returned type ADD", UpdateType.ADD, sampleAtt.updateRequired(getFirst(matching))); sampleRes.uploadToMassive(new UpdateInPlaceStrategy()); File attachment2 = new File(resourceDir, "crc2.txt"); sampleRes.addAttachment(attachment2, AttachmentType.DOCUMENTATION, "documentationAttachment"); matching = sampleRes.findMatchingResource(); // The resource should not need updating assertEquals("Attachment was changed, isUpdateRequired should have returned type NOTHING", UpdateType.NOTHING, sampleRes.updateRequired(getFirst(matching))); // ... but the attachment does need updating sampleAtt = (AttachmentResourceImpl) sampleRes.getAttachment("documentationAttachment"); assertEquals("Attachment was added, isUpdateRequired should have returned type UPDATE", UpdateType.UPDATE, sampleAtt.updateRequired(getFirst(matching))); sampleRes.uploadToMassive(new UpdateInPlaceStrategy()); } /** * This test uploads an attachment, then re-uploads a different attachment under the same * name (causing an update). This test ensures that the information in AttachmentInfo (in this * case we use CRC) is updated correctly when the attachment is updated. * * @throws Exception */ @Test public void testUpdateAttachmentInfo() throws Exception { Method getCRCMethod = RepositoryResourceImpl.class.getDeclaredMethod("getCRC", InputStream.class); getCRCMethod.setAccessible(true); File attachment1 = new File(resourceDir, "TestAttachment.txt"); File attachment2 = new File(resourceDir, "TestAttachment2.txt"); long localFileCRC1 = (Long) getCRCMethod.invoke(null, new FileInputStream(attachment1)); long localFileCRC2 = (Long) getCRCMethod.invoke(null, new FileInputStream(attachment2)); logger.log(Level.INFO, "local1 = " + localFileCRC1); logger.log(Level.INFO, "local2 = " + localFileCRC2); SampleResourceImpl sampleRes = createSampleResource(); sampleRes.addContent(attachment1); uploadResource(sampleRes); long massiveFileCRC = sampleRes.getAttachment(attachment1.getName()).getCRC(); assertEquals("CRC of file before adding to massive is different from the one in massive", localFileCRC1, massiveFileCRC); // Specify that the "TestAttachment2.txt" should be stored under the name "TestAttachment.txt". This // will mean the attachment gets updated, rather than a new attachment added sampleRes.addAttachment(attachment2, AttachmentType.CONTENT, "TestAttachment.txt"); sampleRes.uploadToMassive(new UpdateInPlaceStrategy()); massiveFileCRC = sampleRes.getAttachment(attachment1.getName()).getCRC(); assertEquals("CRC of file before adding to massive is different from the one in massive", localFileCRC2, massiveFileCRC); } /** * This method checks that the provider name is set correctly, and doesn't use a default */ @Test public void testDifferentProvider() throws RepositoryException, URISyntaxException { SampleResourceImpl sampleRes = createSampleResource(); sampleRes.setProviderName(PROVIDER_NAME); uploadResource(sampleRes); RepositoryResourceImpl readBack = (RepositoryResourceImpl) repoConnection.getResource(sampleRes.getId()); logger.log(Level.INFO, "Readback " + readBack); assertTrue("The asset read back from Massive didn't have the expected provider", readBack.toString().contains(PROVIDER_NAME)); assertEquals("The asset read back from Massive didn't have the expected provider", sampleRes.getProviderName(), readBack.getProviderName()); } /** * This tests that we can't refreshFromMassive after a resource has been deleted */ @Test public void testRefreshAfterDelete() throws URISyntaxException, RepositoryException { populateResource(_testRes); uploadResource(_testRes); _testRes.delete(); try { _testRes.refreshFromMassive(); fail("We should not be able to refresh an asset from massive after it has been deleted"); } catch (RepositoryBackendRequestFailureException e) { // expected assertTrue("Unexpected exception caught " + e, e.getMessage().contains(_testRes.getId())); } } /** * This method checks that the size value on an attachment is equal to the * size of the attachment payload */ @Test public void testGetSize() throws URISyntaxException, RepositoryException { SampleResourceImpl sampleRes = createSampleResource(); File attachment = new File(resourceDir, "TestAttachment.txt"); sampleRes.addContent(attachment); uploadResource(sampleRes); long size = sampleRes.getAttachment("TestAttachment.txt").getSize(); assertEquals(size, attachment.length()); } /** * This test checks we can upload 2 attachments in one asset. We check that the attachment * count is 2 and that we can get an InputStream to both attachments * */ @Test public void testAddMultipleAttachments() throws URISyntaxException, RepositoryException { SampleResourceImpl sampleRes = createSampleResource(); File attachment1 = new File(resourceDir, "TestAttachment.txt"); sampleRes.addContent(attachment1); File attachment2 = new File(resourceDir, "license_enus.txt"); sampleRes.addLicense(attachment2, Locale.ENGLISH); uploadResource(sampleRes); String id = sampleRes.getId(); RepositoryResourceImpl readBack = (RepositoryResourceImpl) repoConnection.getResource(id); assertEquals("We expected 2 attachment", 2, readBack.getAttachmentCount()); assertNotNull("No input stream to the attachment1 was found", readBack.getAttachment(attachment1.getName()).getInputStream()); assertNotNull("No input stream to the attachment2 was found", readBack.getLicense(Locale.ENGLISH)); } /** * Tests that we can upload 2 attachments then get a snapshot of the resource from massive. * We then make sure that snapshot is equivalent to the resource we uploaded. We then update * one of the attachments then upload the resource again. We get a 2nd snapshot of the resource * from massive. We ensure that the two snapshots are not equivalent, that the one we uploaded * is equivalent to the 2nd snapshot but not equivalent to the first snapshot. */ @Test public void testAddThenUpdateAttachment() throws URISyntaxException, RepositoryException, SecurityException, NoSuchMethodException, IllegalArgumentException, FileNotFoundException, IllegalAccessException, InvocationTargetException { SampleResourceImpl sampleRes = createSampleResource(); File attachment1 = new File(resourceDir, "TestAttachment.txt"); sampleRes.addContent(attachment1); File attachment2 = new File(resourceDir, "license_enus.txt"); sampleRes.addLicense(attachment2, Locale.US); uploadResource(sampleRes); String id = sampleRes.getId(); RepositoryResourceImpl readBack1 = (RepositoryResourceImpl) repoConnection.getResource(id); assertTrue("Resource should be equivalent", sampleRes.equivalent(readBack1)); attachment1 = new File(resourceDir, "TestAttachment2.txt"); sampleRes.addAttachment(attachment1, AttachmentType.CONTENT, "TestAttachment.txt"); uploadResource(sampleRes); RepositoryResourceImpl readBack2 = (RepositoryResourceImpl) repoConnection.getResource(sampleRes.getId()); assertFalse("Resource should not be equivalent", readBack1.equivalent(readBack2)); assertFalse("Resource should not be equivalent", sampleRes.equivalent(readBack1)); assertTrue("Resource should be equivalent", sampleRes.equivalent(readBack2)); } /** * Tests that an attachment can be added to massive, and that we can then delete * the attachment. We then confirm that we resource has the correct number of * attachments and ensure that we can still get an input stream to the remaining * attachment, and that we can't get an input stream to the deleted attachment. * We then re-add the attachment to ensure there are no problems with adding * an attachment back after deleting it. */ @Test public void testAddThenDeleteThenReadAttachment() throws URISyntaxException, RepositoryException { SampleResourceImpl sampleRes = createSampleResource(); File attachment1 = new File(resourceDir, "TestAttachment.txt"); sampleRes.addContent(attachment1); File attachment2 = new File(resourceDir, "license_enus.txt"); sampleRes.addLicense(attachment2, Locale.ENGLISH); uploadResource(sampleRes); String id = sampleRes.getId(); RepositoryResourceImpl readBack = (RepositoryResourceImpl) repoConnection.getResource(id); assertEquals("We expected 2 attachment", 2, readBack.getAttachmentCount()); assertNotNull("No input stream to the attachment1 was found", readBack.getAttachment(attachment1.getName())); assertNotNull("No input stream to the attachment2 was found", readBack.getLicense(Locale.ENGLISH)); ((AttachmentResourceImpl) sampleRes.getAttachment("TestAttachment.txt")).deleteNow(); readBack = (RepositoryResourceImpl) repoConnection.getResource(id); assertEquals("We expected 1 attachment", 1, readBack.getAttachmentCount()); assertNotNull("No input stream to the attachment2 was found", readBack.getLicense(Locale.ENGLISH)); AttachmentResource at = readBack.getAttachment(attachment1.getName()); assertNull(at); // Lets add it back to ensure there is no problems re-adding a deleted attachment sampleRes.addContent(attachment1); uploadResource(sampleRes); readBack = (RepositoryResourceImpl) repoConnection.getResource(sampleRes.getId()); assertEquals("We expected 2 attachment", 2, readBack.getAttachmentCount()); assertNotNull("No input stream to the attachment1 was found", readBack.getAttachment(attachment1.getName())); assertNotNull("No input stream to the attachment2 was found", readBack.getLicense(Locale.US)); } /** * Tests that the attachment can be downloaded and the file sizes are the same */ @Test public void testDownloadFile() throws RepositoryException, URISyntaxException, IOException { SampleResourceImpl sampleRes = createSampleResource(); File attachment1 = new File(resourceDir, "TestAttachment.txt"); sampleRes.addContent(attachment1); uploadResource(sampleRes); String id = sampleRes.getId(); RepositoryResourceImpl readBack = (RepositoryResourceImpl) repoConnection.getResource(id); AttachmentResourceImpl at = (AttachmentResourceImpl) readBack.getAttachment("TestAttachment.txt"); Logger.getLogger(this.getClass().getName()).log(Level.INFO, at.toString()); File download = new File(resourceDir, "download.file"); if (download.exists()) { download.delete(); } download.createNewFile(); download.deleteOnExit(); at.downloadToFile(download); assertEquals(at.getSize(), download.length()); } /** * CAUTION: The test name is important for this test. * When a sample resource is created it is given the name of the test that created it, so that * if any resource are left behind we know where it was created. This test uses the name of * the resource to locate a resource it uploads so if you change the method name you must * also change the check * if (res.getName().endsWith("testGetAllAssetsDoesntGetAttachments")) { * to match the new methiod name */ @SuppressWarnings("unchecked") @Test public void testGetAllAssetsDoesntGetAttachments() throws Exception { SampleResourceImpl sampleRes = createSampleResource(); sampleRes.setName("Test sample for testGetAllAssetsDoesntGetAttachments"); File attachment1 = new File(resourceDir, "TestAttachment.txt"); File attachment2 = new File(resourceDir, "license_enus.txt"); sampleRes.addContent(attachment1); sampleRes.addLicense(attachment2, Locale.US); uploadResource(sampleRes); Collection<? extends RepositoryResource> allResources = new RepositoryConnectionList(repoConnection).getAllResources(); RepositoryResourceImpl readBack = null; for (RepositoryResource res : allResources) { logger.log(Level.INFO, "Found res " + res.getName()); if (res.getName().endsWith("testGetAllAssetsDoesntGetAttachments")) { readBack = (RepositoryResourceImpl) res; break; } } assertNotNull("Wasn't able to find the resource that was just uploaded. Uh oh", readBack); Field f = RepositoryResourceImpl.class.getDeclaredField("_attachments"); f.setAccessible(true); Object o = f.get(readBack); HashMap<String, AttachmentResource> attachments = (HashMap<String, AttachmentResource>) o; assertTrue(attachments.isEmpty()); assertEquals("There should be 2 attachments (lazily attached) when we try and get them", 2, readBack.getAttachmentCount()); } /** * Test to ensure we can read the attachment of type DOCUMENTATION from an asset without * authentication. * * @throws Exception */ @Test public void testSimpleUnauthDOCUMENTATION() throws Exception { simpleUnauthBASE(AttachmentType.DOCUMENTATION, false); } /** * Test to ensure we can read the attachment of type DOCUMENTATION from an asset without * authentication. * * @throws Exception */ @Test public void testSimpleUnauthLicenseDOCUMENTATION() throws Exception { simpleUnauthBASE(AttachmentType.DOCUMENTATION, true); } /** * Test to ensure we can read the attachment of type CONTENT from an asset without * authentication. * * @throws Exception */ @Test public void testSimpleUnauthCONTENT() throws Exception { simpleUnauthBASE(AttachmentType.CONTENT, false); } /** * Test to ensure we can read the attachment of type CONTENT from an asset without * authentication. * * @throws Exception */ @Test public void testSimpleUnauthLicenseCONTENT() throws Exception { simpleUnauthBASE(AttachmentType.CONTENT, true); } /** * Test to make sure that we always set the asset type when we create it */ @Test public void testTypeSetOnCreation() { for (ResourceType type : ResourceType.values()) { RepositoryResourceImpl resource = ResourceFactory.getInstance().createResource(type, repoConnection, null); assertEquals("The type should be set", type, resource.getType()); } } /** * Method to add an asset with an attachment of the specified type and ensure it can be read back * without authentication. * * @param type * @throws RepositoryException */ public void simpleUnauthBASE(AttachmentType type, boolean licensed) throws RepositoryException { // create provider String prov = "IBM"; // create asset logger.log(Level.INFO, "Creating asset with attachment of type " + type); RepositoryResourceImpl res = new IfixResourceImpl(repoConnection); res.addAttachment(new File(resourceDir, "TestAttachment.txt"), type, "TestAttachment.txt"); res.setProviderName(prov); res.setName("Test ifix resource " + createDateString()); if (licensed) { res.addLicense(new File(resourceDir, "license_enus.txt"), Locale.ENGLISH); } // upload asset and publish it res.uploadToMassive(new UpdateInPlaceStrategy()); String id = res.getId(); res.moveToState(PUBLISHED); // Get resource without authentication IfixResourceImpl unauthIfix; try { unauthIfix = (IfixResourceImpl) fixture.getUserConnection().getResource(id); //UNAUTH // expected } catch (RepositoryBackendException e) { fail("RepositoryIOException thrown: " + e); return; } // check we can get an input stream to all Collection<AttachmentResource> attResources = unauthIfix.getAttachments(); for (AttachmentResource attResource : attResources) { attResource.getInputStream(); } } /** * Create two samples with the same name and type but different providers to ensure that * separate test items are created (name, provider and type are used to work out whether * to do an add or replace) BUT with the same generated vanityRelativeURL (as provider is * not part of the generated vanityURL). Call getAllResourcesWithVanityRelativeURL and * ensure that both are returned. */ @Test public void testGetAllResourcesWithVanityRelativeURL() throws URISyntaxException, RepositoryResourceException, RepositoryBackendException { SampleResourceImpl sampleRes1 = createSampleResource(); sampleRes1.setName("testGetAllResourcesWithVanityRelativeURL"); String p1 = "Provider1"; sampleRes1.setProviderName(p1); uploadResource(sampleRes1); SampleResourceImpl sampleRes2 = createSampleResource(); sampleRes2.setName("testGetAllResourcesWithVanityRelativeURL"); String p2 = "Provider2"; sampleRes2.setProviderName(p2); uploadResource(sampleRes2); String vanityRelativeURL = "samples-testGetAllResourcesWithVanityRelativeURL"; Collection<RepositoryResourceImpl> collection = new RepositoryConnectionList(repoConnection). getAllResourcesWithVanityRelativeURL(vanityRelativeURL); assertEquals("There should be 2 resources returned", 2, collection.size()); } @Test public void testSimpleGetAllFromMultipleRepos() throws URISyntaxException, RepositoryResourceException, RepositoryBackendException { RepositoryConnection repo2 = fixture2.getWritableConnection(); // Creates a collection with just one repo RepositoryConnectionList repo1Only = new RepositoryConnectionList(repoConnection); RepositoryConnectionList repo2Only = new RepositoryConnectionList(repo2); // Creates a collection with both repos in (for reading from). Get repo1 from repoConnection RepositoryConnectionList bothRepos = new RepositoryConnectionList(repoConnection); bothRepos.add(repo2); // Add an asset to repo1 SampleResourceImpl sampleRes1 = createSampleResource(); sampleRes1.setName("samp1"); simpleUpload(sampleRes1); // Add an asset to repo2 SampleResourceImpl sampleRes2 = createSampleResource(); sampleRes2.setName("samp2"); // Override default so asset goes to repo2 sampleRes2.setRepositoryConnection(repo2); simpleUpload(sampleRes2); // Should only get one asset from repo1 assertEquals("Should only be 1 asset in repo1", 1, repo1Only.getAllResources().size()); // Should only get one asset from repo2 assertEquals("Should only be 1 asset in repo2", 1, repo2Only.getAllResources().size()); // Should get two assets when using both repos assertEquals("Should get two assets when using both repos", 2, bothRepos.getAllResources().size()); } @Test public void testGetAllFromMultipleReposWithDupes() throws URISyntaxException, RepositoryResourceException, RepositoryBackendException { RepositoryConnection repo2 = fixture2.getWritableConnection(); // Creates a collection with just one repo in RepositoryConnectionList repo1Only = new RepositoryConnectionList(repoConnection); RepositoryConnectionList repo2Only = new RepositoryConnectionList(repo2); // Creates a collection with both repos in (for reading from). Get repo1 from _loginInfo RepositoryConnectionList bothRepos = new RepositoryConnectionList(repoConnection); bothRepos.add(repo2); // Add an asset to repo1 SampleResourceImpl sampleRes1 = createSampleResource(); sampleRes1.setName("samp1"); simpleUpload(sampleRes1); // Add an asset to repo1 SampleResourceImpl sampleRes2 = createSampleResource(); sampleRes2.setName("samp2"); simpleUpload(sampleRes2); // Add the same asset again to repo2. Override default so asset goes to repo2 sampleRes2.setRepositoryConnection(repo2); simpleUpload(sampleRes2); // Should only get one asset from repo1 assertEquals("Should be 2 assets in repo1", 2, repo1Only.getAllResources().size()); // Should only get one asset from repo2 assertEquals("Should only be 1 asset in repo2", 1, repo2Only.getAllResources().size()); // Should get two assets when using both repos assertEquals("Should get two assets when using both repos", 2, bothRepos.getAllResources().size()); } @Test public void testWriteJson() throws IOException, RepositoryResourceException { RepositoryResourceImpl _testObject = createSampleResource(); _testObject.setName("wibble"); _testObject.setLicenseId("lic id"); _testObject.setDescription("test desc");; _testObject.setState(State.DRAFT); File jsonFile = File.createTempFile("wibble", "json"); FileOutputStream fos = new FileOutputStream(jsonFile); _testObject.writeDiskRepoJSONToStream(fos); logger.log(Level.INFO, "Wrote to " + jsonFile.getAbsolutePath()); } @Test public void testGetAppliesToMinimumVersions() throws URISyntaxException { SampleResourceImpl sampleResource = createSampleResource(); sampleResource.setAppliesTo("a;productVersion=8.5.5.6,b;productVersion=\"1.0.0.0\""); Set<String> expected = new HashSet<String>(); expected.add("8.5.5.6"); expected.add("1.0.0.0"); assertEquals(expected, sampleResource.getAppliesToMinimumVersions()); sampleResource.setAppliesTo(null); assertEquals(new HashSet<String>(), sampleResource.getAppliesToMinimumVersions()); sampleResource.setAppliesTo("a"); assertEquals(new HashSet<String>(), sampleResource.getAppliesToMinimumVersions()); } @Test public void testUpdateGeneratedFieldsAndCheckEditionsWithValidEdition() throws RepositoryResourceCreationException, NoSuchFieldException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { executeUpdateGeneratedFieldsTest("BASE", true, true); } @Test public void testUpdateGeneratedFieldsAndCheckEditionsWithInvalidEdition() throws RepositoryResourceCreationException, NoSuchFieldException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { executeUpdateGeneratedFieldsTest("invalid", true, false); } @Test public void testUpdateGeneratedFieldsAndDontCheckEditionsWithValidEdition() throws RepositoryResourceCreationException, NoSuchFieldException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { executeUpdateGeneratedFieldsTest("BASE", false, true); } @Test public void testUpdateGeneratedFieldsAndDontCheckEditionsWithInvalidEdition() throws RepositoryResourceCreationException, NoSuchFieldException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { executeUpdateGeneratedFieldsTest("invalid", false, true); } @Test public void testMainAttachmentSHA256() throws IOException, RepositoryException { File contentFile = new File(resourceDir, "TestAttachment.txt"); String fileHash = HashUtils.getFileSHA256String(contentFile); RepositoryResourceImpl mr = new EsaResourceImpl(null); mr.addContent(contentFile); String contentHash = mr.getMainAttachmentSHA256(); assertEquals("Main attachment SHA256 hash should be the same as the hash of the file added", fileHash, contentHash); } /** * Run multi-threaded upload of multiple resources * * @throws RepositoryResourceException * @throws RepositoryBackendException */ @Test public void testMultiThreadedUploadAndLocking() throws RepositoryBackendException { final int VANITY_URLS = 3; final int RESOURCES_PER_VANITY_URL = 10; List<EsaResourceImpl> list = createRandomizedListOfResources(VANITY_URLS, RESOURCES_PER_VANITY_URL); ExecutorService executor = Executors.newFixedThreadPool(10); for (EsaResourceImpl esa : list) { Runnable worker = new WorkerThread(esa); executor.execute(worker); } executor.shutdown(); while (!executor.isTerminated()) { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("Finished all threads"); int countVisible = 0; int countHidden = 0; final String highestVersion = "8.5.5." + RESOURCES_PER_VANITY_URL; Collection<? extends RepositoryResource> resources = assertResourceCount(30); for (RepositoryResource result : resources) { EsaResourceWritable esa = (EsaResourceWritable) result; if (esa.getAppliesTo().contains(highestVersion)) { assertEquals(highestVersion + " should be visible", DisplayPolicy.VISIBLE, esa.getWebDisplayPolicy()); countVisible++; } else { assertEquals("other than " + highestVersion + " should be hidden", DisplayPolicy.HIDDEN, esa.getWebDisplayPolicy()); countHidden++; } } assertEquals("Wrong number of recources visible: ", VANITY_URLS, countVisible); assertEquals("Wrong number of recources hidden: ", (VANITY_URLS * RESOURCES_PER_VANITY_URL) - VANITY_URLS, countHidden); } /** * ------------------------------------------------------------------------------------------------ * HELPER METHODS * ------------------------------------------------------------------------------------------------ * * @throws SecurityException * @throws NoSuchMethodException * @throws InvocationTargetException * @throws IllegalArgumentException * @throws IllegalAccessException */ public void executeUpdateGeneratedFieldsTest(String edition, boolean checkEditions, boolean expectSuccess) throws NoSuchFieldException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { RepositoryResourceImpl res = new SampleResourceImpl(null); Asset ass = new Asset(); WlpInformation wlpInfo = new WlpInformation(); wlpInfo.setAppliesTo("com.ibm.fish; productEditions=\"" + edition + "\""); ass.setWlpInformation(wlpInfo); Field f = RepositoryResourceImpl.class.getDeclaredField("_asset"); f.setAccessible(true); f.set(res, ass); try { res.updateGeneratedFields(checkEditions); if (!expectSuccess) { fail("We should have had an exception thrown when we attempted to updateGeneratedFields as the edition is not valid: "); } } catch (RepositoryResourceCreationException e) { if (expectSuccess) { fail("We should not have had an exception thrown when we attempted to updateGeneratedFields as the edition is valid " + e); } } } private class TestResource extends RepositoryResourceImpl { public TestResource(RepositoryConnection loginInfo) { super(loginInfo, null); setType(ResourceType.PRODUCTSAMPLE); } @Override public Asset getAsset() { return _asset; } } /** * Creates a string saying when something is created. This can be used to ensure that * a newly created asset will not be a match for a prior one to ensure that an add not * an update occurs * * @return */ private String createDateString() { SimpleDateFormat dateFormater = new SimpleDateFormat( "yyyy/MM/dd HH:mm:ss.SSS"); String createdString = " created at " + dateFormater.format(Calendar.getInstance().getTime()); return createdString; } /** * Inner class for multi-threaded testing */ public class WorkerThread implements Runnable { private final EsaResourceImpl esa; public WorkerThread(EsaResourceImpl esa) { this.esa = esa; } @Override public void run() { System.out.println(Thread.currentThread().getName() + " Start. resource = " + esa.getName()); processCommand(); System.out.println(Thread.currentThread().getName() + " End."); } private void processCommand() { try { esa.uploadToMassive(new AddThenHideOldStrategy(State.PUBLISHED, State.PUBLISHED)); } catch (RepositoryBackendException e) { System.out.println("RepositoryBackendException thrown"); e.printStackTrace(); } catch (RepositoryResourceException e) { System.out.println("RepositoryResourceException thrown"); e.printStackTrace(); } } } /** * Create a list containing a specified number of features in a random order * * @param noOfVanityUrls - the number of different vanityUrl features to create * @param numberOfResourcesPerVanityUrl - how many of each of them * @return */ private List<EsaResourceImpl> createRandomizedListOfResources(int noOfVanityUrls, int numberOfItemsPerVanityUrl) { final String APPLIES_TO_STEM = "com.ibm.websphere.appserver; productEdition=\"BASE,BASE_ILAN,DEVELOPERS,EXPRESS,ND,zOS\"; productVersion=8.5.5."; final String FEATURE_NAME_STEM = "dummyEsa"; final String VANITY_URL_STEM = "vanityUrl"; System.out.println("START Creating list"); List<EsaResourceImpl> list = new ArrayList<EsaResourceImpl>(); for (int i = 1; i < noOfVanityUrls + 1; i++) { for (int j = 1; j < numberOfItemsPerVanityUrl + 1; j++) { EsaResourceImpl esa = new EsaResourceImpl(repoConnection); String featureName = FEATURE_NAME_STEM + i + "-v" + j; String providesFeature = "Feature" + i; esa.setVisibility(Visibility.PUBLIC); esa.setWebDisplayPolicy(DisplayPolicy.VISIBLE); esa.setProviderName("IBM"); esa.setName(featureName); esa.setAppliesTo(APPLIES_TO_STEM + j); esa.setProvideFeature(providesFeature); esa.setVanityURL(VANITY_URL_STEM + i); esa.setDescription(featureName + " on " + providesFeature); list.add(esa); System.out.println("CREATING v855" + j + ", vanityUrl=" + VANITY_URL_STEM + i + ", feature=" + providesFeature + ", name=" + esa.getName()); } } Collections.shuffle(list); System.out.println("END Creating list"); return list; } /** * Convenience method for both getting all the resources and checking that the correct number are available * * @param expected - the expected number of resources in the repository * @return Collection<? extends RepositoryResource> * @throws RepositoryBackendException */ private Collection<? extends RepositoryResource> assertResourceCount(int expected) throws RepositoryBackendException { Collection<? extends RepositoryResource> countList = new RepositoryConnectionList(repoConnection).getAllResources(); assertEquals("Wrong number of resources returned: ", expected, countList.size()); return countList; } }