1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: CheckMemoryUsage.java,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
30 package complex
.memCheck
;
32 import com
.sun
.star
.beans
.PropertyValue
;
33 import com
.sun
.star
.frame
.XStorable
;
34 import com
.sun
.star
.lang
.XComponent
;
35 import com
.sun
.star
.lang
.XMultiServiceFactory
;
36 import com
.sun
.star
.uno
.UnoRuntime
;
37 import com
.sun
.star
.util
.XCloseable
;
38 import complexlib
.ComplexTestCase
;
39 import helper
.ProcessHandler
;
41 import java
.io
.FilePermission
;
42 import java
.io
.FileWriter
;
43 import java
.io
.FilenameFilter
;
44 import java
.io
.PrintWriter
;
45 import java
.util
.Enumeration
;
46 import java
.util
.StringTokenizer
;
47 import java
.util
.Vector
;
48 import util
.DesktopTools
;
49 import util
.WriterTools
;
53 * Documents are opened and exported with StarOffice. The memory usage of
54 * StarOffice is monitored and if the usage exceeds the allowed kilobytes,
55 * the test is failed. Used for monitoring the StarOffice process is the
56 * command line tool 'pmap', available on Solaris or Linux. This test will not
57 * run on Windows.<br>Test procedure: every given document type is searched in
58 * the source directory
61 * <li>"TestDocumentPath" - the path where test documents are located.</li>
62 * <li>"AllowMemoryIncrease" (optional) - the allowed memory increase measured in kByte per exported document. The default is 10 kByte.</li>
63 * <li>"ExportDocCount" (optional) - the amount of exports for each document that is loaded. Is defaulted to 25.
64 * <li>"FileExportFilter" (optional) - a relation between loaded document type and used export filter. Is defaulted to
65 * writer, calc and impress. This parameter can be set with a number to give more than one relation. Example:<br>
66 * "FileExportFilter1=sxw,writer_pdf_Export"<br>
67 * "FileExportFilter2=sxc,calc_pdf_Export"<br>
68 * "FileExportFilter3=sxi,impress_pdf_Export"<br></li>
69 * All parameters are used for iteration over the test document path.
72 public class CheckMemoryUsage
extends ComplexTestCase
{
73 private final String sWriterDoc
= "sxw,writer_pdf_Export";
74 private final String sCalcDoc
= "sxc,calc_pdf_Export";
75 private final String sImpressDoc
= "sxi,impress_pdf_Export";
76 private String sProcessId
= "ps -ef | grep $USER | grep soffice | grep -v grep";
77 private String sMemoryMonitor
= "pmap <processID> | grep total";
78 private String sChmod
= "chmod 777 ";
79 private String sProcessIdCommand
= null;
80 private String sOfficeMemoryCommand
= null;
81 private String sTempDir
= null;
82 private String sFS
= null;
83 private String sMemoryMap1
= null;
84 private String sMemoryMap2
= null;
85 private String bash
= "#!/bin/bash";
86 private String sDocumentPath
= "";
87 private String
[][] sDocTypeExportFilter
;
88 private String
[][] sDocuments
;
89 private int iAllowMemoryIncrease
= 10;
90 private int iExportDocCount
= 25;
93 * Get all test methods
94 * @return The test methods.
96 public String
[] getTestMethodNames() {
97 return new String
[] {"loadAndSaveDocuments"};
101 * Collect all documnets to load and all filters used for export.
103 public void before() {
104 // test does definitely not run on Windows.
105 if (param
.get("OperatingSystem").equals("wntmsci")) {
106 log
.println("Test can only reasonably be executed with a tool that "
107 + "displays the memory usage of StarOffice.");
108 failed("Test does not run on Windows, only on Solaris or Linux.");
111 // how many times is every document exported.
112 int count
= param
.getInt("ExportDocCount");
114 iExportDocCount
= count
;
116 // get the temp dir for creating the command scripts.
117 sTempDir
= System
.getProperty("java.io.tmpdir");
118 sProcessIdCommand
= sTempDir
+ "getPS";
119 sOfficeMemoryCommand
= sTempDir
+ "getPmap";
121 // get the file extension, export filter connection
122 Enumeration keys
= param
.keys();
123 Vector v
= new Vector();
124 while(keys
.hasMoreElements()) {
125 String key
= (String
)keys
.nextElement();
126 if (key
.startsWith("FileExportFilter")) {
127 v
.add(param
.get(key
));
130 // if no param given, set defaults.
136 // store a file extension
137 sDocTypeExportFilter
= new String
[v
.size()][2];
138 for (int i
=0; i
<v
.size(); i
++) {
139 // 2do: error routine for wrong given params
140 StringTokenizer t
= new StringTokenizer((String
)v
.get(i
), ",");
141 sDocTypeExportFilter
[i
][0] = t
.nextToken();
142 sDocTypeExportFilter
[i
][1] = t
.nextToken();
145 // get files to load and export
146 sDocumentPath
= (String
)param
.get("TestDocumentPath");
147 File f
= new File(sDocumentPath
);
148 sDocumentPath
= f
.getAbsolutePath();
149 String sFS
= System
.getProperty("file.separator");
150 sDocuments
= new String
[sDocTypeExportFilter
.length
][];
151 for (int j
=0; j
<sDocTypeExportFilter
.length
; j
++) {
152 FileFilter filter
= new FileFilter(sDocTypeExportFilter
[j
][0]);
153 String
[] doc
= f
.list(filter
);
154 sDocuments
[j
] = new String
[doc
.length
];
155 for (int i
=0; i
<doc
.length
; i
++) {
156 if (sDocumentPath
.endsWith(sFS
))
157 sDocuments
[j
][i
] = sDocumentPath
+ doc
[i
];
159 sDocuments
[j
][i
] = sDocumentPath
+ sFS
+ doc
[i
];
160 sDocuments
[j
][i
] = utils
.getFullURL(sDocuments
[j
][i
]);
166 * delete all created files on disk
168 public void after() {
169 // delete the constructed files.
170 for (int i
=0; i
<iExportDocCount
; i
++) {
171 File f
= new File(sTempDir
+ "DocExport" + i
+ ".pdf");
174 File f
= new File(sProcessIdCommand
);
176 f
= new File(sOfficeMemoryCommand
);
181 * Thet etst function: load documents and save them using the given filters
182 * for each given document type.
184 public void loadAndSaveDocuments() {
185 int storageBefore
= getOfficeMemoryUsage();
187 XMultiServiceFactory xMSF
= (XMultiServiceFactory
)param
.getMSF();
189 // iterate over all document types
190 for (int k
=0; k
<sDocTypeExportFilter
.length
; k
++) {
191 // iterate over all documents of this type
192 for (int i
=0; i
<sDocuments
[k
].length
; i
++) {
193 System
.out
.println("Document: "+ sDocuments
[k
][i
]);
194 XComponent xComponent
= DesktopTools
.loadDoc(xMSF
, sDocuments
[k
][i
], null);
195 XStorable xStorable
= (XStorable
)UnoRuntime
.queryInterface(XStorable
.class, xComponent
);
196 if (xStorable
!= null) {
197 // export each document iExportDocCount times
198 for (int j
=0; j
<iExportDocCount
; j
++) {
199 String url
= utils
.getFullURL(sTempDir
+ "DocExport" + j
+ ".pdf");
201 PropertyValue
[] props
= new PropertyValue
[1];
202 props
[0] = new PropertyValue();
203 props
[0].Name
= "FilterName";
204 // use export filter for this doc type
205 props
[0].Value
= sDocTypeExportFilter
[k
][1];
206 xStorable
.storeToURL(url
, props
);
208 catch(com
.sun
.star
.io
.IOException e
) {
209 failed("Could not store to '" + url
+ "'", true);
213 XCloseable xCloseable
= (XCloseable
)UnoRuntime
.queryInterface(XCloseable
.class, xStorable
);
215 xCloseable
.close(true);
217 catch(com
.sun
.star
.util
.CloseVetoException e
) {
218 e
.printStackTrace((java
.io
.PrintWriter
)log
);
219 failed("Cannot close document: test is futile, Office will surely use more space.");
223 log
.println("Cannot query for XStorable interface on document '" + sDocuments
[i
] + "'");
224 log
.println(" -> Skipping storage.");
228 // short wait for the office to 'calm down' and free some memory
230 // wait util memory is not freed anymore.
231 int storageAfter
= getOfficeMemoryUsage();
234 while (storageAfter
!= mem
&& count
< 10) {
237 storageAfter
= getOfficeMemoryUsage();
240 assure("The Office consumes now " + (storageAfter
- storageBefore
)
241 + "K more memory than at the start of the test; allowed were "
242 + iAllowMemoryIncrease
* iExportDocCount
+ "K.",
243 storageAfter
- storageBefore
< iAllowMemoryIncrease
* iExportDocCount
);
248 * Get the process ID from the Office
249 * @return the Id as String
251 private String
getOfficeProcessID() {
252 writeExecutableFile(sProcessIdCommand
, sProcessId
);
253 ProcessHandler processID
= new ProcessHandler(sProcessIdCommand
);
254 processID
.executeSynchronously();
255 String text
= processID
.getOutputText();
256 if (text
== null || text
.equals("") || text
.indexOf(' ') == -1)
257 failed("Could not determine Office process ID. Check " + sProcessIdCommand
);
258 StringTokenizer aToken
= new StringTokenizer(text
);
259 // this is not nice, but ps gives the same output on every machine
261 String id
= aToken
.nextToken();
266 * Get the memory usage of the Office in KByte.
267 * @return The memory used by the Office.
269 private int getOfficeMemoryUsage() {
270 String command
= sMemoryMonitor
.replaceAll("<processID>", getOfficeProcessID());
271 writeExecutableFile(sOfficeMemoryCommand
, command
);
272 ProcessHandler processID
= new ProcessHandler(sOfficeMemoryCommand
);
273 processID
.executeSynchronously();
274 String text
= processID
.getOutputText();
275 if (text
== null || text
.equals("") || text
.indexOf(' ') == -1) {
276 failed("Could not determine Office memory usage. Check " + sOfficeMemoryCommand
);
278 StringTokenizer aToken
= new StringTokenizer(text
);
279 // this works, because the output of pmap is quite standardized.
281 String mem
= aToken
.nextToken();
282 mem
= mem
.substring(0, mem
.indexOf('K'));
283 Integer memory
= new Integer(mem
);
284 return memory
.intValue();
288 * Write a script file and set its rights to rwxrwxrwx.
289 * @param fileName The name of the created file
290 * @param line The commandline that has to be written inside of the file.
292 private void writeExecutableFile(String fileName
, String line
) {
294 PrintWriter fWriter
= new PrintWriter(new FileWriter(fileName
));
295 fWriter
.println(bash
);
296 fWriter
.println(line
);
298 // change rights to rwxrwxrwx
299 ProcessHandler processID
= new ProcessHandler(sChmod
+ fileName
);
300 processID
.executeSynchronously();
302 catch(java
.io
.IOException e
) {
307 * Let this thread sleep for some time
308 * @param milliSeconds time to wait in milliseconds.
310 private void shortWait(int milliSeconds
) {
312 Thread
.sleep(milliSeconds
);
314 catch(java
.lang
.InterruptedException e
) { // ignore
319 * Own file filter, will just return ok for all files that end with a given
322 private class FileFilter
implements FilenameFilter
{
323 private String suffix
= null;
326 * @param suffix The suffix each filename should end with.
328 public FileFilter(String suffix
) {
329 this.suffix
= suffix
;
332 * Returns true, if the name of the file has the suffix given to the
334 * @param name The filename that is tested.
335 * @param file Not used.
336 * @return True, if name ends with suffix.
338 public boolean accept(File file
, String name
) {
339 return name
.endsWith(suffix
);