@Test
  public void testServicesInstanciatedOnceAndStartedOnce() throws Exception {

    @ServiceDependencies(TestProvidedService.class)
    class Consumer1 implements Service {
      @Override
      public void start(ServiceProvider<Service> serviceProvider) {}

      @Override
      public void stop() {}
    }

    @ServiceDependencies(TestProvidedService.class)
    class Consumer2 implements Service {
      TestProvidedService testProvidedService;

      @Override
      public void start(ServiceProvider<Service> serviceProvider) {
        testProvidedService = serviceProvider.getService(TestProvidedService.class);
      }

      @Override
      public void stop() {}
    }

    Consumer1 consumer1 = spy(new Consumer1());
    Consumer2 consumer2 = new Consumer2();
    ServiceLocator serviceLocator = new ServiceLocator();

    // add some services
    serviceLocator.addService(consumer1);
    serviceLocator.addService(consumer2);
    serviceLocator.addService(
        new TestService() {
          @Override
          public void start(ServiceProvider<Service> serviceProvider) {}

          @Override
          public void stop() {
            // no-op
          }
        });

    // simulate what is done in ehcachemanager
    serviceLocator.loadDependenciesOf(TestServiceConsumerService.class);
    serviceLocator.startAllServices();

    serviceLocator.stopAllServices();

    verify(consumer1, times(1)).start(serviceLocator);
    verify(consumer1, times(1)).stop();

    assertThat(consumer2.testProvidedService.ctors(), greaterThanOrEqualTo(1));
    assertThat(consumer2.testProvidedService.stops(), equalTo(1));
    assertThat(consumer2.testProvidedService.starts(), equalTo(1));
  }
  @Test
  public void testClassHierarchies() {
    ServiceLocator provider = new ServiceLocator();
    final Service service = new ChildTestService();
    provider.addService(service);
    assertThat(provider.getService(FooProvider.class), sameInstance(service));
    final Service fancyCacheProvider = new FancyCacheProvider();
    provider.addService(fancyCacheProvider);

    final Collection<CacheProvider> servicesOfType =
        provider.getServicesOfType(CacheProvider.class);
    assertThat(servicesOfType, is(not(empty())));
    assertThat(servicesOfType.iterator().next(), sameInstance(fancyCacheProvider));
  }
  @Test
  public void testCanOverrideServiceDependencyWithoutOrderingProblem() throws Exception {
    final AtomicBoolean started = new AtomicBoolean(false);
    ServiceLocator serviceLocator = new ServiceLocator(new TestServiceConsumerService());
    serviceLocator.addService(
        new TestService() {
          @Override
          public void start(ServiceProvider<Service> serviceProvider) {
            started.set(true);
          }

          @Override
          public void stop() {
            // no-op
          }
        });
    serviceLocator.startAllServices();
    assertThat(started.get(), is(true));
  }
  @Test
  public void testCircularDeps() throws Exception {

    final class StartStopCounter {
      final AtomicInteger startCounter = new AtomicInteger(0);
      final AtomicReference<ServiceProvider<Service>> startServiceProvider =
          new AtomicReference<ServiceProvider<Service>>();
      final AtomicInteger stopCounter = new AtomicInteger(0);

      public void countStart(ServiceProvider<Service> serviceProvider) {
        startCounter.incrementAndGet();
        startServiceProvider.set(serviceProvider);
      }

      public void countStop() {
        stopCounter.incrementAndGet();
      }
    }

    @ServiceDependencies(TestProvidedService.class)
    class Consumer1 implements Service {
      final StartStopCounter startStopCounter = new StartStopCounter();

      @Override
      public void start(ServiceProvider<Service> serviceProvider) {
        assertThat(serviceProvider.getService(TestProvidedService.class), is(notNullValue()));
        startStopCounter.countStart(serviceProvider);
      }

      @Override
      public void stop() {
        startStopCounter.countStop();
      }
    }

    @ServiceDependencies(Consumer1.class)
    class Consumer2 implements Service {
      final StartStopCounter startStopCounter = new StartStopCounter();

      @Override
      public void start(ServiceProvider<Service> serviceProvider) {
        assertThat(serviceProvider.getService(Consumer1.class), is(notNullValue()));
        startStopCounter.countStart(serviceProvider);
      }

      @Override
      public void stop() {
        startStopCounter.countStop();
      }
    }

    @ServiceDependencies(Consumer2.class)
    class MyTestProvidedService extends DefaultTestProvidedService {
      final StartStopCounter startStopCounter = new StartStopCounter();

      @Override
      public void start(ServiceProvider<Service> serviceProvider) {
        assertThat(serviceProvider.getService(Consumer2.class), is(notNullValue()));
        startStopCounter.countStart(serviceProvider);
        super.start(serviceProvider);
      }

      @Override
      public void stop() {
        startStopCounter.countStop();
        super.stop();
      }
    }

    @ServiceDependencies(DependsOnMe.class)
    class DependsOnMe implements Service {
      final StartStopCounter startStopCounter = new StartStopCounter();

      @Override
      public void start(ServiceProvider<Service> serviceProvider) {
        assertThat(serviceProvider.getService(DependsOnMe.class), sameInstance(this));
        startStopCounter.countStart(serviceProvider);
      }

      @Override
      public void stop() {
        startStopCounter.countStop();
      }
    }

    ServiceLocator serviceLocator = new ServiceLocator();

    Consumer1 consumer1 = new Consumer1();
    Consumer2 consumer2 = new Consumer2();
    MyTestProvidedService myTestProvidedService = new MyTestProvidedService();
    DependsOnMe dependsOnMe = new DependsOnMe();

    // add some services
    serviceLocator.addService(consumer1);
    serviceLocator.addService(consumer2);
    serviceLocator.addService(myTestProvidedService);
    serviceLocator.addService(dependsOnMe);

    // simulate what is done in ehcachemanager
    serviceLocator.startAllServices();

    serviceLocator.stopAllServices();

    assertThat(consumer1.startStopCounter.startCounter.get(), is(1));
    assertThat(
        consumer1.startStopCounter.startServiceProvider.get(),
        CoreMatchers.<ServiceProvider<Service>>is(serviceLocator));
    assertThat(consumer2.startStopCounter.startCounter.get(), is(1));
    assertThat(
        consumer2.startStopCounter.startServiceProvider.get(),
        CoreMatchers.<ServiceProvider<Service>>is(serviceLocator));
    assertThat(myTestProvidedService.startStopCounter.startCounter.get(), is(1));
    assertThat(
        myTestProvidedService.startStopCounter.startServiceProvider.get(),
        CoreMatchers.<ServiceProvider<Service>>is(serviceLocator));
    assertThat(dependsOnMe.startStopCounter.startCounter.get(), is(1));
    assertThat(
        dependsOnMe.startStopCounter.startServiceProvider.get(),
        CoreMatchers.<ServiceProvider<Service>>is(serviceLocator));

    assertThat(consumer1.startStopCounter.stopCounter.get(), is(1));
    assertThat(consumer2.startStopCounter.stopCounter.get(), is(1));
    assertThat(myTestProvidedService.startStopCounter.stopCounter.get(), is(1));
    assertThat(dependsOnMe.startStopCounter.stopCounter.get(), is(1));
  }