{"action":"created","comment":{"url":"https://api.github.com/repos/apache/incubator-brooklyn/pulls/comments/46172837","id":46172837,"diff_hunk":"@@ -39,122 +42,216 @@\n  * @author m4rkmckenna on 11/11/2015.\n  */\n public class TestFrameworkAssertions {\n-    private static final Logger LOG = LoggerFactory.getLogger(TestFrameworkAssertions.class);\n+\n+    public static final String IS_NULL = \"isNull\";\n+    public static final String NOT_NULL = \"notNull\";\n+    public static final String IS_EQUAL_TO = \"isEqualTo\";\n+    public static final String EQUAL_TO = \"equalTo\";\n+    public static final String EQUALS = \"equals\";\n+    public static final String MATCHES = \"matches\";\n+    public static final String CONTAINS = \"contains\";\n+    public static final String IS_EMPTY = \"isEmpty\";\n+    public static final String NOT_EMPTY = \"notEmpty\";\n+    public static final String HAS_TRUTH_VALUE = \"hasTruthValue\";\n+    public static final String UNKNOWN_CONDITION = \"unknown condition\";\n+\n \n     private TestFrameworkAssertions() {\n     }\n \n+\n     /**\n-     * Evaluates all assertions against dataSupplier\n+     *  Get assertions tolerantly from a configuration key.\n+     *  This supports either a simple map of assertions, such as\n      *\n-     * @param dataSupplier\n-     * @param flags\n-     * @param assertions\n-     */\n-    public static void checkAssertions(final Supplier<String> dataSupplier, final Map flags, final List<Map<String, Object>> assertions) {\n-        //Iterate through assert array\n-        for (final Map<String, Object> assertionsMap : assertions) {\n-            checkAssertions(dataSupplier, flags, assertionsMap);\n-        }\n+     <pre>\n+     assertOut:\n+       contains: 2 users\n+       matches: .*[\\d]* days.*\n+     </pre>\n+     * or a list of such maps, (which allows you to repeat keys):\n+     <pre>\n+     assertOut:\n+     - contains: 2 users\n+     - contains: 2 days\n+     </pre>\n+     or\n+    private static List<Map<String,Object>> getAssertions(ConfigKey<Object> key) {\n     }\n+    */\n+    public static List<Map<String, Object>> getAssertions(Entity entity, ConfigKey<Object> key) {\n+        Object config = entity.getConfig(key);\n+        Maybe<Map<String, Object>> maybeMap = TypeCoercions.tryCoerce(config, new TypeToken<Map<String, Object>>() {});\n+        if (maybeMap.isPresent()) {\n+            return Collections.singletonList(maybeMap.get());\n+        }\n \n-    /**\n-     * Evaluates all assertions against dataSupplier\n-     *\n-     * @param dataSupplier\n-     * @param flags\n-     * @param assertionsMap\n-     */\n-    public static void checkAssertions(final Supplier<String> dataSupplier, final Map flags, final Map<String, Object> assertionsMap) {\n-        for (final Map.Entry<String, Object> assertion : assertionsMap.entrySet()) {\n-            final Maybe<Predicate<String>> optionalPredicate = getPredicate(assertion.getKey(), assertion.getValue());\n-            Asserts.succeedsEventually(flags, new PredicateChecker(dataSupplier, optionalPredicate.get()));\n+        Maybe<List<Map<String, Object>>> maybeList = TypeCoercions.tryCoerce(config,\n+            new TypeToken<List<Map<String, Object>>>() {});\n+        if (maybeList.isPresent()) {\n+            return maybeList.get();\n         }\n+\n+        throw new FatalConfigurationRuntimeException(key.getDescription() + \" is not a map or list of maps\");","path":"usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestFrameworkAssertions.java","position":107,"original_position":107,"commit_id":"e1412e8078c76710f3aedd47191783ab77160553","original_commit_id":"e1412e8078c76710f3aedd47191783ab77160553","user":{"login":"aledsage","id":593113,"avatar_url":"https://avatars.githubusercontent.com/u/593113?v=3","gravatar_id":"","url":"https://api.github.com/users/aledsage","html_url":"https://github.com/aledsage","followers_url":"https://api.github.com/users/aledsage/followers","following_url":"https://api.github.com/users/aledsage/following{/other_user}","gists_url":"https://api.github.com/users/aledsage/gists{/gist_id}","starred_url":"https://api.github.com/users/aledsage/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aledsage/subscriptions","organizations_url":"https://api.github.com/users/aledsage/orgs","repos_url":"https://api.github.com/users/aledsage/repos","events_url":"https://api.github.com/users/aledsage/events{/privacy}","received_events_url":"https://api.github.com/users/aledsage/received_events","type":"User","site_admin":false},"body":"I'd include in error as much context as possible (as long as it doesn't risk logging security info) - e.g. `key.getDescription() + \" of \" + entity + \" must be map or list of maps, but is \" + (config == null ? null : config.getClass().getName())`","created_at":"2015-11-30T17:17:28Z","updated_at":"2015-11-30T17:17:28Z","html_url":"https://github.com/apache/incubator-brooklyn/pull/1066#discussion_r46172837","pull_request_url":"https://api.github.com/repos/apache/incubator-brooklyn/pulls/1066","_links":{"self":{"href":"https://api.github.com/repos/apache/incubator-brooklyn/pulls/comments/46172837"},"html":{"href":"https://github.com/apache/incubator-brooklyn/pull/1066#discussion_r46172837"},"pull_request":{"href":"https://api.github.com/repos/apache/incubator-brooklyn/pulls/1066"}}},"pull_request":{"url":"https://api.github.com/repos/apache/incubator-brooklyn/pulls/1066","id":51677077,"html_url":"https://github.com/apache/incubator-brooklyn/pull/1066","diff_url":"https://github.com/apache/incubator-brooklyn/pull/1066.diff","patch_url":"https://github.com/apache/incubator-brooklyn/pull/1066.patch","issue_url":"https://api.github.com/repos/apache/incubator-brooklyn/issues/1066","number":1066,"state":"open","locked":false,"title":"Updates to Test framework assertions to support multiple assertion failures.","user":{"login":"geomacy","id":14142759,"avatar_url":"https://avatars.githubusercontent.com/u/14142759?v=3","gravatar_id":"","url":"https://api.github.com/users/geomacy","html_url":"https://github.com/geomacy","followers_url":"https://api.github.com/users/geomacy/followers","following_url":"https://api.github.com/users/geomacy/following{/other_user}","gists_url":"https://api.github.com/users/geomacy/gists{/gist_id}","starred_url":"https://api.github.com/users/geomacy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/geomacy/subscriptions","organizations_url":"https://api.github.com/users/geomacy/orgs","repos_url":"https://api.github.com/users/geomacy/repos","events_url":"https://api.github.com/users/geomacy/events{/privacy}","received_events_url":"https://api.github.com/users/geomacy/received_events","type":"User","site_admin":false},"body":"At the moment in the test framework, as noted in [#1030](https://github.com/apache/incubator-brooklyn/pull/1030#issuecomment-158995925), when assertions fail it's not easy to see from the error text in the Activity log what went wrong. In particular if there are multiple assertions that failed this isn't apparent.\r\n\r\nThis update merges the assertion code from SimpleShellCommand and TestFrameworkAssertions to give:\r\n\r\n- Updates test framework assertions so that multiple failures are described in the assertion failure message, such as\r\n```\r\n    Assertions failed: exit code equals 1 stdout equals bogus stdout contains porkpie\r\n```\r\n- Supports generic 'actual' parameter, so we can avoid doing type coercions to String in\r\norder to check assertions.\r\n\r\n- Adds \"hasTruthValue\" condition.","created_at":"2015-11-24T15:51:05Z","updated_at":"2015-11-30T17:17:28Z","closed_at":null,"merged_at":null,"merge_commit_sha":"c4ca90801d37b37560babe4a5061624a1e9a7f7c","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/apache/incubator-brooklyn/pulls/1066/commits","review_comments_url":"https://api.github.com/repos/apache/incubator-brooklyn/pulls/1066/comments","review_comment_url":"https://api.github.com/repos/apache/incubator-brooklyn/pulls/comments{/number}","comments_url":"https://api.github.com/repos/apache/incubator-brooklyn/issues/1066/comments","statuses_url":"https://api.github.com/repos/apache/incubator-brooklyn/statuses/e1412e8078c76710f3aedd47191783ab77160553","head":{"label":"geomacy:update-test-assertions-for-multiple-failures","ref":"update-test-assertions-for-multiple-failures","sha":"e1412e8078c76710f3aedd47191783ab77160553","user":{"login":"geomacy","id":14142759,"avatar_url":"https://avatars.githubusercontent.com/u/14142759?v=3","gravatar_id":"","url":"https://api.github.com/users/geomacy","html_url":"https://github.com/geomacy","followers_url":"https://api.github.com/users/geomacy/followers","following_url":"https://api.github.com/users/geomacy/following{/other_user}","gists_url":"https://api.github.com/users/geomacy/gists{/gist_id}","starred_url":"https://api.github.com/users/geomacy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/geomacy/subscriptions","organizations_url":"https://api.github.com/users/geomacy/orgs","repos_url":"https://api.github.com/users/geomacy/repos","events_url":"https://api.github.com/users/geomacy/events{/privacy}","received_events_url":"https://api.github.com/users/geomacy/received_events","type":"User","site_admin":false},"repo":{"id":41976424,"name":"incubator-brooklyn","full_name":"geomacy/incubator-brooklyn","owner":{"login":"geomacy","id":14142759,"avatar_url":"https://avatars.githubusercontent.com/u/14142759?v=3","gravatar_id":"","url":"https://api.github.com/users/geomacy","html_url":"https://github.com/geomacy","followers_url":"https://api.github.com/users/geomacy/followers","following_url":"https://api.github.com/users/geomacy/following{/other_user}","gists_url":"https://api.github.com/users/geomacy/gists{/gist_id}","starred_url":"https://api.github.com/users/geomacy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/geomacy/subscriptions","organizations_url":"https://api.github.com/users/geomacy/orgs","repos_url":"https://api.github.com/users/geomacy/repos","events_url":"https://api.github.com/users/geomacy/events{/privacy}","received_events_url":"https://api.github.com/users/geomacy/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/geomacy/incubator-brooklyn","description":"Mirror of Apache Brooklyn","fork":true,"url":"https://api.github.com/repos/geomacy/incubator-brooklyn","forks_url":"https://api.github.com/repos/geomacy/incubator-brooklyn/forks","keys_url":"https://api.github.com/repos/geomacy/incubator-brooklyn/keys{/key_id}","collaborators_url":"https://api.github.com/repos/geomacy/incubator-brooklyn/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/geomacy/incubator-brooklyn/teams","hooks_url":"https://api.github.com/repos/geomacy/incubator-brooklyn/hooks","issue_events_url":"https://api.github.com/repos/geomacy/incubator-brooklyn/issues/events{/number}","events_url":"https://api.github.com/repos/geomacy/incubator-brooklyn/events","assignees_url":"https://api.github.com/repos/geomacy/incubator-brooklyn/assignees{/user}","branches_url":"https://api.github.com/repos/geomacy/incubator-brooklyn/branches{/branch}","tags_url":"https://api.github.com/repos/geomacy/incubator-brooklyn/tags","blobs_url":"https://api.github.com/repos/geomacy/incubator-brooklyn/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/geomacy/incubator-brooklyn/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/geomacy/incubator-brooklyn/git/refs{/sha}","trees_url":"https://api.github.com/repos/geomacy/incubator-brooklyn/git/trees{/sha}","statuses_url":"https://api.github.com/repos/geomacy/incubator-brooklyn/statuses/{sha}","languages_url":"https://api.github.com/repos/geomacy/incubator-brooklyn/languages","stargazers_url":"https://api.github.com/repos/geomacy/incubator-brooklyn/stargazers","contributors_url":"https://api.github.com/repos/geomacy/incubator-brooklyn/contributors","subscribers_url":"https://api.github.com/repos/geomacy/incubator-brooklyn/subscribers","subscription_url":"https://api.github.com/repos/geomacy/incubator-brooklyn/subscription","commits_url":"https://api.github.com/repos/geomacy/incubator-brooklyn/commits{/sha}","git_commits_url":"https://api.github.com/repos/geomacy/incubator-brooklyn/git/commits{/sha}","comments_url":"https://api.github.com/repos/geomacy/incubator-brooklyn/comments{/number}","issue_comment_url":"https://api.github.com/repos/geomacy/incubator-brooklyn/issues/comments{/number}","contents_url":"https://api.github.com/repos/geomacy/incubator-brooklyn/contents/{+path}","compare_url":"https://api.github.com/repos/geomacy/incubator-brooklyn/compare/{base}...{head}","merges_url":"https://api.github.com/repos/geomacy/incubator-brooklyn/merges","archive_url":"https://api.github.com/repos/geomacy/incubator-brooklyn/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/geomacy/incubator-brooklyn/downloads","issues_url":"https://api.github.com/repos/geomacy/incubator-brooklyn/issues{/number}","pulls_url":"https://api.github.com/repos/geomacy/incubator-brooklyn/pulls{/number}","milestones_url":"https://api.github.com/repos/geomacy/incubator-brooklyn/milestones{/number}","notifications_url":"https://api.github.com/repos/geomacy/incubator-brooklyn/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/geomacy/incubator-brooklyn/labels{/name}","releases_url":"https://api.github.com/repos/geomacy/incubator-brooklyn/releases{/id}","created_at":"2015-09-05T21:37:49Z","updated_at":"2015-09-05T21:37:59Z","pushed_at":"2015-11-26T14:00:43Z","git_url":"git://github.com/geomacy/incubator-brooklyn.git","ssh_url":"git@github.com:geomacy/incubator-brooklyn.git","clone_url":"https://github.com/geomacy/incubator-brooklyn.git","svn_url":"https://github.com/geomacy/incubator-brooklyn","homepage":null,"size":255212,"stargazers_count":0,"watchers_count":0,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"apache:master","ref":"master","sha":"9fa0e3b34caba6d8b969a0aa32818770be22bf0b","user":{"login":"apache","id":47359,"avatar_url":"https://avatars.githubusercontent.com/u/47359?v=3","gravatar_id":"","url":"https://api.github.com/users/apache","html_url":"https://github.com/apache","followers_url":"https://api.github.com/users/apache/followers","following_url":"https://api.github.com/users/apache/following{/other_user}","gists_url":"https://api.github.com/users/apache/gists{/gist_id}","starred_url":"https://api.github.com/users/apache/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apache/subscriptions","organizations_url":"https://api.github.com/users/apache/orgs","repos_url":"https://api.github.com/users/apache/repos","events_url":"https://api.github.com/users/apache/events{/privacy}","received_events_url":"https://api.github.com/users/apache/received_events","type":"Organization","site_admin":false},"repo":{"id":19368221,"name":"incubator-brooklyn","full_name":"apache/incubator-brooklyn","owner":{"login":"apache","id":47359,"avatar_url":"https://avatars.githubusercontent.com/u/47359?v=3","gravatar_id":"","url":"https://api.github.com/users/apache","html_url":"https://github.com/apache","followers_url":"https://api.github.com/users/apache/followers","following_url":"https://api.github.com/users/apache/following{/other_user}","gists_url":"https://api.github.com/users/apache/gists{/gist_id}","starred_url":"https://api.github.com/users/apache/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apache/subscriptions","organizations_url":"https://api.github.com/users/apache/orgs","repos_url":"https://api.github.com/users/apache/repos","events_url":"https://api.github.com/users/apache/events{/privacy}","received_events_url":"https://api.github.com/users/apache/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/apache/incubator-brooklyn","description":"Mirror of Apache Brooklyn","fork":false,"url":"https://api.github.com/repos/apache/incubator-brooklyn","forks_url":"https://api.github.com/repos/apache/incubator-brooklyn/forks","keys_url":"https://api.github.com/repos/apache/incubator-brooklyn/keys{/key_id}","collaborators_url":"https://api.github.com/repos/apache/incubator-brooklyn/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/apache/incubator-brooklyn/teams","hooks_url":"https://api.github.com/repos/apache/incubator-brooklyn/hooks","issue_events_url":"https://api.github.com/repos/apache/incubator-brooklyn/issues/events{/number}","events_url":"https://api.github.com/repos/apache/incubator-brooklyn/events","assignees_url":"https://api.github.com/repos/apache/incubator-brooklyn/assignees{/user}","branches_url":"https://api.github.com/repos/apache/incubator-brooklyn/branches{/branch}","tags_url":"https://api.github.com/repos/apache/incubator-brooklyn/tags","blobs_url":"https://api.github.com/repos/apache/incubator-brooklyn/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/apache/incubator-brooklyn/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/apache/incubator-brooklyn/git/refs{/sha}","trees_url":"https://api.github.com/repos/apache/incubator-brooklyn/git/trees{/sha}","statuses_url":"https://api.github.com/repos/apache/incubator-brooklyn/statuses/{sha}","languages_url":"https://api.github.com/repos/apache/incubator-brooklyn/languages","stargazers_url":"https://api.github.com/repos/apache/incubator-brooklyn/stargazers","contributors_url":"https://api.github.com/repos/apache/incubator-brooklyn/contributors","subscribers_url":"https://api.github.com/repos/apache/incubator-brooklyn/subscribers","subscription_url":"https://api.github.com/repos/apache/incubator-brooklyn/subscription","commits_url":"https://api.github.com/repos/apache/incubator-brooklyn/commits{/sha}","git_commits_url":"https://api.github.com/repos/apache/incubator-brooklyn/git/commits{/sha}","comments_url":"https://api.github.com/repos/apache/incubator-brooklyn/comments{/number}","issue_comment_url":"https://api.github.com/repos/apache/incubator-brooklyn/issues/comments{/number}","contents_url":"https://api.github.com/repos/apache/incubator-brooklyn/contents/{+path}","compare_url":"https://api.github.com/repos/apache/incubator-brooklyn/compare/{base}...{head}","merges_url":"https://api.github.com/repos/apache/incubator-brooklyn/merges","archive_url":"https://api.github.com/repos/apache/incubator-brooklyn/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/apache/incubator-brooklyn/downloads","issues_url":"https://api.github.com/repos/apache/incubator-brooklyn/issues{/number}","pulls_url":"https://api.github.com/repos/apache/incubator-brooklyn/pulls{/number}","milestones_url":"https://api.github.com/repos/apache/incubator-brooklyn/milestones{/number}","notifications_url":"https://api.github.com/repos/apache/incubator-brooklyn/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/apache/incubator-brooklyn/labels{/name}","releases_url":"https://api.github.com/repos/apache/incubator-brooklyn/releases{/id}","created_at":"2014-05-02T07:00:07Z","updated_at":"2015-11-27T21:12:23Z","pushed_at":"2015-11-30T16:53:44Z","git_url":"git://github.com/apache/incubator-brooklyn.git","ssh_url":"git@github.com:apache/incubator-brooklyn.git","clone_url":"https://github.com/apache/incubator-brooklyn.git","svn_url":"https://github.com/apache/incubator-brooklyn","homepage":null,"size":257785,"stargazers_count":131,"watchers_count":131,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":97,"mirror_url":"git://git.apache.org/incubator-brooklyn.git","open_issues_count":15,"forks":97,"open_issues":15,"watchers":131,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/apache/incubator-brooklyn/pulls/1066"},"html":{"href":"https://github.com/apache/incubator-brooklyn/pull/1066"},"issue":{"href":"https://api.github.com/repos/apache/incubator-brooklyn/issues/1066"},"comments":{"href":"https://api.github.com/repos/apache/incubator-brooklyn/issues/1066/comments"},"review_comments":{"href":"https://api.github.com/repos/apache/incubator-brooklyn/pulls/1066/comments"},"review_comment":{"href":"https://api.github.com/repos/apache/incubator-brooklyn/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/apache/incubator-brooklyn/pulls/1066/commits"},"statuses":{"href":"https://api.github.com/repos/apache/incubator-brooklyn/statuses/e1412e8078c76710f3aedd47191783ab77160553"}}}}