| /************************************************************** |
| * |
| * 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 complex.memCheck; |
| |
| import com.sun.star.beans.PropertyValue; |
| import com.sun.star.frame.XStorable; |
| import com.sun.star.lang.XComponent; |
| import com.sun.star.lang.XMultiServiceFactory; |
| import com.sun.star.uno.UnoRuntime; |
| import com.sun.star.util.XCloseable; |
| // import complexlib.ComplexTestCase; |
| import helper.ProcessHandler; |
| import java.io.File; |
| // import java.io.FilePermission; |
| import java.io.FileWriter; |
| import java.io.FilenameFilter; |
| import java.io.PrintWriter; |
| import java.util.Enumeration; |
| import java.util.StringTokenizer; |
| import java.util.Vector; |
| import lib.*; |
| import util.DesktopTools; |
| // import util.WriterTools; |
| |
| import org.junit.After; |
| import org.junit.AfterClass; |
| import org.junit.Before; |
| import org.junit.BeforeClass; |
| import org.junit.Test; |
| import org.openoffice.test.OfficeConnection; |
| import static org.junit.Assert.*; |
| |
| /** |
| * Documents are opened and exported with StarOffice. The memory usage of |
| * StarOffice is monitored and if the usage exceeds the allowed kilobytes, |
| * the test is failed. Used for monitoring the StarOffice process is the |
| * command line tool 'pmap', available on Solaris or Linux. This test will not |
| * run on Windows.<br>Test procedure: every given document type is searched in |
| * the source directory |
| * Needed paramters: |
| * <ul> |
| * <li>"TestDocumentPath" - the path where test documents are located.</li> |
| * <li>"AllowMemoryIncrease" (optional) - the allowed memory increase measured in kByte per exported document. The default is 10 kByte.</li> |
| * <li>"ExportDocCount" (optional) - the amount of exports for each document that is loaded. Is defaulted to 25. |
| * <li>"FileExportFilter" (optional) - a relation between loaded document type and used export filter. Is defaulted to |
| * writer, calc and impress. This parameter can be set with a number to give more than one relation. Example:<br> |
| * "FileExportFilter1=sxw,writer_pdf_Export"<br> |
| * "FileExportFilter2=sxc,calc_pdf_Export"<br> |
| * "FileExportFilter3=sxi,impress_pdf_Export"<br></li> |
| * All parameters are used for iteration over the test document path. |
| * </ul> |
| */ |
| class TempDir |
| { |
| |
| private String m_sTempDir; |
| |
| public TempDir(String _sTempDir) |
| { |
| m_sTempDir = _sTempDir; |
| } |
| |
| public String getOfficeTempDir() |
| { |
| return m_sTempDir; |
| } |
| |
| public String getTempDir() |
| { |
| final String sTempDir = FileHelper.getJavaCompatibleFilename(m_sTempDir); |
| return sTempDir; |
| } |
| } |
| |
| public class CheckMemoryUsage /* extends ComplexTestCase */ |
| |
| { |
| |
| private final String sWriterDoc = "sxw,writer_pdf_Export"; |
| private final String sCalcDoc = "sxc,calc_pdf_Export"; |
| private final String sImpressDoc = "sxi,impress_pdf_Export"; |
| // private String sProcessIdCommand = null; |
| TempDir m_aTempDir; |
| // private String sFS = null; |
| // private String sMemoryMap1 = null; |
| // private String sMemoryMap2 = null; |
| // private String sDocumentPath = ""; |
| private String[][] sDocTypeExportFilter; |
| private String[][] sDocuments; |
| private int iAllowMemoryIncrease = 10; |
| private int iExportDocCount = 25; |
| /** |
| * The test parameters |
| */ |
| private static TestParameters param = null; |
| |
| /** |
| * Get all test methods |
| * @return The test methods. |
| // */ |
| // public String[] getTestMethodNames() { |
| // return new String[] {"loadAndSaveDocuments"}; |
| // } |
| /** |
| * Collect all documnets to load and all filters used for export. |
| */ |
| @Before |
| public void before() |
| { |
| |
| final XMultiServiceFactory xMsf = getMSF(); |
| |
| // some Tests need the qadevOOo TestParameters, it is like a Hashmap for Properties. |
| param = new TestParameters(); |
| param.put("ServiceFactory", xMsf); // some qadevOOo functions need the ServiceFactory |
| |
| // test does definitely not run on Windows. |
| if (param.get("OperatingSystem").equals("wntmsci")) |
| { |
| System.out.println("Test can only reasonably be executed with a tool that " |
| + "displays the memory usage of StarOffice."); |
| System.out.println("Test does not run on Windows, only on Solaris or Linux."); |
| // in an automatic environment it is better to say, there is no error here. |
| // it is a limitation, but no error. |
| System.exit(0); |
| } |
| |
| |
| // how many times is every document exported. |
| int count = param.getInt("ExportDocCount"); |
| if (count != 0) |
| { |
| iExportDocCount = count; |
| } |
| |
| // get the temp dir for creating the command scripts. |
| // sTempDir = System.getProperty("java.io.tmpdir"); |
| m_aTempDir = new TempDir(util.utils.getOfficeTemp/*Dir*/(xMsf)); |
| |
| // get the file extension, export filter connection |
| Enumeration keys = param.keys(); |
| Vector<String> v = new Vector<String>(); |
| while (keys.hasMoreElements()) |
| { |
| String key = (String) keys.nextElement(); |
| if (key.startsWith("FileExportFilter")) |
| { |
| v.add((String) param.get(key)); |
| } |
| } |
| // if no param given, set defaults. |
| if (v.size() == 0) |
| { |
| v.add(sWriterDoc); |
| v.add(sCalcDoc); |
| v.add(sImpressDoc); |
| } |
| // store a file extension |
| sDocTypeExportFilter = new String[v.size()][2]; |
| for (int i = 0; i < v.size(); i++) |
| { |
| // 2do: error routine for wrong given params |
| final String sVContent = v.get(i); |
| StringTokenizer t = new StringTokenizer(sVContent, ","); |
| final String sExt = t.nextToken(); |
| final String sName = t.nextToken(); |
| sDocTypeExportFilter[i][0] = sExt; |
| sDocTypeExportFilter[i][1] = sName; |
| } |
| |
| // get files to load and export |
| // sDocumentPath = (String) param.get("TestDocumentPath"); |
| String sDocumentPath = TestDocument.getUrl(); |
| File f = new File(FileHelper.getJavaCompatibleFilename(sDocumentPath)); |
| // sDocumentPath = f.getAbsolutePath(); |
| // String sFS = System.getProperty("file.separator"); |
| sDocuments = new String[sDocTypeExportFilter.length][]; |
| for (int j = 0; j < sDocTypeExportFilter.length; j++) |
| { |
| FileFilter filter = new FileFilter(sDocTypeExportFilter[j][0]); |
| String[] doc = f.list(filter); |
| sDocuments[j] = new String[doc.length]; |
| for (int i = 0; i < doc.length; i++) |
| { |
| // final String sDocument = FileHelper.appendPath(sDocumentPath, doc[i]); |
| // sDocuments[j][i] = utils.getFullURL(sDocuments[j][i]); |
| sDocuments[j][i] = TestDocument.getUrl(doc[i]); |
| } |
| } |
| } |
| |
| /** |
| * delete all created files on disk |
| */ |
| @After |
| public void after() |
| { |
| // delete the constructed files. |
| // we don't need to delete anything, all is stored in $USER_TREE |
| // for (int i = 0; i < iExportDocCount; i++) |
| // { |
| // final String sDocumentName = "DocExport" + i + ".pdf"; |
| // final String sFilename = FileHelper.appendPath(m_sTempDir, sDocumentName); |
| // File f = new File(FileHelper.getJavaCompatibleFilename(sFilename)); |
| // f.delete(); |
| // } |
| // File f = new File(sProcessIdCommand); |
| // f.delete(); |
| // f = new File(sOfficeMemoryCommand); |
| // f.delete(); |
| } |
| |
| /** |
| * The test function: load documents and save them using the given filters |
| * for each given document type. |
| */ |
| @Test |
| public void loadAndSaveDocuments() |
| { |
| int nOk = 0; |
| int nRunThrough = 0; |
| |
| // At first: |
| // we load the document, there will be some post work in office like late initialisations |
| // we store exact one time the document |
| // so the memory footprint should be right |
| |
| // iterate over all document types |
| for (int k = 0; k < sDocTypeExportFilter.length; k++) |
| { |
| // iterate over all documents of this type |
| for (int i = 0; i < sDocuments[k].length; i++) |
| { |
| |
| final String sDocument = sDocuments[k][i]; |
| final String sExtension = sDocTypeExportFilter[k][1]; |
| |
| // OfficeMemchecker aChecker = new OfficeMemchecker(); |
| // aChecker.setDocumentName(FileHelper.getBasename(sDocument)); |
| // aChecker.setExtension(sExtension); |
| // aChecker.start(); |
| |
| loadAndSaveNTimesDocument(sDocument, 1, sExtension); |
| |
| // nOk += checkMemory(aChecker); |
| // nRunThrough ++; |
| } |
| System.out.println(); |
| System.out.println(); |
| } |
| |
| shortWait(10000); |
| |
| // Now the real test, load document and store 25 times |
| |
| // iterate over all document types |
| for (int k = 0; k < sDocTypeExportFilter.length; k++) |
| { |
| // iterate over all documents of this type |
| for (int i = 0; i < sDocuments[k].length; i++) |
| { |
| |
| final String sDocument = sDocuments[k][i]; |
| final String sExtension = sDocTypeExportFilter[k][1]; |
| |
| OfficeMemchecker aChecker = new OfficeMemchecker(); |
| aChecker.setDocumentName(FileHelper.getBasename(sDocument)); |
| aChecker.setExtension(sExtension); |
| aChecker.start(); |
| |
| loadAndSaveNTimesDocument(sDocument, iExportDocCount, sExtension); |
| |
| aChecker.stop(); |
| final int nConsumMore = aChecker.getConsumMore(); |
| |
| nOk += checkMemory(nConsumMore); |
| nRunThrough++; |
| } |
| System.out.println(); |
| System.out.println(); |
| } |
| System.out.println("Find the output of used 'pmap' here: " + m_aTempDir.getTempDir() + " if test failed."); |
| assertTrue("Office consumes too many memory.", nOk == nRunThrough); |
| } |
| |
| /** |
| * Checks how much memory should consum |
| * @param storageBefore |
| * @return 1 if consum is ok, else 0 |
| */ |
| private int checkMemory(int nConsumMore) |
| { |
| int nAllowed = iAllowMemoryIncrease * iExportDocCount; |
| System.out.println("The Office consumes now " + nConsumMore |
| + "K more memory than at the start of the test; allowed were " |
| + nAllowed + "K."); |
| if (nConsumMore > nAllowed) |
| { |
| System.out.println("ERROR: This is not allowed."); |
| return 0; |
| } |
| System.out.println("OK."); |
| return 1; |
| } |
| |
| /** |
| * load and save exact one document |
| */ |
| private void loadAndSaveNTimesDocument(String _sDocument, int _nCount, String _sStoreExtension) |
| { |
| System.out.println("Document: " + _sDocument); |
| XComponent xComponent = DesktopTools.loadDoc(getMSF(), _sDocument, null); |
| XStorable xStorable = UnoRuntime.queryInterface(XStorable.class, xComponent); |
| if (xStorable != null) |
| { |
| // export each document iExportDocCount times |
| for (int j = 0; j < _nCount; j++) |
| { |
| final String sDocumentName = FileHelper.getBasename(_sDocument) + "_" + j + ".pdf"; |
| final String sFilename = FileHelper.appendPath(m_aTempDir.getOfficeTempDir(), sDocumentName); |
| // String url = utils.getFullURL(sFilename); |
| String url = sFilename; // graphical.FileHelper.getFileURLFromSystemPath(sFilename); |
| try |
| { |
| PropertyValue[] props = new PropertyValue[1]; |
| props[0] = new PropertyValue(); |
| props[0].Name = "FilterName"; |
| // use export filter for this doc type |
| props[0].Value = _sStoreExtension; |
| xStorable.storeToURL(url, props); |
| } |
| catch (com.sun.star.io.IOException e) |
| { |
| fail("Could not store to '" + url + "'"); |
| } |
| } |
| // close the doc |
| XCloseable xCloseable = UnoRuntime.queryInterface(XCloseable.class, xStorable); |
| try |
| { |
| xCloseable.close(true); |
| } |
| catch (com.sun.star.util.CloseVetoException e) |
| { |
| e.printStackTrace(); |
| fail("Cannot close document: test is futile, Office will surely use more space."); |
| } |
| } |
| else |
| { |
| System.out.println("Cannot query for XStorable interface on document '" + _sDocument + "'"); |
| System.out.println(" -> Skipping storage."); |
| } |
| |
| } |
| |
| // ----------------------------------------------------------------------------- |
| private class OfficeMemchecker |
| { |
| |
| /** |
| * After called start() it contains the memory need at startup |
| */ |
| private int m_nMemoryStart; |
| /** |
| * After called stop() it contains the memory usage |
| */ |
| private int m_nMemoryUsage; |
| private String m_sDocumentName; |
| private String m_sExtension; |
| |
| public OfficeMemchecker() |
| { |
| m_nMemoryStart = 0; |
| } |
| |
| public void setDocumentName(String _sDocName) |
| { |
| m_sDocumentName = _sDocName; |
| } |
| |
| public void setExtension(String _sExt) |
| { |
| m_sExtension = _sExt; |
| } |
| |
| public void start() |
| { |
| m_nMemoryStart = getOfficeMemoryUsage(createModeName("start", 0)); |
| } |
| |
| private String createModeName(String _sSub, int _nCount) |
| { |
| StringBuffer aBuf = new StringBuffer(); |
| aBuf.append(_sSub); |
| aBuf.append('_').append(m_sDocumentName).append('_').append(m_sExtension); |
| aBuf.append('_').append(_nCount); |
| return aBuf.toString(); |
| } |
| |
| public void stop() |
| { |
| // short wait for the office to 'calm down' and free some memory |
| shortWait(20000); |
| // wait util memory is not freed anymore. |
| int storageAfter = getOfficeMemoryUsage(createModeName("stop", 0)); |
| int mem = 0; |
| int count = 0; |
| while (storageAfter != mem && count < 10) |
| { |
| count++; |
| mem = storageAfter; |
| storageAfter = getOfficeMemoryUsage(createModeName("stop", count)); |
| shortWait(1000); |
| } |
| m_nMemoryUsage = (storageAfter - m_nMemoryStart); |
| } |
| |
| public int getConsumMore() |
| { |
| return m_nMemoryUsage; |
| } |
| |
| /** |
| * Get the process ID from the Office |
| * @return the Id as String |
| */ |
| private String getOfficeProcessID() |
| { |
| String sProcessIdCommand = FileHelper.appendPath(m_aTempDir.getTempDir(), "getPS"); |
| final String sofficeArg = org.openoffice.test.Argument.get("soffice"); |
| final String sPSGrep = "ps -ef | grep $USER | grep <soffice>.bin | grep -v grep"; |
| final String sProcessId = sPSGrep.replaceAll("<soffice>", FileHelper.getJavaCompatibleFilename(sofficeArg)); |
| |
| createExecutableFile(sProcessIdCommand, sProcessId); |
| ProcessHandler processID = new ProcessHandler(sProcessIdCommand); |
| processID.noOutput(); |
| processID.executeSynchronously(); |
| String text = processID.getOutputText(); |
| if (text == null || text.equals("") || text.indexOf(' ') == -1) |
| { |
| fail("Could not determine Office process ID. Check " + sProcessIdCommand); |
| } |
| StringTokenizer aToken = new StringTokenizer(text); |
| // this is not nice, but ps gives the same output on every machine |
| aToken.nextToken(); |
| String id = aToken.nextToken(); |
| return id; |
| } |
| |
| /** |
| * Get the memory usage of the Office in KByte. |
| * @return The memory used by the Office. |
| */ |
| private int getOfficeMemoryUsage(String _sMode) |
| { |
| final String sMemoryMonitor = "pmap <processID> |tee <pmapoutputfile> | grep total"; |
| String sOfficeMemoryCommand = null; |
| sOfficeMemoryCommand = FileHelper.appendPath(m_aTempDir.getTempDir(), "getPmap"); |
| // sOfficeMemoryCommand = FileHelper.getJavaCompatibleFilename(sOfficeMemoryCommand); |
| String command = sMemoryMonitor.replaceAll("<processID>", getOfficeProcessID()); |
| String sPmapOutputFile = FileHelper.appendPath(m_aTempDir.getTempDir(), "pmap_" + _sMode + ".txt"); |
| command = command.replaceAll("<pmapoutputfile>", sPmapOutputFile); |
| createExecutableFile(sOfficeMemoryCommand, command); |
| |
| ProcessHandler processID = new ProcessHandler(sOfficeMemoryCommand); |
| processID.noOutput(); |
| processID.executeSynchronously(); |
| int nError = processID.getExitCode(); |
| assertTrue("Execute of " + sOfficeMemoryCommand + " failed", nError == 0); |
| String text = processID.getOutputText(); |
| if (text == null || text.equals("") || text.indexOf(' ') == -1) |
| { |
| fail("Could not determine Office memory usage. Check " + sOfficeMemoryCommand); |
| } |
| StringTokenizer aToken = new StringTokenizer(text); |
| // this works, because the output of pmap is quite standardized. |
| aToken.nextToken(); |
| String mem = aToken.nextToken(); |
| mem = mem.substring(0, mem.indexOf('K')); |
| Integer memory = new Integer(mem); |
| return memory.intValue(); |
| } |
| |
| /** |
| * Write a script file and set its rights to rwxrwxrwx. |
| * @param fileName The name of the created file |
| * @param line The commandline that has to be written inside of the file. |
| */ |
| private void createExecutableFile(String fileName, String line) |
| { |
| final String sChmod = "chmod a+x "; |
| final String bash = "#!/bin/bash"; |
| |
| try |
| { |
| String sFilename = FileHelper.getJavaCompatibleFilename(fileName); |
| PrintWriter fWriter = new PrintWriter(new FileWriter(sFilename)); |
| fWriter.println(bash); |
| fWriter.println(line); |
| fWriter.close(); |
| // change rights to rwxrwxrwx |
| ProcessHandler processID = new ProcessHandler(sChmod + sFilename); |
| processID.noOutput(); |
| processID.executeSynchronously(); |
| int nError = processID.getExitCode(); |
| assertTrue("chmod failed. ", nError == 0); |
| } |
| catch (java.io.IOException e) |
| { |
| } |
| } |
| } |
| |
| /** |
| * Let this thread sleep for some time |
| * @param milliSeconds time to wait in milliseconds. |
| */ |
| public static void shortWait(int milliSeconds) |
| { |
| System.out.println("Wait for: " + milliSeconds + "ms"); |
| try |
| { |
| Thread.sleep(milliSeconds); |
| } |
| catch (java.lang.InterruptedException e) |
| { // ignore |
| } |
| } |
| |
| /** |
| * Own file filter, will just return ok for all files that end with a given |
| * suffix |
| */ |
| private class FileFilter implements FilenameFilter |
| { |
| |
| private String suffix = null; |
| |
| /** |
| * C'tor. |
| * @param suffix The suffix each filename should end with. |
| */ |
| public FileFilter(String suffix) |
| { |
| this.suffix = suffix; |
| } |
| |
| /** |
| * Returns true, if the name of the file has the suffix given to the |
| * c'tor. |
| * @param name The filename that is tested. |
| * @param file Not used. |
| * @return True, if name ends with suffix. |
| */ |
| public boolean accept(File file, String name) |
| { |
| return name.endsWith(suffix); |
| } |
| } |
| |
| private XMultiServiceFactory getMSF() |
| { |
| final XMultiServiceFactory xMSF1 = UnoRuntime.queryInterface(XMultiServiceFactory.class, connection.getComponentContext().getServiceManager()); |
| return xMSF1; |
| } |
| |
| // setup and close connections |
| @BeforeClass |
| public static void setUpConnection() throws Exception |
| { |
| System.out.println("setUpConnection()"); |
| connection.setUp(); |
| } |
| |
| @AfterClass |
| public static void tearDownConnection() |
| throws InterruptedException, com.sun.star.uno.Exception |
| { |
| System.out.println("tearDownConnection()"); |
| connection.tearDown(); |
| } |
| private static final OfficeConnection connection = new OfficeConnection(); |
| } |