Пример #1
0
  @Test
  public void testRace() throws Exception {
    final List<SolrCore> theCores = new ArrayList<>();
    final CoreContainer cc = init();
    try {

      Thread[] threads = new Thread[15];
      for (int idx = 0; idx < threads.length; idx++) {
        threads[idx] =
            new Thread() {
              @Override
              public void run() {
                SolrCore core = cc.getCore("collectionLazy3");
                synchronized (theCores) {
                  theCores.add(core);
                }
              }
            };
        threads[idx].start();
      }
      for (Thread thread : threads) {
        thread.join();
      }
      for (int idx = 0; idx < theCores.size() - 1; ++idx) {
        assertEquals("Cores should be the same!", theCores.get(idx), theCores.get(idx + 1));
      }
      for (SolrCore core : theCores) {
        core.close();
      }

    } finally {
      cc.shutdown();
    }
  }
Пример #2
0
  @Test
  public void testCreateSame() throws Exception {
    final CoreContainer cc = init();
    try {
      // First, try all 4 combinations of load on startup and transient
      final CoreAdminHandler admin = new CoreAdminHandler(cc);
      SolrCore lc2 = cc.getCore("collectionLazy2");
      SolrCore lc4 = cc.getCore("collectionLazy4");
      SolrCore lc5 = cc.getCore("collectionLazy5");
      SolrCore lc6 = cc.getCore("collectionLazy6");

      copyMinConf(new File(solrHomeDirectory, "t2"));
      copyMinConf(new File(solrHomeDirectory, "t4"));
      copyMinConf(new File(solrHomeDirectory, "t5"));
      copyMinConf(new File(solrHomeDirectory, "t6"));

      // Should also fail with the same name
      tryCreateFail(
          admin, "collectionLazy2", "t12", "Core with name", "collectionLazy2", "already exists");
      tryCreateFail(
          admin, "collectionLazy4", "t14", "Core with name", "collectionLazy4", "already exists");
      tryCreateFail(
          admin, "collectionLazy5", "t15", "Core with name", "collectionLazy5", "already exists");
      tryCreateFail(
          admin, "collectionLazy6", "t16", "Core with name", "collectionLazy6", "already exists");

      lc2.close();
      lc4.close();
      lc5.close();
      lc6.close();

    } finally {
      cc.shutdown();
    }
  }
Пример #3
0
  @Test
  public void testRefCount() throws Exception {
    SolrCore core = h.getCore();
    assertTrue("Refcount != 1", core.getOpenCount() == 1);

    final CoreContainer cores = h.getCoreContainer();
    SolrCore c1 = cores.getCore(SolrTestCaseJ4.DEFAULT_TEST_CORENAME);
    assertTrue("Refcount != 2", core.getOpenCount() == 2);

    ClosingRequestHandler handler1 = new ClosingRequestHandler();
    handler1.inform(core);

    String path = "/this/is A path /that won't be registered!";
    SolrRequestHandler old = core.registerRequestHandler(path, handler1);
    assertNull(old); // should not be anything...
    assertEquals(core.getRequestHandlers().get(path), handler1);

    SolrCore c2 = cores.getCore(SolrTestCaseJ4.DEFAULT_TEST_CORENAME);
    c1.close();
    assertTrue("Refcount < 1", core.getOpenCount() >= 1);
    assertTrue("Handler is closed", handler1.closed == false);

    c1 = cores.getCore(SolrTestCaseJ4.DEFAULT_TEST_CORENAME);
    assertTrue("Refcount < 2", core.getOpenCount() >= 2);
    assertTrue("Handler is closed", handler1.closed == false);

    c2.close();
    assertTrue("Refcount < 1", core.getOpenCount() >= 1);
    assertTrue("Handler is closed", handler1.closed == false);

    c1.close();
    cores.shutdown();
    assertTrue("Refcount != 0", core.getOpenCount() == 0);
    assertTrue("Handler not closed", core.isClosed() && handler1.closed == true);
  }
