diff --git a/frontend/util.lua b/frontend/util.lua index 34abc4c89..7aca16dbb 100644 --- a/frontend/util.lua +++ b/frontend/util.lua @@ -597,4 +597,11 @@ function util.shell_escape(args) return table.concat(escaped_args, " ") end +--- Clear all the elements from a table without reassignment. +--- @table t the table to be cleared +function util.clearTable(t) + local c = #t + for i = 0, c do t[i] = nil end +end + return util diff --git a/plugins/backgroundrunner.koplugin/main.lua b/plugins/backgroundrunner.koplugin/main.lua index 50ca35c24..d8d755c44 100644 --- a/plugins/backgroundrunner.koplugin/main.lua +++ b/plugins/backgroundrunner.koplugin/main.lua @@ -66,6 +66,7 @@ local logger = require("logger") local BackgroundRunner = { jobs = PluginShare.backgroundJobs, + running = false, } --- Copies required fields from |job|. @@ -160,6 +161,7 @@ function BackgroundRunner:_execute() local round = 0 while #self.jobs > 0 do local job = table.remove(self.jobs, 1) + logger.dbg("BackgroundRunner: run job ", job, " @ ", os.time()) if job.insert_sec == nil then -- Jobs are first inserted to jobs table from external users. So -- they may not have insert_sec field. @@ -206,14 +208,24 @@ function BackgroundRunner:_execute() end end + self.running = false if PluginShare.stopBackgroundRunner == nil then self:_schedule() + else + logger.dbg("BackgroundRunnerWidget: stop running @ ", os.time()) end end function BackgroundRunner:_schedule() assert(self ~= nil) - UIManager:scheduleIn(2, function() self:_execute() end) + if self.running == false then + logger.dbg("BackgroundRunnerWidget: start running @ ", os.time()) + self.running = true + UIManager:scheduleIn(2, function() self:_execute() end) + else + logger.dbg("BackgroundRunnerWidget: a schedule is pending @ ", + os.time()) + end end function BackgroundRunner:_insert(job) @@ -229,4 +241,15 @@ local BackgroundRunnerWidget = WidgetContainer:new{ runner = BackgroundRunner, } +function BackgroundRunnerWidget:onSuspend() + logger.dbg("BackgroundRunnerWidget:onSuspend() @ ", os.time()) + PluginShare.stopBackgroundRunner = true +end + +function BackgroundRunnerWidget:onResume() + logger.dbg("BackgroundRunnerWidget:onResume() @ ", os.time()) + PluginShare.stopBackgroundRunner = nil + BackgroundRunner:_schedule() +end + return BackgroundRunnerWidget diff --git a/spec/unit/background_runner_spec.lua b/spec/unit/background_runner_spec.lua index eab9cbe9f..0d43cdd35 100644 --- a/spec/unit/background_runner_spec.lua +++ b/spec/unit/background_runner_spec.lua @@ -21,6 +21,10 @@ describe("BackgroundRunner widget tests", function() stopBackgroundRunner() end) + before_each(function() + require("util").clearTable(PluginShare.backgroundJobs) + end) + it("should start job", function() local executed = false table.insert(PluginShare.backgroundJobs, { @@ -288,4 +292,65 @@ describe("BackgroundRunner widget tests", function() UIManager:handleInput() assert.are.equal(2, executed) end) + + it("should stop executing when suspending", function() + local executed = 0 + local job = { + when = 1, + repeated = true, + executable = function() + executed = executed + 1 + end, + } + table.insert(PluginShare.backgroundJobs, job) + + MockTime:increase(2) + UIManager:handleInput() + MockTime:increase(2) + UIManager:handleInput() + assert.are.equal(1, executed) + -- Simulate a suspend event. + requireBackgroundRunner():onSuspend() + for i = 1, 10 do + MockTime:increase(2) + UIManager:handleInput() + assert.are.equal(2, executed) + end + -- Simulate a resume event. + requireBackgroundRunner():onResume() + MockTime:increase(2) + UIManager:handleInput() + assert.are.equal(3, executed) + MockTime:increase(2) + UIManager:handleInput() + assert.are.equal(4, executed) + end) + + it("should not start multiple times after multiple onResume", function() + local executed = 0 + local job = { + when = 1, + repeated = true, + executable = function() + executed = executed + 1 + end, + } + table.insert(PluginShare.backgroundJobs, job) + + for i = 1, 10 do + requireBackgroundRunner():onResume() + end + + MockTime:increase(2) + UIManager:handleInput() + MockTime:increase(2) + UIManager:handleInput() + assert.are.equal(1, executed) + MockTime:increase(2) + UIManager:handleInput() + assert.are.equal(2, executed) + MockTime:increase(2) + UIManager:handleInput() + assert.are.equal(3, executed) + end) end)