{"action":"created","issue":{"url":"https://api.github.com/repos/codice/ddf/issues/3142","repository_url":"https://api.github.com/repos/codice/ddf","labels_url":"https://api.github.com/repos/codice/ddf/issues/3142/labels{/name}","comments_url":"https://api.github.com/repos/codice/ddf/issues/3142/comments","events_url":"https://api.github.com/repos/codice/ddf/issues/3142/events","html_url":"https://github.com/codice/ddf/pull/3142","id":313472766,"number":3142,"title":"DDF-3621 Created a Failsafe test framework to simplify testing code that internally uses failsafe","user":{"login":"paouelle","id":10549555,"avatar_url":"https://avatars0.githubusercontent.com/u/10549555?v=4","gravatar_id":"","url":"https://api.github.com/users/paouelle","html_url":"https://github.com/paouelle","followers_url":"https://api.github.com/users/paouelle/followers","following_url":"https://api.github.com/users/paouelle/following{/other_user}","gists_url":"https://api.github.com/users/paouelle/gists{/gist_id}","starred_url":"https://api.github.com/users/paouelle/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/paouelle/subscriptions","organizations_url":"https://api.github.com/users/paouelle/orgs","repos_url":"https://api.github.com/users/paouelle/repos","events_url":"https://api.github.com/users/paouelle/events{/privacy}","received_events_url":"https://api.github.com/users/paouelle/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":{"login":"figliold","id":4838043,"avatar_url":"https://avatars3.githubusercontent.com/u/4838043?v=4","gravatar_id":"","url":"https://api.github.com/users/figliold","html_url":"https://github.com/figliold","followers_url":"https://api.github.com/users/figliold/followers","following_url":"https://api.github.com/users/figliold/following{/other_user}","gists_url":"https://api.github.com/users/figliold/gists{/gist_id}","starred_url":"https://api.github.com/users/figliold/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/figliold/subscriptions","organizations_url":"https://api.github.com/users/figliold/orgs","repos_url":"https://api.github.com/users/figliold/repos","events_url":"https://api.github.com/users/figliold/events{/privacy}","received_events_url":"https://api.github.com/users/figliold/received_events","type":"User","site_admin":false},"assignees":[{"login":"figliold","id":4838043,"avatar_url":"https://avatars3.githubusercontent.com/u/4838043?v=4","gravatar_id":"","url":"https://api.github.com/users/figliold","html_url":"https://github.com/figliold","followers_url":"https://api.github.com/users/figliold/followers","following_url":"https://api.github.com/users/figliold/following{/other_user}","gists_url":"https://api.github.com/users/figliold/gists{/gist_id}","starred_url":"https://api.github.com/users/figliold/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/figliold/subscriptions","organizations_url":"https://api.github.com/users/figliold/orgs","repos_url":"https://api.github.com/users/figliold/repos","events_url":"https://api.github.com/users/figliold/events{/privacy}","received_events_url":"https://api.github.com/users/figliold/received_events","type":"User","site_admin":false},{"login":"lessarderic","id":11377558,"avatar_url":"https://avatars1.githubusercontent.com/u/11377558?v=4","gravatar_id":"","url":"https://api.github.com/users/lessarderic","html_url":"https://github.com/lessarderic","followers_url":"https://api.github.com/users/lessarderic/followers","following_url":"https://api.github.com/users/lessarderic/following{/other_user}","gists_url":"https://api.github.com/users/lessarderic/gists{/gist_id}","starred_url":"https://api.github.com/users/lessarderic/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lessarderic/subscriptions","organizations_url":"https://api.github.com/users/lessarderic/orgs","repos_url":"https://api.github.com/users/lessarderic/repos","events_url":"https://api.github.com/users/lessarderic/events{/privacy}","received_events_url":"https://api.github.com/users/lessarderic/received_events","type":"User","site_admin":false}],"milestone":null,"comments":4,"created_at":"2018-04-11T20:17:23Z","updated_at":"2018-04-11T22:37:05Z","closed_at":null,"author_association":"CONTRIBUTOR","pull_request":{"url":"https://api.github.com/repos/codice/ddf/pulls/3142","html_url":"https://github.com/codice/ddf/pull/3142","diff_url":"https://github.com/codice/ddf/pull/3142.diff","patch_url":"https://github.com/codice/ddf/pull/3142.patch"},"body":"#### What does this PR do?\r\nIt creates a test framework that can be used to test code that internally uses failsafe. It allows one to create a failsafe controller that intercepts low level failsafe retry executions in order to script/mock responses. It also make testing more deterministic by taking away the time aspect of failsafe and by providing a simple rendez-vous type of synchronization between the test code and failsafe.\r\n\r\n#### Who is reviewing it? \r\n(please choose AT LEAST two reviewers that need to approve the PR before it can get merged)\r\n@tbatie \r\n@emanns95 \r\n@jhunzik \r\n\r\n#### Select relevant component teams: \r\nhttps://github.com/orgs/codice/teams/test\r\n\r\n#### Choose 2 committers to review/merge the PR. \r\n(please choose ONLY two committers from below, delete the rest)\r\n@figliold\r\n@lessarderic\r\n\r\n#### How should this be tested? (List steps with links to updated documentation)\r\nThe build should go through successfully.\r\n\r\n#### Any background context you want to provide?\r\nThis framework is currently being used as part of the ticket listed below to simplify testing the Solr Factory client adapter.\r\n\r\nThe point of entry to the framework is the FailsafeController class.\r\n\r\nWe are forced to define this framework in the same package as Failsafe in order to intercept or access package visible methods or attributes.\r\n\r\nExample of a test that uses the framework:\r\n```public class SolrClientAdapterTest {\r\n  private static final String CORE = \"test_core\";\r\n  private static final int AVAILABLE_TIMEOUT_IN_SECS = 25;\r\n  private static final long AVAILABLE_TIMEOUT =\r\n      SolrClientAdapterTest.AVAILABLE_TIMEOUT_IN_SECS * 1000L;\r\n\r\n  private static final OptionalCause<? extends Throwable> PING_FAILURE =\r\n      SolrClientStatefulProxy.OptionalCause.of(new UnavailableSolrException(\"testing\"));\r\n\r\n  private final SolrPingResponse pingOk = Mockito.mock(SolrPingResponse.class);\r\n\r\n  final FailsafeController<SolrClientProxy> createController =\r\n      new FailsafeController<>(\"SolrClient Creation\");\r\n  final FailsafeController<OptionalCause<? extends Throwable>> pingController =\r\n      new FailsafeController(\"SolrClient Ping\");\r\n\r\n  @Before\r\n  public void setup() throws Exception {\r\n    final NamedList<?> okList = Mockito.mock(NamedList.class);\r\n\r\n    Mockito.doReturn(okList).when(pingOk).getResponse();\r\n    Mockito.doReturn(\"OK\").when(okList).get(\"status\");\r\n  }\r\n\r\n  @After\r\n  public void tearDown() throws Exception {\r\n    createController.shutdown();\r\n    pingController.shutdown();\r\n  }\r\n\r\n  @Test(timeout = SolrClientAdapterTest.AVAILABLE_TIMEOUT)\r\n  public void testIsAvailableAsTheAdapterChangesStates() throws Exception {\r\n    // setup controller's responses\r\n    createController.whenAttempting().doWaitFor(\"create\").then().doProceed().done();\r\n    pingController\r\n        .whenAttempting()\r\n        .doReturn(SolrClientAdapterTest.PING_FAILURE)\r\n        .untilNotifiedFor(\"ping\")\r\n        .then()\r\n        .doProceed()\r\n        .forever();\r\n\r\n    // prepare SolrClient's responses\r\n    final Creator creator = Mockito.mock(Creator.class);\r\n    final SolrClient client = Mockito.mock(SolrClient.class);\r\n\r\n    Mockito.doReturn(client).when(creator).create();\r\n    Mockito.doReturn(pingOk).when(client).ping();\r\n\r\n    // create the adapter\r\n    final SolrClientAdapter adapter =\r\n        new SolrClientAdapter(\r\n            SolrClientAdapterTest.CORE, creator, createController::with, pingController::with);\r\n\r\n    // after adapter creation and before the client is created, the adapter should be unavailable\r\n    Assert.assertThat(adapter.isAvailable(), Matchers.equalTo(false));\r\n\r\n    // trigger the client creation\r\n    createController.notify(\"create\");\r\n\r\n    // after client creation and before the first ping returns, the adapter should still be\r\n    // unavailable\r\n    Assert.assertThat(adapter.isAvailable(), Matchers.equalTo(false));\r\n\r\n    // trigger the first ping\r\n    pingController.notify(\"ping\");\r\n\r\n    // ensures failsafe has completed its job\r\n    createController.waitForCompletion();\r\n    pingController.waitForCompletion();\r\n\r\n    // after the first successful ping, the adapter should become available\r\n    Assert.assertThat(adapter.isAvailable(), Matchers.equalTo(true));\r\n\r\n    // retest isAvailable() with a timeout\r\n    Assert.assertThat(\r\n        adapter.isAvailable(SolrClientAdapterTest.AVAILABLE_TIMEOUT_IN_SECS, TimeUnit.SECONDS),\r\n        Matchers.equalTo(true));\r\n\r\n    // verify there are no failures and no more actions left on the failsafe controllers\r\n    createController.verifyNoMoreActions();\r\n    pingController.verifyNoMoreActions();\r\n  }\r\n}\r\n```\r\n\r\n#### What are the relevant tickets?\r\n[DDF-3621](https://codice.atlassian.net/browse/DDF-3621)\r\n\r\n#### Screenshots (if appropriate)\r\n\r\n#### Checklist:\r\n- [ ] Documentation Updated\r\n- [ ] Update / Add Unit Tests\r\n- [ ] Update / Add Integration Tests\r\n\r\n#### Notes on Review Process\r\nPlease see [Notes on Review Process](https://codice.atlassian.net/wiki/spaces/DDF/pages/71946981/Pull+Request+Guidelines) for further guidance on requirements for merging and abbreviated reviews. \r\n\r\n#### Review Comment Legend:\r\n- ✏️ (Pencil) This comment is a nitpick or style suggestion, no action required for approval. This comment should provide a suggestion either as an in line code snippet or a gist. \r\n- ❓ (Question Mark) This comment is to gain a clearer understanding of design or code choices, clarification is required but action may not be necessary for approval.\r\n- ❗ (Exclamation Mark) This comment is critical and requires clarification or action before approval.\r\n"},"comment":{"url":"https://api.github.com/repos/codice/ddf/issues/comments/380617729","html_url":"https://github.com/codice/ddf/pull/3142#issuecomment-380617729","issue_url":"https://api.github.com/repos/codice/ddf/issues/3142","id":380617729,"user":{"login":"cxbot","id":21088360,"avatar_url":"https://avatars2.githubusercontent.com/u/21088360?v=4","gravatar_id":"","url":"https://api.github.com/users/cxbot","html_url":"https://github.com/cxbot","followers_url":"https://api.github.com/users/cxbot/followers","following_url":"https://api.github.com/users/cxbot/following{/other_user}","gists_url":"https://api.github.com/users/cxbot/gists{/gist_id}","starred_url":"https://api.github.com/users/cxbot/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cxbot/subscriptions","organizations_url":"https://api.github.com/users/cxbot/orgs","repos_url":"https://api.github.com/users/cxbot/repos","events_url":"https://api.github.com/users/cxbot/events{/privacy}","received_events_url":"https://api.github.com/users/cxbot/received_events","type":"User","site_admin":false},"created_at":"2018-04-11T22:37:05Z","updated_at":"2018-04-11T22:37:05Z","author_association":"COLLABORATOR","body":"Internal build has been scheduled, your results will be available at build completion."}}
{"actor":{"display_login":"cxbot"}}