Пример #4
0
  // Make sure that creating a transient core from the admin handler correctly respects the
  // transient limits etc.
  @Test
  public void testCreateTransientFromAdmin() throws Exception {
    final CoreContainer cc = init();
    try {
      copyMinConf(new File(solrHomeDirectory, "core1"));
      copyMinConf(new File(solrHomeDirectory, "core2"));
      copyMinConf(new File(solrHomeDirectory, "core3"));
      copyMinConf(new File(solrHomeDirectory, "core4"));
      copyMinConf(new File(solrHomeDirectory, "core5"));

      createViaAdmin(cc, "core1", "./core1", true, true);
      createViaAdmin(cc, "core2", "./core2", true, false);
      createViaAdmin(cc, "core3", "./core3", true, true);
      createViaAdmin(cc, "core4", "./core4", true, false);
      createViaAdmin(cc, "core5", "./core5", true, false);

      SolrCore c1 = cc.getCore("core1");
      SolrCore c2 = cc.getCore("core2");
      SolrCore c3 = cc.getCore("core3");
      SolrCore c4 = cc.getCore("core4");
      SolrCore c5 = cc.getCore("core5");

      checkNotInCores(
          cc,
          "core1",
          "collectionLazy2",
          "collectionLazy3",
          "collectionLazy4",
          "collectionLazy6",
          "collectionLazy7",
          "collectionLazy8",
          "collectionLazy9");

      checkInCores(cc, "collection1", "collectionLazy5", "core2", "core3", "core4", "core5");

      // While we're at it, a test for SOLR-5366, unloading transient core that's been unloaded b/c
      // it's
      // transient generates a "too many closes" errorl

      unloadViaAdmin(cc, "core1");
      unloadViaAdmin(cc, "core2");
      unloadViaAdmin(cc, "core3");
      unloadViaAdmin(cc, "core4");
      unloadViaAdmin(cc, "core5");

      c1.close();
      c2.close();
      c3.close();
      c4.close();
      c5.close();

    } finally {
      cc.shutdown();
    }
  }
Пример #5
0
 public void disable() {
   if (!enabled) {
     return;
   }
   nakamuraCore.close();
   coreContainer.shutdown();
   enabled = false;
   if (listener != null) {
     listener.disabled();
   }
 }
Пример #6
0
 /**
  * Create a new CoreContainer and load its cores
  *
  * @param solrHome the solr home directory
  * @param configFile the file containing this container's configuration
  * @return a loaded CoreContainer
  */
 public static CoreContainer createAndLoad(Path solrHome, Path configFile) {
   SolrResourceLoader loader = new SolrResourceLoader(solrHome);
   CoreContainer cc = new CoreContainer(SolrXmlConfig.fromFile(loader, configFile));
   try {
     cc.load();
   } catch (Exception e) {
     cc.shutdown();
     throw e;
   }
   return cc;
 }
  @After
  public void cleanUp() throws Exception {
    if (cc != null) {
      cc.shutdown();
      cc = null;
    }

    if (null != solrHome) {
      if (solrHome.exists()) {
        FileUtils.deleteDirectory(solrHome);
      }
      solrHome = null;
    }
  }
Пример #8
0
 @AfterClass
 public static void tearDown() throws Exception {
   try {
     if (solr != null) {
       solr.rollback();
     }
   } catch (SolrException e) {
   }
   solrCore.close();
   if (coreContainer != null) {
     coreContainer.shutdown();
   }
   FileUtils.cleanDirectory(new File(solrCore.getDataDir() + "/index"));
   FileUtils.cleanDirectory(new File(solrCore.getDataDir() + "/tlog"));
 }
Пример #9
0
  @Test
  public void testClose() throws Exception {
    final CoreContainer cores = h.getCoreContainer();
    SolrCore core = cores.getCore(SolrTestCaseJ4.DEFAULT_TEST_CORENAME);

    ClosingRequestHandler handler1 = new ClosingRequestHandler();
    handler1.inform(core);

    String path = "/this/is A path /that won't be registered 2!!!!!!!!!!!";
    SolrRequestHandler old = core.registerRequestHandler(path, handler1);
    assertNull(old); // should not be anything...
    assertEquals(core.getRequestHandlers().get(path), handler1);
    core.close();
    cores.shutdown();
    assertTrue("Handler not closed", handler1.closed == true);
  }
