import { assert } from 'chai'
import fs from 'fs-extra'
import $rdf from 'rdflib'
import { httpRequest as request, cleanDir, rm } from '../utils.mjs'
import path from 'path'
import { fileURLToPath } from 'url'

/**
 * Note: this test suite requires an internet connection, since it actually
 * uses remote accounts https://user1.databox.me and https://user2.databox.me
 */

// Helper functions for the FS
// import { rm } from '../../test/utils.js'
// var write = require('./utils').write
// var cp = require('./utils').cp
// var read = require('./utils').read

import ldnode from '../../index.mjs'
import solidNamespace from 'solid-namespace'

const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
const ns = solidNamespace($rdf)

const port = 7777
const serverUri = 'https://localhost:7777'
const rootPath = path.normalize(path.join(__dirname, '../resources/acl-tls'))
const dbPath = path.join(rootPath, 'db')
const configPath = path.join(rootPath, 'config')

const aclExtension = '.acl'
const metaExtension = '.meta'

const testDir = 'acl-tls/testDir'
const testDirAclFile = testDir + '/' + aclExtension
const testDirMetaFile = testDir + '/' + metaExtension

const abcFile = testDir + '/abc.ttl'

const globFile = testDir + '/*'

const origin1 = 'http://example.org/'
const origin2 = 'http://example.com/'

const user1 = 'https://tim.localhost:7777/profile/card#me'
const user2 = 'https://nicola.localhost:7777/profile/card#me'
const address = 'https://tim.localhost:7777'
const userCredentials = {
  user1: {
    cert: fs.readFileSync(path.normalize(path.join(__dirname, '../keys/user1-cert.pem'))),
    key: fs.readFileSync(path.normalize(path.join(__dirname, '../keys/user1-key.pem')))
  },
  user2: {
    cert: fs.readFileSync(path.normalize(path.join(__dirname, '../keys/user2-cert.pem'))),
    key: fs.readFileSync(path.normalize(path.join(__dirname, '../keys/user2-key.pem')))
  }
}

