2019-03-04 02:34:10 +00:00
|
|
|
/* global it describe beforeEach afterEach */
|
|
|
|
|
|
|
|
import '../indexedDBShims'
|
|
|
|
import assert from 'assert'
|
|
|
|
import { closeDatabase, deleteDatabase, getDatabase } from '../../src/routes/_database/databaseLifecycle'
|
|
|
|
import * as dbApi from '../../src/routes/_database/databaseApis'
|
|
|
|
import times from 'lodash-es/times'
|
|
|
|
import cloneDeep from 'lodash-es/cloneDeep'
|
|
|
|
import {
|
|
|
|
TIMESTAMP, ACCOUNT_ID, STATUS_ID, REBLOG_ID, USERNAME_LOWERCASE,
|
|
|
|
CURRENT_TIME, DB_VERSION_CURRENT, DB_VERSION_SEARCH_ACCOUNTS, DB_VERSION_SNOWFLAKE_IDS
|
|
|
|
} from '../../src/routes/_database/constants'
|
2019-09-08 00:49:58 +00:00
|
|
|
import { cleanup } from '../../src/routes/_database/cleanup'
|
|
|
|
import { CLEANUP_TIME_AGO } from '../../src/routes/_static/database'
|
2019-03-04 02:34:10 +00:00
|
|
|
|
|
|
|
const INSTANCE_NAME = 'localhost:3000'
|
|
|
|
|
|
|
|
const INSTANCE_INFO = {
|
2019-08-03 20:49:37 +00:00
|
|
|
uri: 'localhost:3000',
|
|
|
|
title: 'lolcathost',
|
|
|
|
description: 'blah',
|
|
|
|
foo: {
|
|
|
|
bar: true
|
2019-03-04 02:34:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const createStatus = i => ({
|
|
|
|
id: i.toString(),
|
|
|
|
created_at: new Date().toISOString(),
|
2019-08-20 02:08:59 +00:00
|
|
|
content: 'Status #4{id}',
|
2019-03-04 02:34:10 +00:00
|
|
|
account: {
|
|
|
|
id: '1'
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
const stripDBFields = item => {
|
2019-08-03 20:49:37 +00:00
|
|
|
const res = cloneDeep(item)
|
2019-03-04 02:34:10 +00:00
|
|
|
delete res[TIMESTAMP]
|
|
|
|
delete res[ACCOUNT_ID]
|
|
|
|
delete res[STATUS_ID]
|
|
|
|
delete res[REBLOG_ID]
|
|
|
|
delete res[USERNAME_LOWERCASE]
|
|
|
|
if (res.account) {
|
|
|
|
delete res.account[TIMESTAMP]
|
|
|
|
}
|
|
|
|
return res
|
|
|
|
}
|
|
|
|
|
|
|
|
describe('test-database.js', function () {
|
|
|
|
this.timeout(60000)
|
|
|
|
|
|
|
|
describe('db-basic', () => {
|
|
|
|
beforeEach(async () => {
|
|
|
|
await getDatabase(INSTANCE_NAME)
|
|
|
|
})
|
|
|
|
|
|
|
|
afterEach(async () => {
|
|
|
|
await deleteDatabase(INSTANCE_NAME)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('basic indexeddb test', async () => {
|
|
|
|
let info = await dbApi.getInstanceInfo(INSTANCE_NAME)
|
|
|
|
assert(!info)
|
|
|
|
await dbApi.setInstanceInfo(INSTANCE_NAME, INSTANCE_INFO)
|
|
|
|
info = await dbApi.getInstanceInfo(INSTANCE_NAME)
|
|
|
|
assert.deepStrictEqual(info, INSTANCE_INFO)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('basic indexeddb test 2', async () => {
|
|
|
|
// sanity check to make sure that we have a clean DB between each test
|
|
|
|
let info = await dbApi.getInstanceInfo(INSTANCE_NAME)
|
|
|
|
assert(!info)
|
|
|
|
await dbApi.setInstanceInfo(INSTANCE_NAME, INSTANCE_INFO)
|
|
|
|
info = await dbApi.getInstanceInfo(INSTANCE_NAME)
|
|
|
|
assert.deepStrictEqual(info, INSTANCE_INFO)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('stores and sorts some statuses', async () => {
|
2019-08-03 20:49:37 +00:00
|
|
|
const allStatuses = times(40, createStatus)
|
2019-03-04 02:34:10 +00:00
|
|
|
await dbApi.insertTimelineItems(INSTANCE_NAME, 'local', allStatuses)
|
|
|
|
let statuses = await dbApi.getTimeline(INSTANCE_NAME, 'local', null, 20)
|
|
|
|
let expected = allStatuses.slice().reverse().slice(0, 20)
|
|
|
|
assert.deepStrictEqual(statuses.map(stripDBFields), expected)
|
|
|
|
|
|
|
|
statuses = await dbApi.getTimeline(INSTANCE_NAME, 'local', statuses[statuses.length - 1].id, 20)
|
|
|
|
expected = allStatuses.slice().reverse().slice(20, 40)
|
|
|
|
assert.deepStrictEqual(statuses.map(stripDBFields), expected)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('cleans up old statuses', async () => {
|
|
|
|
// Pretend we are inserting a status from a long time ago. Note that we
|
|
|
|
// set a timestamp based on the *current* date when the status is inserted,
|
|
|
|
// not the date that the status was composed.
|
|
|
|
|
2019-09-08 00:49:58 +00:00
|
|
|
const longAgo = Date.now() - (CLEANUP_TIME_AGO * 2)
|
2019-03-04 02:34:10 +00:00
|
|
|
|
2019-08-03 20:49:37 +00:00
|
|
|
const oldStatus = {
|
2019-03-04 02:34:10 +00:00
|
|
|
id: '1',
|
|
|
|
created_at: new Date(longAgo).toISOString(),
|
|
|
|
content: 'This is old',
|
|
|
|
account: {
|
|
|
|
id: '1'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-03 20:49:37 +00:00
|
|
|
const previousNow = CURRENT_TIME.now
|
2019-03-04 02:34:10 +00:00
|
|
|
CURRENT_TIME.now = () => longAgo
|
|
|
|
|
|
|
|
await dbApi.insertTimelineItems(INSTANCE_NAME, 'local', [oldStatus])
|
|
|
|
|
|
|
|
CURRENT_TIME.now = previousNow
|
|
|
|
|
2019-08-03 20:49:37 +00:00
|
|
|
const newStatus = {
|
2019-03-04 02:34:10 +00:00
|
|
|
id: '2',
|
|
|
|
created_at: new Date().toISOString(),
|
|
|
|
content: 'This is new',
|
|
|
|
account: {
|
|
|
|
id: '2'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
await dbApi.insertTimelineItems(INSTANCE_NAME, 'local', [newStatus])
|
|
|
|
let statuses = await dbApi.getTimeline(INSTANCE_NAME, 'local', null, 20)
|
|
|
|
assert.deepStrictEqual(statuses.map(stripDBFields), [newStatus, oldStatus])
|
|
|
|
|
|
|
|
let status1 = await dbApi.getStatus(INSTANCE_NAME, '1')
|
|
|
|
let status2 = await dbApi.getStatus(INSTANCE_NAME, '2')
|
|
|
|
|
|
|
|
assert.deepStrictEqual(stripDBFields(status1), oldStatus)
|
|
|
|
assert.deepStrictEqual(stripDBFields(status2), newStatus)
|
|
|
|
|
|
|
|
await cleanup(INSTANCE_NAME)
|
|
|
|
|
|
|
|
statuses = await dbApi.getTimeline(INSTANCE_NAME, 'local', null, 20)
|
|
|
|
assert.deepStrictEqual(statuses.map(stripDBFields), [newStatus])
|
|
|
|
|
|
|
|
status1 = await dbApi.getStatus(INSTANCE_NAME, '1')
|
|
|
|
status2 = await dbApi.getStatus(INSTANCE_NAME, '2')
|
|
|
|
|
|
|
|
assert(!!status1)
|
|
|
|
assert.deepStrictEqual(stripDBFields(status2), newStatus)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('db-migrations', () => {
|
|
|
|
let oldCurrentVersion
|
|
|
|
|
|
|
|
beforeEach(async () => {
|
|
|
|
oldCurrentVersion = DB_VERSION_CURRENT.version
|
|
|
|
})
|
|
|
|
|
|
|
|
afterEach(async () => {
|
|
|
|
DB_VERSION_CURRENT.version = oldCurrentVersion
|
|
|
|
await deleteDatabase(INSTANCE_NAME)
|
|
|
|
})
|
|
|
|
|
2019-03-06 04:25:10 +00:00
|
|
|
it('migrates to snowflake IDs', async () => {
|
2019-03-04 02:34:10 +00:00
|
|
|
// open the db using the old version
|
|
|
|
DB_VERSION_CURRENT.version = DB_VERSION_SEARCH_ACCOUNTS
|
|
|
|
await getDatabase(INSTANCE_NAME)
|
|
|
|
|
|
|
|
// insert some statuses
|
2019-08-03 20:49:37 +00:00
|
|
|
const allStatuses = times(40, createStatus)
|
2019-03-04 02:34:10 +00:00
|
|
|
await dbApi.insertTimelineItems(INSTANCE_NAME, 'local', allStatuses)
|
|
|
|
|
2019-03-06 04:25:33 +00:00
|
|
|
let statuses = await dbApi.getTimeline(INSTANCE_NAME, 'local', null, 1000)
|
2019-03-04 02:34:10 +00:00
|
|
|
let expected = allStatuses.slice().reverse()
|
|
|
|
assert.deepStrictEqual(statuses.map(stripDBFields), expected)
|
|
|
|
|
|
|
|
// close the database
|
|
|
|
closeDatabase(INSTANCE_NAME)
|
|
|
|
|
|
|
|
// do a version upgrade
|
|
|
|
DB_VERSION_CURRENT.version = DB_VERSION_SNOWFLAKE_IDS
|
|
|
|
await getDatabase(INSTANCE_NAME)
|
|
|
|
|
|
|
|
// check that the old statuses are correct
|
2019-03-06 04:25:33 +00:00
|
|
|
statuses = await dbApi.getTimeline(INSTANCE_NAME, 'local', null, 1000)
|
2019-03-04 02:34:10 +00:00
|
|
|
expected = allStatuses.slice().reverse()
|
|
|
|
assert.deepStrictEqual(statuses.map(stripDBFields), expected)
|
|
|
|
|
|
|
|
// insert some more statuses for good measure
|
2019-08-03 20:49:37 +00:00
|
|
|
const moreStatuses = times(20, i => 40 + i).map(createStatus)
|
2019-03-04 02:34:10 +00:00
|
|
|
|
|
|
|
await dbApi.insertTimelineItems(INSTANCE_NAME, 'local', moreStatuses)
|
|
|
|
|
2019-03-06 04:25:33 +00:00
|
|
|
statuses = await dbApi.getTimeline(INSTANCE_NAME, 'local', null, 1000)
|
2019-03-04 02:34:10 +00:00
|
|
|
expected = moreStatuses.slice().reverse().concat(allStatuses.reverse())
|
|
|
|
|
|
|
|
assert.deepStrictEqual(statuses.map(stripDBFields), expected)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|