Пример #10
0
  @Test
  public void testLazyLoad() throws Exception {
    CoreContainer cc = init();
    try {

      // NOTE: This checks the initial state for loading, no need to do this elsewhere.
      checkInCores(cc, "collection1", "collectionLazy2", "collectionLazy5");
      checkNotInCores(
          cc,
          "collectionLazy3",
          "collectionLazy4",
          "collectionLazy6",
          "collectionLazy7",
          "collectionLazy8",
          "collectionLazy9");

      SolrCore core1 = cc.getCore("collection1");
      assertFalse("core1 should not be transient", core1.getCoreDescriptor().isTransient());
      assertTrue("core1 should be loadable", core1.getCoreDescriptor().isLoadOnStartup());
      assertNotNull(core1.getSolrConfig());

      SolrCore core2 = cc.getCore("collectionLazy2");
      assertTrue("core2 should be transient", core2.getCoreDescriptor().isTransient());
      assertTrue("core2 should be loadable", core2.getCoreDescriptor().isLoadOnStartup());

      SolrCore core3 = cc.getCore("collectionLazy3");
      assertTrue("core3 should be transient", core3.getCoreDescriptor().isTransient());
      assertFalse("core3 should not be loadable", core3.getCoreDescriptor().isLoadOnStartup());

      SolrCore core4 = cc.getCore("collectionLazy4");
      assertFalse("core4 should not be transient", core4.getCoreDescriptor().isTransient());
      assertFalse("core4 should not be loadable", core4.getCoreDescriptor().isLoadOnStartup());

      SolrCore core5 = cc.getCore("collectionLazy5");
      assertFalse("core5 should not be transient", core5.getCoreDescriptor().isTransient());
      assertTrue("core5 should be loadable", core5.getCoreDescriptor().isLoadOnStartup());

      core1.close();
      core2.close();
      core3.close();
      core4.close();
      core5.close();
    } finally {
      cc.shutdown();
    }
  }
Пример #11
0
  @Test
  public void testLazySearch() throws Exception {
    CoreContainer cc = init();
    try {
      // Make sure Lazy4 isn't loaded. Should be loaded on the get
      checkNotInCores(cc, "collectionLazy4");
      SolrCore core4 = cc.getCore("collectionLazy4");

      checkSearch(core4);

      // Now just insure that the normal searching on "collection1" finds _0_ on the same query that
      // found _2_ above.
      // Use of makeReq above and req below is tricky, very tricky.
      assertQ(
          "test raw query", req("q", "{!raw f=v_t}hello", "wt", "xml"), "//result[@numFound='0']");

      checkInCores(cc, "collectionLazy4");

      core4.close();
    } finally {
      cc.shutdown();
    }
  }
Пример #12
0
  public static void validate(File solrCoreDir, String dataDirPropertyName, Fields schemeFields)
      throws IOException {

    // Verify solrHomeDir exists
    if (!solrCoreDir.exists() || !solrCoreDir.isDirectory()) {
      throw new TapException("Solr core directory doesn't exist: " + solrCoreDir);
    }

    File tmpSolrHome = makeTempSolrHome(solrCoreDir);

    // Set up a temp location for Solr home, where we're write out a synthetic solr.xml
    // that references the core directory.
    String coreName = solrCoreDir.getName();
    String corePath = solrCoreDir.getAbsolutePath();
    String solrXmlContent =
        String.format(
            "<solr><cores><core name=\"%s\" instanceDir=\"%s\"></core></cores></solr>",
            coreName, corePath);
    File solrXmlFile = new File(tmpSolrHome, "solr.xml");
    FileUtils.write(solrXmlFile, solrXmlContent);

    // Set up a temp location for data, so when we instantiate the coreContainer,
    // we don't pollute the solr home with a /data sub-dir.
    String tmpFolder = System.getProperty("java.io.tmpdir");
    File tmpDataDir = new File(tmpFolder, UUID.randomUUID().toString());
    tmpDataDir.mkdir();

    System.setProperty("solr.solr.home", tmpSolrHome.getAbsolutePath());
    System.setProperty(dataDirPropertyName, tmpDataDir.getAbsolutePath());
    System.setProperty(
        "enable.special-handlers", "false"); // All we need is the update request handler
    System.setProperty(
        "enable.cache-warming", "false"); // We certainly don't need to warm the cache

    CoreContainer.Initializer initializer = new CoreContainer.Initializer();
    CoreContainer coreContainer = null;

    try {
      coreContainer = initializer.initialize();
      Collection<SolrCore> cores = coreContainer.getCores();
      SolrCore core = null;

      if (cores.size() == 0) {
        throw new TapException("No Solr cores are available");
      } else if (cores.size() > 1) {
        throw new TapException("Only one Solr core is supported");
      } else {
        core = cores.iterator().next();
      }

      IndexSchema schema = core.getSchema();
      Map<String, SchemaField> solrFields = schema.getFields();
      Set<String> schemeFieldnames = new HashSet<String>();

      for (int i = 0; i < schemeFields.size(); i++) {
        String fieldName = schemeFields.get(i).toString();
        if (!solrFields.containsKey(fieldName)) {
          throw new TapException("Sink field name doesn't exist in Solr schema: " + fieldName);
        }

        schemeFieldnames.add(fieldName);
      }

      for (String solrFieldname : solrFields.keySet()) {
        SchemaField solrField = solrFields.get(solrFieldname);
        if (solrField.isRequired() && !schemeFieldnames.contains(solrFieldname)) {
          throw new TapException("No sink field name for required Solr field: " + solrFieldname);
        }
      }
    } finally {
      if (coreContainer != null) {
        coreContainer.shutdown();
      }
    }
  }