// TODO Remove skip. TLS is currently broken, but is not a priority to fix since
// the current Solid spec does not require supporting webid-tls on the resource
// server. The current spec only requires the resource server to support webid-oidc,
// and it requires the IDP to support webid-tls as a log in method, so that users of
// a webid-tls client certificate can still use their certificate (and not a
// username/password pair or other login method) to "bridge" from webid-tls to
// webid-oidc.
describe.skip('ACL with WebID+TLS', function () {
  let ldpHttpsServer
  const serverConfig = {
    root: rootPath,
    serverUri,
    dbPath,
    port,
    configPath,
    sslKey: path.normalize(path.join(__dirname, '../keys/key.pem')),
    sslCert: path.normalize(path.join(__dirname, '../keys/cert.pem')),
    webid: true,
    multiuser: true,
    auth: 'tls',
    rejectUnauthorized: false,
    strictOrigin: true,
    host: { serverUri }
  }
  const ldp = ldnode.createServer(serverConfig)

  before(function (done) {
    ldpHttpsServer = ldp.listen(port, () => {
      setTimeout(() => {
        done()
      }, 0)
    })
  })

  after(function () {
    if (ldpHttpsServer) ldpHttpsServer.close()
    cleanDir(rootPath)
  })

  function createOptions (path, user) {
    const options = {
      url: address + path,
      headers: {
        accept: 'text/turtle',
        'content-type': 'text/plain'
      }
    }
    if (user) {
      options.agentOptions = userCredentials[user]
    }
    return options
  }

  describe('no ACL', function () {
    it('should return 500 for any resource', function (done) {
      rm('.acl')
      const options = createOptions('/acl-tls/no-acl/', 'user1')
      request(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 500)
        done()
      })
    })

    it('should have `User` set in the Response Header', function (done) {
      rm('.acl')
      const options = createOptions('/acl-tls/no-acl/', 'user1')
      request(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.headers.user, 'https://user1.databox.me/profile/card#me')
        done()
      })
    })

    it.skip('should return a 401 and WWW-Authenticate header without credentials', (done) => {
      rm('.acl')
      const options = {
        url: address + '/acl-tls/no-acl/',
        headers: { accept: 'text/turtle' }
      }

      request(options, (error, response, body) => {
        assert.equal(error, null)
        assert.equal(response.statusCode, 401)
        assert.equal(response.headers['www-authenticate'], 'WebID-TLS realm="https://localhost:8443"')
        done()
      })
    })
  })

  describe('empty .acl', function () {
    describe('with no default in parent path', function () {
      it('should give no access', function (done) {
        const options = createOptions('/acl-tls/empty-acl/test-folder', 'user1')
        options.body = ''
        request.put(options, function (error, response, body) {
          assert.equal(error, null)
          assert.equal(response.statusCode, 403)
          done()
        })
      })
      it('should not let edit the .acl', function (done) {
        const options = createOptions('/acl-tls/empty-acl/.acl', 'user1')
        options.headers = {
          'content-type': 'text/turtle'
        }
        options.body = ''
        request.put(options, function (error, response, body) {
          assert.equal(error, null)
          assert.equal(response.statusCode, 403)
          done()
        })
      })
      it('should not let read the .acl', function (done) {
        const options = createOptions('/acl-tls/empty-acl/.acl', 'user1')
        options.headers = {
          accept: 'text/turtle'
        }
        request.get(options, function (error, response, body) {
          assert.equal(error, null)
          assert.equal(response.statusCode, 403)
          done()
        })
      })
    })
    describe('with default in parent path', function () {
      before(function () {
        rm('/acl-tls/write-acl/empty-acl/another-empty-folder/test-file.acl')
        rm('/acl-tls/write-acl/empty-acl/test-folder/test-file')
        rm('/acl-tls/write-acl/empty-acl/test-file')
        rm('/acl-tls/write-acl/test-file')
        rm('/acl-tls/write-acl/test-file.acl')
      })

      it('should fail to create a container', function (done) {
        const options = createOptions('/acl-tls/write-acl/empty-acl/test-folder/', 'user1')
        options.body = ''
        request.put(options, function (error, response, body) {
          assert.equal(error, null)
          assert.equal(response.statusCode, 403) // TODO: SHOULD THIS RETURN A 409?
          done()
        })
      })
      it('should not allow creation of new files', function (done) {
        const options = createOptions('/acl-tls/write-acl/empty-acl/test-file', 'user1')
        options.body = ''
        request.put(options, function (error, response, body) {
          assert.equal(error, null)
          assert.equal(response.statusCode, 403)
          done()
        })
      })
      it('should not allow creation of new files in deeper paths', function (done) {
        const options = createOptions('/acl-tls/write-acl/empty-acl/test-folder/test-file', 'user1')
        options.body = ''
        request.put(options, function (error, response, body) {
          assert.equal(error, null)
          assert.equal(response.statusCode, 403)
          done()
        })
      })
      it('Should not create empty acl file', function (done) {
        const options = createOptions('/acl-tls/write-acl/empty-acl/another-empty-folder/test-file.acl', 'user1')
        options.headers = {
          'content-type': 'text/turtle'
        }
        options.body = ''
        request.put(options, function (error, response, body) {
          assert.equal(error, null)
          assert.equal(response.statusCode, 403)
          done()
        })
      })
      it('should not return text/turtle for the acl file', function (done) {
        const options = createOptions('/acl-tls/write-acl/.acl', 'user1')
        options.headers = {
          accept: 'text/turtle'
        }
        request.get(options, function (error, response, body) {
          assert.equal(error, null)
          assert.equal(response.statusCode, 403)
          // assert.match(response.headers['content-type'], /text\/turtle/)
          done()
        })
      })
      it('should create test file', function (done) {
        const options = createOptions('/acl-tls/write-acl/test-file', 'user1')
        options.headers = {
          'content-type': 'text/turtle'
        }
        options.body = '<a> <b> <c> .'
        request.put(options, function (error, response, body) {
          assert.equal(error, null)
          assert.equal(response.statusCode, 201)
          done()
        })
      })
      it("should create test file's acl file", function (done) {
        const options = createOptions('/acl-tls/write-acl/test-file.acl', 'user1')
        options.headers = {
          'content-type': 'text/turtle'
        }
        options.body = ''
        request.put(options, function (error, response, body) {
          assert.equal(error, null)
          assert.equal(response.statusCode, 201)
          done()
        })
      })
      it("should not access test file's acl file", function (done) {
        const options = createOptions('/acl-tls/write-acl/test-file.acl', 'user1')
        options.headers = {
          accept: 'text/turtle'
        }
        request.get(options, function (error, response, body) {
          assert.equal(error, null)
          assert.equal(response.statusCode, 403)
          // assert.match(response.headers['content-type'], /text\/turtle/)
          done()
        })
      })

      after(function () {
        rm('/acl-tls/write-acl/empty-acl/another-empty-folder/test-file.acl')
        rm('/acl-tls/write-acl/empty-acl/test-folder/test-file')
        rm('/acl-tls/write-acl/empty-acl/test-file')
        rm('/acl-tls/write-acl/test-file')
        rm('/acl-tls/write-acl/test-file.acl')
      })
    })
  })

  describe('Origin', function () {
    before(function () {
      rm('acl-tls/origin/test-folder/.acl')
    })

    it('should PUT new ACL file', function (done) {
      const options = createOptions('/acl-tls/origin/test-folder/.acl', 'user1', 'text/turtle')
      options.headers = {
        'content-type': 'text/turtle'
      }
      options.body = '<#Owner> a <http://www.w3.org/ns/auth/acl#Authorization>;\n' +
        ' <http://www.w3.org/ns/auth/acl#accessTo> <https://localhost:3456/test/acl-tls/origin/test-folder/>;\n' +
        ' <http://www.w3.org/ns/auth/acl#agent> <' + user1 + '>;\n' +
        ' <http://www.w3.org/ns/auth/acl#origin> <' + origin1 + '>;\n' +
        ' <http://www.w3.org/ns/auth/acl#mode> <http://www.w3.org/ns/auth/acl#Read>, <http://www.w3.org/ns/auth/acl#Write>, <http://www.w3.org/ns/auth/acl#Control> .\n' +
        '<#Public> a <http://www.w3.org/ns/auth/acl#Authorization>;\n' +
        ' <http://www.w3.org/ns/auth/acl#accessTo> <./>;\n' +
        ' <http://www.w3.org/ns/auth/acl#agentClass> <http://www.w3.org/ns/auth/acl#AuthenticatedAgent>;\n' +
        ' <http://www.w3.org/ns/auth/acl#origin> <' + origin1 + '>;\n' +
        ' <http://www.w3.org/ns/auth/acl#mode> <http://www.w3.org/ns/auth/acl#Read> .\n'
      request.put(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 201)
        done()
        // TODO triple header
        // TODO user header
      })
    })
    it('user1 should be able to access test directory', function (done) {
      const options = createOptions('/acl-tls/origin/test-folder/', 'user1')
      options.headers.origin = origin1

      request.head(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 200)
        done()
      })
    })
    it('user1 should be able to access to test directory when origin is valid',
      function (done) {
        const options = createOptions('/acl-tls/origin/test-folder/', 'user1')
        options.headers.origin = origin1

        request.head(options, function (error, response, body) {
          assert.equal(error, null)
          assert.equal(response.statusCode, 200)
          done()
        })
      })
    it('user1 should not be able to access test directory when origin is invalid',
      function (done) {
        const options = createOptions('/acl-tls/origin/test-folder/', 'user1')
        options.headers.origin = origin2

        request.head(options, function (error, response, body) {
          assert.equal(error, null)
          assert.equal(response.statusCode, 403)
          done()
        })
      })
    it('agent not should be able to access test directory', function (done) {
      const options = createOptions('/acl-tls/origin/test-folder/')
      options.headers.origin = origin1

      request.head(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 401)
        done()
      })
    })
    it('agent should be able to access to test directory when origin is valid',
      function (done) {
        const options = createOptions('/acl-tls/origin/test-folder/', 'user1')
        options.headers.origin = origin1

        request.head(options, function (error, response, body) {
          assert.equal(error, null)
          assert.equal(response.statusCode, 200)
          done()
        })
      })
    it('agent should not be able to access test directory when origin is invalid',
      function (done) {
        const options = createOptions('/acl-tls/origin/test-folder/')
        options.headers.origin = origin2

        request.head(options, function (error, response, body) {
          assert.equal(error, null)
          assert.equal(response.statusCode, 401)
          done()
        })
      })

    after(function () {
      rm('acl-tls/origin/test-folder/.acl')
    })
  })

  describe('Mixed statement Origin', function () {
    before(function () {
      rm('acl-tls/origin/test-folder/.acl')
    })

    it('should PUT new ACL file', function (done) {
      const options = createOptions('/acl-tls/origin/test-folder/.acl', 'user1', 'text/turtle')
      options.headers = {
        'content-type': 'text/turtle'
      }
      options.body = '<#Owner1> a <http://www.w3.org/ns/auth/acl#Authorization>;\n' +
        ' <http://www.w3.org/ns/auth/acl#accessTo> <https://localhost:3456/test/acl-tls/origin/test-folder/>;\n' +
        ' <http://www.w3.org/ns/auth/acl#agent> <' + user1 + '>;\n' +
        ' <http://www.w3.org/ns/auth/acl#mode> <http://www.w3.org/ns/auth/acl#Read>, <http://www.w3.org/ns/auth/acl#Write>, <http://www.w3.org/ns/auth/acl#Control> .\n' +
        '<#Owner2> a <http://www.w3.org/ns/auth/acl#Authorization>;\n' +
          ' <http://www.w3.org/ns/auth/acl#accessTo> <https://localhost:3456/test/acl-tls/origin/test-folder/>;\n' +
          ' <http://www.w3.org/ns/auth/acl#origin> <' + origin1 + '>;\n' +
          ' <http://www.w3.org/ns/auth/acl#mode> <http://www.w3.org/ns/auth/acl#Read>, <http://www.w3.org/ns/auth/acl#Write>, <http://www.w3.org/ns/auth/acl#Control> .\n' +
        '<#Public> a <http://www.w3.org/ns/auth/acl#Authorization>;\n' +
        ' <http://www.w3.org/ns/auth/acl#accessTo> <./>;\n' +
        ' <http://www.w3.org/ns/auth/acl#agentClass> <http://www.w3.org/ns/auth/acl#AuthenticatedAgent>;\n' +
        ' <http://www.w3.org/ns/auth/acl#origin> <' + origin1 + '>;\n' +
        ' <http://www.w3.org/ns/auth/acl#mode> <http://www.w3.org/ns/auth/acl#Read> .\n'
      request.put(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 201)
        done()
        // TODO triple header
        // TODO user header
      })
    })
    it('user1 should be able to access test directory', function (done) {
      const options = createOptions('/acl-tls/origin/test-folder/', 'user1')
      options.headers.origin = origin1

      request.head(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 200)
        done()
      })
    })
    it('user1 should be able to access to test directory when origin is valid',
      function (done) {
        const options = createOptions('/acl-tls/origin/test-folder/', 'user1')
        options.headers.origin = origin1

        request.head(options, function (error, response, body) {
          assert.equal(error, null)
          assert.equal(response.statusCode, 200)
          done()
        })
      })
    it('user1 should not be able to access test directory when origin is invalid',
      function (done) {
        const options = createOptions('/acl-tls/origin/test-folder/', 'user1')
        options.headers.origin = origin2

        request.head(options, function (error, response, body) {
          assert.equal(error, null)
          assert.equal(response.statusCode, 403)
          done()
        })
      })
    it('agent should not be able to access test directory for logged in users', function (done) {
      const options = createOptions('/acl-tls/origin/test-folder/')
      options.headers.origin = origin1

      request.head(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 401)
        done()
      })
    })
    it('agent should be able to access to test directory when origin is valid',
      function (done) {
        const options = createOptions('/acl-tls/origin/test-folder/', 'user1')
        options.headers.origin = origin1

        request.head(options, function (error, response, body) {
          assert.equal(error, null)
          assert.equal(response.statusCode, 200)
          done()
        })
      })
    it('agent should not be able to access test directory when origin is invalid',
      function (done) {
        const options = createOptions('/acl-tls/origin/test-folder/')
        options.headers.origin = origin2

        request.head(options, function (error, response, body) {
          assert.equal(error, null)
          assert.equal(response.statusCode, 401)
          done()
        })
      })

    after(function () {
      rm('acl-tls/origin/test-folder/.acl')
    })
  })

  describe('Read-only', function () {
    const body = fs.readFileSync(path.join(__dirname, '../resources/acl-tls/tim.localhost/read-acl/.acl'))
    it('user1 should be able to access ACL file', function (done) {
      const options = createOptions('/acl-tls/read-acl/.acl', 'user1')
      request.head(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 200)
        done()
      })
    })
    it('user1 should be able to access test directory', function (done) {
      const options = createOptions('/acl-tls/read-acl/', 'user1')
      request.head(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 200)
        done()
      })
    })
    it('user1 should be able to modify ACL file', function (done) {
      const options = createOptions('/acl-tls/read-acl/.acl', 'user1')
      options.headers = {
        'content-type': 'text/turtle'
      }
      options.body = body
      request.put(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 201)
        done()
      })
    })
    it('user2 should be able to access test directory', function (done) {
      const options = createOptions('/acl-tls/read-acl/', 'user2')
      request.head(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 200)
        done()
      })
    })
    it('user2 should not be able to access ACL file', function (done) {
      const options = createOptions('/acl-tls/read-acl/.acl', 'user2')
      request.head(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 403)
        done()
      })
    })
    it('user2 should not be able to modify ACL file', function (done) {
      const options = createOptions('/acl-tls/read-acl/.acl', 'user2')
      options.headers = {
        'content-type': 'text/turtle'
      }
      options.body = '<d> <e> <f> .'
      request.put(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 403)
        done()
      })
    })
    it('agent should be able to access test direcotory', function (done) {
      const options = createOptions('/acl-tls/read-acl/')
      request.head(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 200)
        done()
      })
    })
    it('agent should not be able to modify ACL file', function (done) {
      const options = createOptions('/acl-tls/read-acl/.acl')
      options.headers = {
        'content-type': 'text/turtle'
      }
      options.body = '<d> <e> <f> .'
      request.put(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 401)
        done()
      })
    })
  })

  describe.skip('Glob', function () {
    it('user2 should be able to send glob request', function (done) {
      const options = createOptions(globFile, 'user2')
      request.get(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 200)
        const globGraph = $rdf.graph()
        $rdf.parse(body, globGraph, address + testDir + '/', 'text/turtle')
        const authz = globGraph.the(undefined, undefined, ns.acl('Authorization'))
        assert.equal(authz, null)
        done()
      })
    })
    it('user1 should be able to send glob request', function (done) {
      const options = createOptions(globFile, 'user1')
      request.get(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 200)
        const globGraph = $rdf.graph()
        $rdf.parse(body, globGraph, address + testDir + '/', 'text/turtle')
        const authz = globGraph.the(undefined, undefined, ns.acl('Authorization'))
        assert.equal(authz, null)
        done()
      })
    })
    it('user1 should be able to delete ACL file', function (done) {
      const options = createOptions(testDirAclFile, 'user1')
      request.del(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 200)
        done()
      })
    })
  })

  describe('Append-only', function () {
    // var body = fs.readFileSync(__dirname + '/resources/acl-tls/append-acl/abc.ttl.acl')
    it("user1 should be able to access test file's ACL file", function (done) {
      const options = createOptions('/acl-tls/append-acl/abc.ttl.acl', 'user1')
      request.head(options, function (error, response) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 200)
        done()
      })
    })
    it.skip('user1 should be able to PATCH a resource', function (done) {
      const options = createOptions('/acl-tls/append-inherited/test.ttl', 'user1')
      options.headers = {
        'content-type': 'application/sparql-update'
      }
      options.body = 'INSERT DATA { :test  :hello 456 .}'
      request.patch(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 200)
        done()
      })
    })
    it('user1 should be able to access test file', function (done) {
      const options = createOptions('/acl-tls/append-acl/abc.ttl', 'user1')
      request.head(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 200)
        done()
      })
    })
    // TODO POST instead of PUT
    it('user1 should be able to modify test file', function (done) {
      const options = createOptions('/acl-tls/append-acl/abc.ttl', 'user1')
      options.headers = {
        'content-type': 'text/turtle'
      }
      options.body = '<a> <b> <c> .\n'
      request.put(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 201)
        done()
      })
    })
    it("user2 should not be able to access test file's ACL file", function (done) {
      const options = createOptions('/acl-tls/append-acl/abc.ttl.acl', 'user2')
      request.head(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 403)
        done()
      })
    })
    it('user2 should not be able to access test file', function (done) {
      const options = createOptions('/acl-tls/append-acl/abc.ttl', 'user2')
      request.head(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 403)
        done()
      })
    })
    it('user2 (with append permission) cannot use PUT to append', function (done) {
      const options = createOptions('/acl-tls/append-acl/abc.ttl', 'user2')
      options.headers = {
        'content-type': 'text/turtle'
      }
      options.body = '<d> <e> <f> .\n'
      request.put(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 403)
        done()
      })
    })
    it('agent should not be able to access test file', function (done) {
      const options = createOptions('/acl-tls/append-acl/abc.ttl')
      request.head(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 401)
        done()
      })
    })
    it('agent (with append permissions) should not PUT', function (done) {
      const options = createOptions('/acl-tls/append-acl/abc.ttl')
      options.headers = {
        'content-type': 'text/turtle'
      }
      options.body = '<g> <h> <i> .\n'
      request.put(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 401)
        done()
      })
    })
    after(function () {
      rm('acl-tls/append-inherited/test.ttl')
    })
  })

  describe('Restricted', function () {
    const body = '<#Owner> a <http://www.w3.org/ns/auth/acl#Authorization>;\n' +
      ' <http://www.w3.org/ns/auth/acl#accessTo> <./abc2.ttl>;\n' +
      ' <http://www.w3.org/ns/auth/acl#agent> <' + user1 + '>;\n' +
      ' <http://www.w3.org/ns/auth/acl#mode> <http://www.w3.org/ns/auth/acl#Read>, <http://www.w3.org/ns/auth/acl#Write>, <http://www.w3.org/ns/auth/acl#Control> .\n' +
      '<#Restricted> a <http://www.w3.org/ns/auth/acl#Authorization>;\n' +
      ' <http://www.w3.org/ns/auth/acl#accessTo> <./abc2.ttl>;\n' +
      ' <http://www.w3.org/ns/auth/acl#agent> <' + user2 + '>;\n' +
      ' <http://www.w3.org/ns/auth/acl#mode> <http://www.w3.org/ns/auth/acl#Read>, <http://www.w3.org/ns/auth/acl#Write>.\n'
    it("user1 should be able to modify test file's ACL file", function (done) {
      const options = createOptions('/acl-tls/append-acl/abc2.ttl.acl', 'user1')
      options.headers = {
        'content-type': 'text/turtle'
      }
      options.body = body
      request.put(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 201)
        done()
      })
    })
    it("user1 should be able to access test file's ACL file", function (done) {
      const options = createOptions('/acl-tls/append-acl/abc2.ttl.acl', 'user1')
      request.head(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 200)
        done()
      })
    })
    it('user1 should be able to access test file', function (done) {
      const options = createOptions('/acl-tls/append-acl/abc2.ttl', 'user1')
      request.head(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 200)
        done()
      })
    })
    it('user1 should be able to modify test file', function (done) {
      const options = createOptions('/acl-tls/append-acl/abc2.ttl', 'user1')
      options.headers = {
        'content-type': 'text/turtle'
      }
      options.body = '<a> <b> <c> .\n'
      request.put(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 201)
        done()
      })
    })
    it('user2 should be able to access test file', function (done) {
      const options = createOptions('/acl-tls/append-acl/abc2.ttl', 'user2')
      request.head(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 200)
        done()
      })
    })
    it("user2 should not be able to access test file's ACL file", function (done) {
      const options = createOptions('/acl-tls/append-acl/abc2.ttl.acl', 'user2')
      request.head(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 403)
        done()
      })
    })
    it('user2 should be able to modify test file', function (done) {
      const options = createOptions('/acl-tls/append-acl/abc2.ttl', 'user2')
      options.headers = {
        'content-type': 'text/turtle'
      }
      options.body = '<d> <e> <f> .\n'
      request.put(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 201)
        done()
      })
    })
    it('agent should not be able to access test file', function (done) {
      const options = createOptions('/acl-tls/append-acl/abc2.ttl')
      request.head(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 401)
        done()
      })
    })
    it('agent should not be able to modify test file', function (done) {
      const options = createOptions('/acl-tls/append-acl/abc2.ttl')
      options.headers = {
        'content-type': 'text/turtle'
      }
      options.body = '<d> <e> <f> .\n'
      request.put(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 401)
        done()
      })
    })
  })

  describe('default', function () {
    before(function () {
      rm('/acl-tls/write-acl/default-for-new/.acl')
      rm('/acl-tls/write-acl/default-for-new/test-file.ttl')
    })

    const body = '<#Owner> a <http://www.w3.org/ns/auth/acl#Authorization>;\n' +
      ' <http://www.w3.org/ns/auth/acl#accessTo> <./>;\n' +
      ' <http://www.w3.org/ns/auth/acl#agent> <' + user1 + '>;\n' +
      ' <http://www.w3.org/ns/auth/acl#default> <./>;\n' +
      ' <http://www.w3.org/ns/auth/acl#mode> <http://www.w3.org/ns/auth/acl#Read>, <http://www.w3.org/ns/auth/acl#Write>, <http://www.w3.org/ns/auth/acl#Control> .\n' +
      '<#Default> a <http://www.w3.org/ns/auth/acl#Authorization>;\n' +
      ' <http://www.w3.org/ns/auth/acl#accessTo> <./>;\n' +
      ' <http://www.w3.org/ns/auth/acl#default> <./>;\n' +
      ' <http://www.w3.org/ns/auth/acl#agentClass> <http://xmlns.com/foaf/0.1/Agent>;\n' +
      ' <http://www.w3.org/ns/auth/acl#mode> <http://www.w3.org/ns/auth/acl#Read> .\n'
    it("user1 should be able to modify test directory's ACL file", function (done) {
      const options = createOptions('/acl-tls/write-acl/default-for-new/.acl', 'user1')
      options.headers = {
        'content-type': 'text/turtle'
      }
      options.body = body
      request.put(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 201)
        done()
      })
    })
    it("user1 should be able to access test direcotory's ACL file", function (done) {
      const options = createOptions('/acl-tls/write-acl/default-for-new/.acl', 'user1')
      request.head(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 200)
        done()
      })
    })
    it('user1 should be able to create new test file', function (done) {
      const options = createOptions('/acl-tls/write-acl/default-for-new/test-file.ttl', 'user1')
      options.headers = {
        'content-type': 'text/turtle'
      }
      options.body = '<a> <b> <c> .\n'
      request.put(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 201)
        done()
      })
    })
    it('user1 should be able to access new test file', function (done) {
      const options = createOptions('/acl-tls/write-acl/default-for-new/test-file.ttl', 'user1')
      request.head(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 200)
        done()
      })
    })
    it("user2 should not be able to access test direcotory's ACL file", function (done) {
      const options = createOptions('/acl-tls/write-acl/default-for-new/.acl', 'user2')
      request.head(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 403)
        done()
      })
    })
    it('user2 should be able to access new test file', function (done) {
      const options = createOptions('/acl-tls/write-acl/default-for-new/test-file.ttl', 'user2')
      request.head(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 200)
        done()
      })
    })
    it('user2 should not be able to modify new test file', function (done) {
      const options = createOptions('/acl-tls/write-acl/default-for-new/test-file.ttl', 'user2')
      options.headers = {
        'content-type': 'text/turtle'
      }
      options.body = '<d> <e> <f> .\n'
      request.put(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 403)
        done()
      })
    })
    it('agent should be able to access new test file', function (done) {
      const options = createOptions('/acl-tls/write-acl/default-for-new/test-file.ttl')
      request.head(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 200)
        done()
      })
    })
    it('agent should not be able to modify new test file', function (done) {
      const options = createOptions('/acl-tls/write-acl/default-for-new/test-file.ttl')
      options.headers = {
        'content-type': 'text/turtle'
      }
      options.body = '<d> <e> <f> .\n'
      request.put(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 401)
        done()
      })
    })

    after(function () {
      rm('/acl-tls/write-acl/default-for-new/.acl')
      rm('/acl-tls/write-acl/default-for-new/test-file.ttl')
    })
  })

  describe('WebID delegation tests', function () {
    it('user1 should be able delegate to user2', function (done) {
      // var body = '<' + user1 + '> <http://www.w3.org/ns/auth/acl#delegates> <' + user2 + '> .'
      const options = {
        url: user1,
        headers: {
          'content-type': 'text/turtle'
        },
        agentOptions: {
          key: userCredentials.user1.key,
          cert: userCredentials.user1.cert
        }
      }
      request.post(options, function (error, response, body) {
        assert.equal(error, null)
        assert.equal(response.statusCode, 200)
        done()
      })
    })
    // it("user2 should be able to make requests on behalf of user1", function(done) {
    // var options = createOptions(abcdFile, 'user2')
    // options.headers = {
    // 'content-type': 'text/turtle',
    // 'On-Behalf-Of': '<' + user1 + '>'
    // }
    // options.body = "<d> <e> <f> ."
    // request.post(options, function(error, response, body) {
    // assert.equal(error, null)
    // assert.equal(response.statusCode, 200)
    // done()
    // })
    // })
  })

  describe.skip('Cleanup', function () {
    it('should remove all files and dirs created', function (done) {
      try {
        // must remove the ACLs in sync
        fs.unlinkSync(path.join(__dirname, '../resources/' + testDir + '/dir1/dir2/abcd.ttl'))
        fs.rmdirSync(path.join(__dirname, '../resources/' + testDir + '/dir1/dir2/'))
        fs.rmdirSync(path.join(__dirname, '../resources/' + testDir + '/dir1/'))
        fs.unlinkSync(path.join(__dirname, '../resources/' + abcFile))
        fs.unlinkSync(path.join(__dirname, '../resources/' + testDirAclFile))
        fs.unlinkSync(path.join(__dirname, '../resources/' + testDirMetaFile))
        fs.rmdirSync(path.join(__dirname, '../resources/' + testDir))
        fs.rmdirSync(path.join(__dirname, '../resources/acl-tls/'))
        done()
      } catch (e) {
        done(e)
      }
    })
  })
})
