001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.perftest;
043:
044: import java.awt.image.BufferedImage;
045: import java.io.File;
046: import java.io.IOException;
047: import java.util.Enumeration;
048: import java.util.jar.JarEntry;
049: import java.util.jar.JarFile;
050: import junit.framework.*;
051: import java.util.Map;
052: import java.util.SortedMap;
053: import java.util.SortedSet;
054: import java.util.TreeMap;
055: import java.util.TreeSet;
056: import java.util.logging.Level;
057: import java.util.logging.Logger;
058: import javax.imageio.ImageIO;
059: import javax.imageio.ImageReadParam;
060: import javax.imageio.ImageReader;
061: import javax.imageio.stream.ImageInputStream;
062: import org.netbeans.*;
063: import org.netbeans.junit.NbTestCase;
064: import org.netbeans.junit.NbTestSuite;
065:
066: /** Tests for resources contained in modules.
067: *
068: * @author radim
069: */
070: public class ResourcesTest extends NbTestCase {
071:
072: // TODO the idea is to check for duplicates
073: // for patterns that are not effective in NB environment
074: private Logger LOG;
075:
076: public ResourcesTest(String testName) {
077: super (testName);
078: }
079:
080: public static Test suite() {
081: TestSuite suite = new NbTestSuite(ResourcesTest.class);
082:
083: return suite;
084: }
085:
086: @Override
087: protected Level logLevel() {
088: return Level.INFO;
089: }
090:
091: protected void setUp() throws Exception {
092: LOG = Logger.getLogger("TEST-" + getName());
093:
094: super .setUp();
095: }
096:
097: /** If package contains only one resource it is not too frendly to our classloaders.
098: * Generally not a big problem OTOH we want to avoid this if this is simple.
099: */
100: public void testOneInPackage() throws Exception {
101: SortedSet<Violation> violations = new TreeSet<Violation>();
102: for (File f : org.netbeans.core.startup.Main.getModuleSystem()
103: .getModuleJars()) {
104: // check JAR files only
105: if (!f.getName().endsWith(".jar"))
106: continue;
107:
108: // ignore branding
109: if (f.getName().endsWith("_nb.jar"))
110: continue;
111:
112: // a lot of alarms for 3rd party JARs
113: if (f.getName().contains("modules/ext/"))
114: continue;
115:
116: SortedMap<String, Integer> resourcesPerPackage = new TreeMap<String, Integer>();
117: JarFile jar = new JarFile(f);
118: Enumeration<JarEntry> entries = jar.entries();
119: JarEntry entry;
120: int entryCount = 0;
121: while (entries.hasMoreElements()) {
122: entry = entries.nextElement();
123: if (entry.isDirectory())
124: continue;
125:
126: String name = entry.getName();
127: String prefix = (name.lastIndexOf('/') >= 0) ? name
128: .substring(0, name.lastIndexOf('/')) : "";
129: if (prefix.startsWith("META-INF")
130: || prefix.startsWith("1.0/")
131: || prefix.startsWith("com/")
132: || prefix.startsWith("javax/")
133: || prefix.startsWith("freemarker/")
134: || prefix.startsWith("org/apache/tomcat")
135: || prefix.startsWith("org/apache/lucene")
136: || prefix.startsWith("org/w3c/")
137: // || prefix.startsWith("")
138: || prefix
139: .startsWith("org/netbeans/modules/openide/actions")
140: || prefix
141: .startsWith("org/netbeans/modules/openide/awt")
142: || prefix
143: .startsWith("org/netbeans/modules/openide/windows")
144: || prefix
145: .startsWith("org/openide/explorer/propertysheet") // in deprecated core/settings
146: || prefix.startsWith("org/openide/io")
147: || prefix.startsWith("org/netbeans/api")
148: || prefix.startsWith("org/netbeans/spi")
149: || prefix
150: .startsWith("org/netbeans/core/execution/beaninfo")
151: || prefix
152: .startsWith("org/netbeans/modules/web/monitor")
153: || prefix.matches("org/netbeans/.*/[as]pi.*")) {
154: continue;
155: }
156:
157: entryCount++;
158: Integer count = resourcesPerPackage.get(prefix);
159: if (count != null) {
160: resourcesPerPackage.put(prefix, count + 1);
161: } else {
162: resourcesPerPackage.put(prefix, 1);
163: }
164: }
165: if (entryCount > 1) { // filter library wrappes (they have only Bundle.properties)
166: for (Map.Entry<String, Integer> pkgInfo : resourcesPerPackage
167: .entrySet()) {
168: if (pkgInfo.getValue().equals(1)) {
169: violations.add(new Violation(pkgInfo.getKey(),
170: jar.getName(),
171: " has package with just one resource"));
172: }
173: }
174: }
175: }
176: if (!violations.isEmpty()) {
177: StringBuilder msg = new StringBuilder();
178: msg
179: .append("Some JARs in IDE contains sparsely populated packages ("
180: + violations.size() + "):\n");
181: for (Violation viol : violations) {
182: msg.append(viol).append('\n');
183: }
184: fail(msg.toString());
185: }
186: // assertTrue (entry.toString()+" should have line number table", v.foundLineNumberTable());
187: }
188:
189: /** Historically we had problems with some images.
190: */
191: public void testImageCanBeRead() throws Exception {
192: ImageIO.setUseCache(false);
193: ImageReader PNG_READER = ImageIO.getImageReadersByMIMEType(
194: "image/png").next();
195: ImageReader GIF_READER = ImageIO.getImageReadersByMIMEType(
196: "image/gif").next();
197:
198: SortedSet<Violation> violations = new TreeSet<Violation>();
199: for (File f : org.netbeans.core.startup.Main.getModuleSystem()
200: .getModuleJars()) {
201: // check JAR files only
202: if (!f.getName().endsWith(".jar"))
203: continue;
204:
205: JarFile jar = new JarFile(f);
206: Enumeration<JarEntry> entries = jar.entries();
207: JarEntry entry;
208: BufferedImage img;
209: while (entries.hasMoreElements()) {
210: entry = entries.nextElement();
211: if (entry.isDirectory())
212: continue;
213:
214: String name = entry.getName();
215: if (!name.endsWith(".gif") && !name.endsWith(".png")) {
216: continue;
217: }
218: try {
219: img = ImageIO.read(jar.getInputStream(entry));
220: } catch (IOException ioe) {
221: violations.add(new Violation(name, jar.getName(),
222: " cannot be read"));
223: continue;
224: } catch (IndexOutOfBoundsException ioobe) {
225: violations.add(new Violation(name, jar.getName(),
226: " cannot be read"));
227: continue;
228: }
229: // more aggressive way - use reader matching to file extension
230: if (name.endsWith(".png")) {
231: ImageInputStream stream = ImageIO
232: .createImageInputStream(jar
233: .getInputStream(entry));
234: ImageReadParam param = PNG_READER
235: .getDefaultReadParam();
236: try {
237: PNG_READER.setInput(stream, true, true);
238: img = PNG_READER.read(0, param);
239: } catch (IOException ioe1) {
240: violations.add(new Violation(name, jar
241: .getName(), "Not a PNG image"));
242: continue;
243: }
244: stream.close();
245: } else if (name.endsWith(".gif")) {
246: ImageInputStream stream = ImageIO
247: .createImageInputStream(jar
248: .getInputStream(entry));
249: ImageReadParam param = GIF_READER
250: .getDefaultReadParam();
251: try {
252: GIF_READER.setInput(stream, true, true);
253: img = GIF_READER.read(0, param);
254: } catch (IOException ioe1) {
255: violations.add(new Violation(name, jar
256: .getName(), "Not a GIF image"));
257: continue;
258: }
259: stream.close();
260: }
261: }
262: }
263: if (!violations.isEmpty()) {
264: StringBuilder msg = new StringBuilder();
265: msg.append("Some images in IDE have problems ("
266: + violations.size() + "):\n");
267: for (Violation viol : violations) {
268: msg.append(viol).append('\n');
269: }
270: fail(msg.toString());
271: }
272: // assertTrue (entry.toString()+" should have line number table", v.foundLineNumberTable());
273: }
274:
275: private static class Violation implements Comparable<Violation> {
276: String entry;
277: String jarFile;
278: String comment;
279:
280: Violation(String entry, String jarFile, String comment) {
281: this .entry = entry;
282: this .jarFile = jarFile;
283: this .comment = comment;
284: }
285:
286: public int compareTo(Violation v2) {
287: String second = v2.entry + v2.jarFile;
288: return (entry + jarFile).compareTo(second);
289: }
290:
291: @Override
292: public String toString() {
293: return comment + ": " + entry + " in " + jarFile;
294: }
295: }
296:
297: /** Too large or too small (empty) files are suspicious.
298: * There should be just couple of them: splash image
299: */
300: public void testUnusualFileSize() throws Exception {
301: SortedSet<Violation> violations = new TreeSet<Violation>();
302: for (File f : org.netbeans.core.startup.Main.getModuleSystem()
303: .getModuleJars()) {
304: // check JAR files only
305: if (!f.getName().endsWith(".jar"))
306: continue;
307:
308: JarFile jar = new JarFile(f);
309: Enumeration<JarEntry> entries = jar.entries();
310: JarEntry entry;
311: BufferedImage img;
312: while (entries.hasMoreElements()) {
313: entry = entries.nextElement();
314: if (entry.isDirectory())
315: continue;
316:
317: long len = entry.getSize();
318: if (len >= 0 && len < 10) {
319: violations.add(new Violation(entry.getName(), jar
320: .getName(), " is too small (" + len
321: + " bytes)"));
322: }
323: if (len >= 200 * 1024) {
324: violations.add(new Violation(entry.getName(), jar
325: .getName(), " is too large (" + len
326: + " bytes)"));
327: }
328: }
329: }
330: if (!violations.isEmpty()) {
331: StringBuilder msg = new StringBuilder();
332: msg.append("Some files have extreme size ("
333: + violations.size() + "):\n");
334: for (Violation viol : violations) {
335: msg.append(viol).append('\n');
336: }
337: fail(msg.toString());
338: }
339: }
340:
341: /** Scan for accidentally commited files that get into product
342: */
343: public void testInappropraiteEntries() throws Exception {
344: SortedSet<Violation> violations = new TreeSet<Violation>();
345: for (File f : org.netbeans.core.startup.Main.getModuleSystem()
346: .getModuleJars()) {
347: // check JAR files only
348: if (!f.getName().endsWith(".jar"))
349: continue;
350:
351: if (!f.getName().endsWith("cssparser-0-9-4-fs.jar")) // #108644
352: continue;
353:
354: JarFile jar = new JarFile(f);
355: Enumeration<JarEntry> entries = jar.entries();
356: JarEntry entry;
357: BufferedImage img;
358: while (entries.hasMoreElements()) {
359: entry = entries.nextElement();
360: if (entry.isDirectory())
361: continue;
362:
363: if (entry.getName().endsWith("Thumbs.db")) {
364: violations
365: .add(new Violation(entry.getName(), jar
366: .getName(),
367: " should not be in module JAR"));
368: }
369: if (entry.getName().contains("nbproject/private")) {
370: violations
371: .add(new Violation(entry.getName(), jar
372: .getName(),
373: " should not be in module JAR"));
374: }
375: }
376: }
377: if (!violations.isEmpty()) {
378: StringBuilder msg = new StringBuilder();
379: msg.append("Some files does not belong to module JARs ("
380: + violations.size() + "):\n");
381: for (Violation viol : violations) {
382: msg.append(viol).append('\n');
383: }
384: fail(msg.toString());
385: }
386: }
387: }
|