Branch libreoffice-5-0-4
[LibreOffice.git] / vcl / qa / complex / memCheck / CheckMemoryUsage.java
blobbe221e02d63196f35538e2b2327836d500b0d5fd
1 /*
2 * This file is part of the LibreOffice project.
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 * This file incorporates work covered by the following license notice:
10 * Licensed to the Apache Software Foundation (ASF) under one or more
11 * contributor license agreements. See the NOTICE file distributed
12 * with this work for additional information regarding copyright
13 * ownership. The ASF licenses this file to you under the Apache
14 * License, Version 2.0 (the "License"); you may not use this file
15 * except in compliance with the License. You may obtain a copy of
16 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 package complex.memCheck;
20 import static org.junit.Assert.assertTrue;
21 import static org.junit.Assert.fail;
22 import helper.ProcessHandler;
24 import java.io.File;
25 import java.io.FileWriter;
26 import java.io.FilenameFilter;
27 import java.io.PrintWriter;
28 import java.util.StringTokenizer;
30 import lib.TestParameters;
32 import org.junit.After;
33 import org.junit.AfterClass;
34 import org.junit.Before;
35 import org.junit.BeforeClass;
36 import org.junit.Test;
37 import org.openoffice.test.OfficeConnection;
39 import util.DesktopTools;
40 import util.OSName;
41 import util.PropertyName;
43 import com.sun.star.beans.PropertyValue;
44 import com.sun.star.frame.XStorable;
45 import com.sun.star.lang.XComponent;
46 import com.sun.star.lang.XMultiServiceFactory;
47 import com.sun.star.uno.UnoRuntime;
48 import com.sun.star.util.XCloseable;
50 /**
51 * Documents are opened and exported with StarOffice. The memory usage of
52 * StarOffice is monitored and if the usage exceeds the allowed kilobytes,
53 * the test is failed. Used for monitoring the StarOffice process is the
54 * command line tool 'pmap', available on Solaris or Linux. This test will not
55 * run on Windows.<br>Test procedure: every given document type is searched in
56 * the source directory
57 * Needed parameters:
58 * <ul>
59 * <li>"TestDocumentPath" - the path where test documents are located.</li>
60 * All parameters are used for iteration over the test document path.
61 * </ul>
63 class TempDir
66 private final String m_sTempDir;
68 public TempDir(String _sTempDir)
70 m_sTempDir = _sTempDir;
73 public String getOfficeTempDir()
75 return m_sTempDir;
78 public String getTempDir()
80 final String sTempDir = FileHelper.getJavaCompatibleFilename(m_sTempDir);
81 return sTempDir;
85 public class CheckMemoryUsage
88 TempDir m_aTempDir;
89 private String[][] sDocTypeExportFilter;
90 private String[][] sDocuments;
91 // the allowed memory increase measured in kByte per exported document. The default is 10 kByte.
92 // the allowed memory increase per exported document: if the memory increase is higher than this number, the test will fail
93 private static final int iAllowMemoryIncrease = 10;
94 private int iExportDocCount = 25;
96 /**
97 * Collect all documents to load and all filters used for export.
99 @Before
100 public void before()
103 final XMultiServiceFactory xMsf = getMSF();
105 // some Tests need the qadevOOo TestParameters, it is like a Hashmap for Properties.
106 TestParameters param = new TestParameters();
107 param.put(PropertyName.SERVICE_FACTORY, xMsf); // some qadevOOo functions need the ServiceFactory
109 // test does definitely not run on Windows.
110 if (param.get(PropertyName.OPERATING_SYSTEM).equals(OSName.WNTMSCI))
112 System.out.println("Test can only reasonably be executed with a tool that "
113 + "displays the memory usage of StarOffice.");
114 System.out.println("Test does not run on Windows, only on Solaris or Linux.");
115 // in an automatic environment it is better to say, there is no error here.
116 // it is a limitation, but no error.
117 System.exit(0);
121 // how many times is every document exported.
122 // the amount of exported documents: each loaded document will be written 'ExportDocCount' times
123 iExportDocCount = 25;
125 // get the temp dir for creating the command scripts.
126 m_aTempDir = new TempDir(util.utils.getOfficeTemp/*Dir*/(xMsf));
128 // get the file extension, export filter connection
129 // the import and export filters
130 // store a file extension
131 sDocTypeExportFilter = new String[3][2];
132 sDocTypeExportFilter[0][0] = "sxw";
133 sDocTypeExportFilter[0][1] = "writer_pdf_Export";
134 sDocTypeExportFilter[1][0] = "sxc";
135 sDocTypeExportFilter[1][1] = "calc_pdf_Export";
136 sDocTypeExportFilter[2][0] = "sxi";
137 sDocTypeExportFilter[2][1] = "impress_pdf_Export";
139 // get files to load and export
140 String sDocumentPath = TestDocument.getUrl();
141 File f = new File(FileHelper.getJavaCompatibleFilename(sDocumentPath));
142 sDocuments = new String[sDocTypeExportFilter.length][];
143 for (int j = 0; j < sDocTypeExportFilter.length; j++)
145 FileFilter filter = new FileFilter(sDocTypeExportFilter[j][0]);
146 String[] doc = f.list(filter);
147 sDocuments[j] = new String[doc.length];
148 for (int i = 0; i < doc.length; i++)
150 sDocuments[j][i] = TestDocument.getUrl(doc[i]);
156 * delete all created files on disk
158 @After
159 public void after()
164 * The test function: load documents and save them using the given filters
165 * for each given document type.
167 @Test
168 public void loadAndSaveDocuments()
170 int nOk = 0;
171 int nRunThrough = 0;
173 // At first:
174 // we load the document, there will be some post work in office like late initialisations
175 // we store exact one time the document
176 // so the memory footprint should be right
178 // iterate over all document types
179 for (int k = 0; k < sDocTypeExportFilter.length; k++)
181 // iterate over all documents of this type
182 for (int i = 0; i < sDocuments[k].length; i++)
185 final String sDocument = sDocuments[k][i];
186 final String sExtension = sDocTypeExportFilter[k][1];
188 loadAndSaveNTimesDocument(sDocument, 1, sExtension);
191 System.out.println();
192 System.out.println();
195 System.out.println("Wait for: " + 10000 + "ms");
196 util.utils.pause(10000);
198 // Now the real test, load document and store 25 times
200 // iterate over all document types
201 for (int k = 0; k < sDocTypeExportFilter.length; k++)
203 // iterate over all documents of this type
204 for (int i = 0; i < sDocuments[k].length; i++)
207 final String sDocument = sDocuments[k][i];
208 final String sExtension = sDocTypeExportFilter[k][1];
210 OfficeMemchecker aChecker = new OfficeMemchecker();
211 aChecker.setDocumentName(FileHelper.getBasename(sDocument));
212 aChecker.setExtension(sExtension);
213 aChecker.start();
215 loadAndSaveNTimesDocument(sDocument, iExportDocCount, sExtension);
217 aChecker.stop();
218 final int nConsumMore = aChecker.getConsumMore();
220 nOk += checkMemory(nConsumMore);
221 nRunThrough++;
223 System.out.println();
224 System.out.println();
226 System.out.println("Find the output of used 'pmap' here: " + m_aTempDir.getTempDir() + " if test failed.");
227 assertTrue("Office consumes too many memory.", nOk == nRunThrough);
231 * Checks how much memory should consum
232 * @param storageBefore
233 * @return 1 if consum is ok, else 0
235 private int checkMemory(int nConsumMore)
237 int nAllowed = iAllowMemoryIncrease * iExportDocCount;
238 System.out.println("The Office consumes now " + nConsumMore
239 + "K more memory than at the start of the test; allowed were "
240 + nAllowed + "K.");
241 if (nConsumMore > nAllowed)
243 System.out.println("ERROR: This is not allowed.");
244 return 0;
246 System.out.println("OK.");
247 return 1;
251 * load and save exact one document
253 private void loadAndSaveNTimesDocument(String _sDocument, int _nCount, String _sStoreExtension)
255 System.out.println("Document: " + _sDocument);
256 XComponent xComponent = DesktopTools.loadDoc(getMSF(), _sDocument, null);
257 XStorable xStorable = UnoRuntime.queryInterface(XStorable.class, xComponent);
258 if (xStorable != null)
260 // export each document iExportDocCount times
261 for (int j = 0; j < _nCount; j++)
263 final String sDocumentName = FileHelper.getBasename(_sDocument) + "_" + j + ".pdf";
264 final String sFilename = FileHelper.appendPath(m_aTempDir.getOfficeTempDir(), sDocumentName);
265 String url = sFilename; // graphical.FileHelper.getFileURLFromSystemPath(sFilename);
268 PropertyValue[] props = new PropertyValue[1];
269 props[0] = new PropertyValue();
270 props[0].Name = "FilterName";
271 // use export filter for this doc type
272 props[0].Value = _sStoreExtension;
273 xStorable.storeToURL(url, props);
275 catch (com.sun.star.io.IOException e)
277 fail("Could not store to '" + url + "'");
280 // close the doc
281 XCloseable xCloseable = UnoRuntime.queryInterface(XCloseable.class, xStorable);
284 xCloseable.close(true);
286 catch (com.sun.star.util.CloseVetoException e)
288 e.printStackTrace();
289 fail("Cannot close document: test is futile, Office will surely use more space.");
292 else
294 System.out.println("Cannot query for XStorable interface on document '" + _sDocument + "'");
295 System.out.println(" -> Skipping storage.");
301 private class OfficeMemchecker
305 * After called start() it contains the memory need at startup
307 private int m_nMemoryStart;
309 * After called stop() it contains the memory usage
311 private int m_nMemoryUsage;
312 private String m_sDocumentName;
313 private String m_sExtension;
315 public OfficeMemchecker()
317 m_nMemoryStart = 0;
320 public void setDocumentName(String _sDocName)
322 m_sDocumentName = _sDocName;
325 public void setExtension(String _sExt)
327 m_sExtension = _sExt;
330 public void start()
332 m_nMemoryStart = getOfficeMemoryUsage(createModeName("start", 0));
335 private String createModeName(String _sSub, int _nCount)
337 StringBuffer aBuf = new StringBuffer();
338 aBuf.append(_sSub);
339 aBuf.append('_').append(m_sDocumentName).append('_').append(m_sExtension);
340 aBuf.append('_').append(_nCount);
341 return aBuf.toString();
344 public void stop()
346 // short wait for the office to 'calm down' and free some memory
347 System.out.println("Wait for: " + 20000 + "ms");
348 util.utils.pause(20000);
349 // wait util memory is not freed anymore.
350 int storageAfter = getOfficeMemoryUsage(createModeName("stop", 0));
351 int mem = 0;
352 int count = 0;
353 while (storageAfter != mem && count < 10)
355 count++;
356 mem = storageAfter;
357 storageAfter = getOfficeMemoryUsage(createModeName("stop", count));
358 System.out.println("Wait for: " + 1000 + "ms");
359 util.utils.pause(1000);
361 m_nMemoryUsage = (storageAfter - m_nMemoryStart);
364 public int getConsumMore()
366 return m_nMemoryUsage;
370 * Get the process ID from the Office
371 * @return the Id as String
373 private String getOfficeProcessID()
375 String sProcessIdCommand = FileHelper.appendPath(m_aTempDir.getTempDir(), "getPS");
376 final String sofficeArg = org.openoffice.test.Argument.get("soffice");
377 final String sPSGrep = "ps -ef | grep $USER | grep <soffice>.bin | grep -v grep";
378 final String sProcessId = sPSGrep.replaceAll("<soffice>", FileHelper.getJavaCompatibleFilename(sofficeArg));
380 createExecutableFile(sProcessIdCommand, sProcessId);
381 ProcessHandler processID = new ProcessHandler(sProcessIdCommand);
382 processID.noOutput();
383 processID.executeSynchronously();
384 String text = processID.getOutputText();
385 if (text == null || text.equals("") || text.indexOf(' ') == -1)
387 fail("Could not determine Office process ID. Check " + sProcessIdCommand);
389 StringTokenizer aToken = new StringTokenizer(text);
390 // this is not nice, but ps gives the same output on every machine
391 aToken.nextToken();
392 String id = aToken.nextToken();
393 return id;
397 * Get the memory usage of the Office in KByte.
398 * @return The memory used by the Office.
400 private int getOfficeMemoryUsage(String _sMode)
402 final String sMemoryMonitor = "pmap <processID> |tee <pmapoutputfile> | grep total";
403 String sOfficeMemoryCommand = null;
404 sOfficeMemoryCommand = FileHelper.appendPath(m_aTempDir.getTempDir(), "getPmap");
405 String command = sMemoryMonitor.replaceAll("<processID>", getOfficeProcessID());
406 String sPmapOutputFile = FileHelper.appendPath(m_aTempDir.getTempDir(), "pmap_" + _sMode + ".txt");
407 command = command.replaceAll("<pmapoutputfile>", sPmapOutputFile);
408 createExecutableFile(sOfficeMemoryCommand, command);
410 ProcessHandler processID = new ProcessHandler(sOfficeMemoryCommand);
411 processID.noOutput();
412 processID.executeSynchronously();
413 int nError = processID.getExitCode();
414 assertTrue("Execute of " + sOfficeMemoryCommand + " failed", nError == 0);
415 String text = processID.getOutputText();
416 if (text == null || text.equals("") || text.indexOf(' ') == -1)
418 fail("Could not determine Office memory usage. Check " + sOfficeMemoryCommand);
420 StringTokenizer aToken = new StringTokenizer(text);
421 // this works, because the output of pmap is quite standardized.
422 aToken.nextToken();
423 String mem = aToken.nextToken();
424 mem = mem.substring(0, mem.indexOf('K'));
425 Integer memory = Integer.valueOf(mem);
426 return memory.intValue();
430 * Write a script file and set its rights to rwxrwxrwx.
431 * @param fileName The name of the created file
432 * @param line The commandline that has to be written inside of the file.
434 private void createExecutableFile(String fileName, String line)
436 final String sChmod = "chmod a+x ";
437 final String bash = "#!/bin/bash";
441 String sFilename = FileHelper.getJavaCompatibleFilename(fileName);
442 PrintWriter fWriter = new PrintWriter(new FileWriter(sFilename));
443 fWriter.println(bash);
444 fWriter.println(line);
445 fWriter.close();
446 // change rights to rwxrwxrwx
447 ProcessHandler processID = new ProcessHandler(sChmod + sFilename);
448 processID.noOutput();
449 processID.executeSynchronously();
450 int nError = processID.getExitCode();
451 assertTrue("chmod failed. ", nError == 0);
453 catch (java.io.IOException e)
460 * Own file filter, will just return ok for all files that end with a given
461 * suffix
463 private class FileFilter implements FilenameFilter
466 private final String suffix;
469 * C'tor.
470 * @param suffix The suffix each filename should end with.
472 public FileFilter(String suffix)
474 this.suffix = suffix;
478 * Returns true, if the name of the file has the suffix given to the
479 * c'tor.
480 * @param name The filename that is tested.
481 * @param file Not used.
482 * @return True, if name ends with suffix.
484 public boolean accept(File file, String name)
486 return name.endsWith(suffix);
490 private XMultiServiceFactory getMSF()
492 return UnoRuntime.queryInterface(XMultiServiceFactory.class, connection.getComponentContext().getServiceManager());
495 // setup and close connections
496 @BeforeClass
497 public static void setUpConnection() throws Exception
499 System.out.println("setUpConnection()");
500 connection.setUp();
503 @AfterClass
504 public static void tearDownConnection()
505 throws InterruptedException, com.sun.star.uno.Exception
507 System.out.println("tearDownConnection()");
508 connection.tearDown();
510 private static final OfficeConnection connection = new OfficeConnection();