{"action":"created","comment":{"url":"https://api.github.com/repos/corda/corda/pulls/comments/177045936","pull_request_review_id":106836943,"id":177045936,"diff_hunk":"@@ -183,4 +198,97 @@ class NodeSchedulerServiceTest {\n         scheduler.unscheduleStateActivity(schedule(mark + 1.days).stateRef)\n         testClock.advanceBy(1.days)\n     }\n+}\n+\n+class NodeSchedulerPersistenceTest : NodeSchedulerServiceTestBase() {\n+    private val databaseConfig: DatabaseConfig = DatabaseConfig()\n+\n+    fun createScheduler(db: CordaPersistence): NodeSchedulerService {\n+        return NodeSchedulerService(\n+                testClock,\n+                db,\n+                flowStarter,\n+                servicesForResolution,\n+                serverThread = MoreExecutors.directExecutor(),\n+                flowLogicRefFactory = flowLogicRefFactory,\n+                nodeProperties = nodeProperties,\n+                drainingModePollPeriod = Duration.ofSeconds(5),\n+                log = log).apply { start() }\n+    }\n+\n+    fun transactionStateMock(logicRef: FlowLogicRef, time: Instant): TransactionState<*> {\n+        return rigorousMock<TransactionState<SchedulableState>>().also {\n+            doReturn(rigorousMock<SchedulableState>().also {\n+                doReturn(ScheduledActivity(logicRef, time)).whenever(it).nextScheduledActivity(any(), any())\n+            }).whenever(it).data\n+        }\n+    }\n+\n+    @Test\n+    fun `test that schedule is persisted`() {\n+        val dataSourceProps = MockServices.makeTestDataSourceProperties()\n+        val timeInTheFuture = mark + 1.days\n+        val stateRef = StateRef(SecureHash.zeroHash, 0)\n+\n+        val database = configureDatabase(dataSourceProps, databaseConfig, rigorousMock())\n+        val scheduler = database.transaction {\n+            createScheduler(database)\n+        }\n+\n+        val ssr1 = ScheduledStateRef(stateRef, timeInTheFuture)\n+        database.transaction {\n+            scheduler.scheduleStateActivity(ssr1)\n+        }\n+        database.dataSource.connection.commit()\n+        //Force the thread to shut down with operations waiting\n+        scheduler.cancel()\n+        database.close()\n+\n+        val flowLogic = rigorousMock<FlowLogic<*>>()\n+        val logicRef = rigorousMock<FlowLogicRef>()\n+\n+        transactionStates[stateRef] = transactionStateMock(logicRef, timeInTheFuture)\n+        flows[logicRef] = flowLogic\n+\n+        val newDatabase = configureDatabase(dataSourceProps, DatabaseConfig(), rigorousMock())\n+        val newScheduler = newDatabase.transaction {\n+            System.out.println(newDatabase.dataSource.connection.metaData)\n+            createScheduler(newDatabase)\n+        }\n+        testClock.advanceBy(1.days)\n+        assertStarted(flowLogic)\n+\n+        newScheduler.join()\n+    }\n+\n+    @Test\n+    fun `test that if schedule is updated then the flow is invoked on the correct schedule`() {\n+        val dataSourceProps = MockServices.makeTestDataSourceProperties()\n+        val timeInTheFuture = mark + 1.days\n+        val stateRef = StateRef(SecureHash.allOnesHash, 0)\n+\n+        val ssr1 = ScheduledStateRef(stateRef, mark)\n+        val ssr2 = ScheduledStateRef(stateRef, timeInTheFuture)\n+        val logicRef = rigorousMock<FlowLogicRef>()\n+        val flowLogic = rigorousMock<FlowLogic<*>>()\n+        val database = configureDatabase(dataSourceProps, databaseConfig, rigorousMock())","path":"node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt","position":215,"original_position":215,"commit_id":"9109ee1c2d0cd1af6bfbe9c1868ffcf344750fa4","original_commit_id":"9109ee1c2d0cd1af6bfbe9c1868ffcf344750fa4","user":{"login":"andr3ej","id":26927791,"avatar_url":"https://avatars3.githubusercontent.com/u/26927791?v=4","gravatar_id":"","url":"https://api.github.com/users/andr3ej","html_url":"https://github.com/andr3ej","followers_url":"https://api.github.com/users/andr3ej/followers","following_url":"https://api.github.com/users/andr3ej/following{/other_user}","gists_url":"https://api.github.com/users/andr3ej/gists{/gist_id}","starred_url":"https://api.github.com/users/andr3ej/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/andr3ej/subscriptions","organizations_url":"https://api.github.com/users/andr3ej/orgs","repos_url":"https://api.github.com/users/andr3ej/repos","events_url":"https://api.github.com/users/andr3ej/events{/privacy}","received_events_url":"https://api.github.com/users/andr3ej/received_events","type":"User","site_admin":false},"body":"as above, never closed","created_at":"2018-03-26T10:36:22Z","updated_at":"2018-03-26T10:49:11Z","html_url":"https://github.com/corda/corda/pull/2860#discussion_r177045936","pull_request_url":"https://api.github.com/repos/corda/corda/pulls/2860","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/corda/corda/pulls/comments/177045936"},"html":{"href":"https://github.com/corda/corda/pull/2860#discussion_r177045936"},"pull_request":{"href":"https://api.github.com/repos/corda/corda/pulls/2860"}}},"pull_request":{"url":"https://api.github.com/repos/corda/corda/pulls/2860","id":176493774,"html_url":"https://github.com/corda/corda/pull/2860","diff_url":"https://github.com/corda/corda/pull/2860.diff","patch_url":"https://github.com/corda/corda/pull/2860.patch","issue_url":"https://api.github.com/repos/corda/corda/issues/2860","number":2860,"state":"open","locked":false,"title":"CORDA-1002 Add node scheduler persistence tests","user":{"login":"anthonykr3","id":34482776,"avatar_url":"https://avatars3.githubusercontent.com/u/34482776?v=4","gravatar_id":"","url":"https://api.github.com/users/anthonykr3","html_url":"https://github.com/anthonykr3","followers_url":"https://api.github.com/users/anthonykr3/followers","following_url":"https://api.github.com/users/anthonykr3/following{/other_user}","gists_url":"https://api.github.com/users/anthonykr3/gists{/gist_id}","starred_url":"https://api.github.com/users/anthonykr3/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/anthonykr3/subscriptions","organizations_url":"https://api.github.com/users/anthonykr3/orgs","repos_url":"https://api.github.com/users/anthonykr3/repos","events_url":"https://api.github.com/users/anthonykr3/events{/privacy}","received_events_url":"https://api.github.com/users/anthonykr3/received_events","type":"User","site_admin":false},"body":"Adds some extra tests to the NodeSchedulerService that test the database persistence. Related to this github issue: https://github.com/corda/corda/issues/2454.\r\n\r\nThere was no need to fix the NodeSchedulerService, as the underlying issue has been fixed by this commit: https://github.com/corda/corda/commit/9d66214f4a97710109df3baecb1244013c7d41ea however it is not immediately clear why this commit fixed it.\r\n\r\nThe `scheduledStates` were originally declared as a `PersistentMap<StateRef, ScheduledStateRef>` on the `NodeSchedulerService`. The above mentioned commit changes it to be initialised by the constructor and explicitly states the parameter type is the generic base class of type `MutableMap<StateRef, ScheduledStateRef>`.\r\n\r\nIf you assign a value to the `PersistentMap` via index (i.e. `scheduledStates[x] = y`), the `set` operator on `PersistentMap` is called which does nothing. This was the behaviour observed in this bug.\r\n\r\nIf you assign a value to a `PersistentMap` cast to a `MutableMap<StateRef, ScheduledStateRef>` it calls the `set` operator defined as an extension function in the Kotlin standard library (see [here](https://github.com/JetBrains/kotlin/blob/f957b3072b6f678f20a79dad3921aee380586f9f/libraries/stdlib/src/kotlin/collections/Maps.kt#L175)) which just calls the `put` method.\r\n\r\nCasting the `PersistentMap` to the generic base class made the `put` method be called instead of the `set` method, which fixed the issue.\r\n\r\nIt is clear that Kotlin expects `set` and `put` to act the same way on collections, so I will alter the `PersistentMap` as part of [CORDA-1001](https://r3-cev.atlassian.net/browse/CORDA-1001) that they both work the same way.\r\n\r\nAm happy to add more tests if there is any thing that could benefit - I think the unit tests cover most cases apart from the fact they use a map that works the way you expect a map to work which is why this issue wasn't picked up by them.","created_at":"2018-03-21T14:28:25Z","updated_at":"2018-03-26T10:49:11Z","closed_at":null,"merged_at":null,"merge_commit_sha":"5ec474e8fce937e1dd7894e8ad9e4b575a77cbdb","assignee":{"login":"anthonykr3","id":34482776,"avatar_url":"https://avatars3.githubusercontent.com/u/34482776?v=4","gravatar_id":"","url":"https://api.github.com/users/anthonykr3","html_url":"https://github.com/anthonykr3","followers_url":"https://api.github.com/users/anthonykr3/followers","following_url":"https://api.github.com/users/anthonykr3/following{/other_user}","gists_url":"https://api.github.com/users/anthonykr3/gists{/gist_id}","starred_url":"https://api.github.com/users/anthonykr3/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/anthonykr3/subscriptions","organizations_url":"https://api.github.com/users/anthonykr3/orgs","repos_url":"https://api.github.com/users/anthonykr3/repos","events_url":"https://api.github.com/users/anthonykr3/events{/privacy}","received_events_url":"https://api.github.com/users/anthonykr3/received_events","type":"User","site_admin":false},"assignees":[{"login":"anthonykr3","id":34482776,"avatar_url":"https://avatars3.githubusercontent.com/u/34482776?v=4","gravatar_id":"","url":"https://api.github.com/users/anthonykr3","html_url":"https://github.com/anthonykr3","followers_url":"https://api.github.com/users/anthonykr3/followers","following_url":"https://api.github.com/users/anthonykr3/following{/other_user}","gists_url":"https://api.github.com/users/anthonykr3/gists{/gist_id}","starred_url":"https://api.github.com/users/anthonykr3/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/anthonykr3/subscriptions","organizations_url":"https://api.github.com/users/anthonykr3/orgs","repos_url":"https://api.github.com/users/anthonykr3/repos","events_url":"https://api.github.com/users/anthonykr3/events{/privacy}","received_events_url":"https://api.github.com/users/anthonykr3/received_events","type":"User","site_admin":false}],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/corda/corda/pulls/2860/commits","review_comments_url":"https://api.github.com/repos/corda/corda/pulls/2860/comments","review_comment_url":"https://api.github.com/repos/corda/corda/pulls/comments{/number}","comments_url":"https://api.github.com/repos/corda/corda/issues/2860/comments","statuses_url":"https://api.github.com/repos/corda/corda/statuses/9109ee1c2d0cd1af6bfbe9c1868ffcf344750fa4","head":{"label":"corda:anthony-node-scheduler-additional-tests","ref":"anthony-node-scheduler-additional-tests","sha":"9109ee1c2d0cd1af6bfbe9c1868ffcf344750fa4","user":{"login":"corda","id":22600631,"avatar_url":"https://avatars1.githubusercontent.com/u/22600631?v=4","gravatar_id":"","url":"https://api.github.com/users/corda","html_url":"https://github.com/corda","followers_url":"https://api.github.com/users/corda/followers","following_url":"https://api.github.com/users/corda/following{/other_user}","gists_url":"https://api.github.com/users/corda/gists{/gist_id}","starred_url":"https://api.github.com/users/corda/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/corda/subscriptions","organizations_url":"https://api.github.com/users/corda/orgs","repos_url":"https://api.github.com/users/corda/repos","events_url":"https://api.github.com/users/corda/events{/privacy}","received_events_url":"https://api.github.com/users/corda/received_events","type":"Organization","site_admin":false},"repo":{"id":70137417,"name":"corda","full_name":"corda/corda","owner":{"login":"corda","id":22600631,"avatar_url":"https://avatars1.githubusercontent.com/u/22600631?v=4","gravatar_id":"","url":"https://api.github.com/users/corda","html_url":"https://github.com/corda","followers_url":"https://api.github.com/users/corda/followers","following_url":"https://api.github.com/users/corda/following{/other_user}","gists_url":"https://api.github.com/users/corda/gists{/gist_id}","starred_url":"https://api.github.com/users/corda/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/corda/subscriptions","organizations_url":"https://api.github.com/users/corda/orgs","repos_url":"https://api.github.com/users/corda/repos","events_url":"https://api.github.com/users/corda/events{/privacy}","received_events_url":"https://api.github.com/users/corda/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/corda/corda","description":"Corda is a distributed ledger platform designed to record, manage and automate legal agreements between business partners. Designed by (and for) the world's largest financial institutions yet with applications in multiple industries.  It offers a unique response to the privacy and scalability challenges facing decentralised applications.","fork":false,"url":"https://api.github.com/repos/corda/corda","forks_url":"https://api.github.com/repos/corda/corda/forks","keys_url":"https://api.github.com/repos/corda/corda/keys{/key_id}","collaborators_url":"https://api.github.com/repos/corda/corda/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/corda/corda/teams","hooks_url":"https://api.github.com/repos/corda/corda/hooks","issue_events_url":"https://api.github.com/repos/corda/corda/issues/events{/number}","events_url":"https://api.github.com/repos/corda/corda/events","assignees_url":"https://api.github.com/repos/corda/corda/assignees{/user}","branches_url":"https://api.github.com/repos/corda/corda/branches{/branch}","tags_url":"https://api.github.com/repos/corda/corda/tags","blobs_url":"https://api.github.com/repos/corda/corda/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/corda/corda/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/corda/corda/git/refs{/sha}","trees_url":"https://api.github.com/repos/corda/corda/git/trees{/sha}","statuses_url":"https://api.github.com/repos/corda/corda/statuses/{sha}","languages_url":"https://api.github.com/repos/corda/corda/languages","stargazers_url":"https://api.github.com/repos/corda/corda/stargazers","contributors_url":"https://api.github.com/repos/corda/corda/contributors","subscribers_url":"https://api.github.com/repos/corda/corda/subscribers","subscription_url":"https://api.github.com/repos/corda/corda/subscription","commits_url":"https://api.github.com/repos/corda/corda/commits{/sha}","git_commits_url":"https://api.github.com/repos/corda/corda/git/commits{/sha}","comments_url":"https://api.github.com/repos/corda/corda/comments{/number}","issue_comment_url":"https://api.github.com/repos/corda/corda/issues/comments{/number}","contents_url":"https://api.github.com/repos/corda/corda/contents/{+path}","compare_url":"https://api.github.com/repos/corda/corda/compare/{base}...{head}","merges_url":"https://api.github.com/repos/corda/corda/merges","archive_url":"https://api.github.com/repos/corda/corda/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/corda/corda/downloads","issues_url":"https://api.github.com/repos/corda/corda/issues{/number}","pulls_url":"https://api.github.com/repos/corda/corda/pulls{/number}","milestones_url":"https://api.github.com/repos/corda/corda/milestones{/number}","notifications_url":"https://api.github.com/repos/corda/corda/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/corda/corda/labels{/name}","releases_url":"https://api.github.com/repos/corda/corda/releases{/id}","deployments_url":"https://api.github.com/repos/corda/corda/deployments","created_at":"2016-10-06T08:46:29Z","updated_at":"2018-03-26T08:56:50Z","pushed_at":"2018-03-26T10:30:59Z","git_url":"git://github.com/corda/corda.git","ssh_url":"git@github.com:corda/corda.git","clone_url":"https://github.com/corda/corda.git","svn_url":"https://github.com/corda/corda","homepage":"https://www.corda.net","size":117101,"stargazers_count":1705,"watchers_count":1705,"language":"Kotlin","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":448,"mirror_url":null,"archived":false,"open_issues_count":128,"license":{"key":"other","name":"Other","spdx_id":null,"url":null},"forks":448,"open_issues":128,"watchers":1705,"default_branch":"master"}},"base":{"label":"corda:master","ref":"master","sha":"620ba1e8a2e6e82aa3bc3dd2ecba9dafd2f48b00","user":{"login":"corda","id":22600631,"avatar_url":"https://avatars1.githubusercontent.com/u/22600631?v=4","gravatar_id":"","url":"https://api.github.com/users/corda","html_url":"https://github.com/corda","followers_url":"https://api.github.com/users/corda/followers","following_url":"https://api.github.com/users/corda/following{/other_user}","gists_url":"https://api.github.com/users/corda/gists{/gist_id}","starred_url":"https://api.github.com/users/corda/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/corda/subscriptions","organizations_url":"https://api.github.com/users/corda/orgs","repos_url":"https://api.github.com/users/corda/repos","events_url":"https://api.github.com/users/corda/events{/privacy}","received_events_url":"https://api.github.com/users/corda/received_events","type":"Organization","site_admin":false},"repo":{"id":70137417,"name":"corda","full_name":"corda/corda","owner":{"login":"corda","id":22600631,"avatar_url":"https://avatars1.githubusercontent.com/u/22600631?v=4","gravatar_id":"","url":"https://api.github.com/users/corda","html_url":"https://github.com/corda","followers_url":"https://api.github.com/users/corda/followers","following_url":"https://api.github.com/users/corda/following{/other_user}","gists_url":"https://api.github.com/users/corda/gists{/gist_id}","starred_url":"https://api.github.com/users/corda/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/corda/subscriptions","organizations_url":"https://api.github.com/users/corda/orgs","repos_url":"https://api.github.com/users/corda/repos","events_url":"https://api.github.com/users/corda/events{/privacy}","received_events_url":"https://api.github.com/users/corda/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/corda/corda","description":"Corda is a distributed ledger platform designed to record, manage and automate legal agreements between business partners. Designed by (and for) the world's largest financial institutions yet with applications in multiple industries.  It offers a unique response to the privacy and scalability challenges facing decentralised applications.","fork":false,"url":"https://api.github.com/repos/corda/corda","forks_url":"https://api.github.com/repos/corda/corda/forks","keys_url":"https://api.github.com/repos/corda/corda/keys{/key_id}","collaborators_url":"https://api.github.com/repos/corda/corda/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/corda/corda/teams","hooks_url":"https://api.github.com/repos/corda/corda/hooks","issue_events_url":"https://api.github.com/repos/corda/corda/issues/events{/number}","events_url":"https://api.github.com/repos/corda/corda/events","assignees_url":"https://api.github.com/repos/corda/corda/assignees{/user}","branches_url":"https://api.github.com/repos/corda/corda/branches{/branch}","tags_url":"https://api.github.com/repos/corda/corda/tags","blobs_url":"https://api.github.com/repos/corda/corda/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/corda/corda/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/corda/corda/git/refs{/sha}","trees_url":"https://api.github.com/repos/corda/corda/git/trees{/sha}","statuses_url":"https://api.github.com/repos/corda/corda/statuses/{sha}","languages_url":"https://api.github.com/repos/corda/corda/languages","stargazers_url":"https://api.github.com/repos/corda/corda/stargazers","contributors_url":"https://api.github.com/repos/corda/corda/contributors","subscribers_url":"https://api.github.com/repos/corda/corda/subscribers","subscription_url":"https://api.github.com/repos/corda/corda/subscription","commits_url":"https://api.github.com/repos/corda/corda/commits{/sha}","git_commits_url":"https://api.github.com/repos/corda/corda/git/commits{/sha}","comments_url":"https://api.github.com/repos/corda/corda/comments{/number}","issue_comment_url":"https://api.github.com/repos/corda/corda/issues/comments{/number}","contents_url":"https://api.github.com/repos/corda/corda/contents/{+path}","compare_url":"https://api.github.com/repos/corda/corda/compare/{base}...{head}","merges_url":"https://api.github.com/repos/corda/corda/merges","archive_url":"https://api.github.com/repos/corda/corda/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/corda/corda/downloads","issues_url":"https://api.github.com/repos/corda/corda/issues{/number}","pulls_url":"https://api.github.com/repos/corda/corda/pulls{/number}","milestones_url":"https://api.github.com/repos/corda/corda/milestones{/number}","notifications_url":"https://api.github.com/repos/corda/corda/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/corda/corda/labels{/name}","releases_url":"https://api.github.com/repos/corda/corda/releases{/id}","deployments_url":"https://api.github.com/repos/corda/corda/deployments","created_at":"2016-10-06T08:46:29Z","updated_at":"2018-03-26T08:56:50Z","pushed_at":"2018-03-26T10:30:59Z","git_url":"git://github.com/corda/corda.git","ssh_url":"git@github.com:corda/corda.git","clone_url":"https://github.com/corda/corda.git","svn_url":"https://github.com/corda/corda","homepage":"https://www.corda.net","size":117101,"stargazers_count":1705,"watchers_count":1705,"language":"Kotlin","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":448,"mirror_url":null,"archived":false,"open_issues_count":128,"license":{"key":"other","name":"Other","spdx_id":null,"url":null},"forks":448,"open_issues":128,"watchers":1705,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/corda/corda/pulls/2860"},"html":{"href":"https://github.com/corda/corda/pull/2860"},"issue":{"href":"https://api.github.com/repos/corda/corda/issues/2860"},"comments":{"href":"https://api.github.com/repos/corda/corda/issues/2860/comments"},"review_comments":{"href":"https://api.github.com/repos/corda/corda/pulls/2860/comments"},"review_comment":{"href":"https://api.github.com/repos/corda/corda/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/corda/corda/pulls/2860/commits"},"statuses":{"href":"https://api.github.com/repos/corda/corda/statuses/9109ee1c2d0cd1af6bfbe9c1868ffcf344750fa4"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"andr3ej"}}