mirror of
https://github.com/koreader/koreader
synced 2024-11-11 19:11:14 +00:00
962fd02c98
A BackgroundRunner plugin instance will stop running (rescheduling a check every 2 seconds) when there is no (or no more) job to run. Clients of this service now have to emit an event after adding a job into PluginShare.backgroundJobs, so an already loaded but stopped BackgroundRunner can notice it and start running again.
374 lines
10 KiB
Lua
374 lines
10 KiB
Lua
describe("BackgroundRunner widget tests", function()
|
|
local Device, PluginShare, MockTime, UIManager
|
|
|
|
setup(function()
|
|
require("commonrequire")
|
|
package.unloadAll()
|
|
require("document/canvascontext"):init(require("device"))
|
|
-- Device needs to be loaded before UIManager.
|
|
Device = require("device")
|
|
Device.input.waitEvent = function() end
|
|
PluginShare = require("pluginshare")
|
|
MockTime = require("mock_time")
|
|
MockTime:install()
|
|
UIManager = require("ui/uimanager")
|
|
UIManager._run_forever = true
|
|
requireBackgroundRunner()
|
|
end)
|
|
|
|
teardown(function()
|
|
MockTime:uninstall()
|
|
package.unloadAll()
|
|
require("document/canvascontext"):init(require("device"))
|
|
stopBackgroundRunner()
|
|
end)
|
|
|
|
before_each(function()
|
|
require("util").clearTable(PluginShare.backgroundJobs)
|
|
end)
|
|
|
|
it("should start job", function()
|
|
local executed = false
|
|
table.insert(PluginShare.backgroundJobs, {
|
|
when = 10,
|
|
executable = function()
|
|
executed = true
|
|
end,
|
|
})
|
|
notifyBackgroundJobsUpdated()
|
|
|
|
MockTime:increase(2)
|
|
UIManager:handleInput()
|
|
MockTime:increase(9)
|
|
UIManager:handleInput()
|
|
assert.is_false(executed)
|
|
MockTime:increase(2)
|
|
UIManager:handleInput()
|
|
assert.is_true(executed)
|
|
end)
|
|
|
|
it("should repeat job", function()
|
|
local executed = 0
|
|
table.insert(PluginShare.backgroundJobs, {
|
|
when = 1,
|
|
repeated = function() return executed < 10 end,
|
|
executable = function()
|
|
executed = executed + 1
|
|
end,
|
|
})
|
|
notifyBackgroundJobsUpdated()
|
|
|
|
MockTime:increase(2)
|
|
UIManager:handleInput()
|
|
|
|
for i = 1, 10 do
|
|
MockTime:increase(2)
|
|
UIManager:handleInput()
|
|
assert.are.equal(i, executed)
|
|
end
|
|
MockTime:increase(2)
|
|
UIManager:handleInput()
|
|
assert.are.equal(10, executed)
|
|
end)
|
|
|
|
it("should repeat job for predefined times", function()
|
|
local executed = 0
|
|
table.insert(PluginShare.backgroundJobs, {
|
|
when = 1,
|
|
repeated = 10,
|
|
executable = function()
|
|
executed = executed + 1
|
|
end,
|
|
})
|
|
notifyBackgroundJobsUpdated()
|
|
|
|
MockTime:increase(2)
|
|
UIManager:handleInput()
|
|
|
|
for i = 1, 10 do
|
|
MockTime:increase(2)
|
|
UIManager:handleInput()
|
|
assert.are.equal(i, executed)
|
|
end
|
|
MockTime:increase(2)
|
|
UIManager:handleInput()
|
|
assert.are.equal(10, executed)
|
|
end)
|
|
|
|
it("should block long job", function()
|
|
local executed = 0
|
|
local job = {
|
|
when = 1,
|
|
repeated = true,
|
|
executable = function()
|
|
executed = executed + 1
|
|
MockTime:increase(2)
|
|
end,
|
|
}
|
|
table.insert(PluginShare.backgroundJobs, job)
|
|
notifyBackgroundJobsUpdated()
|
|
|
|
MockTime:increase(2)
|
|
UIManager:handleInput()
|
|
MockTime:increase(2)
|
|
UIManager:handleInput()
|
|
assert.are.equal(1, executed)
|
|
assert.is_true(job.timeout)
|
|
assert.is_true(job.blocked)
|
|
MockTime:increase(2)
|
|
UIManager:handleInput()
|
|
assert.are.equal(1, executed)
|
|
end)
|
|
|
|
it("should execute binary", function()
|
|
local executed = false
|
|
local job = {
|
|
when = 1,
|
|
executable = "ls | grep this-should-not-be-a-file",
|
|
callback = function()
|
|
executed = true
|
|
end,
|
|
}
|
|
table.insert(PluginShare.backgroundJobs, job)
|
|
notifyBackgroundJobsUpdated()
|
|
|
|
while job.end_sec == nil do
|
|
MockTime:increase(2)
|
|
UIManager:handleInput()
|
|
end
|
|
|
|
-- grep should return 1 when there is no match.
|
|
assert.are.equal(1, job.result)
|
|
assert.is_false(job.timeout)
|
|
assert.is_false(job.bad_command)
|
|
assert.is_true(executed)
|
|
end)
|
|
|
|
it("should forward string environment to the executable", function()
|
|
local job = {
|
|
when = 1,
|
|
repeated = false,
|
|
executable = "echo $ENV1 | grep $ENV2",
|
|
environment = {
|
|
ENV1 = "yes",
|
|
ENV2 = "yes",
|
|
}
|
|
}
|
|
table.insert(PluginShare.backgroundJobs, job)
|
|
notifyBackgroundJobsUpdated()
|
|
|
|
while job.end_sec == nil do
|
|
MockTime:increase(2)
|
|
UIManager:handleInput()
|
|
end
|
|
|
|
-- grep should return 0 when there is a match.
|
|
assert.are.equal(0, job.result)
|
|
assert.is_false(job.timeout)
|
|
assert.is_false(job.bad_command)
|
|
|
|
job.environment = {
|
|
ENV1 = "yes",
|
|
ENV2 = "no",
|
|
}
|
|
job.end_sec = nil
|
|
table.insert(PluginShare.backgroundJobs, job)
|
|
notifyBackgroundJobsUpdated()
|
|
|
|
while job.end_sec == nil do
|
|
MockTime:increase(2)
|
|
UIManager:handleInput()
|
|
end
|
|
|
|
-- grep should return 1 when there is no match.
|
|
assert.are.equal(1, job.result)
|
|
assert.is_false(job.timeout)
|
|
assert.is_false(job.bad_command)
|
|
|
|
assert.are.not_equal(os.getenv("ENV1"), "yes")
|
|
assert.are.not_equal(os.getenv("ENV2"), "yes")
|
|
assert.are.not_equal(os.getenv("ENV2"), "no")
|
|
end)
|
|
|
|
it("should forward function environment to the executable", function()
|
|
local env2 = "yes"
|
|
local job = {
|
|
when = 1,
|
|
repeated = false,
|
|
executable = "echo $ENV1 | grep $ENV2",
|
|
environment = function()
|
|
return {
|
|
ENV1 = "yes",
|
|
ENV2 = env2,
|
|
}
|
|
end,
|
|
}
|
|
table.insert(PluginShare.backgroundJobs, job)
|
|
notifyBackgroundJobsUpdated()
|
|
|
|
while job.end_sec == nil do
|
|
MockTime:increase(2)
|
|
UIManager:handleInput()
|
|
end
|
|
|
|
-- grep should return 0 when there is a match.
|
|
assert.are.equal(0, job.result)
|
|
assert.is_false(job.timeout)
|
|
assert.is_false(job.bad_command)
|
|
|
|
job.end_sec = nil
|
|
env2 = "no"
|
|
table.insert(PluginShare.backgroundJobs, job)
|
|
notifyBackgroundJobsUpdated()
|
|
|
|
while job.end_sec == nil do
|
|
MockTime:increase(2)
|
|
UIManager:handleInput()
|
|
end
|
|
|
|
-- grep should return 1 when there is no match.
|
|
assert.are.equal(1, job.result)
|
|
assert.is_false(job.timeout)
|
|
assert.is_false(job.bad_command)
|
|
end)
|
|
|
|
it("should block long binary job", function()
|
|
local job = {
|
|
when = 1,
|
|
repeated = true,
|
|
executable = "sleep 1h",
|
|
environment = {
|
|
TIMEOUT = 1
|
|
}
|
|
}
|
|
table.insert(PluginShare.backgroundJobs, job)
|
|
notifyBackgroundJobsUpdated()
|
|
|
|
while job.end_sec == nil do
|
|
MockTime:increase(2)
|
|
UIManager:handleInput()
|
|
end
|
|
|
|
assert.are.equal(255, job.result)
|
|
assert.is_true(job.timeout)
|
|
assert.is_true(job.blocked)
|
|
end)
|
|
|
|
it("should execute callback", function()
|
|
local executed = 0
|
|
table.insert(PluginShare.backgroundJobs, {
|
|
when = 1,
|
|
repeated = 10,
|
|
executable = function() end,
|
|
callback = function()
|
|
executed = executed + 1
|
|
end,
|
|
})
|
|
notifyBackgroundJobsUpdated()
|
|
|
|
MockTime:increase(2)
|
|
UIManager:handleInput()
|
|
|
|
for i = 1, 10 do
|
|
MockTime:increase(2)
|
|
UIManager:handleInput()
|
|
assert.are.equal(i, executed)
|
|
end
|
|
MockTime:increase(2)
|
|
UIManager:handleInput()
|
|
assert.are.equal(10, executed)
|
|
end)
|
|
|
|
it("should not execute two jobs sequentially", function()
|
|
local executed = 0
|
|
table.insert(PluginShare.backgroundJobs, {
|
|
when = 1,
|
|
executable = function()
|
|
executed = executed + 1
|
|
end,
|
|
})
|
|
table.insert(PluginShare.backgroundJobs, {
|
|
when = 1,
|
|
executable = function()
|
|
executed = executed + 1
|
|
end,
|
|
})
|
|
notifyBackgroundJobsUpdated()
|
|
|
|
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(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)
|
|
notifyBackgroundJobsUpdated()
|
|
|
|
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)
|
|
notifyBackgroundJobsUpdated()
|
|
|
|
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)
|