--- /dev/null
+.. _component:
+
+############################
+Component Tests (with Guice)
+############################
+
+*Note: This document is a work in progress.*
+
+Introduction
+============
+
+Code which uses `dependency injection with standard
+annotations <https://wiki-archive.opendaylight.org/view/BestPractices/DI_Guidelines>`__
+is well suite for component tests.
+
+Component tests cover the functionality of 1 single ODL bundle (e.g.
+netvirt's aclservice, genius' interfacemanager, etc.) They are focused
+on end-to-end testing of APIs, not individual internal implementation
+classes (that's what Unit Tests are for). They focus on testing the code
+in their own module, and typically stub required external services. They
+assert outcome on the system, often those external services, and the
+data store. They wire together the internal beans through a Dependency
+Injection (DI) Framework called Guice, which leverages standard Java
+annotations in the code, which is equally used by Blueprints.
+
+This `presentation from the ODL Summit
+2016 <https://docs.google.com/presentation/d/1bnwj8CrFGo5KekONYSeIHySdkoXZiewJxkHcZjXnzkQ/edit#slide=id.g17d8ae4d92_0_137>`__
+has some content related to this topic.
+
+Maven
+=====
+
+In order to use Google Guice in your end2end API component tests to wire
+bean objects using the same annotations as BP, use:
+
+.. code:: xml
+
+ <dependency>
+ <groupId>org.opendaylight.infrautils</groupId>
+ <artifactId>inject.guice.testutils</artifactId>
+ <version>${infrautils.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+Code
+====
+
+Object Wiring Binding
+---------------------
+
+You can write Guice object binding wiring classes like this:
+
+.. code:: java
+
+ public class AclServiceModule extends AbstractGuiceJsr250Module {
+ @Override
+ protected void configureBindings() {
+ bind(AclServiceManager.class).to(AclServiceManagerImpl.class);
+ bind(AclInterfaceStateListener.class);
+ }
+ ...
+ }
+
+for any OSGi service external to the bundle (not local bean) you use
+bind() like this:
+
+.. code:: text
+
+ bind(DataTreeEventCallbackRegistrar).annotatedWith(OsgiService.class).to(DataTreeEventCallbackRegistrarImpl.class)
+
+JUnit with GuiceRule
+--------------------
+
+Use \*Module classes which define Object Wiring Binding in a JUnit \* Test class
+like this:
+
+.. code:: java
+
+ public @Rule MethodRule guice = new GuiceRule(AclServiceModule.class, AclServiceTestModule.class);
+
+ @Inject DataBroker dataBroker;
+ @Inject AclServiceManager mdsalApiManager;
+ @Inject AclInterfaceStateListener mdsalApiManager;
+
+Async
+=====
+
+In these Component Tests (more so than in simple Unit Tests), one often
+hits problems due to the extensive use of highly asynchronous code in
+ODL. Some progress has been made with testing utilities for each
+respective async API, detailed in this chapter.
+
+genius AsyncClusteredDataTreeChangeListenerBase & AsyncDataTreeChangeListenerBase
+----------------------------------------------------------------------------------
+
+In order to make a test wait for something which happens in a
+AsyncClusteredDataTreeChangeListenerBase or
+AsyncDataTreeChangeListenerBase subclass before then asserting on the
+outcome of what happened, you just add the
+TestableDataTreeChangeListenerModule to the GuiceRule of your \*Test,
+and then @Inject AsyncEventsWaiter asyncEventsWaiter, and use
+awaitEventsConsumption() AFTER having done action like a data store
+write for which a listener should kick in, and BEFORE reading the
+datastore to check the effect:
+
+.. code:: java
+
+ public final @Rule MethodRule guice = new GuiceRule(
+ new YourTestModule(),
+ new TestableDataTreeChangeListenerModule());
+ @Inject AsyncEventsWaiter asyncEventsWaiter;
+ asyncEventsWaiter.awaitEventsConsumption();
+
+If a AsyncClusteredDataTreeChangeListenerBase or
+AsyncDataTreeChangeListenerBase (subclass) has "fired", then the
+AsyncEventsWaiter verifies that a test has indeed used
+awaitEventsConsumption() - and fails the test with
+IllegalStateException: Test forgot an awaitEventsConsumption() if it
+does not. This mechanism ensures that a test does not "forget" to
+awaitEventsConsumption and assert an expected outcome. NB however that
+if the test runs fast, it may end before the listeners kicked in, and
+the IllegalStateException may not always been seen (i.e. leading to a
+"heisenbug", found with the RunUntilFailureRule). Therefore, if in your
+test you do not need to awaitEventsConsumption() at all, then you should
+not use the TestableDataTreeChangeListenerModule. However, this is
+likely an indication of lack of better test coverage in your test - you
+probably do want to assert on the effect of your
+AsyncClusteredDataTreeChangeListenerBase or
+AsyncDataTreeChangeListenerBase subclasses?
+
+infrautils JobCoordinator (formerly genius DataStoreJobCoordinator)
+---------------------------------------------------------------------
+
+similarly to above, using the JobCoordinatorEventsWaiter:
+
+.. code:: text
+
+ @Inject JobCoordinatorEventsWaiter coordinatorEventsWaiter;
+ coordinatorEventsWaiter.awaitEventsConsumption();
+ (TODO still need to be ported from genius to infrautils)
+ (TODO need to write a combined AsyncEventsWaiter instead of doing e.g. InterfaceManagerTestUtil's waitTillOperationCompletes)
+
+It is HIGHLY (!) recommended to FIRST switch code from the @Deprecated
+DataStoreJobCoordinator (in genius) to the JobCoordinator (in
+infrautils), because that does not suffer from the problem where a
+background job can "continue on" from one @Test method into another
+@Test, or even from one \*Test class into another, due to use of
+"static", which can lead to VERY confusing log messages.
+
+genius ResourceBatchingManager
+-------------------------------
+
+The ResourceBatchingManager API does not yet have an AsyncEventsWaiter
+companion.
+
+Other
+-----
+
+Some of our "new style" Component Tests, such as e.g.
+InterfaceManagerConfigurationTest, and others, still need Thread.sleep()
+in some places.. the eventual goal is to be able to eventually
+completely eliminate them from all tests.
+
+Tutorial
+========
+
+Let's imagine you want to make a change e.g. in aclservice, just as an
+example. Specifically, you've added a new argument for another new
+internal bean or external service to the @Singleton
+AclServiceManagerImpl @Inject annotated constructor, let's say to an
+IdManagerService for the sake of this example discussion.
+
+A component test based on Guice wiring, such as AclServiceTest, will now
+fail on you with a message saying something like this:
+
+*No implementation for (...your new service...) was bound while locating
+(...) for the X-th parameter of AclServiceManagerImpl.*
+
+The \*Module classes referenced from the GuiceRule in a \*Test is where
+the wiring is defined - that's what determines, for that test, what
+implementation class is bound to what service interface etc. If you have
+a look at e.g. the AclServiceModule & AclServiceTestModule, it should be
+obvious what that does - just 1 single line for each binding.
+
+The error message shown above simply means that an interface was
+encountered but you have not specified what implementation you would
+like to use for that interface in a given test. (Different tests could
+have different Module with varying bindings; but don't have to.)
+
+To fix this after having made your change, you would now have to add 1
+line in AclServiceTestModule to do a bind() of IdManagerService to...
+something.
+
+If IdManagerServiceas was some new internal helper class of aclservice
+which you would like to test, then you would just do:
+
+.. code:: java
+
+ bind(IdManagerService.class).to(YOURIdManagerServiceImpl.class);
+
+The YOURIdManagerServiceImpl would have a @Singleton annotation on its
+class, and have an @Inject annotation on its constructor, to
+automatically get its dependencies injected (and perhaps have
+@PostConstruct and @PreDestroy, if it has a "lifecycle"; or extend
+AbstractLifecycle). This is further documented on the `DI
+Guidelines <https://wiki-archive.opendaylight.org/view/BestPractices/DI_Guidelines>`__
+page.
+
+Now, in the case of an existing ODL service from another project, you
+typically didn't actually write your own implementation of the
+IdManagerService interface. At full system runtime, you probably would
+like that to use the IdManager class (and you probably added that to
+your BP XML). So, having understood above, you COULD now be tempted to
+add this in AclServiceTestModule:
+
+.. code:: java
+
+ bind(IdManagerService.class).to(IdManager.class);
+
+but there is two problems with this, 1. small practical (easy to fix),
+2. conceptual (more important):
+
+1. IdManager at the time of initially writing this documentation didnt't
+have @Singleton @Inject and @PreDestroy on its close() .. this may have
+already changed - or you could, easily, make a contribution to Genius to
+change that; I'd recommend making IdManager extend AbstractLifecycle in
+this case. This can theoretically, even though we wouldn't recommend
+that, also be worked-around by doing the IdManager "wiring" manually
+through 2 lines of like new IdManager(...) and then use
+bind(IdManagerService.class) .toInstance(myIdManager). BUT...
+
+2. ... it would, typically IMHO, be wrong to use IdManager as
+IdManagerService implementation in AclServiceTest. This is more of a
+general recommendation than a hard rule. The idea is that the component
+test of aclservice should NOT have to depend on the real implementation
+of all external services the aclservice code depends on (only all of the
+internal beans of aclservice). So it would, generally, be considered
+better to bind a local test implementation of IdManager, which does the
+minimum you need for the test. A full coverage test of IdManager would
+be the responsibility of genius' idmanager-impl, not aclservice-impl. So
+what I would probably start with doing in your case, unless there is a
+very strong need that you must absolutely have the "full" IdManager for
+the AclServiceTest, is to just put this into AclServiceTestModule's
+configure() method:
+
+.. code:: java
+
+ // import static org.opendaylight.yangtools.testutils.mockito.MoreAnswers.*;
+ bind(IdManagerService.class).toInstance(Mockito.mock(IdManagerService.class, exception());
+
+Doing this will resolve the Guice Exception you have run into below. But
+whenever some aclservice code now actually calls a method
+IdManagerService, you'll get an UnstubbedMethodException .. and this is
+normal - because you just mocked IdManagerService! I would still
+recommend to start like this, and then go about fixing
+UnstubbedMethodException as they arise when you run AclServiceTest ...
+
+Let's for example say that your new code calls IdManagerServices'
+allocateIdRange() method somewhere - I don't know if it does, so this is
+just for Illustration. You could make your mocked IdManagerService do
+something else than throw a UnstubbedMethodException for
+allocateIdRange() in two different "styles", this is somewhat dependant
+on personal preference:
+
+A) Write out a partial "fake" implementation of it:
+
+Write an inner class right there inside at the end of the
+AclServiceTestModule.java - just because it's easier to have this
+together and immediately evident when reading code; unless it becomes
+very long, in which case you could also move it outside, of course:
+
+.. code:: java
+
+ private abstract static class TestIdManagerService implements IdManagerService {
+ @Override
+ public Future<RpcResult<AllocateIdOutput>> allocateId(AllocateIdInput input) {
+ // TODO do something minimalistic here, just useful for the test, not a general implementation
+ }
+ }
+
+Note that the code in such test service implementations are typically
+simplistic and trivial, and not "real full fledged". Note also that only
+methods which the test actually requires are implemented; because it's
+abstract, we don't have to write anything at all for other methods of
+the interface.
+
+You can then change the binding in configure() to be:
+
+.. code:: text
+
+ bind(IdManagerService.class).toInstance(Mockito.mock(TestIdManagerService.class, realOrException())
+
+Note the subtle difference with the use of realOrException() instead of
+just exception().
+
+This first style is vorburger's personal preference; finding this code
+clearer to read and understand for anyone than "traditional" Mockito
+usage, and not minding to have to type a few extra lines (for the
+class), which the IDE will put for me on Ctrl-Space anyway, than having
+to understand the Mockito magic. This is particular true when the
+implemented methods have anything but non-trivial arguments and return
+types - which is often the case in ODL.
+
+B) Write the implementation using traditional Mockito API:
+
+Write a method, just for clarify, such as:
+
+.. code:: java
+
+ private IdManagerService idManagerService() {
+ IdManagerService idManagerService = Mockito.mock(IdManagerService.class);
+ Mockito.when(idManagerService.allocateId(...)).thenReturn(...);
+ // etc.
+ return idManagerService;
+ }
+
+and then changing the binding in configure() to be:
+
+.. code:: java
+
+ bind(IdManagerService.class).toInstance(idManagerService());