1 /*
   2  * Copyright 2007-2008 Sun Microsystems, Inc.  All Rights Reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  20  * CA 95054 USA or visit www.sun.com if you need additional information or
  21  * have any questions.
  22  */
  23 
  24 import java.io.*;
  25 import java.module.*;
  26 import java.net.*;
  27 import java.util.*;
  28 import sun.module.JamUtils;
  29 import sun.module.tools.JRepo;
  30 
  31 /**
  32  * @test
  33  * @summary Test execution of JRepo
  34  * @library ..
  35  * @compile -XDignore.symbol.file JRepoTest.java ../JamBuilder.java
  36  * @run main JRepoTest
  37  */
  38 public class JRepoTest {
  39     private static final boolean debug = true;/*Boolean.getBoolean("module.tools.debug"); ZZZ */
  40 
  41     static final ByteArrayOutputStream bout = new ByteArrayOutputStream();
  42     static final ByteArrayOutputStream berr = new ByteArrayOutputStream();
  43 
  44     public static void realMain(String args[]) throws Throwable {
  45         JRepo jr = new JRepo(new PrintStream(bout), new PrintStream(berr), null);
  46 
  47         /*
  48          * Check common error reporting.
  49          */
  50         check(!jr.run(new String[] {" "}) && usageOK(0));
  51         check(!jr.run(getArgs("notASubCcommand")) && usageOK(0));
  52         check(!jr.run(getArgs("list -+")) && usageOK(-5));
  53 
  54         /*
  55          * Do many tests on a LocalRepository, then a few on a URLRepository
  56          * as a sanity check.
  57          */
  58 
  59         // Create a temporary directory for JAM files and repositories.
  60         File tmp = new File(
  61             System.getProperty("test.scratch", "."), "JRepoTestDir").getCanonicalFile();
  62         JamUtils.recursiveDelete(tmp);
  63         tmp.mkdirs();
  64 
  65         // Create a directory for JAM files
  66         File jamDir = new File(tmp, "JRepoTestJamDir");
  67         JamUtils.recursiveDelete(jamDir);
  68         jamDir.mkdirs();
  69 
  70         /* Check install command */
  71 
  72         check(!jr.run(getArgs("install")) && usageOK(-3));
  73         check(!jr.run(getArgs("install repo module")) && usageOK(-3));
  74         check(!jr.run(getArgs("install -r repoDoesNotExist module")) && errorOK(1));
  75         check(!jr.run(getArgs("install -p -r repoDoesNotExist module")) && errorOK(4));
  76 
  77         // Create a directory for a local repository.
  78         File localRepoDir = new File(tmp, "JRepoTestLocalRepoDir");
  79         JamUtils.recursiveDelete(localRepoDir);
  80         localRepoDir.mkdirs();
  81         String repo = localRepoDir.getCanonicalPath();
  82 
  83         // Verify that you can't install a module which doesn't exist
  84         check(!jr.run(getArgs("install -r " + repo + " NoSuchModule")) && errorOK(1));
  85 
  86         // Each install must be of a different module
  87 
  88         // Verify silent output
  89         File jamFile = JamBuilder.createJam(
  90                 "jrepotest", "Example", "JRepoModuleA", "1.0", "platform1", "archA", false, jamDir);
  91         jamFile.deleteOnExit();
  92         String jam = jamFile.getCanonicalPath();
  93         check(jr.run(getArgs("install -r " + repo + " " + jam)) && outputOK(0));
  94 
  95         // Verify verbose output
  96         jamFile = JamBuilder.createJam(
  97                 "jrepotest", "Example", "JRepoModuleB", "1.0", "platform2", "archB", false, jamDir);
  98         jamFile.deleteOnExit();
  99         jam = jamFile.getCanonicalPath();
 100         check(jr.run(getArgs("ins -v -r " + repo + " " + jam)) && outputOK(1));
 101 
 102         // Verify multiple versions of same named module
 103         jamFile = JamBuilder.createJam(
 104                 "jrepotest", "Example", "JRepoModuleB", "2.0", "platform3", "archC", false, jamDir);
 105         jamFile.deleteOnExit();
 106         jam = jamFile.getCanonicalPath();
 107         check(jr.run(getArgs("install -v -r " + repo + " " + jam)) && outputOK(1));
 108         jamFile = JamBuilder.createJam(
 109                 "jrepotest", "Example", "JRepoModuleB", "2.5", "platform4", "archD", false, jamDir);
 110         jamFile.deleteOnExit();
 111         jam = jamFile.getCanonicalPath();
 112         check(jr.run(getArgs("install -v -r " + repo + " " + jam)) && outputOK(1));
 113 
 114         // Verify modules are installed
 115         check(jr.run(getArgs("list -v -r " + repo)) && outputOK(6));
 116 
 117         // Verify -p is not applicable to install
 118         check(!jr.run(getArgs("install -p -r " + repo + " " + jam)) && usageOK(-4));
 119 
 120         /* Check list command */
 121 
 122         check(!jr.run(getArgs("list")) && errorOK(0));
 123         check(jr.run(getArgs("list -p")) && outputOK(14));
 124         check(!jr.run(getArgs("list -v")) && errorOK(1));
 125         check(jr.run(getArgs("list -p -v")) && outputOK(22));
 126 
 127         // Common prefixes of "list"
 128         check(jr.run(getArgs("lis -r " + repo)) && outputOK(6));
 129         check(jr.run(getArgs("li -p -r " + repo)) && outputOK(20));
 130         check(jr.run(getArgs("l -v -r " + repo)) && outputOK(6));
 131         check(jr.run(getArgs("list -p -v -r " + repo)) && outputOK(28));
 132 
 133         // Check that repositories are shown in sorted order
 134         check(jr.run(getArgs("l -v -r " + repo)) && sortedOK());
 135 
 136         // Nonexist things are not there
 137         check(!jr.run(getArgs("list ThisWillNotBeFound")) && outputOK(0));
 138         check(!jr.run(getArgs("list -v ThisWillNotBeFound")) && errorOK(1));
 139 
 140         // Bootstrap repository contents are there
 141         check(!jr.run(getArgs("list java.se.core")) && errorOK(0));
 142         check(jr.run(getArgs("list -p java.se.core")) && outputOK(3));
 143         check(!jr.run(getArgs("list -v java.se.core")) && errorOK(1));
 144         check(jr.run(getArgs("list -p -v java.se.core")) && outputOK(11));
 145 
 146         // Various options work
 147         check(jr.run(getArgs("list -r " + repo + " JRepoModuleA")) && outputOK(3));
 148         check(jr.run(getArgs("list -p -r " + repo + " JRepoModuleA")) && outputOK(3));
 149         check(jr.run(getArgs("list -v -r " + repo + " JRepoModuleA")) && outputOK(3));
 150         check(jr.run(getArgs("list -p -v -r " + repo + " JRepoModuleA")) && outputOK(11));
 151 
 152         // Given module name is treated as substring of full module names
 153         check(jr.run(getArgs("list -r " + repo + " JRepoModule")) && outputOK(6));
 154         check(jr.run(getArgs("list -p -r " + repo + " JRepoModu")) && outputOK(6));
 155         check(jr.run(getArgs("list -v -r " + repo + " JRepo")) && outputOK(6));
 156         check(jr.run(getArgs("list -p -v -r " + repo + " JR")) && outputOK(14));
 157 
 158         /* Check uninstall command */
 159 
 160         check(!jr.run(getArgs("uninstall")) && usageOK(-3));
 161         check(!jr.run(getArgs("uninstall repo MODULE")) && usageOK(-3));
 162         check(!jr.run(getArgs("uninstall -r repoDoesNotExist module")) && errorOK(1));
 163         check(!jr.run(getArgs("uninstall -p -r repoDoesNotExist module")) && errorOK(4));
 164 
 165         check(!jr.run(getArgs("uninstall -r " + repo + " Fred")) && errorOK(0));
 166         check(!jr.run(getArgs("uninstall -v -r " + repo + " Fred")) && errorOK(1));
 167 
 168         // Install one more module for tests below
 169         jamFile = JamBuilder.createJam(
 170                 "jrepotest", "Example", "JRepoModuleC", "1.0", "platform5", "archE", false, jamDir);
 171         jamFile.deleteOnExit();
 172         jam = jamFile.getCanonicalPath();
 173         check(jr.run(getArgs("ins -v -r " + repo + " " + jam)) && outputOK(1));
 174 
 175         // Verify a straightforward uninstall.
 176         check(jr.run(getArgs("unin -v -r " + repo + " JRepoModuleA")) && outputOK(1));
 177 
 178         // Verify we can't uninstall from module name alone when there is more
 179         // than one version with that name...
 180         check(!jr.run(getArgs("un -r " + repo + " JRepoModuleB")) && outputOK(0));
 181 
 182         // ... and that with -v the JRepo says what ones there are...
 183         check(!jr.run(getArgs("un -v -r " + repo + " JRepoModuleB")) && errorOK(4));
 184 
 185         // ... but that by appending the version, uninstall succeeds.
 186         check(jr.run(getArgs("un -v -r " + repo + " JRepoModuleB 2.0")) && outputOK(1));
 187         check(jr.run(getArgs("list -v -r " + repo)) && outputOK(5));
 188 
 189         // Verify that the -f flag causes the remaining JRepoModuleB versions
 190         // to be uninstalled
 191         check(jr.run(getArgs("un -v -f -r " + repo + " JRepoModuleB")) && outputOK(2));
 192         check(jr.run(getArgs("list -v -r " + repo)) && outputOK(3));
 193 
 194         // Install more modules to verify -i works
 195         jamFile = JamBuilder.createJam(
 196                 "jrepotest", "Interact", "JRepoModuleD", "2.7", "platform6", "archF", false, jamDir);
 197         jamFile.deleteOnExit();
 198         jam = jamFile.getCanonicalPath();
 199         check(jr.run(getArgs("install -v -r " + repo + " " + jam)) && outputOK(1));
 200         jamFile = JamBuilder.createJam(
 201                 "jrepotest", "Interact", "JRepoModuleD", "3.1", "platform7", "archG", false, jamDir);
 202         jamFile.deleteOnExit();
 203         jam = jamFile.getCanonicalPath();
 204         check(jr.run(getArgs("install -v -r " + repo + " " + jam)) && outputOK(1));
 205 
 206         // This reader will let us delete the module JRepoModuleD version 3.1.
 207         class MockReader extends BufferedReader {
 208             MockReader() {
 209                 super(new StringReader("1\n"));
 210             }
 211         }
 212         JRepo jr2 = new JRepo(
 213             new PrintStream(bout), new PrintStream(berr), new MockReader());
 214         check(jr2.run(getArgs("un -v -i -r " + repo + " JRepoModuleD")) && outputOK(5));
 215         check(jr2.run(getArgs("list -v -r " + repo)) && outputOK(4));
 216 
 217         /*
 218          * End of checks on LocalRepository, now try a few on URLRepository.
 219          */
 220 
 221         // Create a directory for a url repository.
 222         File urlRepoDir = new File(tmp, "JRepoTestURLRepoDir");
 223         JamUtils.recursiveDelete(urlRepoDir);
 224         urlRepoDir.mkdirs();
 225 
 226         File repoDownloadDir = new File(urlRepoDir, "download");
 227         Map<String, String> config = new HashMap<String, String>();
 228         config.put(
 229             "sun.module.repository.URLRepository.cacheDirectory",
 230             repoDownloadDir.getAbsolutePath());
 231 
 232         String urlRepoPath = urlRepoDir.getCanonicalPath();
 233         if (!urlRepoPath.startsWith("/")) {
 234             urlRepoPath = "/" + urlRepoPath;
 235         }
 236         urlRepoPath = "file://" + urlRepoPath;
 237         Repository urlrepo = Modules.newURLRepository("JRepoTestURLRepository",
 238                                                       new URL(urlRepoPath), config);
 239 
 240         // Verify multiple versions of same named module
 241         jamFile = JamBuilder.createJam(
 242                 "jrepotest", "Example", "URLModuleX", "7.0", "platform8", "archH", false, jamDir);
 243         jamFile.deleteOnExit();
 244         jam = jamFile.getCanonicalPath();
 245         check(jr.run(getArgs("install -v -r " + urlRepoPath + " " + jam)) && outputOK(1));
 246 
 247         jamFile = JamBuilder.createJam(
 248                 "jrepotest", "Example", "URLModuleX", "13.0", "platform9", "archI", false, jamDir);
 249         jamFile.deleteOnExit();
 250         jam = jamFile.getCanonicalPath();
 251         check(jr.run(getArgs("install -v -r " + urlRepoPath + " " + jam)) && outputOK(1));
 252 
 253         // Verify list
 254         check(jr.run(getArgs("list -v -r " + urlRepoPath)) && outputOK(4));
 255 
 256         // Verify uninstall
 257         check(jr.run(getArgs("un -v -f -r " + urlRepoPath + " URLModuleX 13")) && outputOK(1));
 258 
 259         // Verify uninstall worked
 260         check(jr.run(getArgs("list -v -r " + urlRepoPath)) && outputOK(3));
 261 
 262         JRepo jr3 = new JRepo(System.out, System.err, null);
 263         jr3.run(getArgs("list -v -r " + urlRepoPath));
 264 
 265         // Cleanup test directories
 266         if (failed == 0) {
 267             JamUtils.recursiveDelete(jamDir);
 268             JamUtils.recursiveDelete(localRepoDir);
 269             JamUtils.recursiveDelete(urlRepoDir);
 270         }
 271     }
 272 
 273     /** Return an array of Strings from the given String. */
 274     static String[] getArgs(String s) {
 275         List<String> args = new ArrayList<String>();
 276         StringTokenizer st = new StringTokenizer(s);
 277         while (st.hasMoreTokens()) {
 278             String token = st.nextToken();
 279             if (debug) System.err.println("adding arg " + token);
 280             args.add(token);
 281         }
 282         if (debug) System.err.println("args length is " + args.size());
 283         return args.toArray(new String[0]);
 284     }
 285 
 286     /**
 287      * If the output is OK, returns true.  For now, being OK means only
 288      * having {code len} lines.
 289      */
 290     static boolean checkOutput(int len, ByteArrayOutputStream baos) throws Throwable {
 291         String s = baos.toString("ASCII");
 292         BufferedReader r = new BufferedReader(new StringReader(s));
 293         int count = 0;
 294         while (r.readLine() != null) {
 295             count++;
 296         }
 297         if (debug) System.err.println(
 298             "Checking expected length " + len
 299             + " = given length " + count
 300             + " on '" + s + "'");
 301         bout.reset();
 302         berr.reset();
 303         return len == count;
 304     }
 305 
 306     /** Check stdout. */
 307     static boolean outputOK(int len) throws Throwable {
 308         return checkOutput(len, bout);
 309     }
 310 
 311     /** Check stderr. */
 312     static boolean errorOK(int len) throws Throwable {
 313         return checkOutput(len, berr);
 314     }
 315 
 316     /** Check that usage is provided as expected. */
 317     static boolean usageOK(int len) throws Throwable {
 318         // If len < 0, use negative of that, else use len + default
 319         return checkOutput(len < 0 ? -len : 20 + len, berr);
 320     }
 321 
 322     /** Check that output is sorted, after skipping the firsts header line. */
 323     static boolean sortedOK() throws Throwable {
 324         int numFailed = failed;
 325         String allLines = bout.toString();
 326         if (debug) System.err.println("Checking sort order on '" + allLines + "'");
 327         BufferedReader r = new BufferedReader(new StringReader(allLines));
 328         check(r.readLine() != null); // Skip heading
 329         List<String> lines = new ArrayList<String>();
 330         String s;
 331         while ((s = r.readLine()) != null) {
 332             check(!lines.contains(s));
 333             check(lines.add(s));
 334         }
 335         String prev = lines.get(2);
 336         for (int i = 3; i < lines.size(); i++) {
 337             String cur = lines.get(i);
 338             if (!check(prev.compareTo(cur) < 0)) {
 339                 System.err.println(
 340                     "'" + prev + "'\nis not less than \n'" + cur + "'");
 341             }
 342             prev = cur;
 343         }
 344         bout.reset();
 345         return numFailed == failed;
 346     }
 347 
 348     //--------------------- Infrastructure ---------------------------
 349     static volatile int passed = 0, failed = 0;
 350     static boolean pass() {passed++; return true;}
 351     static boolean fail() {failed++; Thread.dumpStack(); return false;}
 352     static boolean fail(String msg) {System.err.println(msg); return fail();}
 353     static void unexpected(Throwable t) {failed++; t.printStackTrace();}
 354     static boolean check(boolean cond) {if (cond) pass(); else fail(); return cond;}
 355     static boolean equal(Object x, Object y) {
 356         if (x == null ? y == null : x.equals(y)) return pass();
 357         else return fail(x + " not equal to " + y);}
 358     public static void main(String[] args) throws Throwable {
 359         try {realMain(args);} catch (Throwable t) {unexpected(t);}
 360         System.out.println("\nPassed = " + passed + " failed = " + failed);
 361         if (failed > 0) throw new AssertionError("Some tests failed");}
 362 }