1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with this
4 * work for additional information regarding copyright ownership. The ASF
5 * licenses this file to You under the Apache License, Version 2.0 (the
6 * "License"); you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 * License for the specific language governing permissions and limitations under
15 * the License.
16 */
17
18package org.apache.harmony.archive.tests.java.util.jar;
19
20import dalvik.annotation.KnownFailure;
21import dalvik.annotation.TestLevel;
22import dalvik.annotation.TestTargetClass;
23import dalvik.annotation.TestTargetNew;
24import static tests.support.Support_Exec.execAndGetOutput;
25import static tests.support.Support_Exec.javaProcessBuilder;
26import tests.support.resource.Support_Resources;
27
28import java.io.File;
29import java.io.FileInputStream;
30import java.io.FileOutputStream;
31import java.io.IOException;
32import java.util.jar.Attributes;
33import java.util.jar.JarEntry;
34import java.util.jar.JarOutputStream;
35import java.util.jar.Manifest;
36
37/**
38 *
39 * tests for various cases of java -jar ... execution
40 *
41 */
42
43@TestTargetClass(JarOutputStream.class)
44public class JarExecTest extends junit.framework.TestCase {
45    /**
46     * regression test for HARMONY-1562 issue
47     *
48     */
49    @TestTargetNew(
50        level = TestLevel.ADDITIONAL,
51        notes = "Regression functional test. Exception checking missed.",
52        method = "putNextEntry",
53        args = {java.util.zip.ZipEntry.class}
54    )
55    @KnownFailure("Maybe not a failure, but dalvikvm -jar is not supported (, as yet).")
56    public void test_1562() throws Exception {
57        // create the manifest
58        Manifest man = new Manifest();
59        Attributes att = man.getMainAttributes();
60        att.put(Attributes.Name.MANIFEST_VERSION, "1.0");
61        att.put(Attributes.Name.MAIN_CLASS, "foo.bar.execjartest.Foo");
62
63        File outputJar = File.createTempFile("hyts_", ".jar");
64        outputJar.deleteOnExit();
65        JarOutputStream jout = new JarOutputStream(new FileOutputStream(
66                outputJar), man);
67        File resources = Support_Resources.createTempFolder();
68
69        for (String jarClass : new String[] {"Foo", "Bar"}) {
70            jout.putNextEntry(new JarEntry("foo/bar/execjartest/" + jarClass
71                    + ".class"));
72            jout.write(getResource(resources, "hyts_" + jarClass + ".ser"));
73        }
74
75        jout.close();
76
77        // execute the JAR and read the result
78        ProcessBuilder builder = javaProcessBuilder();
79        builder.command().add("-jar");
80        builder.command().add(outputJar.getAbsolutePath());
81        assertTrue("Error executing JAR",
82                execAndGetOutput(builder).startsWith("FOOBAR"));
83    }
84
85    /**
86     * tests Class-Path entry in manifest
87     *
88     * @throws Exception in case of troubles
89     */
90    @TestTargetNew(
91        level = TestLevel.ADDITIONAL,
92        notes = "Functional test.",
93        method = "JarOutputStream",
94        args = {java.io.OutputStream.class, java.util.jar.Manifest.class}
95    )
96    @KnownFailure("Maybe not a failure, but dalvikvm -jar is not supported (, as yet).")
97    public void test_jar_class_path() throws Exception {
98        File fooJar = File.createTempFile("hyts_", ".jar");
99        File barJar = File.createTempFile("hyts_", ".jar");
100        fooJar.deleteOnExit();
101        barJar.deleteOnExit();
102
103        // create the manifest
104        Manifest man = new Manifest();
105        Attributes att = man.getMainAttributes();
106        att.put(Attributes.Name.MANIFEST_VERSION, "1.0");
107        att.put(Attributes.Name.MAIN_CLASS, "foo.bar.execjartest.Foo");
108        att.put(Attributes.Name.CLASS_PATH, barJar.getName());
109
110        File resources = Support_Resources.createTempFolder();
111
112        JarOutputStream joutFoo = new JarOutputStream(new FileOutputStream(
113                fooJar), man);
114        joutFoo.putNextEntry(new JarEntry("foo/bar/execjartest/Foo.class"));
115        joutFoo.write(getResource(resources, "hyts_Foo.ser"));
116        joutFoo.close();
117
118        JarOutputStream joutBar = new JarOutputStream(new FileOutputStream(
119                barJar));
120        joutBar.putNextEntry(new JarEntry("foo/bar/execjartest/Bar.class"));
121        joutBar.write(getResource(resources, "hyts_Bar.ser"));
122        joutBar.close();
123
124        // execute the JAR and read the result
125        ProcessBuilder builder = javaProcessBuilder();
126        builder.command().add("-jar");
127        builder.command().add(fooJar.getAbsolutePath());
128        assertTrue("Error executing JAR",
129                execAndGetOutput(builder).startsWith("FOOBAR"));
130
131        // rewrite manifest so it contains not only reference to bar but useless
132        // entries as well
133        att.put(Attributes.Name.CLASS_PATH, "xx yy zz " + barJar.getName());
134        joutFoo = new JarOutputStream(new FileOutputStream(fooJar), man);
135        joutFoo.putNextEntry(new JarEntry("foo/bar/execjartest/Foo.class"));
136        joutFoo.write(getResource(resources, "hyts_Foo.ser"));
137        joutFoo.close();
138        // execute the JAR and read the result
139        assertTrue("Error executing JAR",
140                execAndGetOutput(builder).startsWith( "FOOBAR"));
141
142        // play with relative file names - put relative path as ../<parent dir
143        // name>/xx.jar
144        att.put(Attributes.Name.CLASS_PATH, ".." + File.separator
145                + barJar.getParentFile().getName() + File.separator
146                + barJar.getName());
147        joutFoo = new JarOutputStream(new FileOutputStream(fooJar), man);
148        joutFoo.putNextEntry(new JarEntry("foo/bar/execjartest/Foo.class"));
149        joutFoo.write(getResource(resources, "hyts_Foo.ser"));
150        joutFoo.close();
151        // execute the JAR and read the result
152        assertTrue("Error executing JAR",
153                execAndGetOutput(builder).startsWith( "FOOBAR"));
154    }
155
156    /**
157     * tests case when Main-Class is not in the jar launched but in another jar
158     * referenced by Class-Path
159     *
160     * @throws Exception in case of troubles
161     */
162    @TestTargetNew(
163        level = TestLevel.ADDITIONAL,
164        notes = "Functional test.",
165        method = "JarOutputStream",
166        args = {java.io.OutputStream.class, java.util.jar.Manifest.class}
167    )
168    @KnownFailure("Maybe not a failure, but dalvikvm -jar is not supported (, as yet).")
169    public void test_main_class_in_another_jar() throws Exception {
170        File fooJar = File.createTempFile("hyts_", ".jar");
171        File barJar = File.createTempFile("hyts_", ".jar");
172        fooJar.deleteOnExit();
173        barJar.deleteOnExit();
174
175        // create the manifest
176        Manifest man = new Manifest();
177        Attributes att = man.getMainAttributes();
178        att.put(Attributes.Name.MANIFEST_VERSION, "1.0");
179        att.put(Attributes.Name.MAIN_CLASS, "foo.bar.execjartest.Foo");
180        att.put(Attributes.Name.CLASS_PATH, fooJar.getName());
181
182        File resources = Support_Resources.createTempFolder();
183
184        JarOutputStream joutFoo = new JarOutputStream(new FileOutputStream(
185                fooJar));
186        joutFoo.putNextEntry(new JarEntry("foo/bar/execjartest/Foo.class"));
187        joutFoo.write(getResource(resources, "hyts_Foo.ser"));
188        joutFoo.close();
189
190        JarOutputStream joutBar = new JarOutputStream(new FileOutputStream(
191                barJar), man);
192        joutBar.putNextEntry(new JarEntry("foo/bar/execjartest/Bar.class"));
193        joutBar.write(getResource(resources, "hyts_Bar.ser"));
194        joutBar.close();
195
196        // execute the JAR and read the result
197        ProcessBuilder builder = javaProcessBuilder();
198        builder.command().add("-jar");
199        builder.command().add(barJar.getAbsolutePath());
200        assertTrue("Error executing JAR",
201                execAndGetOutput(builder).startsWith("FOOBAR"));
202    }
203
204    @TestTargetNew(
205        level = TestLevel.ADDITIONAL,
206        notes = "Functional test.",
207        method = "JarOutputStream",
208        args = {java.io.OutputStream.class, java.util.jar.Manifest.class}
209    )
210    @KnownFailure("Maybe not a failure, but dalvikvm -jar is not supported (, as yet).")
211    public void test_classpath() throws Exception {
212        File resources = Support_Resources.createTempFolder();
213
214        File fooJar = File.createTempFile("hyts_", ".jar");
215        fooJar.deleteOnExit();
216
217        JarOutputStream joutFoo = new JarOutputStream(new FileOutputStream(
218                fooJar));
219        joutFoo.putNextEntry(new JarEntry("foo/bar/execjartest/Foo.class"));
220        joutFoo.write(getResource(resources, "hyts_Foo.ser"));
221        joutFoo.putNextEntry(new JarEntry("foo/bar/execjartest/Bar.class"));
222        joutFoo.write(getResource(resources, "hyts_Bar.ser"));
223        joutFoo.close();
224
225        // execute the JAR and read the result
226        ProcessBuilder builder = javaProcessBuilder();
227        builder.environment().put("CLASSPATH", fooJar.getAbsolutePath());
228        builder.command().add("foo.bar.execjartest.Foo");
229
230        assertTrue("Error executing class from ClassPath",
231                execAndGetOutput(builder).startsWith("FOOBAR"));
232
233        // ok - next try - add -cp to path - it should override env
234        File booJar = File.createTempFile("hyts_", ".jar");
235        booJar.deleteOnExit();
236
237        JarOutputStream joutBoo = new JarOutputStream(new FileOutputStream(
238                booJar));
239        joutBoo.putNextEntry(new JarEntry("foo/bar/execjartest/Foo.class"));
240        String booBody = new String(getResource(resources, "hyts_Foo.ser"),
241                "iso-8859-1");
242        booBody = booBody.replaceFirst("FOO", "BOO");
243        joutBoo.write(booBody.getBytes("iso-8859-1"));
244        joutBoo.putNextEntry(new JarEntry("foo/bar/execjartest/Bar.class"));
245        String farBody = new String(getResource(resources, "hyts_Bar.ser"),
246                "iso-8859-1");
247        farBody = farBody.replaceFirst("BAR", "FAR");
248        joutBoo.write(farBody.getBytes("iso-8859-1"));
249        joutBoo.close();
250
251        builder = javaProcessBuilder();
252        builder.environment().put("CLASSPATH", fooJar.getAbsolutePath());
253        builder.command().add("-cp");
254        builder.command().add(booJar.getAbsolutePath());
255        builder.command().add("foo.bar.execjartest.Foo");
256
257        assertTrue("Error executing class specified by -cp",
258                execAndGetOutput(builder).startsWith("BOOFAR"));
259
260        // now add -jar option - it should override env and classpath
261        Manifest man = new Manifest();
262        Attributes att = man.getMainAttributes();
263        att.put(Attributes.Name.MANIFEST_VERSION, "1.0");
264        att.put(Attributes.Name.MAIN_CLASS, "foo.bar.execjartest.Foo");
265
266        File zooJar = File.createTempFile("hyts_", ".jar");
267        zooJar.deleteOnExit();
268
269        JarOutputStream joutZoo = new JarOutputStream(new FileOutputStream(
270                zooJar), man);
271        joutZoo.putNextEntry(new JarEntry("foo/bar/execjartest/Foo.class"));
272        String zooBody = new String(getResource(resources, "hyts_Foo.ser"),
273                "iso-8859-1");
274        zooBody = zooBody.replaceFirst("FOO", "ZOO");
275        joutZoo.write(zooBody.getBytes("iso-8859-1"));
276        joutZoo.putNextEntry(new JarEntry("foo/bar/execjartest/Bar.class"));
277        String zarBody = new String(getResource(resources, "hyts_Bar.ser"),
278                "iso-8859-1");
279        zarBody = zarBody.replaceFirst("BAR", "ZAR");
280        joutZoo.write(zarBody.getBytes("iso-8859-1"));
281        joutZoo.close();
282
283        builder = javaProcessBuilder();
284        builder.environment().put("CLASSPATH", fooJar.getAbsolutePath());
285        builder.command().add("-cp");
286        builder.command().add(booJar.getAbsolutePath());
287        builder.command().add("-jar");
288        builder.command().add(zooJar.getAbsolutePath());
289
290        assertTrue("Error executing class specified by -jar",
291                execAndGetOutput(builder).startsWith("ZOOZAR"));
292    }
293
294    private static byte[] getResource(File tempDir, String resourceName)
295            throws IOException {
296        Support_Resources.copyFile(tempDir, null, resourceName);
297        File resourceFile = new File(tempDir, resourceName);
298        resourceFile.deleteOnExit();
299
300        // read whole resource data into memory
301        byte[] resourceBody = new byte[(int) resourceFile.length()];
302        FileInputStream fis = new FileInputStream(resourceFile);
303        fis.read(resourceBody);
304        fis.close();
305
306        return resourceBody;
307    }
308
309}
310