Problem: sync backends were hardcoded in `SYNC_BACKENDS` list in `init.lua`, auth routed directly through `oauth.google_client`, and adding a non-OAuth backend required editing multiple files. Solution: replace hardcoded list with `discover_backends()` that globs `lua/pending/sync/*.lua` at runtime. Rewrite `M.auth()` to dispatch to per-backend `auth()` methods with `vim.ui.select` fallback. Add `lua/pending/sync/s3.lua` with push/pull/sync via AWS CLI, per-task merge by `_s3_sync_id` (UUID), and `pending.S3Config` type.
185 lines
5 KiB
Lua
185 lines
5 KiB
Lua
require('spec.helpers')
|
|
|
|
local config = require('pending.config')
|
|
|
|
describe('sync', function()
|
|
local tmpdir
|
|
local pending
|
|
|
|
before_each(function()
|
|
tmpdir = vim.fn.tempname()
|
|
vim.fn.mkdir(tmpdir, 'p')
|
|
vim.g.pending = { data_path = tmpdir .. '/tasks.json' }
|
|
config.reset()
|
|
package.loaded['pending'] = nil
|
|
pending = require('pending')
|
|
end)
|
|
|
|
after_each(function()
|
|
vim.fn.delete(tmpdir, 'rf')
|
|
vim.g.pending = nil
|
|
config.reset()
|
|
package.loaded['pending'] = nil
|
|
end)
|
|
|
|
describe('dispatch', function()
|
|
it('errors on unknown subcommand', function()
|
|
local msg
|
|
local orig = vim.notify
|
|
vim.notify = function(m, level)
|
|
if level == vim.log.levels.ERROR then
|
|
msg = m
|
|
end
|
|
end
|
|
pending.command('notreal')
|
|
vim.notify = orig
|
|
assert.are.equal('[pending.nvim]: Unknown subcommand: notreal', msg)
|
|
end)
|
|
|
|
it('errors on unknown action for valid backend', function()
|
|
local msg
|
|
local orig = vim.notify
|
|
vim.notify = function(m, level)
|
|
if level == vim.log.levels.ERROR then
|
|
msg = m
|
|
end
|
|
end
|
|
pending.command('gcal notreal')
|
|
vim.notify = orig
|
|
assert.are.equal("[pending.nvim]: gcal: No 'notreal' action.", msg)
|
|
end)
|
|
|
|
it('lists actions when action is omitted', function()
|
|
local msg = nil
|
|
local orig = vim.notify
|
|
vim.notify = function(m)
|
|
msg = m
|
|
end
|
|
pending.command('gcal')
|
|
vim.notify = orig
|
|
assert.is_not_nil(msg)
|
|
assert.is_truthy(msg:find('push'))
|
|
end)
|
|
|
|
it('routes explicit push action', function()
|
|
local called = false
|
|
local gcal = require('pending.sync.gcal')
|
|
local orig_push = gcal.push
|
|
gcal.push = function()
|
|
called = true
|
|
end
|
|
pending.command('gcal push')
|
|
gcal.push = orig_push
|
|
assert.is_true(called)
|
|
end)
|
|
|
|
it('routes auth command', function()
|
|
local called = false
|
|
local orig_auth = pending.auth
|
|
pending.auth = function()
|
|
called = true
|
|
end
|
|
pending.command('auth')
|
|
pending.auth = orig_auth
|
|
assert.is_true(called)
|
|
end)
|
|
end)
|
|
|
|
it('works with sync.gcal config', function()
|
|
config.reset()
|
|
vim.g.pending = {
|
|
data_path = tmpdir .. '/tasks.json',
|
|
sync = { gcal = { client_id = 'test-id' } },
|
|
}
|
|
local cfg = config.get()
|
|
assert.are.equal('test-id', cfg.sync.gcal.client_id)
|
|
end)
|
|
|
|
describe('gcal module', function()
|
|
it('has name field', function()
|
|
local gcal = require('pending.sync.gcal')
|
|
assert.are.equal('gcal', gcal.name)
|
|
end)
|
|
|
|
it('has push function', function()
|
|
local gcal = require('pending.sync.gcal')
|
|
assert.are.equal('function', type(gcal.push))
|
|
end)
|
|
|
|
it('has health function', function()
|
|
local gcal = require('pending.sync.gcal')
|
|
assert.are.equal('function', type(gcal.health))
|
|
end)
|
|
|
|
it('has auth function', function()
|
|
local gcal = require('pending.sync.gcal')
|
|
assert.are.equal('function', type(gcal.auth))
|
|
end)
|
|
|
|
it('has auth_complete function', function()
|
|
local gcal = require('pending.sync.gcal')
|
|
local completions = gcal.auth_complete()
|
|
assert.is_true(vim.tbl_contains(completions, 'clear'))
|
|
assert.is_true(vim.tbl_contains(completions, 'reset'))
|
|
end)
|
|
end)
|
|
|
|
describe('auto-discovery', function()
|
|
it('discovers gcal and gtasks backends', function()
|
|
local backends = pending.sync_backends()
|
|
assert.is_true(vim.tbl_contains(backends, 'gcal'))
|
|
assert.is_true(vim.tbl_contains(backends, 'gtasks'))
|
|
end)
|
|
|
|
it('excludes modules without name field', function()
|
|
local set = pending.sync_backend_set()
|
|
assert.is_nil(set['oauth'])
|
|
assert.is_nil(set['util'])
|
|
end)
|
|
|
|
it('populates backend set correctly', function()
|
|
local set = pending.sync_backend_set()
|
|
assert.is_true(set['gcal'] == true)
|
|
assert.is_true(set['gtasks'] == true)
|
|
end)
|
|
end)
|
|
|
|
describe('auth dispatch', function()
|
|
it('routes auth to specific backend', function()
|
|
local called_with = nil
|
|
local gcal = require('pending.sync.gcal')
|
|
local orig_auth = gcal.auth
|
|
gcal.auth = function(args)
|
|
called_with = args or 'default'
|
|
end
|
|
pending.auth('gcal')
|
|
gcal.auth = orig_auth
|
|
assert.are.equal('default', called_with)
|
|
end)
|
|
|
|
it('routes auth with sub-action', function()
|
|
local called_with = nil
|
|
local gcal = require('pending.sync.gcal')
|
|
local orig_auth = gcal.auth
|
|
gcal.auth = function(args)
|
|
called_with = args
|
|
end
|
|
pending.auth('gcal clear')
|
|
gcal.auth = orig_auth
|
|
assert.are.equal('clear', called_with)
|
|
end)
|
|
|
|
it('errors on unknown backend', function()
|
|
local msg
|
|
local orig = vim.notify
|
|
vim.notify = function(m, level)
|
|
if level == vim.log.levels.ERROR then
|
|
msg = m
|
|
end
|
|
end
|
|
pending.auth('nonexistent')
|
|
vim.notify = orig
|
|
assert.truthy(msg and msg:find('No auth method'))
|
|
end)
|
|
end)
|
|
end)
|