Пример #13
0
  // Test that transient cores
  // 1> produce errors as appropriate when the config or schema files are foo'd
  // 2> "self heal". That is, if the problem is corrected can the core be reloaded and used?
  // 3> that OK cores can be searched even when some cores failed to load.
  @Test
  public void testBadConfigsGenerateErrors() throws Exception {
    final CoreContainer cc =
        initGoodAndBad(
            Arrays.asList("core1", "core2"),
            Arrays.asList("badSchema1", "badSchema2"),
            Arrays.asList("badConfig1", "badConfig2"));
    try {
      // first, did the two good cores load successfully?
      checkInCores(cc, "core1", "core2");

      // Did the bad cores fail to load?
      checkNotInCores(cc, "badSchema1", "badSchema2", "badConfig1", "badConfig2");

      //  Can we still search the "good" cores even though there were core init failures?
      SolrCore core1 = cc.getCore("core1");
      checkSearch(core1);

      // Did we get the expected message for each of the cores that failed to load? Make sure we
      // don't run afoul of
      // the dreaded slash/backslash difference on Windows and *nix machines.
      testMessage(
          cc.getCoreInitFailures(),
          "TestLazyCores" + File.separator + "badConfig1" + File.separator + "solrconfig.xml");
      testMessage(
          cc.getCoreInitFailures(),
          "TestLazyCores" + File.separator + "badConfig2" + File.separator + "solrconfig.xml");
      testMessage(
          cc.getCoreInitFailures(),
          "TestLazyCores" + File.separator + "badSchema1" + File.separator + "schema.xml");
      testMessage(
          cc.getCoreInitFailures(),
          "TestLazyCores" + File.separator + "badSchema2" + File.separator + "schema.xml");

      // Status should report that there are failure messages for the bad cores and none for the
      // good cores.
      checkStatus(cc, true, "core1");
      checkStatus(cc, true, "core2");
      checkStatus(cc, false, "badSchema1");
      checkStatus(cc, false, "badSchema2");
      checkStatus(cc, false, "badConfig1");
      checkStatus(cc, false, "badConfig2");

      // Copy good config and schema files in and see if you can then load them (they are transient
      // after all)
      copyGoodConf("badConfig1", "solrconfig-minimal.xml", "solrconfig.xml");
      copyGoodConf("badConfig2", "solrconfig-minimal.xml", "solrconfig.xml");
      copyGoodConf("badSchema1", "schema-tiny.xml", "schema.xml");
      copyGoodConf("badSchema2", "schema-tiny.xml", "schema.xml");

      // This should force a reload of the cores.
      SolrCore bc1 = cc.getCore("badConfig1");
      SolrCore bc2 = cc.getCore("badConfig2");
      SolrCore bs1 = cc.getCore("badSchema1");
      SolrCore bs2 = cc.getCore("badSchema2");

      // all the cores should be found in the list now.
      checkInCores(cc, "core1", "core2", "badSchema1", "badSchema2", "badConfig1", "badConfig2");

      // Did we clear out the errors by putting good files in place? And the cores that never were
      // bad should be OK too.
      checkStatus(cc, true, "core1");
      checkStatus(cc, true, "core2");
      checkStatus(cc, true, "badSchema1");
      checkStatus(cc, true, "badSchema2");
      checkStatus(cc, true, "badConfig1");
      checkStatus(cc, true, "badConfig2");

      // Are the formerly bad cores now searchable? Testing one of each should do.
      checkSearch(core1);
      checkSearch(bc1);
      checkSearch(bs1);

      core1.close();
      bc1.close();
      bc2.close();
      bs1.close();
      bs2.close();
    } finally {
      cc.shutdown();
    }
  }
