Unify compact workspace controls and panel transitions, move directory actions into the context menu, and remove backlink UI. Reorganize settings with searchable sections, per-setting resets, shortcut search, and accurate save feedback. Remove sharing UI, APIs, authentication helpers, and storage code; provide a transactional cleanup script with retirement tests. Reject directories during orphan image cleanup and cover mixed-batch preservation.
110 lines
4.2 KiB
Go
110 lines
4.2 KiB
Go
package store
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
func TestRemoveSharingPreservesApplicationData(t *testing.T) {
|
|
script, err := os.ReadFile("../../scripts/remove-sharing.sql")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, layout := range []string{"current", "legacy", "fresh"} {
|
|
t.Run(layout, func(t *testing.T) {
|
|
path := filepath.Join(t.TempDir(), "rawmark.db")
|
|
st, err := Open(path)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Cleanup(func() { st.Close() })
|
|
if _, err := st.db.Exec(`
|
|
INSERT INTO settings VALUES ('auth.password','password-hash'), ('plugin.setting','keep'),
|
|
('share.secret','old-secret'),
|
|
('app.settings','{"fontSize":18,"shortcuts":{"note.share":["Alt+S"],"app.shares":[],"note.open":["Ctrl+O"],"plugin.command":[]},"plugin.data":{"keep":true}}');
|
|
INSERT INTO sessions VALUES ('session-hash',123,456);
|
|
INSERT INTO api_tokens VALUES ('token-id','automation','token-hash','read',123,456);`); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
switch layout {
|
|
case "current":
|
|
_, err = st.db.Exec(`CREATE TABLE shares(token TEXT PRIMARY KEY,password_hash TEXT,created_at INTEGER,expires_at INTEGER);
|
|
CREATE TABLE share_items(share_token TEXT REFERENCES shares(token),item_id INTEGER,path TEXT);
|
|
CREATE INDEX share_items_path ON share_items(path);
|
|
INSERT INTO shares VALUES ('old-token','hash',123,0);
|
|
INSERT INTO share_items VALUES ('old-token',0,'note.md');`)
|
|
case "legacy":
|
|
_, err = st.db.Exec(`CREATE TABLE shares(token TEXT PRIMARY KEY,path TEXT,password_hash TEXT,created_at INTEGER,expires_at INTEGER);
|
|
CREATE INDEX shares_path ON shares(path);
|
|
INSERT INTO shares VALUES ('old-token','note.md','hash',123,0);`)
|
|
}
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for range 2 {
|
|
if _, err := st.db.Exec(string(script)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
if err := st.Close(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
st, err = Open(path)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var remaining int
|
|
if err := st.db.QueryRow(`SELECT count(*) FROM sqlite_master WHERE name IN ('shares','share_items','share_items_path','shares_path')`).Scan(&remaining); err != nil || remaining != 0 {
|
|
t.Fatalf("重启后不应创建分享结构:%d %v", remaining, err)
|
|
}
|
|
if _, ok, err := st.Setting("share.secret"); err != nil || ok {
|
|
t.Fatalf("分享密钥未清除:%v", err)
|
|
}
|
|
for key, want := range map[string]string{
|
|
"auth.password": "password-hash", "plugin.setting": "keep",
|
|
"app.settings": `{"fontSize":18,"shortcuts":{"note.open":["Ctrl+O"],"plugin.command":[]},"plugin.data":{"keep":true}}`,
|
|
} {
|
|
if got, ok, err := st.Setting(key); err != nil || !ok || got != want {
|
|
t.Fatalf("非分享设置被改变:%s %v", key, err)
|
|
}
|
|
}
|
|
var sessions, tokens int
|
|
if err := st.db.QueryRow(`SELECT count(*) FROM sessions WHERE token_hash='session-hash' AND created_at=123 AND expires_at=456`).Scan(&sessions); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := st.db.QueryRow(`SELECT count(*) FROM api_tokens WHERE id='token-id' AND name='automation' AND token_hash='token-hash' AND scope='read' AND created_at=123 AND last_used_at=456`).Scan(&tokens); err != nil || sessions != 1 || tokens != 1 {
|
|
t.Fatalf("会话或 API 令牌被改变:%d %d %v", sessions, tokens, err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRemoveSharingRollsBackOnInvalidSettings(t *testing.T) {
|
|
st, err := Open(filepath.Join(t.TempDir(), "rawmark.db"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer st.Close()
|
|
if _, err := st.db.Exec(`CREATE TABLE shares(token TEXT); INSERT INTO shares VALUES ('old-token'); INSERT INTO settings VALUES ('share.secret','old-secret'),('app.settings','invalid-json');`); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
script, err := os.ReadFile("../../scripts/remove-sharing.sql")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := st.db.Exec(string(script)); err == nil {
|
|
t.Fatal("设置损坏时必须报告错误")
|
|
}
|
|
if _, err := st.db.Exec("ROLLBACK"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var count int
|
|
if err := st.db.QueryRow(`SELECT count(*) FROM shares WHERE token='old-token'`).Scan(&count); err != nil || count != 1 {
|
|
t.Fatalf("失败后分享数据未恢复:%v", err)
|
|
}
|
|
if got, ok, err := st.Setting("share.secret"); err != nil || !ok || got != "old-secret" {
|
|
t.Fatalf("失败后分享密钥未恢复:%v", err)
|
|
}
|
|
}
|