Added: ace/trunk/org.apache.ace.obr/src/org/osgi/service/obr/Resolver.java URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.obr/src/org/osgi/service/obr/Resolver.java?rev=1463529&view=auto ============================================================================== --- ace/trunk/org.apache.ace.obr/src/org/osgi/service/obr/Resolver.java (added) +++ ace/trunk/org.apache.ace.obr/src/org/osgi/service/obr/Resolver.java Tue Apr 2 13:26:43 2013 @@ -0,0 +1,44 @@ +/* + * $Header: /cvshome/build/org.osgi.service.obr/src/org/osgi/service/obr/Resolver.java,v 1.3 2006/03/16 14:56:17 hargrave Exp $ + * + * Copyright (c) OSGi Alliance (2006). All Rights Reserved. + * + * 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. + */ + +// This document is an experimental draft to enable interoperability +// between bundle repositories. There is currently no commitment to +// turn this draft into an official specification. +package org.osgi.service.obr; + +public interface Resolver +{ + + void add(Resource resource); + + Requirement[] getUnsatisfiedRequirements(); + + Resource[] getOptionalResources(); + + Requirement[] getReason(Resource resource); + + Resource[] getResources(Requirement requirement); + + Resource[] getRequiredResources(); + + Resource[] getAddedResources(); + + boolean resolve(); + + void deploy(boolean start); +} \ No newline at end of file
Added: ace/trunk/org.apache.ace.obr/src/org/osgi/service/obr/Resource.java URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.obr/src/org/osgi/service/obr/Resource.java?rev=1463529&view=auto ============================================================================== --- ace/trunk/org.apache.ace.obr/src/org/osgi/service/obr/Resource.java (added) +++ ace/trunk/org.apache.ace.obr/src/org/osgi/service/obr/Resource.java Tue Apr 2 13:26:43 2013 @@ -0,0 +1,86 @@ +/* + * $Header: /cvshome/build/org.osgi.service.obr/src/org/osgi/service/obr/Resource.java,v 1.5 2006/03/16 14:56:17 hargrave Exp $ + * + * Copyright (c) OSGi Alliance (2006). All Rights Reserved. + * + * 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. + */ + +// This document is an experimental draft to enable interoperability +// between bundle repositories. There is currently no commitment to +// turn this draft into an official specification. +package org.osgi.service.obr; + +import java.net.URL; +import java.util.Map; + +import org.osgi.framework.Version; + +/** + * A resource is an abstraction of a downloadable thing, like a bundle. + * + * Resources have capabilities and requirements. All a resource's requirements + * must be satisfied before it can be installed. + * + * @version $Revision: 1.5 $ + */ +public interface Resource +{ + final String LICENSE_URL = "license"; + + final String DESCRIPTION = "description"; + + final String DOCUMENTATION_URL = "documentation"; + + final String COPYRIGHT = "copyright"; + + final String SOURCE_URL = "source"; + + final String SYMBOLIC_NAME = "symbolicname"; + + final String PRESENTATION_NAME = "presentationname"; + + final String ID = "id"; + + final String VERSION = "version"; + + final String URL = "url"; + + final String SIZE = "size"; + + final static String[] KEYS = { DESCRIPTION, SIZE, ID, LICENSE_URL, + DOCUMENTATION_URL, COPYRIGHT, SOURCE_URL, PRESENTATION_NAME, + SYMBOLIC_NAME, VERSION, URL }; + + // get readable name + + Map getProperties(); + + String getSymbolicName(); + + String getPresentationName(); + + Version getVersion(); + + String getId(); + + URL getURL(); + + Requirement[] getRequirements(); + + Capability[] getCapabilities(); + + String[] getCategories(); + + Repository getRepository(); +} \ No newline at end of file Added: ace/trunk/org.apache.ace.obr/src/org/osgi/service/obr/packageinfo URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.obr/src/org/osgi/service/obr/packageinfo?rev=1463529&view=auto ============================================================================== --- ace/trunk/org.apache.ace.obr/src/org/osgi/service/obr/packageinfo (added) +++ ace/trunk/org.apache.ace.obr/src/org/osgi/service/obr/packageinfo Tue Apr 2 13:26:43 2013 @@ -0,0 +1 @@ +version 1.0 \ No newline at end of file Added: ace/trunk/org.apache.ace.obr/storage.bnd URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.obr/storage.bnd?rev=1463529&view=auto ============================================================================== --- ace/trunk/org.apache.ace.obr/storage.bnd (added) +++ ace/trunk/org.apache.ace.obr/storage.bnd Tue Apr 2 13:26:43 2013 @@ -0,0 +1,5 @@ +Private-Package: org.apache.ace.obr.storage.file,\ + org.apache.ace.obr.storage.file.constants +Bundle-Activator: org.apache.ace.obr.storage.file.Activator +Export-Package: org.apache.ace.obr.storage +Bundle-Version: 1.0.0 \ No newline at end of file Added: ace/trunk/org.apache.ace.obr/test/org/apache/ace/obr/metadata/bindeximpl/BindexMetadataTest.java URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.obr/test/org/apache/ace/obr/metadata/bindeximpl/BindexMetadataTest.java?rev=1463529&view=auto ============================================================================== --- ace/trunk/org.apache.ace.obr/test/org/apache/ace/obr/metadata/bindeximpl/BindexMetadataTest.java (added) +++ ace/trunk/org.apache.ace.obr/test/org/apache/ace/obr/metadata/bindeximpl/BindexMetadataTest.java Tue Apr 2 13:26:43 2013 @@ -0,0 +1,98 @@ +/* + * 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.ace.obr.metadata.bindeximpl; + +import static org.apache.ace.test.utils.TestUtils.UNIT; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; + +import org.apache.ace.deployment.provider.ArtifactData; +import org.apache.ace.deployment.provider.impl.ArtifactDataImpl; +import org.apache.ace.obr.metadata.MetadataGenerator; +import org.apache.ace.obr.metadata.bindex.BIndexMetadataGenerator; +import org.apache.ace.test.utils.deployment.BundleStreamGenerator; +import org.testng.annotations.Test; + +public class BindexMetadataTest { + + private ArtifactData generateBundle(File file, String symbolicName, String version) throws Exception { + ArtifactData bundle = new ArtifactDataImpl(file.getName(), symbolicName, version, file.toURI().toURL(), false); + BundleStreamGenerator.generateBundle(bundle); + return bundle; + } + + /** + * Generate metadata index, verify contents + */ + @Test(groups = { UNIT }) + public void generateMetaData() throws Exception { + File dir = File.createTempFile("meta", ""); + dir.delete(); + dir.mkdir(); + generateBundle(File.createTempFile("bundle", ".jar", dir), "bundle.symbolicname.1", "1.0.0"); + generateBundle(File.createTempFile("bundle", ".jar", dir), "bundle.symbolicname.2", "1.0.0"); + generateBundle(File.createTempFile("bundle", ".jar", dir), "bundle.symbolicname.3", "1.0.0"); + MetadataGenerator meta = new BIndexMetadataGenerator(); + meta.generateMetadata(dir); + File index = new File(dir, "repository.xml"); + assert index.exists() : "No repository index was generated"; + assert index.length() > 0 : "Repository index can not be size 0"; + int count = 0; + String line; + BufferedReader in = new BufferedReader(new FileReader(index)); + while ((line = in.readLine()) != null) { + if (line.contains("<resource")) { + count++; + } + } + in.close(); + assert count == 3 : "Expected 3 resources in the repositoty index, found " + count + "."; + } + + /** + * Generate a metadata index, remove a bundle, regenerate metadata, verify. + */ + @Test(groups = { UNIT }) + public void updateMetaData() throws Exception { + File dir = File.createTempFile("meta", ""); + dir.delete(); + dir.mkdir(); + File bundle = File.createTempFile("bundle", ".jar", dir); + generateBundle(bundle, "bundle.symbolicname.1", "1.0.0"); + MetadataGenerator meta = new BIndexMetadataGenerator(); + meta.generateMetadata(dir); + bundle.delete(); + meta.generateMetadata(dir); + File index = new File(dir, "repository.xml"); + assert index.exists() : "No repository index was generated"; + assert index.length() > 0 : "Repository index can not be size 0"; + int count = 0; + String line; + BufferedReader in = new BufferedReader(new FileReader(index)); + while ((line = in.readLine()) != null) { + if (line.contains("<resource")) { + count++; + } + } + in.close(); + assert count == 0 : "Expected 0 resources in the repositoty index, found " + count + "."; + } +} Added: ace/trunk/org.apache.ace.obr/test/org/apache/ace/obr/metadata/bindeximpl/VersionRangeTest.java URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.obr/test/org/apache/ace/obr/metadata/bindeximpl/VersionRangeTest.java?rev=1463529&view=auto ============================================================================== --- ace/trunk/org.apache.ace.obr/test/org/apache/ace/obr/metadata/bindeximpl/VersionRangeTest.java (added) +++ ace/trunk/org.apache.ace.obr/test/org/apache/ace/obr/metadata/bindeximpl/VersionRangeTest.java Tue Apr 2 13:26:43 2013 @@ -0,0 +1,32 @@ +/* + * 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.ace.obr.metadata.bindeximpl; + +import static org.apache.ace.test.utils.TestUtils.UNIT; +import org.osgi.impl.bundle.obr.resource.VersionRange; +import org.testng.annotations.Test; + +public class VersionRangeTest { + @Test(groups = { UNIT }) + public void testACE95() throws Exception { + new VersionRange("[4.1,4.2)"); + new VersionRange("[4.2,4.2]"); + } +} \ No newline at end of file Added: ace/trunk/org.apache.ace.obr/test/org/apache/ace/obr/servlet/BundleServletTest.java URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.obr/test/org/apache/ace/obr/servlet/BundleServletTest.java?rev=1463529&view=auto ============================================================================== --- ace/trunk/org.apache.ace.obr/test/org/apache/ace/obr/servlet/BundleServletTest.java (added) +++ ace/trunk/org.apache.ace.obr/test/org/apache/ace/obr/servlet/BundleServletTest.java Tue Apr 2 13:26:43 2013 @@ -0,0 +1,257 @@ +/* + * 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.ace.obr.servlet; + +import static org.apache.ace.test.utils.TestUtils.UNIT; + +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Random; + +import javax.servlet.ServletInputStream; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.ace.obr.storage.BundleStore; +import org.apache.ace.test.constants.TestConstants; +import org.apache.ace.test.utils.FileUtils; +import org.apache.ace.test.utils.TestUtils; +import org.osgi.service.log.LogService; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class BundleServletTest { + private HttpServletRequest m_request; + private HttpServletResponse m_response; + private ByteArrayOutputStream m_byteStream = new ByteArrayOutputStream(); + protected int m_status; + private MockBundleStore m_store; + private BundleServlet m_bundleServlet; + private File m_testFile; + private String m_requestFile; + + @BeforeMethod(alwaysRun = true) + protected void setUp() throws IOException { + m_testFile = createRandomFileWithContent(); + m_store = new MockBundleStore(new FileInputStream(m_testFile)); + m_bundleServlet = new BundleServlet(); + + TestUtils.configureObject(m_bundleServlet, LogService.class); + TestUtils.configureObject(m_bundleServlet, BundleStore.class, m_store); + + m_request = TestUtils.createMockObjectAdapter(HttpServletRequest.class, new Object() { + @SuppressWarnings("unused") + public String getParameter(String param) { + return m_requestFile; + } + + @SuppressWarnings("unused") + public String getPathInfo() { + return "/" + m_requestFile; + } + + @SuppressWarnings("unused") + public StringBuffer getRequestURL() { + return new StringBuffer("http://localhost:" + TestConstants.PORT + "/obr/" + m_requestFile); + } + + @SuppressWarnings("unused") + public ServletInputStream getInputStream() { + return new ServletInputStream() { + int i = 0; + @Override + public int read() throws IOException { + if (i == 0) { + i++; + return 'a'; + } + else { + return -1; + } + } + + }; + } + }); + + // create a HttpServletResponse mock object + m_response = TestUtils.createMockObjectAdapter(HttpServletResponse.class, new Object() { + @SuppressWarnings("unused") + public ServletOutputStream getOutputStream() { + return new ServletOutputStream() { + @Override + public void write(int b) throws IOException { + m_byteStream.write(b); + } + + @Override + public void println(String s) throws IOException { + for (int i = 0; i < s.length(); i++) { + m_byteStream.write(s.charAt(i)); + } + } + }; + } + + @SuppressWarnings("unused") + public void sendError(int status) { + m_status = status; + } + + @SuppressWarnings("unused") + public void sendError(int status, String description) { + m_status = status; + } + }); + m_status = HttpServletResponse.SC_OK; + } + + private File createRandomFileWithContent() throws IOException { + OutputStream fileOut = null; + File file = null; + try { + file = FileUtils.createTempFile(null); + fileOut = new FileOutputStream(file); + byte[] byteArray = new byte[12345]; + Random randomContentCreator = new Random(); + randomContentCreator.nextBytes(byteArray); + fileOut.write(byteArray); + + return file; + } + finally { + try { + if (fileOut != null) { + fileOut.close(); + } + } + catch (IOException e) { + throw e; + } + } + } + + @Test(groups = { UNIT }) + public void testGetValidResource() throws Exception { + m_requestFile = m_testFile.getName(); + m_bundleServlet.doGet(m_request, m_response); + + assert m_status == HttpServletResponse.SC_OK : "We should have got response code " + HttpServletResponse.SC_OK + " and we got " + m_status; + + boolean checkStream = checkOutputStreamForFile(); + assert checkStream : "One stream stopped before the other one did."; + } + + @Test(groups = { UNIT }) + public void testGetInValidResource() throws Exception { + m_requestFile = "UnknownFile"; + m_bundleServlet.doGet(m_request, m_response); + + assert m_status == HttpServletResponse.SC_NOT_FOUND : "We should have got response code " + HttpServletResponse.SC_NOT_FOUND + " and we got " + m_status; + } + + @Test(groups = { UNIT }) + public void testPostResource() throws Exception { + m_requestFile = "NewFile"; + m_bundleServlet.doPost(m_request, m_response); + assert m_status == HttpServletResponse.SC_OK; + m_requestFile = "ExistingFile"; + m_bundleServlet.doPost(m_request, m_response); + assert m_status == HttpServletResponse.SC_CONFLICT; + m_requestFile = ""; + m_bundleServlet.doPost(m_request, m_response); + assert m_status == HttpServletResponse.SC_BAD_REQUEST; + } + + @Test(groups = { UNIT }) + public void testPostResourceInPath() throws Exception { + m_requestFile = "path/to/file"; + m_bundleServlet.doPost(m_request, m_response); + assert m_status == HttpServletResponse.SC_OK; + } + + @Test(groups = { UNIT }) + public void testRemoveResource() throws Exception { + m_requestFile = "RemoveMe"; + m_bundleServlet.doDelete(m_request, m_response); + assert m_status == HttpServletResponse.SC_OK; + m_requestFile = "NonExistingFile"; + m_bundleServlet.doDelete(m_request, m_response); + assert m_status == HttpServletResponse.SC_NOT_FOUND; + } + + @Test(groups = { UNIT }) + public void testRemoveResourceInPath() throws Exception { + m_requestFile = "path/to/file"; + m_bundleServlet.doDelete(m_request, m_response); + assert m_status == HttpServletResponse.SC_OK; + m_requestFile = "path/to/NonExistingFile"; + m_bundleServlet.doDelete(m_request, m_response); + assert m_status == HttpServletResponse.SC_NOT_FOUND; + } + + /** + * Check if the output from the server is the configured file + */ + private boolean checkOutputStreamForFile() throws Exception { + assert m_testFile.length() == m_byteStream.size() : "Different filesize"; + + InputStream inStream = null; + InputStream outStream = null; + try { + // ok, the length is the same, now compare the content. + inStream = new BufferedInputStream(m_testFile.toURI().toURL().openStream()); + outStream = new BufferedInputStream(new ByteArrayInputStream(m_byteStream.toByteArray())); + int inByte = inStream.read(); + int outByte = outStream.read(); + while ((inByte != -1) && (outByte != -1)) { + assert inByte == outByte : "Unexpected Stream content found"; + inByte = inStream.read(); + outByte = outStream.read(); + } + return inByte == outByte; + } + finally { + try { + if (inStream != null) { + inStream.close(); + } + } finally { + if (outStream != null) { + outStream.close(); + } + } + } + } + + @AfterMethod(alwaysRun = true) + protected void tearDown() { + m_byteStream = new ByteArrayOutputStream(); + m_testFile.delete(); + } +} Added: ace/trunk/org.apache.ace.obr/test/org/apache/ace/obr/servlet/MockBundleStore.java URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.obr/test/org/apache/ace/obr/servlet/MockBundleStore.java?rev=1463529&view=auto ============================================================================== --- ace/trunk/org.apache.ace.obr/test/org/apache/ace/obr/servlet/MockBundleStore.java (added) +++ ace/trunk/org.apache.ace.obr/test/org/apache/ace/obr/servlet/MockBundleStore.java Tue Apr 2 13:26:43 2013 @@ -0,0 +1,72 @@ +/* + * 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.ace.obr.servlet; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Dictionary; + +import org.apache.ace.obr.storage.BundleStore; +import org.osgi.service.cm.ConfigurationException; + +public class MockBundleStore implements BundleStore { + + private InputStream m_outFile; + + public MockBundleStore(InputStream outFile) { + m_outFile = outFile; + } + + public InputStream get(String fileName) throws IOException { + if (fileName.equals("UnknownFile")) { + return null; + } + return m_outFile; + } + + public void put(String fileName, OutputStream data) throws IOException { + // TODO does nothing yet + } + + public boolean put(String fileName, InputStream data) throws IOException { + if (fileName.equals("NewFile")) { + return true; + } + if (fileName.equals("path/to/file")) { + return true; + } + return false; + } + + public boolean remove(String fileName) throws IOException { + if (fileName.equals("RemoveMe")) { + return true; + } + if (fileName.equals("path/to/file")) { + return true; + } + return false; + } + + @SuppressWarnings("unchecked") + public void updated(Dictionary arg0) throws ConfigurationException { + // TODO does nothing yet + } +} Added: ace/trunk/org.apache.ace.obr/test/org/apache/ace/obr/storage/file/BundleFileStoreTest.java URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.obr/test/org/apache/ace/obr/storage/file/BundleFileStoreTest.java?rev=1463529&view=auto ============================================================================== --- ace/trunk/org.apache.ace.obr/test/org/apache/ace/obr/storage/file/BundleFileStoreTest.java (added) +++ ace/trunk/org.apache.ace.obr/test/org/apache/ace/obr/storage/file/BundleFileStoreTest.java Tue Apr 2 13:26:43 2013 @@ -0,0 +1,378 @@ +/* + * 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.ace.obr.storage.file; + +import static org.apache.ace.test.utils.TestUtils.UNIT; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Arrays; +import java.util.Properties; +import java.util.Random; + +import org.apache.ace.obr.metadata.MetadataGenerator; +import org.apache.ace.obr.storage.BundleStore; +import org.apache.ace.obr.storage.file.constants.OBRFileStoreConstants; +import org.apache.ace.test.utils.FileUtils; +import org.apache.ace.test.utils.TestUtils; +import org.osgi.service.cm.ConfigurationException; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class BundleFileStoreTest { + + private BundleStore m_bundleStore; + private MockMetadataGenerator m_metadata; + + private File m_directory; + + private File m_bundleSubstitute1; + private File m_bundleSubstitute1Larger; + private File m_bundleSubstitute2; + private File m_bundleSubstitute3; + private File m_bundleRepositoryFile; + + @BeforeMethod(alwaysRun = true) + protected void setUp() throws Exception { + m_bundleStore = new BundleFileStore(); + + m_directory = FileUtils.createTempFile(null); + m_directory.mkdir(); + + Properties props = new Properties(); + props.put(OBRFileStoreConstants.FILE_LOCATION_KEY, m_directory.getAbsolutePath()); + m_bundleStore.updated(props); + + // create a mock MetadataGenerator + m_metadata = new MockMetadataGenerator(); + TestUtils.configureObject(m_bundleStore, MetadataGenerator.class, m_metadata); + + // create some bundles to work with + m_bundleSubstitute1 = createFileWithContent(m_directory.getAbsoluteFile(), "bundleSub1.jar", 1000); + m_bundleSubstitute2 = createFileWithContent(m_directory.getAbsoluteFile(), "bundleSub2.jar", 2000); + m_bundleSubstitute3 = createFileWithContent(m_directory.getAbsoluteFile(), "bundleSub3.jar", 3000); + m_bundleRepositoryFile = createFileWithContent(m_directory.getAbsoluteFile(), "repository.xml", 1000); + } + + @AfterMethod(alwaysRun = true) + public void tearDown() throws Exception { + m_bundleSubstitute1.delete(); + m_bundleSubstitute2.delete(); + m_bundleSubstitute3.delete(); + m_bundleRepositoryFile.delete(); + m_directory.delete(); + } + + /** + * Test whether the metadata is generated when getting a bundle from the repository. + */ + @Test(groups = { UNIT }) + public void getBundle() throws Exception { + m_bundleStore.get(m_bundleSubstitute1.getName()); + assert !m_metadata.generated() : "During getting a bundle, the metadata should not be regenerated."; + } + + /** + * Test that the bundle store reutrns null for non-existing files. + */ + @Test(groups = { UNIT }) + public void getNonExistingBundle() throws Exception { + assert m_bundleStore.get("blaat") == null : "Getting an non-existing file did not result in null?"; + } + + /** + * Test whether retrieving the repository.xml results in a call to the (mock) metadata generator, + * and the original file should correspond with the retrieved file. + */ + @Test(groups = { UNIT }) + public void getRepositoryFile() throws Exception { + InputStream newInputStream = m_bundleStore.get("repository.xml"); + assert m_metadata.generated() : "During getting the repository file, the metadata should be regenerated."; + + byte[] orgContentBuffer = new byte[1000]; + newInputStream.read(orgContentBuffer); + + FileInputStream orgInputStream = new FileInputStream(m_bundleRepositoryFile); + byte[] newContentBuffer = new byte[1000]; + orgInputStream.read(newContentBuffer); + + assert Arrays.equals(orgContentBuffer, newContentBuffer) : "The original repository.xml content should equal the newly retrieved content."; + } + + /** + * Test whether the BundleStore notices the set of bundles has changed (bundle updated), + * and makes a call to the (mock) metadata generator. + */ + @Test(groups = { UNIT }) + public void updateBundle() throws Exception { + m_bundleStore.get("repository.xml"); + assert m_metadata.numberOfCalls() == 1 : "The MetadataGenerator should be called once"; + + m_bundleSubstitute1Larger = createFileWithContent(m_directory.getAbsoluteFile(), "bundleSub1.jar", 2000); + + m_bundleStore.get("repository.xml"); + assert m_metadata.numberOfCalls() == 2 : "The MetadataGenerator should be called twice"; + + // test specific tear down + m_bundleSubstitute1Larger.delete(); + } + + /** + * Test whether the BundleStore notices the set of bundles has changed (bundle added), + * and makes a call to the (mock) metadata generator. Also a call should be made when + * a bundle is replaced by another one (number of bundles stay the same, but one bundle + * is replaced by another). + */ + @Test(groups = { UNIT }) + public void addBundle() throws Exception { + m_bundleStore.get("repository.xml"); + assert m_metadata.numberOfCalls() == 1 : "The MetadataGenerator should be called once"; + + File bundleSubstituteX = createFileWithContent(m_directory.getAbsoluteFile(), "bundleSubX.jar", 2000); + + m_bundleStore.get("repository.xml"); + assert m_metadata.numberOfCalls() == 2 : "The MetadataGenerator should be called twice"; + + bundleSubstituteX.delete(); + + File bundleSubstituteY = createFileWithContent(m_directory.getAbsoluteFile(), "bundleSubY.jar", 2000); + + m_bundleStore.get("repository.xml"); + assert m_metadata.numberOfCalls() == 3 : "The MetadataGenerator should be called three times"; + + // test specific tear down + bundleSubstituteY.delete(); + } + + /** + * Test whether the BundleStore notices the set of bundles has not changed, and thus + * will not make a call to the (mock) metadata generator. + */ + @Test(groups = { UNIT }) + public void replaceWithSameBundle() throws Exception { + m_bundleStore.get("bundleSub1.jar"); + assert m_metadata.numberOfCalls() == 0 : "The MetadataGenerator should not be called"; + + FileInputStream inputStream = new FileInputStream(m_bundleSubstitute1); + byte[] buffer = new byte[1000]; + inputStream.read(buffer); + m_bundleSubstitute1.delete(); + + File newFile = new File(m_directory, "bundleSub1.jar"); + FileOutputStream outputStream = new FileOutputStream(newFile); + + outputStream.write(buffer); + outputStream.close(); + + m_bundleStore.get("bundleSub1.jar"); + assert m_metadata.numberOfCalls() == 0 : "The MetadataGenerator should still not be called"; + } + + /** + * Test whether changing the directory where the bundles are stored, does not result in a call + * to the (mock) metadata generator, as the metadata will only be regenerated after getting + * a file. + */ + @Test(groups = { UNIT }) + public void updateConfigurationWithValidConfiguration() throws Exception { + File subDir = new File(m_directory.getAbsolutePath(), "changedDirectory"); + subDir.mkdir(); + + Properties props = new Properties(); + props.put(OBRFileStoreConstants.FILE_LOCATION_KEY, subDir.getAbsolutePath()); + try { + m_bundleStore.updated(props); + } + catch (ConfigurationException e) { + assert false : "Reconfiguring directory failed, directory was '" + m_directory + "' but should be '" + subDir + "'"; + } + + assert !m_metadata.generated() : "After changing the directory, the metadata should not be regenerated."; + + // test specific tear down + subDir.delete(); + } + + /** + * Test whether changing the directory where the bundles are stored to something that is not + * a directory, this should fail. + */ + @Test(groups = { UNIT }) + public void updateConfigurationWithIsNotDirectory() throws Exception { + boolean exceptionThrown = false; + + File file = new File(m_directory.getAbsolutePath(), "file"); + file.createNewFile(); + + Properties props = new Properties(); + props.put(OBRFileStoreConstants.FILE_LOCATION_KEY, file.getAbsolutePath()); + try { + m_bundleStore.updated(props); + } + catch (ConfigurationException e) { + // exception should be thrown as attempting to configure with File that is no directory + exceptionThrown = true; + } + assert exceptionThrown : "Reconfiguring directory succeeded, but should fail as it is no directory"; + + // test specific tear down + file.delete(); + } + + @Test(groups = { UNIT }) + public void putBundle() throws Exception { + String fileName = "filename"; + m_bundleStore.put(fileName, new ByteArrayInputStream("a".getBytes())); + File file = new File(m_directory, fileName); + FileInputStream input = new FileInputStream(file); + assert input.read() == 'a'; + assert input.read() == -1; + input.close(); + } + + @Test(groups = { UNIT }) + public void putBundleInPathAndRemoveItAgain() throws Exception { + String fileName = "path/to/filename"; + m_bundleStore.put(fileName, new ByteArrayInputStream("a".getBytes())); + File file = new File(m_directory, fileName); + FileInputStream input = new FileInputStream(file); + assert input.read() == 'a'; + assert input.read() == -1; + input.close(); + assert m_bundleStore.remove(fileName); + } + + @Test(groups = { UNIT }) + public void putBundleInInvalidPathShouldFail() throws Exception { + String fileName = "path/to/name"; + String fileName2 = "path/to/name/invalid"; + m_bundleStore.put(fileName, new ByteArrayInputStream("a".getBytes())); + try { + m_bundleStore.put(fileName2, new ByteArrayInputStream("a".getBytes())); + assert false; + } + catch (IOException e) { + // we expect this to happen + } + } + + + @Test(groups = { UNIT }) + public void removeExistingBundle() throws Exception { + m_bundleStore.put("filename", new InputStream() { + private int i = 0; + + @Override + public int read() throws IOException { + if (i < 1) { + i++; + return 'a'; + } + else { + return -1; + } + } + }); + File file = new File(m_directory, "filename"); + assert file.exists(); + m_bundleStore.remove("filename"); + assert !file.exists(); + } + + /** + * Test whether not configuring the directory (so retrieving the directory returns null), + * results in a ConfigurationException. Updating with null as dictionary should only clean up + * things, and nothing else. + */ + @Test(groups = { UNIT }) + public void updateConfigurationWithNull() throws Exception { + boolean exceptionThrown = false; + + Properties props = new Properties(); + try { + m_bundleStore.updated(props); + } + catch (ConfigurationException e) { + exceptionThrown = true; + } + assert exceptionThrown : "Reconfiguring directory succeeded but should fail, as property is supposed to be missing"; + assert !m_metadata.generated() : "After changing the directory, the metadata should not be regenerated."; + + + exceptionThrown = false; + try { + m_bundleStore.updated(null); + } + catch (ConfigurationException e) { + exceptionThrown = true; + } + assert !exceptionThrown : "Reconfiguring succeeded as the bundle should only do the clean up, and not throw exception"; + assert !m_metadata.generated() : "After changing the directory, the metadata should not be regenerated."; + } + + /** + * Test whether not configuring the directory (so retrieving the directory returns null), + * results in a ConfigurationException. + */ + @Test(groups = { UNIT }) + public void updateConfigurationWithSameDirectory() throws Exception { + + Properties props = new Properties(); + props.put(OBRFileStoreConstants.FILE_LOCATION_KEY, m_directory.getAbsolutePath()); + try { + m_bundleStore.updated(props); + } + catch (ConfigurationException e) { + assert false : "Nothing should happen, as the directory did not change"; + } + assert !m_metadata.generated() : "After changing the directory, the metadata should not be regenerated."; + } + + private File createFileWithContent(File baseDir, String filename, int size) throws IOException { + OutputStream fileOut = null; + File file = new File(baseDir, filename); + try { + fileOut = new FileOutputStream(file); + byte[] byteArray = new byte[size]; + Random randomContentCreator = new Random(); + randomContentCreator.nextBytes(byteArray); + fileOut.write(byteArray); + + return file; + } + finally { + try { + if (fileOut != null) { + fileOut.close(); + } + } + catch (IOException e) { + throw e; + } + } + } + + +} Added: ace/trunk/org.apache.ace.obr/test/org/apache/ace/obr/storage/file/MockMetadataGenerator.java URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.obr/test/org/apache/ace/obr/storage/file/MockMetadataGenerator.java?rev=1463529&view=auto ============================================================================== --- ace/trunk/org.apache.ace.obr/test/org/apache/ace/obr/storage/file/MockMetadataGenerator.java (added) +++ ace/trunk/org.apache.ace.obr/test/org/apache/ace/obr/storage/file/MockMetadataGenerator.java Tue Apr 2 13:26:43 2013 @@ -0,0 +1,42 @@ +/* + * 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.ace.obr.storage.file; + +import java.io.File; + +import org.apache.ace.obr.metadata.MetadataGenerator; + +public class MockMetadataGenerator implements MetadataGenerator{ + + private boolean m_generated = false; + private int m_numberOfCalls = 0; + + public void generateMetadata(File metadataFilePath) { + m_numberOfCalls++; + m_generated = true; + } + + public boolean generated() { + return m_generated; + } + + public int numberOfCalls() { + return m_numberOfCalls; + } +}