Пример #14
0
  @Test
  public void testPersistence() throws Exception {
    final CoreContainer cc = init();
    try {
      copyMinConf(new File(solrHomeDirectory, "core1"));
      copyMinConf(new File(solrHomeDirectory, "core2"));
      copyMinConf(new File(solrHomeDirectory, "core3"));
      copyMinConf(new File(solrHomeDirectory, "core4"));

      final CoreDescriptor cd1 =
          buildCoreDescriptor(cc, "core1", "./core1").isTransient(true).loadOnStartup(true).build();
      final CoreDescriptor cd2 =
          buildCoreDescriptor(cc, "core2", "./core2")
              .isTransient(true)
              .loadOnStartup(false)
              .build();
      final CoreDescriptor cd3 =
          buildCoreDescriptor(cc, "core3", "./core3")
              .isTransient(false)
              .loadOnStartup(true)
              .build();
      final CoreDescriptor cd4 =
          buildCoreDescriptor(cc, "core4", "./core4")
              .isTransient(false)
              .loadOnStartup(false)
              .build();

      SolrCore core1 = cc.create(cd1);
      SolrCore core2 = cc.create(cd2);
      SolrCore core3 = cc.create(cd3);
      SolrCore core4 = cc.create(cd4);

      SolrXMLCoresLocator.NonPersistingLocator locator =
          (SolrXMLCoresLocator.NonPersistingLocator) cc.getCoresLocator();

      TestHarness.validateXPath(
          locator.xml,
          "/solr/cores/core[@name='collection1']",
          "/solr/cores/core[@name='collectionLazy2']",
          "/solr/cores/core[@name='collectionLazy3']",
          "/solr/cores/core[@name='collectionLazy4']",
          "/solr/cores/core[@name='collectionLazy5']",
          "/solr/cores/core[@name='collectionLazy6']",
          "/solr/cores/core[@name='collectionLazy7']",
          "/solr/cores/core[@name='collectionLazy8']",
          "/solr/cores/core[@name='collectionLazy9']",
          "/solr/cores/core[@name='core1']",
          "/solr/cores/core[@name='core2']",
          "/solr/cores/core[@name='core3']",
          "/solr/cores/core[@name='core4']",
          "13=count(/solr/cores/core)");

      removeOne(cc, "collectionLazy2");
      removeOne(cc, "collectionLazy3");
      removeOne(cc, "collectionLazy4");
      removeOne(cc, "collectionLazy5");
      removeOne(cc, "collectionLazy6");
      removeOne(cc, "collectionLazy7");
      removeOne(cc, "core1");
      removeOne(cc, "core2");
      removeOne(cc, "core3");
      removeOne(cc, "core4");

      // now test that unloading a core means the core is not persisted
      TestHarness.validateXPath(locator.xml, "3=count(/solr/cores/core)");

    } finally {
      cc.shutdown();
    }
  }
