mirror of
https://github.com/dnote/dnote
synced 2026-03-14 22:45:50 +01:00
Write migration and test
This commit is contained in:
parent
78d941da90
commit
4fe23fe996
21 changed files with 1435 additions and 1185 deletions
11
Makefile
11
Makefile
|
|
@ -33,7 +33,7 @@ endif
|
|||
test: test-cli test-api test-e2e
|
||||
.PHONY: test
|
||||
|
||||
test-cli:
|
||||
test-cli: generate-cli-schema
|
||||
@echo "==> running CLI test"
|
||||
@(${currentDir}/scripts/cli/test.sh)
|
||||
.PHONY: test-cli
|
||||
|
|
@ -76,7 +76,14 @@ endif
|
|||
@(cd ${currentDir}/host/docker && ./build.sh $(version) $(platform))
|
||||
.PHONY: build-server-docker
|
||||
|
||||
build-cli:
|
||||
generate-cli-schema:
|
||||
@echo "==> generating CLI database schema"
|
||||
@mkdir -p pkg/cli/database
|
||||
@touch pkg/cli/database/schema.sql
|
||||
@go run -tags fts5 pkg/cli/database/cmd/generate-schema.go
|
||||
.PHONY: generate-cli-schema
|
||||
|
||||
build-cli: generate-cli-schema
|
||||
ifeq ($(debug), true)
|
||||
@echo "==> building cli in dev mode"
|
||||
@${currentDir}/scripts/cli/dev.sh
|
||||
|
|
|
|||
|
|
@ -1,35 +0,0 @@
|
|||
/* Copyright (C) 2019, 2020, 2021, 2022, 2023, 2024, 2025 Dnote contributors
|
||||
*
|
||||
* This file is part of Dnote.
|
||||
*
|
||||
* Dnote is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Dnote is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Dnote. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package sync
|
||||
|
||||
import (
|
||||
"github.com/dnote/dnote/pkg/cli/context"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
var testDir = "../../tmp"
|
||||
|
||||
var paths context.Paths = context.Paths{
|
||||
Home: testDir,
|
||||
Cache: testDir,
|
||||
Config: testDir,
|
||||
Data: testDir,
|
||||
}
|
||||
|
||||
var dbPath = filepath.Join(testDir, "test.db")
|
||||
|
|
@ -36,6 +36,17 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// getTestPaths creates unique test paths for parallel test execution
|
||||
func getTestPaths(t *testing.T) context.Paths {
|
||||
testDir := t.TempDir()
|
||||
return context.Paths{
|
||||
Home: testDir,
|
||||
Cache: testDir,
|
||||
Config: testDir,
|
||||
Data: testDir,
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessFragments(t *testing.T) {
|
||||
fragments := []client.SyncFragment{
|
||||
{
|
||||
|
|
@ -106,8 +117,7 @@ func TestProcessFragments(t *testing.T) {
|
|||
|
||||
func TestGetLastSyncAt(t *testing.T) {
|
||||
// set up
|
||||
db := database.InitTestDB(t, "../../tmp/.dnote", nil)
|
||||
defer database.TeardownTestDB(t, db)
|
||||
db := database.InitTestMemoryDB(t)
|
||||
database.MustExec(t, "setting up last_sync_at", db, "INSERT INTO system (key, value) VALUES (?, ?)", consts.SystemLastSyncAt, 1541108743)
|
||||
|
||||
// exec
|
||||
|
|
@ -129,8 +139,7 @@ func TestGetLastSyncAt(t *testing.T) {
|
|||
|
||||
func TestGetLastMaxUSN(t *testing.T) {
|
||||
// set up
|
||||
db := database.InitTestDB(t, "../../tmp/.dnote", nil)
|
||||
defer database.TeardownTestDB(t, db)
|
||||
db := database.InitTestMemoryDB(t)
|
||||
database.MustExec(t, "setting up last_max_usn", db, "INSERT INTO system (key, value) VALUES (?, ?)", consts.SystemLastMaxUSN, 20001)
|
||||
|
||||
// exec
|
||||
|
|
@ -176,8 +185,7 @@ func TestResolveLabel(t *testing.T) {
|
|||
for idx, tc := range testCases {
|
||||
func() {
|
||||
// set up
|
||||
db := database.InitTestDB(t, "../../tmp/.dnote", nil)
|
||||
defer database.TeardownTestDB(t, db)
|
||||
db := database.InitTestMemoryDB(t)
|
||||
|
||||
database.MustExec(t, fmt.Sprintf("inserting book for test case %d", idx), db, "INSERT INTO books (uuid, label) VALUES (?, ?)", "b1-uuid", "js")
|
||||
database.MustExec(t, fmt.Sprintf("inserting book for test case %d", idx), db, "INSERT INTO books (uuid, label) VALUES (?, ?)", "b2-uuid", "css_2")
|
||||
|
|
@ -206,8 +214,7 @@ func TestResolveLabel(t *testing.T) {
|
|||
func TestSyncDeleteNote(t *testing.T) {
|
||||
t.Run("exists on server only", func(t *testing.T) {
|
||||
// set up
|
||||
db := database.InitTestDB(t, dbPath, nil)
|
||||
defer database.TeardownTestDB(t, db)
|
||||
db := database.InitTestMemoryDB(t)
|
||||
|
||||
// execute
|
||||
tx, err := db.Begin()
|
||||
|
|
@ -235,8 +242,7 @@ func TestSyncDeleteNote(t *testing.T) {
|
|||
b1UUID := testutils.MustGenerateUUID(t)
|
||||
|
||||
// set up
|
||||
db := database.InitTestDB(t, dbPath, nil)
|
||||
defer database.TeardownTestDB(t, db)
|
||||
db := database.InitTestMemoryDB(t)
|
||||
|
||||
database.MustExec(t, "inserting b1 for test case %d", db, "INSERT INTO books (uuid, label) VALUES (?, ?)", b1UUID, "b1-label")
|
||||
database.MustExec(t, "inserting n1 for test case %d", db, "INSERT INTO notes (uuid, book_uuid, usn, body, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n1-uuid", b1UUID, 10, "n1 body", 1541108743, false, true)
|
||||
|
|
@ -305,8 +311,7 @@ func TestSyncDeleteNote(t *testing.T) {
|
|||
b1UUID := testutils.MustGenerateUUID(t)
|
||||
|
||||
// set up
|
||||
db := database.InitTestDB(t, dbPath, nil)
|
||||
defer database.TeardownTestDB(t, db)
|
||||
db := database.InitTestMemoryDB(t)
|
||||
|
||||
database.MustExec(t, "inserting b1 for test case %d", db, "INSERT INTO books (uuid, label) VALUES (?, ?)", b1UUID, "b1-label")
|
||||
database.MustExec(t, "inserting n1 for test case %d", db, "INSERT INTO notes (uuid, book_uuid, usn, body, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n1-uuid", b1UUID, 10, "n1 body", 1541108743, false, false)
|
||||
|
|
@ -361,8 +366,7 @@ func TestSyncDeleteNote(t *testing.T) {
|
|||
func TestSyncDeleteBook(t *testing.T) {
|
||||
t.Run("exists on server only", func(t *testing.T) {
|
||||
// set up
|
||||
db := database.InitTestDB(t, dbPath, nil)
|
||||
defer database.TeardownTestDB(t, db)
|
||||
db := database.InitTestMemoryDB(t)
|
||||
database.MustExec(t, "inserting b1 for test case %d", db, "INSERT INTO books (uuid, label) VALUES (?, ?)", "b1-uuid", "b1-label")
|
||||
|
||||
var b1 database.Book
|
||||
|
|
@ -406,8 +410,7 @@ func TestSyncDeleteBook(t *testing.T) {
|
|||
b1UUID := testutils.MustGenerateUUID(t)
|
||||
|
||||
// set up
|
||||
db := database.InitTestDB(t, dbPath, nil)
|
||||
defer database.TeardownTestDB(t, db)
|
||||
db := database.InitTestMemoryDB(t)
|
||||
|
||||
database.MustExec(t, "inserting b1 for test case %d", db, "INSERT INTO books (uuid, label, usn, dirty) VALUES (?, ?, ?, ?)", b1UUID, "b1-label", 12, true)
|
||||
database.MustExec(t, "inserting n1 for test case %d", db, "INSERT INTO notes (uuid, book_uuid, usn, body, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n1-uuid", b1UUID, 10, "n1 body", 1541108743, false, true)
|
||||
|
|
@ -472,8 +475,7 @@ func TestSyncDeleteBook(t *testing.T) {
|
|||
b2UUID := testutils.MustGenerateUUID(t)
|
||||
|
||||
// set up
|
||||
db := database.InitTestDB(t, dbPath, nil)
|
||||
defer database.TeardownTestDB(t, db)
|
||||
db := database.InitTestMemoryDB(t)
|
||||
|
||||
database.MustExec(t, "inserting b1 for test case %d", db, "INSERT INTO books (uuid, label) VALUES (?, ?)", b1UUID, "b1-label")
|
||||
database.MustExec(t, "inserting n1 for test case %d", db, "INSERT INTO notes (uuid, book_uuid, usn, body, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n1-uuid", b1UUID, 10, "n1 body", 1541108743, false, false)
|
||||
|
|
@ -538,8 +540,7 @@ func TestSyncDeleteBook(t *testing.T) {
|
|||
b1UUID := testutils.MustGenerateUUID(t)
|
||||
|
||||
// set up
|
||||
db := database.InitTestDB(t, dbPath, nil)
|
||||
defer database.TeardownTestDB(t, db)
|
||||
db := database.InitTestMemoryDB(t)
|
||||
|
||||
database.MustExec(t, "inserting b1 for test case %d", db, "INSERT INTO books (uuid, label) VALUES (?, ?)", b1UUID, "b1-label")
|
||||
database.MustExec(t, "inserting n1 for test case %d", db, "INSERT INTO notes (uuid, book_uuid, usn, body, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n1-uuid", b1UUID, 10, "n1 body", 1541108743, false, true)
|
||||
|
|
@ -590,8 +591,7 @@ func TestSyncDeleteBook(t *testing.T) {
|
|||
func TestFullSyncNote(t *testing.T) {
|
||||
t.Run("exists on server only", func(t *testing.T) {
|
||||
// set up
|
||||
db := database.InitTestDB(t, dbPath, nil)
|
||||
defer database.TeardownTestDB(t, db)
|
||||
db := database.InitTestMemoryDB(t)
|
||||
|
||||
b1UUID := testutils.MustGenerateUUID(t)
|
||||
database.MustExec(t, "inserting book", db, "INSERT INTO books (uuid, label) VALUES (?, ?)", b1UUID, "b1-label")
|
||||
|
|
@ -822,8 +822,7 @@ n1 body edited
|
|||
for idx, tc := range testCases {
|
||||
func() {
|
||||
// set up
|
||||
db := database.InitTestDB(t, dbPath, nil)
|
||||
defer database.TeardownTestDB(t, db)
|
||||
db := database.InitTestMemoryDB(t)
|
||||
|
||||
database.MustExec(t, fmt.Sprintf("inserting b1 for test case %d", idx), db, "INSERT INTO books (uuid, label) VALUES (?, ?)", b1UUID, "b1-label")
|
||||
database.MustExec(t, fmt.Sprintf("inserting b2 for test case %d", idx), db, "INSERT INTO books (uuid, label) VALUES (?, ?)", b2UUID, "b2-label")
|
||||
|
|
@ -884,8 +883,7 @@ n1 body edited
|
|||
func TestFullSyncBook(t *testing.T) {
|
||||
t.Run("exists on server only", func(t *testing.T) {
|
||||
// set up
|
||||
db := database.InitTestDB(t, dbPath, nil)
|
||||
defer database.TeardownTestDB(t, db)
|
||||
db := database.InitTestMemoryDB(t)
|
||||
|
||||
b1UUID := testutils.MustGenerateUUID(t)
|
||||
database.MustExec(t, "inserting book", db, "INSERT INTO books (uuid, usn, label, dirty, deleted) VALUES (?, ?, ?, ?, ?)", b1UUID, 555, "b1-label", true, false)
|
||||
|
|
@ -1023,8 +1021,7 @@ func TestFullSyncBook(t *testing.T) {
|
|||
for idx, tc := range testCases {
|
||||
func() {
|
||||
// set up
|
||||
db := database.InitTestDB(t, dbPath, nil)
|
||||
defer database.TeardownTestDB(t, db)
|
||||
db := database.InitTestMemoryDB(t)
|
||||
|
||||
b1UUID := testutils.MustGenerateUUID(t)
|
||||
database.MustExec(t, fmt.Sprintf("inserting book for test case %d", idx), db, "INSERT INTO books (uuid, usn, label, dirty, deleted) VALUES (?, ?, ?, ?, ?)", b1UUID, tc.clientUSN, tc.clientLabel, tc.clientDirty, tc.clientDeleted)
|
||||
|
|
@ -1076,8 +1073,7 @@ func TestFullSyncBook(t *testing.T) {
|
|||
func TestStepSyncNote(t *testing.T) {
|
||||
t.Run("exists on server only", func(t *testing.T) {
|
||||
// set up
|
||||
db := database.InitTestDB(t, dbPath, nil)
|
||||
defer database.TeardownTestDB(t, db)
|
||||
db := database.InitTestMemoryDB(t)
|
||||
|
||||
b1UUID := testutils.MustGenerateUUID(t)
|
||||
database.MustExec(t, "inserting book", db, "INSERT INTO books (uuid, label) VALUES (?, ?)", b1UUID, "b1-label")
|
||||
|
|
@ -1234,8 +1230,7 @@ n1 body edited
|
|||
for idx, tc := range testCases {
|
||||
func() {
|
||||
// set up
|
||||
db := database.InitTestDB(t, dbPath, nil)
|
||||
defer database.TeardownTestDB(t, db)
|
||||
db := database.InitTestMemoryDB(t)
|
||||
|
||||
database.MustExec(t, fmt.Sprintf("inserting b1 for test case %d", idx), db, "INSERT INTO books (uuid, label) VALUES (?, ?)", b1UUID, "b1-label")
|
||||
database.MustExec(t, fmt.Sprintf("inserting b2 for test case %d", idx), db, "INSERT INTO books (uuid, label) VALUES (?, ?)", b2UUID, "b2-label")
|
||||
|
|
@ -1296,8 +1291,7 @@ n1 body edited
|
|||
func TestStepSyncBook(t *testing.T) {
|
||||
t.Run("exists on server only", func(t *testing.T) {
|
||||
// set up
|
||||
db := database.InitTestDB(t, dbPath, nil)
|
||||
defer database.TeardownTestDB(t, db)
|
||||
db := database.InitTestMemoryDB(t)
|
||||
|
||||
b1UUID := testutils.MustGenerateUUID(t)
|
||||
database.MustExec(t, "inserting book", db, "INSERT INTO books (uuid, usn, label, dirty, deleted) VALUES (?, ?, ?, ?, ?)", b1UUID, 555, "b1-label", true, false)
|
||||
|
|
@ -1419,8 +1413,7 @@ func TestStepSyncBook(t *testing.T) {
|
|||
for idx, tc := range testCases {
|
||||
func() {
|
||||
// set up
|
||||
db := database.InitTestDB(t, dbPath, nil)
|
||||
defer database.TeardownTestDB(t, db)
|
||||
db := database.InitTestMemoryDB(t)
|
||||
|
||||
b1UUID := testutils.MustGenerateUUID(t)
|
||||
database.MustExec(t, fmt.Sprintf("inserting book for test case %d", idx), db, "INSERT INTO books (uuid, usn, label, dirty, deleted) VALUES (?, ?, ?, ?, ?)", b1UUID, tc.clientUSN, tc.clientLabel, tc.clientDirty, tc.clientDeleted)
|
||||
|
|
@ -1483,8 +1476,7 @@ func TestStepSyncBook(t *testing.T) {
|
|||
func TestMergeBook(t *testing.T) {
|
||||
t.Run("insert, no duplicates", func(t *testing.T) {
|
||||
// set up
|
||||
db := database.InitTestDB(t, dbPath, nil)
|
||||
defer database.TeardownTestDB(t, db)
|
||||
db := database.InitTestMemoryDB(t)
|
||||
|
||||
// test
|
||||
tx, err := db.Begin()
|
||||
|
|
@ -1527,8 +1519,7 @@ func TestMergeBook(t *testing.T) {
|
|||
|
||||
t.Run("insert, 1 duplicate", func(t *testing.T) {
|
||||
// set up
|
||||
db := database.InitTestDB(t, dbPath, nil)
|
||||
defer database.TeardownTestDB(t, db)
|
||||
db := database.InitTestMemoryDB(t)
|
||||
database.MustExec(t, "inserting book", db, "INSERT INTO books (uuid, usn, label, dirty, deleted) VALUES (?, ?, ?, ?, ?)", "b1-uuid", 1, "foo", false, false)
|
||||
|
||||
// test
|
||||
|
|
@ -1579,8 +1570,7 @@ func TestMergeBook(t *testing.T) {
|
|||
|
||||
t.Run("insert, 3 duplicates", func(t *testing.T) {
|
||||
// set up
|
||||
db := database.InitTestDB(t, dbPath, nil)
|
||||
defer database.TeardownTestDB(t, db)
|
||||
db := database.InitTestMemoryDB(t)
|
||||
|
||||
database.MustExec(t, "inserting book", db, "INSERT INTO books (uuid, usn, label, dirty, deleted) VALUES (?, ?, ?, ?, ?)", "b1-uuid", 1, "foo", false, false)
|
||||
database.MustExec(t, "inserting book", db, "INSERT INTO books (uuid, usn, label, dirty, deleted) VALUES (?, ?, ?, ?, ?)", "b2-uuid", 2, "foo_2", true, false)
|
||||
|
|
@ -1648,8 +1638,7 @@ func TestMergeBook(t *testing.T) {
|
|||
|
||||
t.Run("update, no duplicates", func(t *testing.T) {
|
||||
// set up
|
||||
db := database.InitTestDB(t, dbPath, nil)
|
||||
defer database.TeardownTestDB(t, db)
|
||||
db := database.InitTestMemoryDB(t)
|
||||
|
||||
// test
|
||||
tx, err := db.Begin()
|
||||
|
|
@ -1695,8 +1684,7 @@ func TestMergeBook(t *testing.T) {
|
|||
|
||||
t.Run("update, 1 duplicate", func(t *testing.T) {
|
||||
// set up
|
||||
db := database.InitTestDB(t, dbPath, nil)
|
||||
defer database.TeardownTestDB(t, db)
|
||||
db := database.InitTestMemoryDB(t)
|
||||
|
||||
database.MustExec(t, "inserting book", db, "INSERT INTO books (uuid, usn, label, dirty, deleted) VALUES (?, ?, ?, ?, ?)", "b1-uuid", 1, "foo", false, false)
|
||||
database.MustExec(t, "inserting book", db, "INSERT INTO books (uuid, usn, label, dirty, deleted) VALUES (?, ?, ?, ?, ?)", "b2-uuid", 2, "bar", false, false)
|
||||
|
|
@ -1749,8 +1737,7 @@ func TestMergeBook(t *testing.T) {
|
|||
|
||||
t.Run("update, 3 duplicate", func(t *testing.T) {
|
||||
// set uj
|
||||
db := database.InitTestDB(t, dbPath, nil)
|
||||
defer database.TeardownTestDB(t, db)
|
||||
db := database.InitTestMemoryDB(t)
|
||||
|
||||
database.MustExec(t, "inserting book", db, "INSERT INTO books (uuid, usn, label, dirty, deleted) VALUES (?, ?, ?, ?, ?)", "b1-uuid", 1, "foo", false, false)
|
||||
database.MustExec(t, "inserting book", db, "INSERT INTO books (uuid, usn, label, dirty, deleted) VALUES (?, ?, ?, ?, ?)", "b2-uuid", 2, "bar", false, false)
|
||||
|
|
@ -1820,11 +1807,8 @@ func TestMergeBook(t *testing.T) {
|
|||
|
||||
func TestSaveServerState(t *testing.T) {
|
||||
// set up
|
||||
ctx := context.InitTestCtx(t, paths, nil)
|
||||
defer context.TeardownTestCtx(t, ctx)
|
||||
testutils.Login(t, &ctx)
|
||||
|
||||
db := ctx.DB
|
||||
db := database.InitTestMemoryDB(t)
|
||||
testutils.LoginDB(t, db)
|
||||
|
||||
database.MustExec(t, "inserting last synced at", db, "INSERT INTO system (key, value) VALUES (?, ?)", consts.SystemLastSyncAt, int64(1231108742))
|
||||
database.MustExec(t, "inserting last max usn", db, "INSERT INTO system (key, value) VALUES (?, ?)", consts.SystemLastMaxUSN, 8)
|
||||
|
|
@ -1864,7 +1848,7 @@ func TestSaveServerState(t *testing.T) {
|
|||
// are updated accordingly based on the server response.
|
||||
func TestSendBooks(t *testing.T) {
|
||||
// set up
|
||||
ctx := context.InitTestCtx(t, paths, nil)
|
||||
ctx := context.InitTestCtx(t, getTestPaths(t))
|
||||
defer context.TeardownTestCtx(t, ctx)
|
||||
testutils.Login(t, &ctx)
|
||||
|
||||
|
|
@ -1900,7 +1884,7 @@ func TestSendBooks(t *testing.T) {
|
|||
var updatesUUIDs []string
|
||||
var deletedUUIDs []string
|
||||
|
||||
// fire up a test server. It decrypts the payload for test purposes.
|
||||
// fire up a test server
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.String() == "/v3/books" && r.Method == "POST" {
|
||||
var payload client.CreateBookPayload
|
||||
|
|
@ -1967,7 +1951,7 @@ func TestSendBooks(t *testing.T) {
|
|||
|
||||
// test
|
||||
|
||||
// First, decrypt data so that they can be asserted
|
||||
// First, sort data so that they can be asserted
|
||||
sort.SliceStable(createdLabels, func(i, j int) bool {
|
||||
return strings.Compare(createdLabels[i], createdLabels[j]) < 0
|
||||
})
|
||||
|
|
@ -2097,7 +2081,7 @@ func TestSendBooks_isBehind(t *testing.T) {
|
|||
for idx, tc := range testCases {
|
||||
func() {
|
||||
// set up
|
||||
ctx := context.InitTestCtx(t, paths, nil)
|
||||
ctx := context.InitTestCtx(t, getTestPaths(t))
|
||||
ctx.APIEndpoint = ts.URL
|
||||
defer context.TeardownTestCtx(t, ctx)
|
||||
testutils.Login(t, &ctx)
|
||||
|
|
@ -2145,7 +2129,7 @@ func TestSendBooks_isBehind(t *testing.T) {
|
|||
for idx, tc := range testCases {
|
||||
func() {
|
||||
// set up
|
||||
ctx := context.InitTestCtx(t, paths, nil)
|
||||
ctx := context.InitTestCtx(t, getTestPaths(t))
|
||||
ctx.APIEndpoint = ts.URL
|
||||
defer context.TeardownTestCtx(t, ctx)
|
||||
testutils.Login(t, &ctx)
|
||||
|
|
@ -2193,7 +2177,7 @@ func TestSendBooks_isBehind(t *testing.T) {
|
|||
for idx, tc := range testCases {
|
||||
func() {
|
||||
// set up
|
||||
ctx := context.InitTestCtx(t, paths, nil)
|
||||
ctx := context.InitTestCtx(t, getTestPaths(t))
|
||||
ctx.APIEndpoint = ts.URL
|
||||
defer context.TeardownTestCtx(t, ctx)
|
||||
testutils.Login(t, &ctx)
|
||||
|
|
@ -2228,7 +2212,7 @@ func TestSendBooks_isBehind(t *testing.T) {
|
|||
// uuid from the incoming data.
|
||||
func TestSendNotes(t *testing.T) {
|
||||
// set up
|
||||
ctx := context.InitTestCtx(t, paths, nil)
|
||||
ctx := context.InitTestCtx(t, getTestPaths(t))
|
||||
defer context.TeardownTestCtx(t, ctx)
|
||||
testutils.Login(t, &ctx)
|
||||
|
||||
|
|
@ -2264,7 +2248,7 @@ func TestSendNotes(t *testing.T) {
|
|||
var updatedUUIDs []string
|
||||
var deletedUUIDs []string
|
||||
|
||||
// fire up a test server. It decrypts the payload for test purposes.
|
||||
// fire up a test server
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.String() == "/v3/notes" && r.Method == "POST" {
|
||||
var payload client.CreateNotePayload
|
||||
|
|
@ -2381,7 +2365,7 @@ func TestSendNotes(t *testing.T) {
|
|||
|
||||
func TestSendNotes_addedOn(t *testing.T) {
|
||||
// set up
|
||||
ctx := context.InitTestCtx(t, paths, nil)
|
||||
ctx := context.InitTestCtx(t, getTestPaths(t))
|
||||
defer context.TeardownTestCtx(t, ctx)
|
||||
testutils.Login(t, &ctx)
|
||||
|
||||
|
|
@ -2393,7 +2377,7 @@ func TestSendNotes_addedOn(t *testing.T) {
|
|||
b1UUID := "b1-uuid"
|
||||
database.MustExec(t, "inserting n1", db, "INSERT INTO notes (uuid, book_uuid, usn, body, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n1-uuid", b1UUID, 0, "n1-body", 1541108743, false, true)
|
||||
|
||||
// fire up a test server. It decrypts the payload for test purposes.
|
||||
// fire up a test server
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.String() == "/v3/notes" && r.Method == "POST" {
|
||||
resp := client.CreateNoteResp{
|
||||
|
|
@ -2513,7 +2497,7 @@ func TestSendNotes_isBehind(t *testing.T) {
|
|||
for idx, tc := range testCases {
|
||||
func() {
|
||||
// set up
|
||||
ctx := context.InitTestCtx(t, paths, nil)
|
||||
ctx := context.InitTestCtx(t, getTestPaths(t))
|
||||
defer context.TeardownTestCtx(t, ctx)
|
||||
testutils.Login(t, &ctx)
|
||||
ctx.APIEndpoint = ts.URL
|
||||
|
|
@ -2562,7 +2546,7 @@ func TestSendNotes_isBehind(t *testing.T) {
|
|||
for idx, tc := range testCases {
|
||||
func() {
|
||||
// set up
|
||||
ctx := context.InitTestCtx(t, paths, nil)
|
||||
ctx := context.InitTestCtx(t, getTestPaths(t))
|
||||
defer context.TeardownTestCtx(t, ctx)
|
||||
testutils.Login(t, &ctx)
|
||||
ctx.APIEndpoint = ts.URL
|
||||
|
|
@ -2611,7 +2595,7 @@ func TestSendNotes_isBehind(t *testing.T) {
|
|||
for idx, tc := range testCases {
|
||||
func() {
|
||||
// set up
|
||||
ctx := context.InitTestCtx(t, paths, nil)
|
||||
ctx := context.InitTestCtx(t, getTestPaths(t))
|
||||
defer context.TeardownTestCtx(t, ctx)
|
||||
testutils.Login(t, &ctx)
|
||||
ctx.APIEndpoint = ts.URL
|
||||
|
|
@ -2777,8 +2761,7 @@ n1 body edited
|
|||
for idx, tc := range testCases {
|
||||
func() {
|
||||
// set up
|
||||
db := database.InitTestDB(t, "../../tmp/.dnote", nil)
|
||||
defer database.TeardownTestDB(t, db)
|
||||
db := database.InitTestMemoryDB(t)
|
||||
|
||||
database.MustExec(t, fmt.Sprintf("inserting b1 for test case %d", idx), db, "INSERT INTO books (uuid, label, usn, dirty) VALUES (?, ?, ?, ?)", b1UUID, "b1-label", 5, false)
|
||||
database.MustExec(t, fmt.Sprintf("inserting b2 for test case %d", idx), db, "INSERT INTO books (uuid, label, usn, dirty) VALUES (?, ?, ?, ?)", b2UUID, "b2-label", 6, false)
|
||||
|
|
@ -2859,8 +2842,7 @@ n1 body edited
|
|||
|
||||
func TestCheckBookPristine(t *testing.T) {
|
||||
// set up
|
||||
db := database.InitTestDB(t, "../../tmp/.dnote", nil)
|
||||
defer database.TeardownTestDB(t, db)
|
||||
db := database.InitTestMemoryDB(t)
|
||||
|
||||
database.MustExec(t, "inserting b1", db, "INSERT INTO books (uuid, label, usn, dirty) VALUES (?, ?, ?, ?)", "b1-uuid", "b1-label", 5, false)
|
||||
database.MustExec(t, "inserting b2", db, "INSERT INTO books (uuid, label, usn, dirty) VALUES (?, ?, ?, ?)", "b2-uuid", "b2-label", 6, false)
|
||||
|
|
@ -3033,8 +3015,7 @@ func TestCheckBookInList(t *testing.T) {
|
|||
|
||||
func TestCleanLocalNotes(t *testing.T) {
|
||||
// set up
|
||||
db := database.InitTestDB(t, "../../tmp/.dnote", nil)
|
||||
defer database.TeardownTestDB(t, db)
|
||||
db := database.InitTestMemoryDB(t)
|
||||
|
||||
list := syncList{
|
||||
Notes: map[string]client.SyncFragNote{
|
||||
|
|
@ -3105,8 +3086,7 @@ func TestCleanLocalNotes(t *testing.T) {
|
|||
|
||||
func TestCleanLocalBooks(t *testing.T) {
|
||||
// set up
|
||||
db := database.InitTestDB(t, "../../tmp/.dnote", nil)
|
||||
defer database.TeardownTestDB(t, db)
|
||||
db := database.InitTestMemoryDB(t)
|
||||
|
||||
list := syncList{
|
||||
Notes: map[string]client.SyncFragNote{
|
||||
|
|
@ -3173,8 +3153,7 @@ func TestCleanLocalBooks(t *testing.T) {
|
|||
|
||||
func TestPrepareEmptyServerSync(t *testing.T) {
|
||||
// set up
|
||||
db := database.InitTestDB(t, "../../tmp/.dnote", nil)
|
||||
defer database.TeardownTestDB(t, db)
|
||||
db := database.InitTestMemoryDB(t)
|
||||
|
||||
// Setup: local has synced data (usn > 0, dirty = false) and some deleted items
|
||||
database.MustExec(t, "inserting b1", db, "INSERT INTO books (uuid, label, usn, deleted, dirty) VALUES (?, ?, ?, ?, ?)", "b1-uuid", "b1-label", 5, false, false)
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@
|
|||
package context
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/dnote/dnote/pkg/cli/consts"
|
||||
|
|
@ -29,11 +29,69 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// InitTestCtx initializes a test context
|
||||
func InitTestCtx(t *testing.T, paths Paths, dbOpts *database.TestDBOptions) DnoteCtx {
|
||||
dbPath := fmt.Sprintf("%s/%s/%s", paths.Data, consts.DnoteDirName, consts.DnoteDBFileName)
|
||||
// createTestDirectories creates test directories for the given paths
|
||||
func createTestDirectories(t *testing.T, paths Paths) {
|
||||
if paths.Config != "" {
|
||||
configDir := filepath.Join(paths.Config, consts.DnoteDirName)
|
||||
if err := os.MkdirAll(configDir, 0755); err != nil {
|
||||
t.Fatal(errors.Wrap(err, "creating test config directory"))
|
||||
}
|
||||
}
|
||||
if paths.Data != "" {
|
||||
dataDir := filepath.Join(paths.Data, consts.DnoteDirName)
|
||||
if err := os.MkdirAll(dataDir, 0755); err != nil {
|
||||
t.Fatal(errors.Wrap(err, "creating test data directory"))
|
||||
}
|
||||
}
|
||||
if paths.Cache != "" {
|
||||
cacheDir := filepath.Join(paths.Cache, consts.DnoteDirName)
|
||||
if err := os.MkdirAll(cacheDir, 0755); err != nil {
|
||||
t.Fatal(errors.Wrap(err, "creating test cache directory"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
db := database.InitTestDB(t, dbPath, dbOpts)
|
||||
// InitTestCtx initializes a test context with an in-memory database
|
||||
func InitTestCtx(t *testing.T, paths Paths) DnoteCtx {
|
||||
db := database.InitTestMemoryDB(t)
|
||||
createTestDirectories(t, paths)
|
||||
|
||||
return DnoteCtx{
|
||||
DB: db,
|
||||
Paths: paths,
|
||||
Clock: clock.NewMock(), // Use a mock clock to test times
|
||||
}
|
||||
}
|
||||
|
||||
// InitTestCtxWithDB initializes a test context with the provided database.
|
||||
// Used when you need full control over database initialization (e.g. migration tests).
|
||||
func InitTestCtxWithDB(t *testing.T, paths Paths, db *database.DB) DnoteCtx {
|
||||
createTestDirectories(t, paths)
|
||||
|
||||
return DnoteCtx{
|
||||
DB: db,
|
||||
Paths: paths,
|
||||
Clock: clock.NewMock(), // Use a mock clock to test times
|
||||
}
|
||||
}
|
||||
|
||||
// InitTestCtxWithFileDB initializes a test context with a file-based database
|
||||
// at the expected XDG path. This is used for e2e tests that spawn CLI processes
|
||||
// which need to access the database file.
|
||||
func InitTestCtxWithFileDB(t *testing.T, paths Paths) DnoteCtx {
|
||||
createTestDirectories(t, paths)
|
||||
|
||||
dbPath := filepath.Join(paths.Data, consts.DnoteDirName, consts.DnoteDBFileName)
|
||||
db, err := database.Open(dbPath)
|
||||
if err != nil {
|
||||
t.Fatal(errors.Wrap(err, "opening database"))
|
||||
}
|
||||
|
||||
if _, err := db.Exec(database.GetDefaultSchemaSQL()); err != nil {
|
||||
t.Fatal(errors.Wrap(err, "running schema sql"))
|
||||
}
|
||||
|
||||
database.MarkMigrationComplete(t, db)
|
||||
|
||||
return DnoteCtx{
|
||||
DB: db,
|
||||
|
|
|
|||
160
pkg/cli/database/cmd/generate-schema.go
Normal file
160
pkg/cli/database/cmd/generate-schema.go
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
/* Copyright (C) 2019, 2020, 2021, 2022, 2023, 2024, 2025 Dnote contributors
|
||||
*
|
||||
* This file is part of Dnote.
|
||||
*
|
||||
* Dnote is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Dnote is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Dnote. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// generate-schema creates a schema.sql file
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/dnote/dnote/pkg/cli/config"
|
||||
"github.com/dnote/dnote/pkg/cli/context"
|
||||
"github.com/dnote/dnote/pkg/cli/database"
|
||||
"github.com/dnote/dnote/pkg/cli/infra"
|
||||
"github.com/dnote/dnote/pkg/cli/migrate"
|
||||
)
|
||||
|
||||
func main() {
|
||||
tmpDir, err := os.MkdirTemp("", "dnote-schema-gen-*")
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
schemaPath := filepath.Join("pkg", "cli", "database", "schema.sql")
|
||||
|
||||
if err := run(tmpDir, schemaPath); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func run(tmpDir, outputPath string) error {
|
||||
schema, err := generateSchema(tmpDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := os.WriteFile(outputPath, []byte(schema), 0644); err != nil {
|
||||
return fmt.Errorf("writing schema file: %w", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Schema generated successfully at %s\n", outputPath)
|
||||
return nil
|
||||
}
|
||||
|
||||
// generateSchema creates a fresh database, runs all migrations, and extracts the schema
|
||||
func generateSchema(tmpDir string) (string, error) {
|
||||
// Create dnote directory structure in temp dir
|
||||
dnoteDir := filepath.Join(tmpDir, "dnote")
|
||||
if err := os.MkdirAll(dnoteDir, 0755); err != nil {
|
||||
return "", fmt.Errorf("creating dnote dir: %w", err)
|
||||
}
|
||||
|
||||
// Use a file-based database
|
||||
dbPath := filepath.Join(tmpDir, "schema.db")
|
||||
|
||||
// Create context
|
||||
ctx := context.DnoteCtx{
|
||||
Paths: context.Paths{
|
||||
Home: tmpDir,
|
||||
Config: tmpDir,
|
||||
Data: tmpDir,
|
||||
Cache: tmpDir,
|
||||
},
|
||||
Version: "schema-gen",
|
||||
}
|
||||
|
||||
// Open database
|
||||
db, err := database.Open(dbPath)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("opening database: %w", err)
|
||||
}
|
||||
defer db.Close()
|
||||
ctx.DB = db
|
||||
|
||||
// Initialize database with base tables
|
||||
if err := infra.InitDB(ctx); err != nil {
|
||||
return "", fmt.Errorf("initializing database: %w", err)
|
||||
}
|
||||
|
||||
// Initialize system data
|
||||
if err := infra.InitSystem(ctx); err != nil {
|
||||
return "", fmt.Errorf("initializing system: %w", err)
|
||||
}
|
||||
|
||||
// Create minimal config file
|
||||
if err := config.Write(ctx, config.Config{}); err != nil {
|
||||
return "", fmt.Errorf("writing initial config: %w", err)
|
||||
}
|
||||
|
||||
// Run all local migrations
|
||||
if err := migrate.Run(ctx, migrate.LocalSequence, migrate.LocalMode); err != nil {
|
||||
return "", fmt.Errorf("running migrations: %w", err)
|
||||
}
|
||||
|
||||
// Extract schema before closing database
|
||||
schema, err := extractSchema(db)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("extracting schema: %w", err)
|
||||
}
|
||||
|
||||
return schema, nil
|
||||
}
|
||||
|
||||
// extractSchema extracts the complete schema by querying sqlite_master
|
||||
func extractSchema(db *database.DB) (string, error) {
|
||||
// Query sqlite_master for all schema objects, excluding FTS shadow tables
|
||||
// FTS shadow tables are internal tables automatically created by FTS virtual tables
|
||||
rows, err := db.Conn.Query(`SELECT sql FROM sqlite_master
|
||||
WHERE sql IS NOT NULL
|
||||
AND name NOT LIKE 'sqlite_%'
|
||||
AND (type != 'table'
|
||||
OR (type = 'table' AND name NOT IN (
|
||||
SELECT m1.name FROM sqlite_master m1
|
||||
JOIN sqlite_master m2 ON m1.name LIKE m2.name || '_%'
|
||||
WHERE m2.type = 'table' AND m2.sql LIKE '%VIRTUAL TABLE%'
|
||||
)))`)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("querying sqlite_master: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var schemas []string
|
||||
for rows.Next() {
|
||||
var sql string
|
||||
if err := rows.Scan(&sql); err != nil {
|
||||
return "", fmt.Errorf("scanning row: %w", err)
|
||||
}
|
||||
schemas = append(schemas, sql)
|
||||
}
|
||||
|
||||
if err := rows.Err(); err != nil {
|
||||
return "", fmt.Errorf("iterating rows: %w", err)
|
||||
}
|
||||
|
||||
// Add autogenerated header comment
|
||||
header := `-- This is the final state of the CLI database after all migrations.
|
||||
-- Auto-generated by generate-schema.go. Do not edit manually.
|
||||
`
|
||||
return header + strings.Join(schemas, ";\n") + ";\n", nil
|
||||
}
|
||||
76
pkg/cli/database/cmd/generate-schema_test.go
Normal file
76
pkg/cli/database/cmd/generate-schema_test.go
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
/* Copyright (C) 2019, 2020, 2021, 2022, 2023, 2024, 2025 Dnote contributors
|
||||
*
|
||||
* This file is part of Dnote.
|
||||
*
|
||||
* Dnote is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Dnote is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Dnote. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/dnote/dnote/pkg/assert"
|
||||
)
|
||||
|
||||
func TestRun(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
outputPath := filepath.Join(tmpDir, "schema.sql")
|
||||
|
||||
// Run the function
|
||||
if err := run(tmpDir, outputPath); err != nil {
|
||||
t.Fatalf("run() failed: %v", err)
|
||||
}
|
||||
|
||||
// Verify schema.sql was created
|
||||
content, err := os.ReadFile(outputPath)
|
||||
if err != nil {
|
||||
t.Fatalf("reading schema.sql: %v", err)
|
||||
}
|
||||
|
||||
schema := string(content)
|
||||
|
||||
// Verify it has the header
|
||||
assert.Equal(t, strings.HasPrefix(schema, "-- This is the final state"), true, "schema.sql should have header comment")
|
||||
|
||||
// Verify schema contains expected tables
|
||||
expectedTables := []string{
|
||||
"CREATE TABLE books",
|
||||
"CREATE TABLE system",
|
||||
"CREATE TABLE \"notes\"",
|
||||
"CREATE VIRTUAL TABLE note_fts",
|
||||
}
|
||||
|
||||
for _, expected := range expectedTables {
|
||||
assert.Equal(t, strings.Contains(schema, expected), true, fmt.Sprintf("schema should contain %s", expected))
|
||||
}
|
||||
|
||||
// Verify schema contains triggers
|
||||
expectedTriggers := []string{
|
||||
"CREATE TRIGGER notes_after_insert",
|
||||
"CREATE TRIGGER notes_after_delete",
|
||||
"CREATE TRIGGER notes_after_update",
|
||||
}
|
||||
|
||||
for _, expected := range expectedTriggers {
|
||||
assert.Equal(t, strings.Contains(schema, expected), true, fmt.Sprintf("schema should contain %s", expected))
|
||||
}
|
||||
|
||||
// Verify schema does not contain sqlite internal tables
|
||||
assert.Equal(t, strings.Contains(schema, "sqlite_sequence"), false, "schema should not contain sqlite_sequence")
|
||||
}
|
||||
|
|
@ -109,8 +109,8 @@ func TestNoteInsert(t *testing.T) {
|
|||
for idx, tc := range testCases {
|
||||
func() {
|
||||
// Setup
|
||||
db := InitTestDB(t, "../tmp/dnote-test.db", nil)
|
||||
defer TeardownTestDB(t, db)
|
||||
db := InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
n := Note{
|
||||
UUID: tc.uuid,
|
||||
|
|
@ -243,8 +243,8 @@ func TestNoteUpdate(t *testing.T) {
|
|||
for idx, tc := range testCases {
|
||||
func() {
|
||||
// Setup
|
||||
db := InitTestDB(t, "../tmp/dnote-test.db", nil)
|
||||
defer TeardownTestDB(t, db)
|
||||
db := InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
n1 := Note{
|
||||
UUID: tc.uuid,
|
||||
|
|
@ -335,8 +335,8 @@ func TestNoteUpdateUUID(t *testing.T) {
|
|||
for idx, tc := range testCases {
|
||||
t.Run(fmt.Sprintf("testCase%d", idx), func(t *testing.T) {
|
||||
// Setup
|
||||
db := InitTestDB(t, "../tmp/dnote-test.db", nil)
|
||||
defer TeardownTestDB(t, db)
|
||||
db := InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
n1 := Note{
|
||||
UUID: "n1-uuid",
|
||||
|
|
@ -390,8 +390,8 @@ func TestNoteUpdateUUID(t *testing.T) {
|
|||
|
||||
func TestNoteExpunge(t *testing.T) {
|
||||
// Setup
|
||||
db := InitTestDB(t, "../tmp/dnote-test.db", nil)
|
||||
defer TeardownTestDB(t, db)
|
||||
db := InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
n1 := Note{
|
||||
UUID: "n1-uuid",
|
||||
|
|
@ -513,8 +513,8 @@ func TestBookInsert(t *testing.T) {
|
|||
for idx, tc := range testCases {
|
||||
func() {
|
||||
// Setup
|
||||
db := InitTestDB(t, "../tmp/dnote-test.db", nil)
|
||||
defer TeardownTestDB(t, db)
|
||||
db := InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
b := Book{
|
||||
UUID: tc.uuid,
|
||||
|
|
@ -594,8 +594,8 @@ func TestBookUpdate(t *testing.T) {
|
|||
for idx, tc := range testCases {
|
||||
func() {
|
||||
// Setup
|
||||
db := InitTestDB(t, "../tmp/dnote-test.db", nil)
|
||||
defer TeardownTestDB(t, db)
|
||||
db := InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
b1 := Book{
|
||||
UUID: "b1-uuid",
|
||||
|
|
@ -673,8 +673,8 @@ func TestBookUpdateUUID(t *testing.T) {
|
|||
t.Run(fmt.Sprintf("testCase%d", idx), func(t *testing.T) {
|
||||
|
||||
// Setup
|
||||
db := InitTestDB(t, "../tmp/dnote-test.db", nil)
|
||||
defer TeardownTestDB(t, db)
|
||||
db := InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
b1 := Book{
|
||||
UUID: "b1-uuid",
|
||||
|
|
@ -724,8 +724,8 @@ func TestBookUpdateUUID(t *testing.T) {
|
|||
|
||||
func TestBookExpunge(t *testing.T) {
|
||||
// Setup
|
||||
db := InitTestDB(t, "../tmp/dnote-test.db", nil)
|
||||
defer TeardownTestDB(t, db)
|
||||
db := InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
b1 := Book{
|
||||
UUID: "b1-uuid",
|
||||
|
|
@ -779,8 +779,8 @@ func TestBookExpunge(t *testing.T) {
|
|||
// TestNoteFTS tests that note full text search indices stay in sync with the notes after insert, update and delete
|
||||
func TestNoteFTS(t *testing.T) {
|
||||
// set up
|
||||
db := InitTestDB(t, "../tmp/dnote-test.db", nil)
|
||||
defer TeardownTestDB(t, db)
|
||||
db := InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
// execute - insert
|
||||
n := Note{
|
||||
|
|
|
|||
|
|
@ -47,8 +47,8 @@ func TestInsertSystem(t *testing.T) {
|
|||
for _, tc := range testCases {
|
||||
t.Run(fmt.Sprintf("insert %s %s", tc.key, tc.val), func(t *testing.T) {
|
||||
// Setup
|
||||
db := InitTestDB(t, "../tmp/dnote-test.db", nil)
|
||||
defer TeardownTestDB(t, db)
|
||||
db := InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
// execute
|
||||
tx, err := db.Begin()
|
||||
|
|
@ -95,8 +95,8 @@ func TestUpsertSystem(t *testing.T) {
|
|||
for _, tc := range testCases {
|
||||
t.Run(fmt.Sprintf("insert %s %s", tc.key, tc.val), func(t *testing.T) {
|
||||
// Setup
|
||||
db := InitTestDB(t, "../tmp/dnote-test.db", nil)
|
||||
defer TeardownTestDB(t, db)
|
||||
db := InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
MustExec(t, "inserting a system configuration", db, "INSERT INTO system (key, value) VALUES (?, ?)", "baz", "quz")
|
||||
|
||||
|
|
@ -134,8 +134,8 @@ func TestUpsertSystem(t *testing.T) {
|
|||
func TestGetSystem(t *testing.T) {
|
||||
t.Run(fmt.Sprintf("get string value"), func(t *testing.T) {
|
||||
// Setup
|
||||
db := InitTestDB(t, "../tmp/dnote-test.db", nil)
|
||||
defer TeardownTestDB(t, db)
|
||||
db := InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
// execute
|
||||
MustExec(t, "inserting a system configuration", db, "INSERT INTO system (key, value) VALUES (?, ?)", "foo", "bar")
|
||||
|
|
@ -157,8 +157,8 @@ func TestGetSystem(t *testing.T) {
|
|||
|
||||
t.Run(fmt.Sprintf("get int64 value"), func(t *testing.T) {
|
||||
// Setup
|
||||
db := InitTestDB(t, "../tmp/dnote-test.db", nil)
|
||||
defer TeardownTestDB(t, db)
|
||||
db := InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
// execute
|
||||
MustExec(t, "inserting a system configuration", db, "INSERT INTO system (key, value) VALUES (?, ?)", "foo", 1234)
|
||||
|
|
@ -198,8 +198,8 @@ func TestUpdateSystem(t *testing.T) {
|
|||
for _, tc := range testCases {
|
||||
t.Run(fmt.Sprintf("update %s %s", tc.key, tc.val), func(t *testing.T) {
|
||||
// Setup
|
||||
db := InitTestDB(t, "../tmp/dnote-test.db", nil)
|
||||
defer TeardownTestDB(t, db)
|
||||
db := InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
MustExec(t, "inserting a system configuration", db, "INSERT INTO system (key, value) VALUES (?, ?)", "foo", "fuz")
|
||||
MustExec(t, "inserting a system configuration", db, "INSERT INTO system (key, value) VALUES (?, ?)", "baz", "quz")
|
||||
|
|
@ -238,8 +238,8 @@ func TestUpdateSystem(t *testing.T) {
|
|||
func TestGetActiveNote(t *testing.T) {
|
||||
t.Run("not deleted", func(t *testing.T) {
|
||||
// set up
|
||||
db := InitTestDB(t, "../tmp/dnote-test.db", nil)
|
||||
defer TeardownTestDB(t, db)
|
||||
db := InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
n1UUID := "n1-uuid"
|
||||
MustExec(t, "inserting n1", db, "INSERT INTO notes (uuid, book_uuid, body, added_on, edited_on, usn, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", n1UUID, "b1-uuid", "n1 content", 1542058875, 1542058876, 1, false, true)
|
||||
|
|
@ -267,8 +267,8 @@ func TestGetActiveNote(t *testing.T) {
|
|||
|
||||
t.Run("deleted", func(t *testing.T) {
|
||||
// set up
|
||||
db := InitTestDB(t, "../tmp/dnote-test.db", nil)
|
||||
defer TeardownTestDB(t, db)
|
||||
db := InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
n1UUID := "n1-uuid"
|
||||
MustExec(t, "inserting n1", db, "INSERT INTO notes (uuid, book_uuid, body, added_on, edited_on, usn, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", n1UUID, "b1-uuid", "n1 content", 1542058875, 1542058876, 1, true, true)
|
||||
|
|
@ -291,8 +291,8 @@ func TestGetActiveNote(t *testing.T) {
|
|||
|
||||
func TestUpdateNoteContent(t *testing.T) {
|
||||
// set up
|
||||
db := InitTestDB(t, "../tmp/dnote-test.db", nil)
|
||||
defer TeardownTestDB(t, db)
|
||||
db := InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
uuid := "n1-uuid"
|
||||
MustExec(t, "inserting n1", db, "INSERT INTO notes (uuid, book_uuid, body, added_on, edited_on, usn, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", uuid, "b1-uuid", "n1 content", 1542058875, 0, 1, false, false)
|
||||
|
|
@ -323,8 +323,8 @@ func TestUpdateNoteContent(t *testing.T) {
|
|||
|
||||
func TestUpdateNoteBook(t *testing.T) {
|
||||
// set up
|
||||
db := InitTestDB(t, "../tmp/dnote-test.db", nil)
|
||||
defer TeardownTestDB(t, db)
|
||||
db := InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
b1UUID := "b1-uuid"
|
||||
b2UUID := "b2-uuid"
|
||||
|
|
@ -360,8 +360,8 @@ func TestUpdateNoteBook(t *testing.T) {
|
|||
|
||||
func TestUpdateBookName(t *testing.T) {
|
||||
// set up
|
||||
db := InitTestDB(t, "../tmp/dnote-test.db", nil)
|
||||
defer TeardownTestDB(t, db)
|
||||
db := InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
b1UUID := "b1-uuid"
|
||||
MustExec(t, "inserting b1", db, "INSERT INTO books (uuid, label, usn, deleted, dirty) VALUES (?, ?, ?, ?, ?)", b1UUID, "b1-label", 8, false, false)
|
||||
|
|
|
|||
36
pkg/cli/database/schema.sql
Normal file
36
pkg/cli/database/schema.sql
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
-- This is the final state of the CLI database after all migrations.
|
||||
-- Auto-generated by generate-schema.go. Do not edit manually.
|
||||
CREATE TABLE books
|
||||
(
|
||||
uuid text PRIMARY KEY,
|
||||
label text NOT NULL
|
||||
, dirty bool DEFAULT false, usn int DEFAULT 0 NOT NULL, deleted bool DEFAULT false);
|
||||
CREATE TABLE system
|
||||
(
|
||||
key string NOT NULL,
|
||||
value text NOT NULL
|
||||
);
|
||||
CREATE UNIQUE INDEX idx_books_label ON books(label);
|
||||
CREATE UNIQUE INDEX idx_books_uuid ON books(uuid);
|
||||
CREATE TABLE "notes"
|
||||
(
|
||||
uuid text NOT NULL,
|
||||
book_uuid text NOT NULL,
|
||||
body text NOT NULL,
|
||||
added_on integer NOT NULL,
|
||||
edited_on integer DEFAULT 0,
|
||||
dirty bool DEFAULT false,
|
||||
usn int DEFAULT 0 NOT NULL,
|
||||
deleted bool DEFAULT false
|
||||
);
|
||||
CREATE VIRTUAL TABLE note_fts USING fts5(content=notes, body, tokenize="porter unicode61 categories 'L* N* Co Ps Pe'");
|
||||
CREATE TRIGGER notes_after_insert AFTER INSERT ON notes BEGIN
|
||||
INSERT INTO note_fts(rowid, body) VALUES (new.rowid, new.body);
|
||||
END;
|
||||
CREATE TRIGGER notes_after_delete AFTER DELETE ON notes BEGIN
|
||||
INSERT INTO note_fts(note_fts, rowid, body) VALUES ('delete', old.rowid, old.body);
|
||||
END;
|
||||
CREATE TRIGGER notes_after_update AFTER UPDATE ON notes BEGIN
|
||||
INSERT INTO note_fts(note_fts, rowid, body) VALUES ('delete', old.rowid, old.body);
|
||||
INSERT INTO note_fts(rowid, body) VALUES (new.rowid, new.body);
|
||||
END;
|
||||
27
pkg/cli/database/test_embed.go
Normal file
27
pkg/cli/database/test_embed.go
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
package database
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSchemaEmbed(t *testing.T) {
|
||||
db := InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
// Try to insert a book to verify schema is loaded
|
||||
_, err := db.Exec("INSERT INTO books (uuid, label) VALUES (?, ?)", "test-uuid", "test-label")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to insert into books: %v", err)
|
||||
}
|
||||
|
||||
// Verify it was inserted
|
||||
var label string
|
||||
err = db.QueryRow("SELECT label FROM books WHERE uuid = ?", "test-uuid").Scan(&label)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to query books: %v", err)
|
||||
}
|
||||
if label != "test-label" {
|
||||
t.Fatalf("Expected label 'test-label', got '%s'", label)
|
||||
}
|
||||
t.Log("Schema embed test passed!")
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@ package database
|
|||
|
||||
import (
|
||||
"database/sql"
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
|
@ -30,55 +31,13 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var defaultSchemaSQL = `CREATE TABLE books
|
||||
(
|
||||
uuid text PRIMARY KEY,
|
||||
label text NOT NULL
|
||||
, dirty bool DEFAULT false, usn int DEFAULT 0 NOT NULL, deleted bool DEFAULT false);
|
||||
CREATE TABLE system
|
||||
(
|
||||
key string NOT NULL,
|
||||
value text NOT NULL
|
||||
);
|
||||
CREATE UNIQUE INDEX idx_books_label ON books(label);
|
||||
CREATE UNIQUE INDEX idx_books_uuid ON books(uuid);
|
||||
CREATE TABLE IF NOT EXISTS "notes"
|
||||
(
|
||||
uuid text NOT NULL,
|
||||
book_uuid text NOT NULL,
|
||||
body text NOT NULL,
|
||||
added_on integer NOT NULL,
|
||||
edited_on integer DEFAULT 0,
|
||||
dirty bool DEFAULT false,
|
||||
usn int DEFAULT 0 NOT NULL,
|
||||
deleted bool DEFAULT false
|
||||
);
|
||||
CREATE VIRTUAL TABLE note_fts USING fts5(content=notes, body, tokenize="porter unicode61 categories 'L* N* Co Ps Pe'")
|
||||
/* note_fts(body) */;
|
||||
CREATE TABLE IF NOT EXISTS 'note_fts_data'(id INTEGER PRIMARY KEY, block BLOB);
|
||||
CREATE TABLE IF NOT EXISTS 'note_fts_idx'(segid, term, pgno, PRIMARY KEY(segid, term)) WITHOUT ROWID;
|
||||
CREATE TABLE IF NOT EXISTS 'note_fts_docsize'(id INTEGER PRIMARY KEY, sz BLOB);
|
||||
CREATE TABLE IF NOT EXISTS 'note_fts_config'(k PRIMARY KEY, v) WITHOUT ROWID;
|
||||
CREATE TRIGGER notes_after_insert AFTER INSERT ON notes BEGIN
|
||||
INSERT INTO note_fts(rowid, body) VALUES (new.rowid, new.body);
|
||||
END;
|
||||
CREATE TRIGGER notes_after_delete AFTER DELETE ON notes BEGIN
|
||||
INSERT INTO note_fts(note_fts, rowid, body) VALUES ('delete', old.rowid, old.body);
|
||||
END;
|
||||
CREATE TRIGGER notes_after_update AFTER UPDATE ON notes BEGIN
|
||||
INSERT INTO note_fts(note_fts, rowid, body) VALUES ('delete', old.rowid, old.body);
|
||||
INSERT INTO note_fts(rowid, body) VALUES (new.rowid, new.body);
|
||||
END;
|
||||
CREATE TABLE actions
|
||||
(
|
||||
uuid text PRIMARY KEY,
|
||||
schema integer NOT NULL,
|
||||
type text NOT NULL,
|
||||
data text NOT NULL,
|
||||
timestamp integer NOT NULL
|
||||
);
|
||||
CREATE UNIQUE INDEX idx_notes_uuid ON notes(uuid);
|
||||
CREATE INDEX idx_notes_book_uuid ON notes(book_uuid);`
|
||||
//go:embed schema.sql
|
||||
var defaultSchemaSQL string
|
||||
|
||||
// GetDefaultSchemaSQL returns the default schema SQL for tests
|
||||
func GetDefaultSchemaSQL() string {
|
||||
return defaultSchemaSQL
|
||||
}
|
||||
|
||||
// MustScan scans the given row and fails a test in case of any errors
|
||||
func MustScan(t *testing.T, message string, row *sql.Row, args ...interface{}) {
|
||||
|
|
@ -98,29 +57,50 @@ func MustExec(t *testing.T, message string, db *DB, query string, args ...interf
|
|||
return result
|
||||
}
|
||||
|
||||
// TestDBOptions contains options for test database
|
||||
type TestDBOptions struct {
|
||||
SchemaSQLPath string
|
||||
SkipMigration bool
|
||||
// InitTestMemoryDB initializes an in-memory test database with the default schema.
|
||||
func InitTestMemoryDB(t *testing.T) *DB {
|
||||
db := InitTestMemoryDBRaw(t, "")
|
||||
MarkMigrationComplete(t, db)
|
||||
return db
|
||||
}
|
||||
|
||||
// InitTestDB initializes a test database and opens connection to it
|
||||
func InitTestDB(t *testing.T, dbPath string, options *TestDBOptions) *DB {
|
||||
// InitTestFileDB initializes a file-based test database with the default schema.
|
||||
func InitTestFileDB(t *testing.T) (*DB, string) {
|
||||
dbPath := filepath.Join(t.TempDir(), "dnote.db")
|
||||
|
||||
return InitTestFileDBRaw(t, dbPath), dbPath
|
||||
}
|
||||
|
||||
// InitTestFileDBRaw initializes a file-based test database at the specified path with the default schema.
|
||||
func InitTestFileDBRaw(t *testing.T, dbPath string) *DB {
|
||||
db, err := Open(dbPath)
|
||||
if err != nil {
|
||||
t.Fatal(errors.Wrap(err, "opening database connection"))
|
||||
t.Fatal(errors.Wrap(err, "opening database"))
|
||||
}
|
||||
|
||||
dir, _ := filepath.Split(dbPath)
|
||||
err = os.MkdirAll(dir, 0777)
|
||||
if _, err := db.Exec(defaultSchemaSQL); err != nil {
|
||||
t.Fatal(errors.Wrap(err, "running schema sql"))
|
||||
}
|
||||
|
||||
MarkMigrationComplete(t, db)
|
||||
|
||||
return db
|
||||
}
|
||||
|
||||
// InitTestMemoryDBRaw initializes an in-memory test database without marking migrations complete.
|
||||
// If schemaPath is empty, uses the default schema. Used for migration testing.
|
||||
func InitTestMemoryDBRaw(t *testing.T, schemaPath string) *DB {
|
||||
uuid := mustGenerateTestUUID(t)
|
||||
dbName := fmt.Sprintf("file:%s?mode=memory&cache=shared", uuid)
|
||||
|
||||
db, err := Open(dbName)
|
||||
if err != nil {
|
||||
t.Fatal(errors.Wrap(err, "creating the directory for test database file"))
|
||||
t.Fatal(errors.Wrap(err, "opening in-memory database"))
|
||||
}
|
||||
|
||||
var schemaSQL string
|
||||
if options != nil && options.SchemaSQLPath != "" {
|
||||
b := utils.ReadFileAbs(options.SchemaSQLPath)
|
||||
schemaSQL = string(b)
|
||||
if schemaPath != "" {
|
||||
schemaSQL = string(utils.ReadFileAbs(schemaPath))
|
||||
} else {
|
||||
schemaSQL = defaultSchemaSQL
|
||||
}
|
||||
|
|
@ -129,10 +109,6 @@ func InitTestDB(t *testing.T, dbPath string, options *TestDBOptions) *DB {
|
|||
t.Fatal(errors.Wrap(err, "running schema sql"))
|
||||
}
|
||||
|
||||
if options == nil || !options.SkipMigration {
|
||||
MarkMigrationComplete(t, db)
|
||||
}
|
||||
|
||||
return db
|
||||
}
|
||||
|
||||
|
|
@ -161,10 +137,19 @@ func OpenTestDB(t *testing.T, dnoteDir string) *DB {
|
|||
|
||||
// MarkMigrationComplete marks all migrations as complete in the database
|
||||
func MarkMigrationComplete(t *testing.T, db *DB) {
|
||||
if _, err := db.Exec("INSERT INTO system (key, value) VALUES (? , ?);", consts.SystemSchema, 12); err != nil {
|
||||
if _, err := db.Exec("INSERT INTO system (key, value) VALUES (? , ?);", consts.SystemSchema, 14); err != nil {
|
||||
t.Fatal(errors.Wrap(err, "inserting schema"))
|
||||
}
|
||||
if _, err := db.Exec("INSERT INTO system (key, value) VALUES (? , ?);", consts.SystemRemoteSchema, 1); err != nil {
|
||||
t.Fatal(errors.Wrap(err, "inserting remote schema"))
|
||||
}
|
||||
}
|
||||
|
||||
// mustGenerateTestUUID generates a UUID for test databases and fails the test on error
|
||||
func mustGenerateTestUUID(t *testing.T) string {
|
||||
uuid, err := utils.GenerateUUID()
|
||||
if err != nil {
|
||||
t.Fatal(errors.Wrap(err, "generating UUID for test database"))
|
||||
}
|
||||
return uuid
|
||||
}
|
||||
|
|
|
|||
|
|
@ -329,6 +329,7 @@ func getEditorCommand() string {
|
|||
return ret
|
||||
}
|
||||
|
||||
// initDir creates a directory if it doesn't exist
|
||||
func initDir(path string) error {
|
||||
ok, err := utils.FileExists(path)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@ import (
|
|||
|
||||
func TestInitSystemKV(t *testing.T) {
|
||||
// Setup
|
||||
db := database.InitTestDB(t, "../tmp/dnote-test.db", nil)
|
||||
defer database.TeardownTestDB(t, db)
|
||||
db := database.InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
var originalCount int
|
||||
database.MustScan(t, "counting system configs", db.QueryRow("SELECT count(*) FROM system"), &originalCount)
|
||||
|
|
@ -64,8 +64,8 @@ func TestInitSystemKV(t *testing.T) {
|
|||
|
||||
func TestInitSystemKV_existing(t *testing.T) {
|
||||
// Setup
|
||||
db := database.InitTestDB(t, "../tmp/dnote-test.db", nil)
|
||||
defer database.TeardownTestDB(t, db)
|
||||
db := database.InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
database.MustExec(t, "inserting a system config", db, "INSERT INTO system (key, value) VALUES (?, ?)", "testKey", "testVal")
|
||||
|
||||
|
|
|
|||
|
|
@ -35,14 +35,17 @@ import (
|
|||
|
||||
var binaryName = "test-dnote"
|
||||
|
||||
var testDir = "./tmp/.dnote"
|
||||
|
||||
var opts = testutils.RunDnoteCmdOptions{
|
||||
Env: []string{
|
||||
fmt.Sprintf("XDG_CONFIG_HOME=%s", testDir),
|
||||
fmt.Sprintf("XDG_DATA_HOME=%s", testDir),
|
||||
fmt.Sprintf("XDG_CACHE_HOME=%s", testDir),
|
||||
},
|
||||
// setupTestEnv creates a unique test directory for parallel test execution
|
||||
func setupTestEnv(t *testing.T) (string, testutils.RunDnoteCmdOptions) {
|
||||
testDir := t.TempDir()
|
||||
opts := testutils.RunDnoteCmdOptions{
|
||||
Env: []string{
|
||||
fmt.Sprintf("XDG_CONFIG_HOME=%s", testDir),
|
||||
fmt.Sprintf("XDG_DATA_HOME=%s", testDir),
|
||||
fmt.Sprintf("XDG_CACHE_HOME=%s", testDir),
|
||||
},
|
||||
}
|
||||
return testDir, opts
|
||||
}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
|
|
@ -55,10 +58,11 @@ func TestMain(m *testing.M) {
|
|||
}
|
||||
|
||||
func TestInit(t *testing.T) {
|
||||
testDir, opts := setupTestEnv(t)
|
||||
|
||||
// Execute
|
||||
// run an arbitrary command "view" due to https://github.com/spf13/cobra/issues/1056
|
||||
testutils.RunDnoteCmd(t, opts, binaryName, "view")
|
||||
defer testutils.RemoveDir(t, testDir)
|
||||
|
||||
db := database.OpenTestDB(t, testDir)
|
||||
|
||||
|
|
@ -107,12 +111,12 @@ func TestInit(t *testing.T) {
|
|||
|
||||
func TestAddNote(t *testing.T) {
|
||||
t.Run("new book", func(t *testing.T) {
|
||||
testDir, opts := setupTestEnv(t)
|
||||
|
||||
// Set up and execute
|
||||
testutils.RunDnoteCmd(t, opts, binaryName, "add", "js", "-c", "foo")
|
||||
testutils.MustWaitDnoteCmd(t, opts, testutils.UserContent, binaryName, "add", "js")
|
||||
|
||||
defer testutils.RemoveDir(t, testDir)
|
||||
|
||||
db := database.OpenTestDB(t, testDir)
|
||||
|
||||
// Test
|
||||
|
|
@ -138,13 +142,15 @@ func TestAddNote(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("existing book", func(t *testing.T) {
|
||||
_, opts := setupTestEnv(t)
|
||||
|
||||
// Setup
|
||||
db := database.InitTestDB(t, fmt.Sprintf("%s/%s/%s", testDir, consts.DnoteDirName, consts.DnoteDBFileName), nil)
|
||||
db, dbPath := database.InitTestFileDB(t)
|
||||
defer database.TeardownTestDB(t, db)
|
||||
testutils.Setup3(t, db)
|
||||
|
||||
// Execute
|
||||
testutils.RunDnoteCmd(t, opts, binaryName, "add", "js", "-c", "foo")
|
||||
defer testutils.RemoveDir(t, testDir)
|
||||
testutils.RunDnoteCmd(t, opts, binaryName, "--dbPath", dbPath, "add", "js", "-c", "foo")
|
||||
|
||||
// Test
|
||||
|
||||
|
|
@ -179,13 +185,15 @@ func TestAddNote(t *testing.T) {
|
|||
|
||||
func TestEditNote(t *testing.T) {
|
||||
t.Run("content flag", func(t *testing.T) {
|
||||
_, opts := setupTestEnv(t)
|
||||
|
||||
// Setup
|
||||
db := database.InitTestDB(t, fmt.Sprintf("%s/%s/%s", testDir, consts.DnoteDirName, consts.DnoteDBFileName), nil)
|
||||
db, dbPath := database.InitTestFileDB(t)
|
||||
defer database.TeardownTestDB(t, db)
|
||||
testutils.Setup4(t, db)
|
||||
|
||||
// Execute
|
||||
testutils.RunDnoteCmd(t, opts, binaryName, "edit", "2", "-c", "foo bar")
|
||||
defer testutils.RemoveDir(t, testDir)
|
||||
testutils.RunDnoteCmd(t, opts, binaryName, "--dbPath", dbPath, "edit", "2", "-c", "foo bar")
|
||||
|
||||
// Test
|
||||
var noteCount, bookCount int
|
||||
|
|
@ -212,13 +220,15 @@ func TestEditNote(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("book flag", func(t *testing.T) {
|
||||
_, opts := setupTestEnv(t)
|
||||
|
||||
// Setup
|
||||
db := database.InitTestDB(t, fmt.Sprintf("%s/%s/%s", testDir, consts.DnoteDirName, consts.DnoteDBFileName), nil)
|
||||
db, dbPath := database.InitTestFileDB(t)
|
||||
defer database.TeardownTestDB(t, db)
|
||||
testutils.Setup5(t, db)
|
||||
|
||||
// Execute
|
||||
testutils.RunDnoteCmd(t, opts, binaryName, "edit", "2", "-b", "linux")
|
||||
defer testutils.RemoveDir(t, testDir)
|
||||
testutils.RunDnoteCmd(t, opts, binaryName, "--dbPath", dbPath, "edit", "2", "-b", "linux")
|
||||
|
||||
// Test
|
||||
var noteCount, bookCount int
|
||||
|
|
@ -246,13 +256,15 @@ func TestEditNote(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("book flag and content flag", func(t *testing.T) {
|
||||
_, opts := setupTestEnv(t)
|
||||
|
||||
// Setup
|
||||
db := database.InitTestDB(t, fmt.Sprintf("%s/%s/%s", testDir, consts.DnoteDirName, consts.DnoteDBFileName), nil)
|
||||
db, dbPath := database.InitTestFileDB(t)
|
||||
defer database.TeardownTestDB(t, db)
|
||||
testutils.Setup5(t, db)
|
||||
|
||||
// Execute
|
||||
testutils.RunDnoteCmd(t, opts, binaryName, "edit", "2", "-b", "linux", "-c", "n2 body updated")
|
||||
defer testutils.RemoveDir(t, testDir)
|
||||
testutils.RunDnoteCmd(t, opts, binaryName, "--dbPath", dbPath, "edit", "2", "-b", "linux", "-c", "n2 body updated")
|
||||
|
||||
// Test
|
||||
var noteCount, bookCount int
|
||||
|
|
@ -282,13 +294,15 @@ func TestEditNote(t *testing.T) {
|
|||
|
||||
func TestEditBook(t *testing.T) {
|
||||
t.Run("name flag", func(t *testing.T) {
|
||||
_, opts := setupTestEnv(t)
|
||||
|
||||
// Setup
|
||||
db := database.InitTestDB(t, fmt.Sprintf("%s/%s/%s", testDir, consts.DnoteDirName, consts.DnoteDBFileName), nil)
|
||||
db, dbPath := database.InitTestFileDB(t)
|
||||
defer database.TeardownTestDB(t, db)
|
||||
testutils.Setup1(t, db)
|
||||
|
||||
// Execute
|
||||
testutils.RunDnoteCmd(t, opts, binaryName, "edit", "js", "-n", "js-edited")
|
||||
defer testutils.RemoveDir(t, testDir)
|
||||
testutils.RunDnoteCmd(t, opts, binaryName, "--dbPath", dbPath, "edit", "js", "-n", "js-edited")
|
||||
|
||||
// Test
|
||||
var noteCount, bookCount int
|
||||
|
|
@ -341,17 +355,19 @@ func TestRemoveNote(t *testing.T) {
|
|||
|
||||
for _, tc := range testCases {
|
||||
t.Run(fmt.Sprintf("--yes=%t", tc.yesFlag), func(t *testing.T) {
|
||||
_, opts := setupTestEnv(t)
|
||||
|
||||
// Setup
|
||||
db := database.InitTestDB(t, fmt.Sprintf("%s/%s/%s", testDir, consts.DnoteDirName, consts.DnoteDBFileName), nil)
|
||||
db, dbPath := database.InitTestFileDB(t)
|
||||
defer database.TeardownTestDB(t, db)
|
||||
testutils.Setup2(t, db)
|
||||
|
||||
// Execute
|
||||
if tc.yesFlag {
|
||||
testutils.RunDnoteCmd(t, opts, binaryName, "remove", "-y", "1")
|
||||
testutils.RunDnoteCmd(t, opts, binaryName, "--dbPath", dbPath, "remove", "-y", "1")
|
||||
} else {
|
||||
testutils.MustWaitDnoteCmd(t, opts, testutils.ConfirmRemoveNote, binaryName, "remove", "1")
|
||||
testutils.MustWaitDnoteCmd(t, opts, testutils.ConfirmRemoveNote, binaryName, "--dbPath", dbPath, "remove", "1")
|
||||
}
|
||||
defer testutils.RemoveDir(t, testDir)
|
||||
|
||||
// Test
|
||||
var noteCount, bookCount, jsNoteCount, linuxNoteCount int
|
||||
|
|
@ -428,19 +444,20 @@ func TestRemoveBook(t *testing.T) {
|
|||
|
||||
for _, tc := range testCases {
|
||||
t.Run(fmt.Sprintf("--yes=%t", tc.yesFlag), func(t *testing.T) {
|
||||
_, opts := setupTestEnv(t)
|
||||
|
||||
// Setup
|
||||
db := database.InitTestDB(t, fmt.Sprintf("%s/%s/%s", testDir, consts.DnoteDirName, consts.DnoteDBFileName), nil)
|
||||
db, dbPath := database.InitTestFileDB(t)
|
||||
defer database.TeardownTestDB(t, db)
|
||||
testutils.Setup2(t, db)
|
||||
|
||||
// Execute
|
||||
if tc.yesFlag {
|
||||
testutils.RunDnoteCmd(t, opts, binaryName, "remove", "-y", "js")
|
||||
testutils.RunDnoteCmd(t, opts, binaryName, "--dbPath", dbPath, "remove", "-y", "js")
|
||||
} else {
|
||||
testutils.MustWaitDnoteCmd(t, opts, testutils.ConfirmRemoveBook, binaryName, "remove", "js")
|
||||
testutils.MustWaitDnoteCmd(t, opts, testutils.ConfirmRemoveBook, binaryName, "--dbPath", dbPath, "remove", "js")
|
||||
}
|
||||
|
||||
defer testutils.RemoveDir(t, testDir)
|
||||
|
||||
// Test
|
||||
var noteCount, bookCount, jsNoteCount, linuxNoteCount int
|
||||
database.MustScan(t, "counting books", db.QueryRow("SELECT count(*) FROM books"), &bookCount)
|
||||
|
|
@ -537,17 +554,9 @@ func TestDBPathFlag(t *testing.T) {
|
|||
}
|
||||
|
||||
// Setup - use two different custom database paths
|
||||
customDBPath1 := "./tmp/custom-test1.db"
|
||||
customDBPath2 := "./tmp/custom-test2.db"
|
||||
defer testutils.RemoveDir(t, "./tmp")
|
||||
|
||||
customOpts := testutils.RunDnoteCmdOptions{
|
||||
Env: []string{
|
||||
fmt.Sprintf("XDG_CONFIG_HOME=%s", testDir),
|
||||
fmt.Sprintf("XDG_DATA_HOME=%s", testDir),
|
||||
fmt.Sprintf("XDG_CACHE_HOME=%s", testDir),
|
||||
},
|
||||
}
|
||||
testDir, customOpts := setupTestEnv(t)
|
||||
customDBPath1 := fmt.Sprintf("%s/custom-test1.db", testDir)
|
||||
customDBPath2 := fmt.Sprintf("%s/custom-test2.db", testDir)
|
||||
|
||||
// Execute - add different notes to each database
|
||||
testutils.RunDnoteCmd(t, customOpts, binaryName, "--dbPath", customDBPath1, "add", "db1-book", "-c", "content in db1")
|
||||
|
|
|
|||
|
|
@ -353,14 +353,19 @@ func TestMigrateToV7(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestMigrateToV8(t *testing.T) {
|
||||
opts := database.TestDBOptions{SchemaSQLPath: "./fixtures/local-1-pre-schema.sql", SkipMigration: true}
|
||||
db := database.InitTestDB(t, "../tmp/.dnote/dnote-test.db", &opts)
|
||||
tmpDir := t.TempDir()
|
||||
dnoteDir := tmpDir + "/.dnote"
|
||||
if err := os.MkdirAll(dnoteDir, 0755); err != nil {
|
||||
t.Fatal(errors.Wrap(err, "creating legacy dnote directory"))
|
||||
}
|
||||
|
||||
db := database.InitTestMemoryDBRaw(t, "./fixtures/local-1-pre-schema.sql")
|
||||
defer database.TeardownTestDB(t, db)
|
||||
|
||||
ctx := context.DnoteCtx{
|
||||
Paths: context.Paths{
|
||||
Home: "../tmp",
|
||||
LegacyDnote: "../tmp/.dnote",
|
||||
Home: tmpDir,
|
||||
LegacyDnote: dnoteDir,
|
||||
},
|
||||
DB: db,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,14 +38,18 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var paths context.Paths = context.Paths{
|
||||
Home: "../../tmp",
|
||||
Cache: "../../tmp",
|
||||
Config: "../../tmp",
|
||||
Data: "../../tmp",
|
||||
func getTestPaths(t *testing.T) context.Paths {
|
||||
tmpDir := t.TempDir()
|
||||
return context.Paths{
|
||||
Home: tmpDir,
|
||||
Cache: tmpDir,
|
||||
Config: tmpDir,
|
||||
Data: tmpDir,
|
||||
}
|
||||
}
|
||||
|
||||
func TestExecute_bump_schema(t *testing.T) {
|
||||
paths := getTestPaths(t)
|
||||
testCases := []struct {
|
||||
schemaKey string
|
||||
}{
|
||||
|
|
@ -60,12 +64,10 @@ func TestExecute_bump_schema(t *testing.T) {
|
|||
for _, tc := range testCases {
|
||||
func() {
|
||||
// set up
|
||||
opts := database.TestDBOptions{SkipMigration: true}
|
||||
ctx := context.InitTestCtx(t, paths, &opts)
|
||||
db := database.InitTestMemoryDBRaw(t, "")
|
||||
ctx := context.InitTestCtxWithDB(t, paths, db)
|
||||
defer context.TeardownTestCtx(t, ctx)
|
||||
|
||||
db := ctx.DB
|
||||
|
||||
database.MustExec(t, "inserting a schema", db, "INSERT INTO system (key, value) VALUES (?, ?)", tc.schemaKey, 8)
|
||||
|
||||
m1 := migration{
|
||||
|
|
@ -100,6 +102,7 @@ func TestExecute_bump_schema(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestRun_nonfresh(t *testing.T) {
|
||||
paths := getTestPaths(t)
|
||||
testCases := []struct {
|
||||
mode int
|
||||
schemaKey string
|
||||
|
|
@ -117,11 +120,9 @@ func TestRun_nonfresh(t *testing.T) {
|
|||
for _, tc := range testCases {
|
||||
func() {
|
||||
// set up
|
||||
opts := database.TestDBOptions{SkipMigration: true}
|
||||
ctx := context.InitTestCtx(t, paths, &opts)
|
||||
db := database.InitTestMemoryDBRaw(t, "")
|
||||
ctx := context.InitTestCtxWithDB(t, paths, db)
|
||||
defer context.TeardownTestCtx(t, ctx)
|
||||
|
||||
db := ctx.DB
|
||||
database.MustExec(t, "inserting a schema", db, "INSERT INTO system (key, value) VALUES (?, ?)", tc.schemaKey, 2)
|
||||
database.MustExec(t, "creating a temporary table for testing", db,
|
||||
"CREATE TABLE migrate_run_test ( name string )")
|
||||
|
|
@ -180,6 +181,7 @@ func TestRun_nonfresh(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestRun_fresh(t *testing.T) {
|
||||
paths := getTestPaths(t)
|
||||
testCases := []struct {
|
||||
mode int
|
||||
schemaKey string
|
||||
|
|
@ -197,12 +199,10 @@ func TestRun_fresh(t *testing.T) {
|
|||
for _, tc := range testCases {
|
||||
func() {
|
||||
// set up
|
||||
opts := database.TestDBOptions{SkipMigration: true}
|
||||
ctx := context.InitTestCtx(t, paths, &opts)
|
||||
db := database.InitTestMemoryDBRaw(t, "")
|
||||
ctx := context.InitTestCtxWithDB(t, paths, db)
|
||||
defer context.TeardownTestCtx(t, ctx)
|
||||
|
||||
db := ctx.DB
|
||||
|
||||
database.MustExec(t, "creating a temporary table for testing", db,
|
||||
"CREATE TABLE migrate_run_test ( name string )")
|
||||
|
||||
|
|
@ -254,6 +254,7 @@ func TestRun_fresh(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestRun_up_to_date(t *testing.T) {
|
||||
paths := getTestPaths(t)
|
||||
testCases := []struct {
|
||||
mode int
|
||||
schemaKey string
|
||||
|
|
@ -271,12 +272,10 @@ func TestRun_up_to_date(t *testing.T) {
|
|||
for _, tc := range testCases {
|
||||
func() {
|
||||
// set up
|
||||
opts := database.TestDBOptions{SkipMigration: true}
|
||||
ctx := context.InitTestCtx(t, paths, &opts)
|
||||
db := database.InitTestMemoryDBRaw(t, "")
|
||||
ctx := context.InitTestCtxWithDB(t, paths, db)
|
||||
defer context.TeardownTestCtx(t, ctx)
|
||||
|
||||
db := ctx.DB
|
||||
|
||||
database.MustExec(t, "creating a temporary table for testing", db,
|
||||
"CREATE TABLE migrate_run_test ( name string )")
|
||||
|
||||
|
|
@ -325,12 +324,11 @@ func TestRun_up_to_date(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestLocalMigration1(t *testing.T) {
|
||||
paths := getTestPaths(t)
|
||||
// set up
|
||||
opts := database.TestDBOptions{SchemaSQLPath: "./fixtures/local-1-pre-schema.sql", SkipMigration: true}
|
||||
ctx := context.InitTestCtx(t, paths, &opts)
|
||||
db := database.InitTestMemoryDBRaw(t, "./fixtures/local-1-pre-schema.sql")
|
||||
ctx := context.InitTestCtxWithDB(t, paths, db)
|
||||
defer context.TeardownTestCtx(t, ctx)
|
||||
|
||||
db := ctx.DB
|
||||
data := testutils.MustMarshalJSON(t, actions.AddBookDataV1{BookName: "js"})
|
||||
a1UUID := testutils.MustGenerateUUID(t)
|
||||
database.MustExec(t, "inserting action", db,
|
||||
|
|
@ -403,12 +401,11 @@ func TestLocalMigration1(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestLocalMigration2(t *testing.T) {
|
||||
paths := getTestPaths(t)
|
||||
// set up
|
||||
opts := database.TestDBOptions{SchemaSQLPath: "./fixtures/local-1-pre-schema.sql", SkipMigration: true}
|
||||
ctx := context.InitTestCtx(t, paths, &opts)
|
||||
db := database.InitTestMemoryDBRaw(t, "./fixtures/local-1-pre-schema.sql")
|
||||
ctx := context.InitTestCtxWithDB(t, paths, db)
|
||||
defer context.TeardownTestCtx(t, ctx)
|
||||
|
||||
db := ctx.DB
|
||||
c1 := "note 1 - v1"
|
||||
c2 := "note 1 - v2"
|
||||
css := "css"
|
||||
|
|
@ -490,12 +487,11 @@ func TestLocalMigration2(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestLocalMigration3(t *testing.T) {
|
||||
paths := getTestPaths(t)
|
||||
// set up
|
||||
opts := database.TestDBOptions{SchemaSQLPath: "./fixtures/local-1-pre-schema.sql", SkipMigration: true}
|
||||
ctx := context.InitTestCtx(t, paths, &opts)
|
||||
db := database.InitTestMemoryDBRaw(t, "./fixtures/local-1-pre-schema.sql")
|
||||
ctx := context.InitTestCtxWithDB(t, paths, db)
|
||||
defer context.TeardownTestCtx(t, ctx)
|
||||
|
||||
db := ctx.DB
|
||||
data := testutils.MustMarshalJSON(t, actions.AddNoteDataV2{NoteUUID: "note-1-uuid", BookName: "js", Content: "note 1", Public: false})
|
||||
a1UUID := testutils.MustGenerateUUID(t)
|
||||
database.MustExec(t, "inserting action", db,
|
||||
|
|
@ -565,13 +561,12 @@ func TestLocalMigration3(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestLocalMigration4(t *testing.T) {
|
||||
paths := getTestPaths(t)
|
||||
// set up
|
||||
opts := database.TestDBOptions{SchemaSQLPath: "./fixtures/local-1-pre-schema.sql", SkipMigration: true}
|
||||
ctx := context.InitTestCtx(t, paths, &opts)
|
||||
db := database.InitTestMemoryDBRaw(t, "./fixtures/local-1-pre-schema.sql")
|
||||
ctx := context.InitTestCtxWithDB(t, paths, db)
|
||||
defer context.TeardownTestCtx(t, ctx)
|
||||
|
||||
db := ctx.DB
|
||||
|
||||
b1UUID := testutils.MustGenerateUUID(t)
|
||||
database.MustExec(t, "inserting css book", db, "INSERT INTO books (uuid, label) VALUES (?, ?)", b1UUID, "css")
|
||||
n1UUID := testutils.MustGenerateUUID(t)
|
||||
|
|
@ -609,13 +604,12 @@ func TestLocalMigration4(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestLocalMigration5(t *testing.T) {
|
||||
paths := getTestPaths(t)
|
||||
// set up
|
||||
opts := database.TestDBOptions{SchemaSQLPath: "./fixtures/local-5-pre-schema.sql", SkipMigration: true}
|
||||
ctx := context.InitTestCtx(t, paths, &opts)
|
||||
db := database.InitTestMemoryDBRaw(t, "./fixtures/local-5-pre-schema.sql")
|
||||
ctx := context.InitTestCtxWithDB(t, paths, db)
|
||||
defer context.TeardownTestCtx(t, ctx)
|
||||
|
||||
db := ctx.DB
|
||||
|
||||
b1UUID := testutils.MustGenerateUUID(t)
|
||||
database.MustExec(t, "inserting css book", db, "INSERT INTO books (uuid, label) VALUES (?, ?)", b1UUID, "css")
|
||||
b2UUID := testutils.MustGenerateUUID(t)
|
||||
|
|
@ -671,13 +665,12 @@ func TestLocalMigration5(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestLocalMigration6(t *testing.T) {
|
||||
paths := getTestPaths(t)
|
||||
// set up
|
||||
opts := database.TestDBOptions{SchemaSQLPath: "./fixtures/local-5-pre-schema.sql", SkipMigration: true}
|
||||
ctx := context.InitTestCtx(t, paths, &opts)
|
||||
db := database.InitTestMemoryDBRaw(t, "./fixtures/local-5-pre-schema.sql")
|
||||
ctx := context.InitTestCtxWithDB(t, paths, db)
|
||||
defer context.TeardownTestCtx(t, ctx)
|
||||
|
||||
db := ctx.DB
|
||||
|
||||
data := testutils.MustMarshalJSON(t, actions.AddBookDataV1{BookName: "js"})
|
||||
a1UUID := testutils.MustGenerateUUID(t)
|
||||
database.MustExec(t, "inserting action", db,
|
||||
|
|
@ -704,13 +697,12 @@ func TestLocalMigration6(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestLocalMigration7_trash(t *testing.T) {
|
||||
paths := getTestPaths(t)
|
||||
// set up
|
||||
opts := database.TestDBOptions{SchemaSQLPath: "./fixtures/local-7-pre-schema.sql", SkipMigration: true}
|
||||
ctx := context.InitTestCtx(t, paths, &opts)
|
||||
db := database.InitTestMemoryDBRaw(t, "./fixtures/local-7-pre-schema.sql")
|
||||
ctx := context.InitTestCtxWithDB(t, paths, db)
|
||||
defer context.TeardownTestCtx(t, ctx)
|
||||
|
||||
db := ctx.DB
|
||||
|
||||
b1UUID := testutils.MustGenerateUUID(t)
|
||||
database.MustExec(t, "inserting trash book", db, "INSERT INTO books (uuid, label) VALUES (?, ?)", b1UUID, "trash")
|
||||
|
||||
|
|
@ -737,13 +729,12 @@ func TestLocalMigration7_trash(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestLocalMigration7_conflicts(t *testing.T) {
|
||||
paths := getTestPaths(t)
|
||||
// set up
|
||||
opts := database.TestDBOptions{SchemaSQLPath: "./fixtures/local-7-pre-schema.sql", SkipMigration: true}
|
||||
ctx := context.InitTestCtx(t, paths, &opts)
|
||||
db := database.InitTestMemoryDBRaw(t, "./fixtures/local-7-pre-schema.sql")
|
||||
ctx := context.InitTestCtxWithDB(t, paths, db)
|
||||
defer context.TeardownTestCtx(t, ctx)
|
||||
|
||||
db := ctx.DB
|
||||
|
||||
b1UUID := testutils.MustGenerateUUID(t)
|
||||
database.MustExec(t, "inserting book", db, "INSERT INTO books (uuid, label) VALUES (?, ?)", b1UUID, "conflicts")
|
||||
|
||||
|
|
@ -770,13 +761,12 @@ func TestLocalMigration7_conflicts(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestLocalMigration7_conflicts_dup(t *testing.T) {
|
||||
paths := getTestPaths(t)
|
||||
// set up
|
||||
opts := database.TestDBOptions{SchemaSQLPath: "./fixtures/local-7-pre-schema.sql", SkipMigration: true}
|
||||
ctx := context.InitTestCtx(t, paths, &opts)
|
||||
db := database.InitTestMemoryDBRaw(t, "./fixtures/local-7-pre-schema.sql")
|
||||
ctx := context.InitTestCtxWithDB(t, paths, db)
|
||||
defer context.TeardownTestCtx(t, ctx)
|
||||
|
||||
db := ctx.DB
|
||||
|
||||
b1UUID := testutils.MustGenerateUUID(t)
|
||||
database.MustExec(t, "inserting book", db, "INSERT INTO books (uuid, label) VALUES (?, ?)", b1UUID, "conflicts")
|
||||
b2UUID := testutils.MustGenerateUUID(t)
|
||||
|
|
@ -808,13 +798,12 @@ func TestLocalMigration7_conflicts_dup(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestLocalMigration8(t *testing.T) {
|
||||
paths := getTestPaths(t)
|
||||
// set up
|
||||
opts := database.TestDBOptions{SchemaSQLPath: "./fixtures/local-8-pre-schema.sql", SkipMigration: true}
|
||||
ctx := context.InitTestCtx(t, paths, &opts)
|
||||
db := database.InitTestMemoryDBRaw(t, "./fixtures/local-8-pre-schema.sql")
|
||||
ctx := context.InitTestCtxWithDB(t, paths, db)
|
||||
defer context.TeardownTestCtx(t, ctx)
|
||||
|
||||
db := ctx.DB
|
||||
|
||||
b1UUID := testutils.MustGenerateUUID(t)
|
||||
database.MustExec(t, "inserting book 1", db, "INSERT INTO books (uuid, label) VALUES (?, ?)", b1UUID, "b1")
|
||||
|
||||
|
|
@ -874,13 +863,12 @@ func TestLocalMigration8(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestLocalMigration9(t *testing.T) {
|
||||
paths := getTestPaths(t)
|
||||
// set up
|
||||
opts := database.TestDBOptions{SchemaSQLPath: "./fixtures/local-9-pre-schema.sql", SkipMigration: true}
|
||||
ctx := context.InitTestCtx(t, paths, &opts)
|
||||
db := database.InitTestMemoryDBRaw(t, "./fixtures/local-9-pre-schema.sql")
|
||||
ctx := context.InitTestCtxWithDB(t, paths, db)
|
||||
defer context.TeardownTestCtx(t, ctx)
|
||||
|
||||
db := ctx.DB
|
||||
|
||||
b1UUID := testutils.MustGenerateUUID(t)
|
||||
database.MustExec(t, "inserting book 1", db, "INSERT INTO books (uuid, label) VALUES (?, ?)", b1UUID, "b1")
|
||||
|
||||
|
|
@ -920,13 +908,12 @@ func TestLocalMigration9(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestLocalMigration10(t *testing.T) {
|
||||
paths := getTestPaths(t)
|
||||
// set up
|
||||
opts := database.TestDBOptions{SchemaSQLPath: "./fixtures/local-10-pre-schema.sql", SkipMigration: true}
|
||||
ctx := context.InitTestCtx(t, paths, &opts)
|
||||
db := database.InitTestMemoryDBRaw(t, "./fixtures/local-10-pre-schema.sql")
|
||||
ctx := context.InitTestCtxWithDB(t, paths, db)
|
||||
defer context.TeardownTestCtx(t, ctx)
|
||||
|
||||
db := ctx.DB
|
||||
|
||||
b1UUID := testutils.MustGenerateUUID(t)
|
||||
database.MustExec(t, "inserting book ", db, "INSERT INTO books (uuid, label) VALUES (?, ?)", b1UUID, "123")
|
||||
b2UUID := testutils.MustGenerateUUID(t)
|
||||
|
|
@ -992,13 +979,12 @@ func TestLocalMigration10(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestLocalMigration11(t *testing.T) {
|
||||
paths := getTestPaths(t)
|
||||
// set up
|
||||
opts := database.TestDBOptions{SchemaSQLPath: "./fixtures/local-11-pre-schema.sql", SkipMigration: true}
|
||||
ctx := context.InitTestCtx(t, paths, &opts)
|
||||
db := database.InitTestMemoryDBRaw(t, "./fixtures/local-11-pre-schema.sql")
|
||||
ctx := context.InitTestCtxWithDB(t, paths, db)
|
||||
defer context.TeardownTestCtx(t, ctx)
|
||||
|
||||
db := ctx.DB
|
||||
|
||||
b1UUID := testutils.MustGenerateUUID(t)
|
||||
database.MustExec(t, "inserting book 1", db, "INSERT INTO books (uuid, label) VALUES (?, ?)", b1UUID, "foo")
|
||||
b2UUID := testutils.MustGenerateUUID(t)
|
||||
|
|
@ -1072,9 +1058,10 @@ func TestLocalMigration11(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestLocalMigration12(t *testing.T) {
|
||||
paths := getTestPaths(t)
|
||||
// set up
|
||||
opts := database.TestDBOptions{SchemaSQLPath: "./fixtures/local-12-pre-schema.sql", SkipMigration: true}
|
||||
ctx := context.InitTestCtx(t, paths, &opts)
|
||||
db := database.InitTestMemoryDBRaw(t, "./fixtures/local-12-pre-schema.sql")
|
||||
ctx := context.InitTestCtxWithDB(t, paths, db)
|
||||
defer context.TeardownTestCtx(t, ctx)
|
||||
|
||||
data := []byte("editor: vim")
|
||||
|
|
@ -1109,9 +1096,10 @@ func TestLocalMigration12(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestLocalMigration13(t *testing.T) {
|
||||
paths := getTestPaths(t)
|
||||
// set up
|
||||
opts := database.TestDBOptions{SchemaSQLPath: "./fixtures/local-12-pre-schema.sql", SkipMigration: true}
|
||||
ctx := context.InitTestCtx(t, paths, &opts)
|
||||
db := database.InitTestMemoryDBRaw(t, "./fixtures/local-12-pre-schema.sql")
|
||||
ctx := context.InitTestCtxWithDB(t, paths, db)
|
||||
defer context.TeardownTestCtx(t, ctx)
|
||||
|
||||
data := []byte("editor: vim\napiEndpoint: https://test.com/api")
|
||||
|
|
@ -1151,13 +1139,12 @@ func TestLocalMigration13(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestLocalMigration14(t *testing.T) {
|
||||
paths := getTestPaths(t)
|
||||
// set up
|
||||
opts := database.TestDBOptions{SchemaSQLPath: "./fixtures/local-14-pre-schema.sql", SkipMigration: true}
|
||||
ctx := context.InitTestCtx(t, paths, &opts)
|
||||
db := database.InitTestMemoryDBRaw(t, "./fixtures/local-14-pre-schema.sql")
|
||||
ctx := context.InitTestCtxWithDB(t, paths, db)
|
||||
defer context.TeardownTestCtx(t, ctx)
|
||||
|
||||
db := ctx.DB
|
||||
|
||||
b1UUID := testutils.MustGenerateUUID(t)
|
||||
database.MustExec(t, "inserting book", db, "INSERT INTO books (uuid, label) VALUES (?, ?)", b1UUID, "b1")
|
||||
|
||||
|
|
@ -1201,9 +1188,10 @@ func TestLocalMigration14(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestRemoteMigration1(t *testing.T) {
|
||||
paths := getTestPaths(t)
|
||||
// set up
|
||||
opts := database.TestDBOptions{SchemaSQLPath: "./fixtures/remote-1-pre-schema.sql", SkipMigration: true}
|
||||
ctx := context.InitTestCtx(t, paths, &opts)
|
||||
db := database.InitTestMemoryDBRaw(t, "./fixtures/remote-1-pre-schema.sql")
|
||||
ctx := context.InitTestCtxWithDB(t, paths, db)
|
||||
defer context.TeardownTestCtx(t, ctx)
|
||||
testutils.Login(t, &ctx)
|
||||
|
||||
|
|
@ -1244,7 +1232,6 @@ func TestRemoteMigration1(t *testing.T) {
|
|||
|
||||
ctx.APIEndpoint = server.URL
|
||||
|
||||
db := ctx.DB
|
||||
database.MustExec(t, "inserting js book", db, "INSERT INTO books (uuid, label) VALUES (?, ?)", JSBookUUID, "js")
|
||||
database.MustExec(t, "inserting css book", db, "INSERT INTO books (uuid, label) VALUES (?, ?)", CSSBookUUID, "css")
|
||||
database.MustExec(t, "inserting linux book", db, "INSERT INTO books (uuid, label) VALUES (?, ?)", linuxBookUUID, "linux")
|
||||
|
|
|
|||
|
|
@ -48,12 +48,15 @@ const (
|
|||
// Timeout for waiting for prompts in tests
|
||||
const promptTimeout = 10 * time.Second
|
||||
|
||||
// Login simulates a logged in user by inserting credentials in the local database
|
||||
func Login(t *testing.T, ctx *context.DnoteCtx) {
|
||||
db := ctx.DB
|
||||
|
||||
// LoginDB sets up login credentials in the database for tests
|
||||
func LoginDB(t *testing.T, db *database.DB) {
|
||||
database.MustExec(t, "inserting sessionKey", db, "INSERT INTO system (key, value) VALUES (?, ?)", consts.SystemSessionKey, "someSessionKey")
|
||||
database.MustExec(t, "inserting sessionKeyExpiry", db, "INSERT INTO system (key, value) VALUES (?, ?)", consts.SystemSessionKeyExpiry, time.Now().Add(24*time.Hour).Unix())
|
||||
}
|
||||
|
||||
// Login simulates a logged in user by inserting credentials in the local database
|
||||
func Login(t *testing.T, ctx *context.DnoteCtx) {
|
||||
LoginDB(t, ctx.DB)
|
||||
|
||||
ctx.SessionKey = "someSessionKey"
|
||||
ctx.SessionKeyExpiry = time.Now().Add(24 * time.Hour).Unix()
|
||||
|
|
|
|||
|
|
@ -30,10 +30,11 @@ import (
|
|||
|
||||
func TestGetTmpContentPath(t *testing.T) {
|
||||
t.Run("no collision", func(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
ctx := context.InitTestCtx(t, context.Paths{
|
||||
Data: "../tmp",
|
||||
Cache: "../tmp",
|
||||
}, nil)
|
||||
Data: tmpDir,
|
||||
Cache: tmpDir,
|
||||
})
|
||||
defer context.TeardownTestCtx(t, ctx)
|
||||
|
||||
res, err := GetTmpContentPath(ctx)
|
||||
|
|
@ -47,10 +48,11 @@ func TestGetTmpContentPath(t *testing.T) {
|
|||
|
||||
t.Run("one existing session", func(t *testing.T) {
|
||||
// set up
|
||||
tmpDir := t.TempDir()
|
||||
ctx := context.InitTestCtx(t, context.Paths{
|
||||
Data: "../tmp2",
|
||||
Cache: "../tmp2",
|
||||
}, nil)
|
||||
Data: tmpDir,
|
||||
Cache: tmpDir,
|
||||
})
|
||||
defer context.TeardownTestCtx(t, ctx)
|
||||
|
||||
p := fmt.Sprintf("%s/%s", ctx.Paths.Cache, "DNOTE_TMPCONTENT_0.md")
|
||||
|
|
@ -71,10 +73,11 @@ func TestGetTmpContentPath(t *testing.T) {
|
|||
|
||||
t.Run("two existing sessions", func(t *testing.T) {
|
||||
// set up
|
||||
tmpDir := t.TempDir()
|
||||
ctx := context.InitTestCtx(t, context.Paths{
|
||||
Data: "../tmp3",
|
||||
Cache: "../tmp3",
|
||||
}, nil)
|
||||
Data: tmpDir,
|
||||
Cache: tmpDir,
|
||||
})
|
||||
defer context.TeardownTestCtx(t, ctx)
|
||||
|
||||
p1 := fmt.Sprintf("%s/%s", ctx.Paths.Cache, "DNOTE_TMPCONTENT_0.md")
|
||||
|
|
|
|||
1538
pkg/e2e/sync_test.go
1538
pkg/e2e/sync_test.go
File diff suppressed because it is too large
Load diff
|
|
@ -67,26 +67,6 @@ func InitMemoryDB(t *testing.T) *gorm.DB {
|
|||
return db
|
||||
}
|
||||
|
||||
// ClearData deletes all records from the database
|
||||
func ClearData(db *gorm.DB) {
|
||||
// Delete in order: child tables first, parent tables last
|
||||
if err := db.Where("1 = 1").Delete(&database.Note{}).Error; err != nil {
|
||||
panic(errors.Wrap(err, "Failed to clear notes"))
|
||||
}
|
||||
if err := db.Where("1 = 1").Delete(&database.Book{}).Error; err != nil {
|
||||
panic(errors.Wrap(err, "Failed to clear books"))
|
||||
}
|
||||
if err := db.Where("1 = 1").Delete(&database.Token{}).Error; err != nil {
|
||||
panic(errors.Wrap(err, "Failed to clear tokens"))
|
||||
}
|
||||
if err := db.Where("1 = 1").Delete(&database.Session{}).Error; err != nil {
|
||||
panic(errors.Wrap(err, "Failed to clear sessions"))
|
||||
}
|
||||
if err := db.Where("1 = 1").Delete(&database.User{}).Error; err != nil {
|
||||
panic(errors.Wrap(err, "Failed to clear users"))
|
||||
}
|
||||
}
|
||||
|
||||
// MustUUID generates a UUID and fails the test on error
|
||||
func MustUUID(t *testing.T) string {
|
||||
uuid, err := helpers.GenUUID()
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
#!/usr/bin/env bash
|
||||
# test.sh runs test files sequentially
|
||||
# https://stackoverflow.com/questions/23715302/go-how-to-run-tests-for-multiple-packages
|
||||
# test.sh runs tests for CLI packages
|
||||
set -eux
|
||||
|
||||
dir=$(dirname "${BASH_SOURCE[0]}")
|
||||
|
|
@ -8,7 +7,5 @@ pushd "$dir/../../pkg/cli"
|
|||
# clear tmp dir in case not properly torn down
|
||||
rm -rf "./tmp"
|
||||
|
||||
go test -a ./... \
|
||||
-p 1\
|
||||
--tags "fts5"
|
||||
go test ./... --tags "fts5"
|
||||
popd
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue