192 lines
		
	
	
	
		
			6.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			192 lines
		
	
	
	
		
			6.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/* 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'
 | 
						|
import { cleanup, TIME_AGO } from '../../src/routes/_database/cleanup'
 | 
						|
 | 
						|
const INSTANCE_NAME = 'localhost:3000'
 | 
						|
 | 
						|
const INSTANCE_INFO = {
 | 
						|
  'uri': 'localhost:3000',
 | 
						|
  'title': 'lolcathost',
 | 
						|
  'description': 'blah',
 | 
						|
  'foo': {
 | 
						|
    'bar': true
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
const createStatus = i => ({
 | 
						|
  id: i.toString(),
 | 
						|
  created_at: new Date().toISOString(),
 | 
						|
  content: `Status #4{id}`,
 | 
						|
  account: {
 | 
						|
    id: '1'
 | 
						|
  }
 | 
						|
})
 | 
						|
 | 
						|
const stripDBFields = item => {
 | 
						|
  let res = cloneDeep(item)
 | 
						|
  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 () => {
 | 
						|
      let allStatuses = times(40, createStatus)
 | 
						|
      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.
 | 
						|
 | 
						|
      let longAgo = Date.now() - (TIME_AGO * 2)
 | 
						|
 | 
						|
      let oldStatus = {
 | 
						|
        id: '1',
 | 
						|
        created_at: new Date(longAgo).toISOString(),
 | 
						|
        content: 'This is old',
 | 
						|
        account: {
 | 
						|
          id: '1'
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      let previousNow = CURRENT_TIME.now
 | 
						|
      CURRENT_TIME.now = () => longAgo
 | 
						|
 | 
						|
      await dbApi.insertTimelineItems(INSTANCE_NAME, 'local', [oldStatus])
 | 
						|
 | 
						|
      CURRENT_TIME.now = previousNow
 | 
						|
 | 
						|
      let newStatus = {
 | 
						|
        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)
 | 
						|
    })
 | 
						|
 | 
						|
    it('migrates to snowflake IDs', async () => {
 | 
						|
      // open the db using the old version
 | 
						|
      DB_VERSION_CURRENT.version = DB_VERSION_SEARCH_ACCOUNTS
 | 
						|
      await getDatabase(INSTANCE_NAME)
 | 
						|
 | 
						|
      // insert some statuses
 | 
						|
      let allStatuses = times(40, createStatus)
 | 
						|
      await dbApi.insertTimelineItems(INSTANCE_NAME, 'local', allStatuses)
 | 
						|
 | 
						|
      let statuses = await dbApi.getTimeline(INSTANCE_NAME, 'local', null, 1000)
 | 
						|
      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
 | 
						|
      statuses = await dbApi.getTimeline(INSTANCE_NAME, 'local', null, 1000)
 | 
						|
      expected = allStatuses.slice().reverse()
 | 
						|
      assert.deepStrictEqual(statuses.map(stripDBFields), expected)
 | 
						|
 | 
						|
      // insert some more statuses for good measure
 | 
						|
      let moreStatuses = times(20, i => 40 + i).map(createStatus)
 | 
						|
 | 
						|
      await dbApi.insertTimelineItems(INSTANCE_NAME, 'local', moreStatuses)
 | 
						|
 | 
						|
      statuses = await dbApi.getTimeline(INSTANCE_NAME, 'local', null, 1000)
 | 
						|
      expected = moreStatuses.slice().reverse().concat(allStatuses.reverse())
 | 
						|
 | 
						|
      assert.deepStrictEqual(statuses.map(stripDBFields), expected)
 | 
						|
    })
 | 
						|
  })
 | 
						|
})
 |