Пример #15
0
  @Test
  public void testCachingLimit() throws Exception {
    CoreContainer cc = init();
    try {
      // First check that all the cores that should be loaded at startup actually are.

      checkInCores(cc, "collection1", "collectionLazy2", "collectionLazy5");
      checkNotInCores(
          cc,
          "collectionLazy3",
          "collectionLazy4",
          "collectionLazy6",
          "collectionLazy7",
          "collectionLazy8",
          "collectionLazy9");

      // By putting these in non-alpha order, we're also checking that we're  not just seeing an
      // artifact.
      SolrCore core1 = cc.getCore("collection1");
      SolrCore core3 = cc.getCore("collectionLazy3");
      SolrCore core4 = cc.getCore("collectionLazy4");
      SolrCore core2 = cc.getCore("collectionLazy2");
      SolrCore core5 = cc.getCore("collectionLazy5");

      checkInCores(
          cc,
          "collection1",
          "collectionLazy2",
          "collectionLazy3",
          "collectionLazy4",
          "collectionLazy5");
      checkNotInCores(
          cc, "collectionLazy6", "collectionLazy7", "collectionLazy8", "collectionLazy9");

      // map should be full up, add one more and verify
      SolrCore core6 = cc.getCore("collectionLazy6");
      checkInCores(
          cc,
          "collection1",
          "collectionLazy2",
          "collectionLazy3",
          "collectionLazy4",
          "collectionLazy5",
          "collectionLazy6");
      checkNotInCores(cc, "collectionLazy7", "collectionLazy8", "collectionLazy9");

      SolrCore core7 = cc.getCore("collectionLazy7");
      checkInCores(
          cc,
          "collection1",
          "collectionLazy2",
          "collectionLazy3",
          "collectionLazy4",
          "collectionLazy5",
          "collectionLazy6",
          "collectionLazy7");
      checkNotInCores(cc, "collectionLazy8", "collectionLazy9");

      SolrCore core8 = cc.getCore("collectionLazy8");
      checkInCores(
          cc,
          "collection1",
          "collectionLazy2",
          "collectionLazy4",
          "collectionLazy5",
          "collectionLazy6",
          "collectionLazy7",
          "collectionLazy8");
      checkNotInCores(cc, "collectionLazy3", "collectionLazy9");

      SolrCore core9 = cc.getCore("collectionLazy9");
      checkInCores(
          cc,
          "collection1",
          "collectionLazy4",
          "collectionLazy5",
          "collectionLazy6",
          "collectionLazy7",
          "collectionLazy8",
          "collectionLazy9");
      checkNotInCores(cc, "collectionLazy2", "collectionLazy3");

      // Note decrementing the count when the core is removed from the lazyCores list is
      // appropriate, since the
      // refcount is 1 when constructed. anyone _else_ who's opened up one has to close it.
      core1.close();
      core2.close();
      core3.close();
      core4.close();
      core5.close();
      core6.close();
      core7.close();
      core8.close();
      core9.close();
    } finally {
      cc.shutdown();
    }
  }
Пример #16
0
  @Test
  public void testRefCountMT() throws Exception {
    SolrCore core = h.getCore();
    assertTrue("Refcount != 1", core.getOpenCount() == 1);

    final ClosingRequestHandler handler1 = new ClosingRequestHandler();
    handler1.inform(core);
    String path = "/this/is A path /that won't be registered!";
    SolrRequestHandler old = core.registerRequestHandler(path, handler1);
    assertNull(old); // should not be anything...
    assertEquals(core.getRequestHandlers().get(path), handler1);

    final int LOOP = 100;
    final int MT = 16;
    ExecutorService service =
        ExecutorUtil.newMDCAwareFixedThreadPool(MT, new DefaultSolrThreadFactory("refCountMT"));
    List<Callable<Integer>> callees = new ArrayList<>(MT);
    final CoreContainer cores = h.getCoreContainer();
    for (int i = 0; i < MT; ++i) {
      Callable<Integer> call =
          new Callable<Integer>() {
            void yield(int n) {
              try {
                Thread.sleep(0, (n % 13 + 1) * 10);
              } catch (InterruptedException xint) {
              }
            }

            @Override
            public Integer call() {
              SolrCore core = null;
              int r = 0;
              try {
                for (int l = 0; l < LOOP; ++l) {
                  r += 1;
                  core = cores.getCore(SolrTestCaseJ4.DEFAULT_TEST_CORENAME);
                  // sprinkle concurrency hinting...
                  yield(l);
                  assertTrue("Refcount < 1", core.getOpenCount() >= 1);
                  yield(l);
                  assertTrue("Refcount > 17", core.getOpenCount() <= 17);
                  yield(l);
                  assertTrue("Handler is closed", handler1.closed == false);
                  yield(l);
                  core.close();
                  core = null;
                  yield(l);
                }
                return r;
              } finally {
                if (core != null) core.close();
              }
            }
          };
      callees.add(call);
    }

    List<Future<Integer>> results = service.invokeAll(callees);
    for (Future<Integer> result : results) {
      assertTrue("loop=" + result.get() + " < " + LOOP, result.get() >= LOOP);
    }

    cores.shutdown();
    assertTrue("Refcount != 0", core.getOpenCount() == 0);
    assertTrue("Handler not closed", core.isClosed() && handler1.closed == true);

    service.shutdown();
    assertTrue("Running for too long...", service.awaitTermination(60, TimeUnit.SECONDS));
  }