public void testNbmWithExternal() throws Exception {
    String moduleCNB = "org.netbeans.modules.mymodule";
    String moduleReleaseVersion = "1";
    String moduleImplVersion = "2";
    String moduleSpecVersion = "1.0";

    prepareNBM(moduleCNB, moduleReleaseVersion, moduleImplVersion, moduleSpecVersion, false, null);

    writeCatalog();
    UpdateUnitProviderFactory.getDefault().refreshProviders(null, true);
    OperationContainer<InstallSupport> installContainer = OperationContainer.createForInstall();
    UpdateUnit moduleUnit = getUpdateUnit(moduleCNB);
    assertNull("cannot be installed", moduleUnit.getInstalled());
    UpdateElement moduleElement = getAvailableUpdate(moduleUnit, 0);
    assertEquals(moduleElement.getSpecificationVersion(), moduleSpecVersion);
    OperationInfo<InstallSupport> independentInfo = installContainer.add(moduleElement);
    assertNotNull(independentInfo);
    doInstall(installContainer);

    File module = new File(new File(getWorkDir(), "modules"), "org-netbeans-modules-mymodule.jar");
    assertTrue("module file exists", module.exists());
    assertTrue("module was not installed from NBM external", moduleUnit.getInstalled() != null);
    File ext =
        new File(new File(getWorkDir(), "modules"), "org-netbeans-modules-mymodule.jar.external");
    assertFalse("Ext file is not written", ext.exists());
    File utf =
        new File(new File(getWorkDir(), "update_tracking"), "org-netbeans-modules-mymodule.xml");
    assertTrue("Update tracking exists", utf.exists());
    String content;
    {
      byte[] arr = new byte[(int) utf.length()];
      FileInputStream is = new FileInputStream(utf);
      is.read(arr);
      is.close();
      content = new String(arr);
    }
    if (!content.contains("\"modules/org-netbeans-modules-mymodule.jar\"")) {
      fail("Wrong content:\n" + content);
    }
    if (content.contains("\"modules/org-netbeans-modules-mymodule.jar.external\"")) {
      fail("Wrong content:\n" + content);
    }
    if (!content.contains("crc=\"" + UpdateTracking.getFileCRC(module) + "\"")) {
      fail("Wrong content:\n" + content);
    }
  }
  private File prepareNBM(
      String codeName,
      String releaseVersion,
      String implVersion,
      String specVersion,
      boolean visible,
      String dependency)
      throws Exception {
    String moduleName = codeName.substring(codeName.lastIndexOf(".") + 1);
    String moduleFile = codeName.replace(".", "-");
    String moduleDir = codeName.replace(".", "/") + "/";
    File nbm = File.createTempFile(moduleFile + "-", ".nbm", tmpDirectory);

    final String MODULE_NAME_PROP = "OpenIDE-Module-Name";

    File jar = new File(tmpDirectory, "x.jar");
    jar.getParentFile().mkdirs();
    JarOutputStream jos = new JarOutputStream(new FileOutputStream(jar));
    int idx = moduleDir.indexOf("/");
    while (idx != -1) {
      jos.putNextEntry(new ZipEntry(moduleDir.substring(0, idx + 1)));
      idx = moduleDir.indexOf("/", idx + 1);
    }

    jos.putNextEntry(new ZipEntry(moduleDir + "Bundle.properties"));
    jos.write(new String(MODULE_NAME_PROP + "=" + moduleName).getBytes("UTF-8"));
    jos.putNextEntry(new ZipEntry("META-INF/"));
    jos.putNextEntry(new ZipEntry("META-INF/manifest.mf"));
    jos.write(
        getManifest(
                codeName, releaseVersion, implVersion, moduleDir, specVersion, visible, dependency)
            .getBytes("UTF-8"));
    jos.close();
    File ext = new File(jar.getParentFile(), jar.getName() + ".external");
    FileOutputStream os = new FileOutputStream(ext);
    os.write(("CRC: " + UpdateTracking.getFileCRC(jar) + "\n").getBytes());
    os.write(("URL: " + Utilities.toURI(jar).toString() + "\n").getBytes());
    os.close();

    Manifest mf = new Manifest();
    mf.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");

    jos = new JarOutputStream(new FileOutputStream(nbm), mf);
    jos.putNextEntry(new ZipEntry("Info/"));
    jos.putNextEntry(new ZipEntry("Info/info.xml"));
    jos.write(
        createInfoXML(
                visible,
                codeName,
                releaseVersion,
                implVersion,
                moduleName,
                Utilities.toURI(nbm).toURL().toString(),
                specVersion,
                dependency)
            .getBytes("UTF-8"));

    jos.putNextEntry(new ZipEntry("netbeans/"));
    jos.putNextEntry(new ZipEntry("netbeans/modules/"));
    jos.putNextEntry(new ZipEntry("netbeans/config/"));
    jos.putNextEntry(new ZipEntry("netbeans/config/Modules/"));
    jos.putNextEntry(new ZipEntry("netbeans/config/Modules/" + moduleFile + ".xml"));

    jos.write(getConfigXML(codeName, moduleFile, specVersion).getBytes("UTF-8"));

    jos.putNextEntry(new ZipEntry("netbeans/modules/" + moduleFile + ".jar.external"));

    FileInputStream fis = new FileInputStream(ext);
    FileUtil.copy(fis, jos);
    fis.close();
    ext.delete();
    jos.close();
    nbms.add(nbm);

    return nbm;
  }