text: 'use strict'
  
  const assert = require('assert')
  const mapSeries = require('p-each-series')
  const rmrf = require('rimraf')
  const OrbitDB = require('../src/OrbitDB')
  // Include test utilities
  const {
    config,
    startIpfs,
    stopIpfs,
    testAPIs,
    connectPeers,
    waitForPeers
  } = require('orbit-db-test-utils')
  
  const orbitdbPath1 = './orbitdb/tests/counters/1'
  const orbitdbPath2 = './orbitdb/tests/counters/2'
  const dbPath1 = './orbitdb/tests/counters/db1'
  const dbPath2 = './orbitdb/tests/counters/db2'
  
  Object.keys(testAPIs).forEach(API => {
    describe(`orbit-db - Counters (${API})`, function () {
      this.timeout(config.timeout)
  
      let orbitdb1, orbitdb2
      let ipfsd1, ipfsd2, ipfs1, ipfs2
  
      before(async () => {
        rmrf.sync(dbPath1)
        rmrf.sync(dbPath2)
        rmrf.sync(orbitdbPath1)
        rmrf.sync(orbitdbPath2)
        ipfsd1 = await startIpfs(API, config.daemon1)
        ipfsd2 = await startIpfs(API, config.daemon2)
        ipfs1 = ipfsd1.api
        ipfs2 = ipfsd2.api
        // Connect the peers manually to speed up test times
        const isLocalhostAddress = (addr) => addr.toString().includes('127.0.0.1')
        await connectPeers(ipfs1, ipfs2, { filter: isLocalhostAddress })
      })
  
      after(async () => {
        if (orbitdb1)
          await orbitdb1.stop()
  
        if (orbitdb2)
          await orbitdb2.stop()
  
        if (ipfsd1)
          await stopIpfs(ipfsd1)
  
        if (ipfsd2)
          await stopIpfs(ipfsd2)
      })
  
      beforeEach(async () => {
        orbitdb1 = await OrbitDB.createInstance(ipfs1, { directory: './orbitdb/1' })
        orbitdb2 = await OrbitDB.createInstance(ipfs2, { directory: './orbitdb/2' })
      })
  
      afterEach(async () => {
        if (orbitdb1)
          await orbitdb1.stop()
  
        if (orbitdb2)
          await orbitdb2.stop()
      })
  
      describe('counters', function() {
        let address
  
        it('creates and opens a database', async () => {
          const db = await orbitdb1.counter('counter database')
          assert.notEqual(db, null)
          assert.equal(db.type, 'counter')
          assert.equal(db.dbname, 'counter database')
        })
  
        it('value is zero when it\'s a fresh database', async () => {
          const db = await orbitdb1.counter('counter database')
          assert.equal(db.value, 0)
          await db.close()
        })
  
        it('increases a counter value', async () => {
          const counter = await orbitdb1.counter('counter test', { path: dbPath1 })
          address = counter.address.toString()
          await mapSeries([13, 1], (f) => counter.inc(f))
          assert.equal(counter.value, 14)
          await counter.close()
        })
  
        it('opens a saved counter', async () => {
          const counter = await orbitdb1.counter(address, { path: dbPath1 })
          await counter.load()
          assert.equal(counter.value, 14)
          await counter.drop()
        })
  
        it('syncs counters', async () => {
          console.log("Sync counters")
  
          let options = {
            accessController: {
              // Set write access for both clients
              write: [
                orbitdb1.identity.id,
                orbitdb2.identity.id
              ]
            }
          }
  
          const dbName = new Date().getTime().toString()
  
          const numbers = [[13, 10], [2, 5]]
          const increaseCounter = (counterDB, i) => mapSeries(numbers[i], n => counterDB.inc(n))
  
          // Create a new counter database in the first client
          options = Object.assign({}, options, { path: dbPath1 })
          const counter1 = await orbitdb1.counter(dbName, options)
  
          // Open the database in the second client
          options = Object.assign({}, options, { path: dbPath2 })
          const counter2 = await orbitdb2.counter(dbName, options)
  
          // Make sure database addresses match since they're built deterministically
          assert.equal(counter1.address.toString(), counter2.address.toString())
  
          // Wait for peers to connect
          console.log("Waiting for peers to connect")
          await waitForPeers(ipfs1, [orbitdb2.id], counter1.address.toString())
          await waitForPeers(ipfs2, [orbitdb1.id], counter1.address.toString())
  
          let finished1 = counter1.value === 30
          let finished2 = counter2.value === 30
  
          counter1.events.on('replicated', () => {
            finished1 = (counter1.value === 30)
            finished2 = (counter2.value === 30)
          })
          counter2.events.on('replicated', () => {
            finished1 = (counter1.value === 30)
            finished2 = (counter2.value === 30)
          })
          counter1.events.on('write', () => {
            finished1 = (counter1.value === 30)
            finished2 = (counter2.value === 30)
          })
          counter2.events.on('write', () => {
            finished1 = (counter1.value === 30)
            finished2 = (counter2.value === 30)
          })
  
          // Increase the counters sequentially
          await mapSeries([counter1, counter2], increaseCounter)
          console.log("Waiting for replication to finish")
  
          return new Promise((resolve, reject) => {
            let timer = setInterval(async () => {
              if (finished1 && finished2) {
                try {
                  clearInterval(timer)
                  assert.equal(counter1.value, 30)
                  assert.equal(counter2.value, 30)
                  await counter1.close()
                  await counter2.close()
                  resolve()
                } catch (e) {
                  reject(e)
                }
              }
            }, 100)
          })
        })
      })
    })
  })
  