Repository: Azure/azure-data-lake-store-python

Issue:
PRI 0: Use the Offset parameter in append to ensure we are always appending at the offset we expect
The append API allows for a query parameter called offset, which allows you to specify where you think the end of the file is to append data to. This is very useful for us, since it allows us to submit an append call where we "think" the file should currently be. If data has already been uploaded at that location, you will receive a 400 error with a BadOffsetException, which you can catch. This will indicate that data is already at that location and we can move on to the next 4mb chunk to upload. This will help preserve the uploaded file and ensure that its final length is the same as the source file.

Here is a sample request/response where the offset is not the end of the file (meaning there is already data at or ahead of the offset specified):

**Request:** 
POST https://adlspysample01.azuredatalakestore.net/webhdfs/v1/sample.txt?op=APPEND&append=true&**offset=4**&api-version=2015-10-01-preview HTTP/1.1
x-ms-client-request-id: 33401497-4ac0-451e-ab13-eccd305e3706
accept-language: en-US
Authorization:
User-Agent: Microsoft.Azure.Management.DataLake.Store.DataLakeStoreFileSystemManagementClient/0.12.6-preview AzurePowershell/v2.1.0.0
CommandName: Add-AzureRmDataLakeStoreItemContent
ParameterSetName: __AllParameterSets
Content-Type: application/octet-stream
Host: adlspysample01.azuredatalakestore.net
Content-Length: 4
Expect: 100-continue

test

**Response**
HTTP/1.1 400 Bad Request
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 260
Content-Type: application/json; charset=utf-8
Expires: -1
x-ms-request-id: a8b65992-21f3-4c5d-8fe0-f0b49d0320f1
Server-Perf: [a8b65992-21f3-4c5d-8fe0-f0b49d0320f1][ AuthTime::0::PostAuthTime::0 ][S-FsOpenStream :: 00:00:010 ms]%0a[BufferingTime :: 00:00:000 ms]%0a[WriteTime :: 00:00:000 ms]%0a[S-FsAppendStream :: 00:00:036 ms]%0a[S-FsCloseHandle :: 00:00:001 ms]%0a[APPEND :: 00:00:269 ms]%0a
x-ms-webhdfs-version: 16.07.18.01
Status: 0x83090015
X-Content-Type-Options: nosniff
Strict-Transport-Security: max-age=15724800; includeSubDomains
Date: Thu, 15 Sep 2016 01:21:15 GMT

**{"RemoteException":{"exception":"BadOffsetException","message":"FsAppendStream failed with error 0x83090015 (Bad offset). [a8b65992-21f3-4c5d-8fe0-f0b49d0320f1][2016-09-14T18:21:16.0457431-07:00]","javaClassName":"org.apache.hadoop.fs.adl.BadOffsetException"}}**

Discussion:
jbcrail: All benchmarks completed without errors:
```
[bench_upload_1_100gb] starting...
[bench_upload_1_100gb] finished in 612.4005s
[bench_download_1_100gb] starting...
[bench_download_1_100gb] finished in 1234.5771s
[bench_upload_100_1gb] starting...
[bench_upload_100_1gb] finished in 762.1828s
[bench_download_100_1gb] starting...
[bench_download_100_1gb] finished in 1207.7382s
```
jbcrail: Updated benchmark results:
```
[bench_upload_1_50gb] starting...
local file      : D:\ingress\50gbfile.txt
local file size : 52425000000
remote file     : joseph/50gbfile.txt
remote file size: 52425000000
[bench_upload_1_50gb] finished in 263.0346s

[bench_download_1_50gb] starting...
local file      : D:\ingress\50gbfile.txt.out
local file size : 52425000000
remote file     : joseph/50gbfile.txt
remote file size: 52425000000
[bench_download_1_50gb] finished in 397.7892s

>>> md5sum('D:\\ingress\\50gbfile.txt')
'60f5fba5f5eb30ab75f84214e184acae'
>>> md5sum('D:\\ingress\\50gbfile.txt.out')
'6c37bf52d23560df955d36b6d32b822a'
```
jbcrail: Updated benchmark results:
```
md5sum('D:\ingress\50gbfile.txt') = 60f5fba5f5eb30ab75f84214e184acae
[bench_upload_1_50gb] starting...
local file      : D:\ingress\50gbfile.txt
local file size : 52425000000
remote file     : joseph/50gbfile.txt
remote file size: 52425000000
[bench_upload_1_50gb] finished in 281.7676s
[bench_download_1_50gb] starting...
local file      : D:\ingress\50gbfile.txt.out
local file size : 52425000000
remote file     : joseph/50gbfile.txt
remote file size: 52425000000
[bench_download_1_50gb] finished in 466.3828s
md5sum('D:\ingress\50gbfile.txt.out') = 60f5fba5f5eb30ab75f84214e184acae
```
begoldsm: Thank you for the updated benchmark test @jbcrail!

Patch:
diff --git a/adlfs/cli.py b/adlfs/cli.py
index 0c6c2ca..f8d2a1f 100644
--- a/adlfs/cli.py
+++ b/adlfs/cli.py
@@ -179,7 +179,7 @@ class AzureDataLakeFSCommand(cmd.Cmd, object):
         parser = argparse.ArgumentParser(prog="get", add_help=False)
         parser.add_argument('remote_path', type=str)
         parser.add_argument('local_path', type=str, nargs='?', default='.')
-        parser.add_argument('-b', '--chunksize', type=int, default=2**22)
+        parser.add_argument('-b', '--chunksize', type=int, default=2**28)
         parser.add_argument('-c', '--threads', type=int, default=None)
         args = parser.parse_args(line.split())
 
@@ -303,7 +303,7 @@ class AzureDataLakeFSCommand(cmd.Cmd, object):
         parser = argparse.ArgumentParser(prog="put", add_help=False)
         parser.add_argument('local_path', type=str)
         parser.add_argument('remote_path', type=str, nargs='?', default='.')
-        parser.add_argument('-b', '--chunksize', type=int, default=2**22)
+        parser.add_argument('-b', '--chunksize', type=int, default=2**28)
         parser.add_argument('-c', '--threads', type=int, default=None)
         args = parser.parse_args(line.split())
 
diff --git a/adlfs/core.py b/adlfs/core.py
index b36944c..a803176 100644
--- a/adlfs/core.py
+++ b/adlfs/core.py
@@ -24,7 +24,7 @@ import time
 
 # local imports
 from .lib import DatalakeRESTInterface, auth, refresh_token
-from .utils import FileNotFoundError, PY2, ensure_writable, read_block
+from .utils import FileNotFoundError, PermissionError, PY2, ensure_writable, read_block
 
 if sys.version_info >= (3, 4):
     import pathlib
@@ -619,10 +619,12 @@ class AzureDLFile(object):
         if self.mode in {'wb', 'ab'} and not self.closed:
             if self.buffer.tell() == 0:
                 if force and self.first_write:
-                    self.azure.azure.call('CREATE',
-                                          path=self.path.as_posix(),
-                                          overwrite='true',
-                                          write='true')
+                    _put_data(self.azure.azure,
+                              'CREATE',
+                              path=self.path.as_posix(),
+                              data=None,
+                              overwrite='true',
+                              write='true')
                     self.first_write = False
                 return
             self.buffer.seek(0)
@@ -636,37 +638,44 @@ class AzureDLFile(object):
                     else:
                         limit = place + len(self.delimiter)
                     if self.first_write:
-                        out = self.azure.azure.call('CREATE',
-                                                    path=self.path.as_posix(),
-                                                    data=data[:limit],
-                                                    overwrite='true',
-                                                    write='true')
+                        out = _put_data(self.azure.azure,
+                                        'CREATE',
+                                        path=self.path.as_posix(),
+                                        data=data[:limit],
+                                        overwrite='true',
+                                        write='true')
                         self.first_write = False
                     else:
-                        out = self.azure.azure.call('APPEND',
-                                                    path=self.path.as_posix(),
-                                                    data=data[:limit],
-                                                    append='true')
+                        out = _put_data(self.azure.azure,
+                                        'APPEND',
+                                        path=self.path.as_posix(),
+                                        data=data[:limit],
+                                        append='true')
                     logger.debug('Wrote %d bytes to %s' % (limit, self))
                     data = data[limit:]
                 self.buffer = io.BytesIO(data)
                 self.buffer.seek(0, 2)
             if not self.delimiter or force:
+                zero_offset = self.tell() - len(data)
                 offsets = range(0, len(data), self.blocksize)
                 for o in offsets:
+                    offset = zero_offset + o
                     d2 = data[o:o+self.blocksize]
                     if self.first_write:
-                        out = self.azure.azure.call('CREATE',
-                                                    path=self.path.as_posix(),
-                                                    data=d2,
-                                                    overwrite='true',
-                                                    write='true')
+                        out = _put_data(self.azure.azure,
+                                        'CREATE',
+                                        path=self.path.as_posix(),
+                                        data=d2,
+                                        overwrite='true',
+                                        write='true')
                         self.first_write = False
                     else:
-                        out = self.azure.azure.call('APPEND',
-                                                    path=self.path.as_posix(),
-                                                    data=d2,
-                                                    append='true')
+                        out = _put_data(self.azure.azure,
+                                        'APPEND',
+                                        path=self.path.as_posix(),
+                                        data=d2,
+                                        offset=offset,
+                                        append='true')
                     logger.debug('Wrote %d bytes to %s' % (len(d2), self))
                 self.buffer = io.BytesIO()
             return out
@@ -725,6 +734,20 @@ def _fetch_range(rest, path, start, end, max_attempts=10):
     raise RuntimeError("Max number of ADL retries exceeded")
 
 
+def _put_data(rest, op, path, data, max_attempts=10, **kwargs):
+    logger.debug("Put: %s %s, %s", op, path, kwargs)
+    for i in range(max_attempts):
+        try:
+            resp = rest.call(op, path=path, data=data, **kwargs)
+            return resp
+        except (PermissionError, FileNotFoundError):
+            raise
+        except Exception as e:
+            logger.debug('Exception %s on ADL upload, retrying', e,
+                         exc_info=True)
+    raise RuntimeError("Max number of ADL retries exceeded")
+
+
 class AzureDLPath(type(pathlib.PurePath())):
     """
     Subclass of native object-oriented filesystem path.
diff --git a/adlfs/lib.py b/adlfs/lib.py
index fac6e4f..862a42f 100644
--- a/adlfs/lib.py
+++ b/adlfs/lib.py
@@ -25,6 +25,8 @@ import time
 import adal
 import azure
 
+from .utils import FileNotFoundError, PermissionError
+
 client_id = "1950a258-227b-4e31-a9cf-717495945fc2"
 
 logger = logging.getLogger(__name__)
@@ -181,7 +183,7 @@ class DatalakeRESTInterface:
 
     ends = {
         # OP: (HTTP method, required fields, allowed fields)
-        'APPEND': ('post', set(), {'append'}),
+        'APPEND': ('post', set(), {'append', 'offset'}),
         'CHECKACCESS': ('get', set(), {'fsaction'}),
         'CONCAT': ('post', {'sources'}, {'sources'}),
         'MSCONCAT': ('post', set(), {'deleteSourceDirectory'}),
@@ -246,7 +248,11 @@ class DatalakeRESTInterface:
             r = func(url, params=params, headers=self.head, data=data)
         except requests.exceptions.RequestException as e:
             raise DatalakeRESTException('HTTP error: %s', str(e))
-        if r.status_code >= 400:
+        if r.status_code == 403:
+            raise PermissionError(path)
+        elif r.status_code == 404:
+            raise FileNotFoundError(path)
+        elif r.status_code >= 400:
             raise DatalakeRESTException("Data-lake REST exception: %s, %s, %s" %
                                         (op, r.status_code, r.content.decode()))
         if r.content:
diff --git a/adlfs/multithread.py b/adlfs/multithread.py
index aceb05e..7f6997a 100644
--- a/adlfs/multithread.py
+++ b/adlfs/multithread.py
@@ -135,7 +135,7 @@ class ADLDownloader(object):
             with open(dst, 'wb'):
                 pass
 
-        self.client.run(nthreads, monitor, before_scatter=touch)
+        self.client.run(nthreads, monitor, before_start=touch)
 
     @staticmethod
     def load():
@@ -160,6 +160,7 @@ def get_chunk(adlfs, src, dst, offset, size, blocksize, retries=MAXRETRIES,
 
     Internal function used by `download`.
     """
+    nbytes = 0
     with adlfs.open(src, 'rb') as fin:
         end = offset + size
         miniblock = min(size, blocksize)
@@ -168,21 +169,23 @@ def get_chunk(adlfs, src, dst, offset, size, blocksize, retries=MAXRETRIES,
             fin.seek(offset)
             for o in range(offset, end, miniblock):
                 if shutdown_event and shutdown_event.is_set():
-                    return
+                    return nbytes, None
                 tries = 0
                 while True:
                     try:
-                        fout.write(fin.read(miniblock))
+                        data = fin.read(miniblock)
+                        nbytes += fout.write(data)
                         break
                     except Exception as e:
                         # TODO : only some exceptions should be retriable
                         logger.debug('Download failed %s, byte offset %s; %s, %s', dst,
-                                    o, e, e.args)
+                                     o, e, e.args)
                         tries += 1
                         if tries >= retries:
                             logger.debug('Aborting %s, byte offset %s', dst, o)
-                            raise
+                            return nbytes, str(e)
     logger.debug('Downloaded to %s, byte offset %s', dst, offset)
+    return nbytes, None
 
 
 class ADLUploader(object):
@@ -306,17 +309,19 @@ def put_chunk(adlfs, src, dst, offset, size, blocksize, retries=MAXRETRIES,
 
     Internal function used by `upload`.
     """
+    nbytes = 0
     with adlfs.open(dst, 'wb', delimiter=delimiter) as fout:
         end = offset + size
         miniblock = min(size, blocksize)
         with open(src, 'rb') as fin:
             for o in range(offset, end, miniblock):
                 if shutdown_event and shutdown_event.is_set():
-                    return False
+                    return nbytes, None
                 tries = 0
                 while True:
                     try:
-                        fout.write(read_block(fin, o, miniblock, delimiter))
+                        data = read_block(fin, o, miniblock, delimiter)
+                        nbytes += fout.write(data)
                         break
                     except Exception as e:
                         # TODO : only some exceptions should be retriable
@@ -325,9 +330,9 @@ def put_chunk(adlfs, src, dst, offset, size, blocksize, retries=MAXRETRIES,
                         tries += 1
                         if tries >= retries:
                             logger.debug('Aborting %s, byte offset %s', src, o)
-                            raise
+                            return nbytes, str(e)
     logger.debug('Uploaded from %s, byte offset %s', src, offset)
-    return True
+    return nbytes, None
 
 
 def merge_chunks(adlfs, outfile, files, shutdown_event=None):
diff --git a/adlfs/transfer.py b/adlfs/transfer.py
index b1c938a..07f1aeb 100644
--- a/adlfs/transfer.py
+++ b/adlfs/transfer.py
@@ -102,8 +102,8 @@ class StateManager(object):
 
 
 # Named tuples used to serialize client progress
-File = namedtuple('File', 'src dst state nbytes start stop chunks')
-Chunk = namedtuple('Chunk', 'name state offset retries')
+File = namedtuple('File', 'src dst state length start stop chunks')
+Chunk = namedtuple('Chunk', 'name state offset retries expected actual exception')
 
 
 class ADLTransferClient(object):
@@ -157,8 +157,7 @@ class ADLTransferClient(object):
     When a merge step is available, the client will write chunks to temporary
     files before merging. The exact temporary file is dependent upon on two
     parameters (`tmp_path`, `tmp_unique`). Given those values, the full
-    temporary file can be accessed via the `temporary_path` property and looks
-    like this in pseudo-BNF:
+    temporary file looks like this in pseudo-BNF:
 
     >>> # /{tmp_path}[/{unique_str}]/{basename}_{offset}
 
@@ -175,7 +174,8 @@ class ADLTransferClient(object):
     and destination of the respective file transfer. `offset` is the location
     in `src` to read `size` bytes from. `blocksize` is the number of bytes in a
     chunk to write at one time. `retries` is the number of time an Azure query
-    will be tried.
+    will be tried. The callable should return an integer representing the
+    number of bytes written.
 
     The `merge` callable has the function signature,
     `fn(adlfs, outfile, files, delete_source, shutdown_event)`. `adlfs` is
@@ -187,13 +187,37 @@ class ADLTransferClient(object):
     The event will be set when a shutdown is requested. It is good practice
     to listen for this.
 
+    Internal State
+    --------------
+
+    self._fstates: StateManager
+        This captures the current state of each transferred file.
+    self._files: dict
+        Using a tuple of the file source/destination as the key, this
+        dictionary stores the file metadata and all chunk states. The
+        dictionary key is `(src, dst)` and the value is
+        `dict(length, start, stop, cstates)`.
+    self._chunks: dict
+        Using a tuple of the chunk name/offset as the key, this dictionary
+        stores the chunk metadata and has a reference to the chunk's parent
+        file. The dictionary key is `(name, offset)` and the value is
+        `dict(parent=(src, dst), retries, expected, actual, exception)`.
+    self._ffutures: dict
+        Using a Future object as the key, this dictionary provides a reverse
+        lookup for the file associated with the given future. The returned
+        value is the file's primary key, `(src, dst)`.
+    self._cfutures: dict
+        Using a Future object as the key, this dictionary provides a reverse
+        lookup for the chunk associated with the given future. The returned
+        value is the chunk's primary key, `(name, offset)`.
+
     See Also
     --------
     adlfs.multithread.ADLDownloader
     adlfs.multithread.ADLUploader
     """
 
-    DEFAULT_TMP_PATH = os.path.join(os.path.sep, 'tmp')
+    DEFAULT_TMP_PATH = 'tmp'
 
     def __init__(self, adlfs, name, transfer, merge=None, nthreads=None,
                  chunksize=2**28, blocksize=2**25, tmp_path=DEFAULT_TMP_PATH,
@@ -211,54 +235,74 @@ class ADLTransferClient(object):
         self._persist_path = persist_path
         self._pool = ThreadPoolExecutor(self._nthreads)
         self._shutdown_event = threading.Event()
+
+        # Internal state tracking files/chunks/futures
         self._files = {}
+        self._chunks = {}
+        self._ffutures = {}
+        self._cfutures = {}
         self._fstates = StateManager(
             'pending', 'transferring', 'merging', 'finished', 'cancelled',
             'errored')
 
-    def submit(self, src, dst, nbytes):
+    def submit(self, src, dst, length):
         """
-        All submitted files start in the `pending` state until `run()` is
-        called.
+        Split a given file into chunks.
+
+        All submitted files/chunks start in the `pending` state until `run()`
+        is called.
         """
-        self._fstates[(src, dst)] = 'pending'
-        self._files[(src, dst)] = dict(
-            nbytes=nbytes,
-            start=None,
-            stop=None,
-            chunks={},
-            cstates=StateManager('running', 'finished', 'cancelled', 'errored'),
-            merge=None)
+        cstates = StateManager(
+            'pending', 'running', 'finished', 'cancelled', 'errored')
 
-    def _submit(self, fn, *args, **kwargs):
-        kwargs['shutdown_event'] = self._shutdown_event
-        return self._pool.submit(fn, *args, **kwargs)
+        # Create unique temporary directory for each file
+        if self._tmp_unique and self._tmp_path:
+            tmpdir = os.path.join(self._tmp_path, uuid.uuid4().hex)
+        else:
+            tmpdir = self._tmp_path
 
-    def _scatter(self, src, dst, transfer):
-        """ Split a given file into chunks """
-        dic = self._files[(src, dst)]
-        self._fstates[(src, dst)] = 'transferring'
-        offsets = list(range(0, dic['nbytes'], self._chunksize))
+        offsets = list(range(0, length, self._chunksize))
         for offset in offsets:
             if self._tmp_path and len(offsets) > 1:
                 name = os.path.join(
-                    self.temporary_path,
+                    os.path.sep,
+                    tmpdir,
                     dst.name + '_' + str(offset))
             else:
                 name = dst
-            logger.debug("Submitted %s, byte offset %d", name, offset)
-            dic['cstates'][name] = 'running'
-            dic['chunks'][name] = dict(
-                future=self._submit(transfer, self._adlfs, src, name, offset,
-                                    self._chunksize, self._blocksize),
+            cstates[(name, offset)] = 'pending'
+            self._chunks[(name, offset)] = dict(
+                parent=(src, dst),
                 retries=self._chunkretries,
-                offset=offset)
+                expected=min(length - offset, self._chunksize),
+                actual=0,
+                exception=None)
+            logger.debug("Submitted %s, byte offset %d", name, offset)
 
-    @property
-    def temporary_path(self):
-        """ Return temporary path used to store chunks before merging """
-        subdir = uuid.uuid1().hex[:10] if self._tmp_unique else ''
-        return os.path.join(self._tmp_path, subdir)
+        self._fstates[(src, dst)] = 'pending'
+        self._files[(src, dst)] = dict(
+            length=length,
+            start=None,
+            stop=None,
+            cstates=cstates)
+
+    def _submit(self, fn, *args, **kwargs):
+        kwargs['shutdown_event'] = self._shutdown_event
+        future = self._pool.submit(fn, *args, **kwargs)
+        future.add_done_callback(self._update)
+        return future
+
+    def _start(self, src, dst):
+        key = (src, dst)
+        self._fstates[key] = 'transferring'
+        self._files[key]['start'] = time.time()
+        for obj in self._files[key]['cstates'].objects:
+            name, offset = obj
+            self._files[key]['cstates'][obj] = 'running'
+            future = self._submit(
+                self._transfer, self._adlfs, src, name, offset,
+                self._chunksize, self._blocksize)
+            self._cfutures[future] = obj
 
     @property
     def progress(self):
@@ -267,110 +311,110 @@ class ADLTransferClient(object):
         for key in self._files:
             src, dst = key
             chunks = []
-            for name in self._files[key]['chunks']:
+            for obj in self._files[key]['cstates'].objects:
+                name, offset = obj
                 chunks.append(Chunk(
                     name=name,
-                    state=self._files[key]['cstates'][name],
-                    offset=self._files[key]['chunks'][name]['offset'],
-                    retries=self._files[key]['chunks'][name]['retries']))
+                    offset=offset,
+                    state=self._files[key]['cstates'][obj],
+                    retries=self._chunks[obj]['retries'],
+                    expected=self._chunks[obj]['expected'],
+                    actual=self._chunks[obj]['actual'],
+                    exception=self._chunks[obj]['exception']))
             files.append(File(
                 src=src,
                 dst=dst,
                 state=self._fstates[key],
-                nbytes=self._files[key]['nbytes'],
+                length=self._files[key]['length'],
                 start=self._files[key]['start'],
                 stop=self._files[key]['stop'],
                 chunks=chunks))
         return files
 
-    def _status(self, src, dst, nbytes, start, stop):
-        elapsed = stop - start
-        rate = nbytes / elapsed / 1024 / 1024
+    def _status(self, src, dst):
+        dic = self._files[(src, dst)]
+        elapsed = dic['stop'] - dic['start']
+        rate = dic['length'] / elapsed / 1024 / 1024
         logger.info("Transferred %s -> %s in %f seconds at %f MB/s",
                     src, dst, elapsed, rate)
 
-    def _update(self):
-        for (src, dst), dic in self._files.items():
-            if self._fstates[(src, dst)] == 'transferring':
-                for name in list(dic['chunks']):
-                    future = dic['chunks'][name]['future']
-                    if not future.done():
-                        continue
-                    if future.cancelled():
-                        dic['cstates'][name] = 'cancelled'
-                    elif future.exception():
-                        dic['cstates'][name] = 'errored'
-                    else:
-                        dic['cstates'][name] = 'finished'
-                if dic['cstates'].contains_all('finished'):
-                    logger.debug("Chunks transferred")
-                    chunks = list(dic['chunks'])
-                    if self._merge and len(chunks) > 1:
-                        logger.debug("Merging file: %s", self._fstates[(src, dst)])
-                        self._fstates[(src, dst)] = 'merging'
-                        dic['merge'] = self._submit(self._merge, self._adlfs,
-                                                    dst, chunks)
-                    else:
-                        dic['stop'] = time.time()
-                        self._fstates[(src, dst)] = 'finished'
-                        self._status(src, dst, dic['nbytes'], dic['start'], dic['stop'])
-                elif dic['cstates'].contains_none('running'):
-                    logger.debug("Transfer failed: %s", dic['cstates'])
-                    self._fstates[(src, dst)] = 'errored'
+    def _update(self, future):
+        if future in self._cfutures:
+            obj = self._cfutures[future]
+            parent = self._chunks[obj]['parent']
+            cstates = self._files[parent]['cstates']
+
+            if future.cancelled():
+                cstates[obj] = 'cancelled'
+            elif future.exception():
+                cstates[obj] = 'errored'
+            else:
+                nbytes, exception = future.result()
+                self._chunks[obj]['actual'] = nbytes
+                self._chunks[obj]['exception'] = exception
+                if exception:
+                    cstates[obj] = 'errored'
+                elif self._chunks[obj]['expected'] != nbytes:
+                    cstates[obj] = 'errored'
                 else:
-                    logger.debug("Transferring chunks: %s", dic['cstates'])
-            elif self._fstates[(src, dst)] == 'merging':
-                future = dic['merge']
-                if not future.done():
-                    continue
-                if future.cancelled():
-                    self._fstates[(src, dst)] = 'cancelled'
-                elif future.exception():
-                    self._fstates[(src, dst)] = 'errored'
+                    cstates[obj] = 'finished'
+
+            if cstates.contains_all('finished'):
+                logger.debug("Chunks transferred")
+                src, dst = parent
+                if self._merge and len(cstates.objects) > 1:
+                    logger.debug("Merging file: %s", self._fstates[parent])
+                    self._fstates[parent] = 'merging'
+                    merge_future = self._submit(
+                        self._merge, self._adlfs, dst,
+                        [name for name, _ in sorted(cstates.objects,
+                                                    key=lambda obj: obj[1])])
+                    self._ffutures[merge_future] = parent
                 else:
-                    dic['stop'] = time.time()
-                    self._fstates[(src, dst)] = 'finished'
-                    self._status(src, dst, dic['nbytes'], dic['start'], dic['stop'])
+                    self._fstates[parent] = 'finished'
+                    self._files[parent]['stop'] = time.time()
+                    self._status(src, dst)
+            elif cstates.contains_none('running'):
+                logger.debug("Transfer failed: %s", cstates)
+                self._fstates[parent] = 'errored'
+        elif future in self._ffutures:
+            src, dst = self._ffutures[future]
+
+            if future.cancelled():
+                self._fstates[(src, dst)] = 'cancelled'
+            elif future.exception():
+                self._fstates[(src, dst)] = 'errored'
+            else:
+                result = future.result()
+                self._fstates[(src, dst)] = 'finished'
+                self._files[(src, dst)]['stop'] = time.time()
+                self._status(src, dst)
         self.save()
 
-    def run(self, nthreads=None, monitor=True, before_scatter=None):
+    def run(self, nthreads=None, monitor=True, before_start=None):
         self._nthreads = nthreads or self._nthreads
         for src, dst in self._files:
-            self._files[(src, dst)]['start'] = time.time()
-            self._fstates[(src, dst)] = 'transferring'
-            if before_scatter:
-                before_scatter(self._adlfs, src, dst)
-            self._scatter(src, dst, self._transfer)
+            if before_start:
+                before_start(self._adlfs, src, dst)
+            self._start(src, dst)
         if monitor:
             self.monitor()
 
-    def _cancel(self):
-        for dic in self._files.values():
-            for transfer in dic['chunks'].values():
-                transfer['future'].cancel()
-            if dic['merge']:
-                dic['merge'].cancel()
-
     def _wait(self, poll=0.1, timeout=0):
         start = time.time()
         while not self._fstates.contains_none('pending', 'transferring', 'merging'):
             if timeout > 0 and time.time() - start > timeout:
                 break
             time.sleep(poll)
-            self._update()
 
     def _clear(self):
-        for dic in self._files.values():
-            for name in dic['chunks']:
-                dic['chunks'][name]['future'] = None
-            dic['merge'] = None
+        self._cfutures = {}
+        self._ffutures = {}
         self._pool = None
 
     def shutdown(self):
         self._shutdown_event.set()
-        self._cancel()
         self._pool.shutdown(wait=True)
-        self._update()
 
     def monitor(self, poll=0.1, timeout=0):
         """ Wait for download to happen """
@@ -384,20 +428,16 @@ class ADLTransferClient(object):
 
     def __getstate__(self):
         dic2 = self.__dict__.copy()
+        dic2.pop('_cfutures', None)
+        dic2.pop('_ffutures', None)
         dic2.pop('_transfer', None)
         dic2.pop('_merge', None)
         dic2.pop('_pool', None)
         dic2.pop('_shutdown_event', None)
+
         dic2['_files'] = dic2.get('_files', {}).copy()
-        for k, v in list(dic2['_files'].items()):
-            v = v.copy()
-            v['chunks'] = v['chunks'].copy()
-            for ck, cv in list(v['chunks'].items()):
-                cv = cv.copy()
-                cv['future'] = None
-                v['chunks'][ck] = cv
-            v['merge'] = None
-            dic2['_files'][k] = v
+        dic2['_chunks'] = dic2.get('_chunks', {}).copy()
+
         return dic2
 
     @staticmethod
diff --git a/adlfs/utils.py b/adlfs/utils.py
index 89b8327..a295f24 100644
--- a/adlfs/utils.py
+++ b/adlfs/utils.py
@@ -21,6 +21,12 @@ except NameError:
     class FileNotFoundError(IOError):
         pass
 
+try:
+    PermissionError = PermissionError
+except NameError:
+    class PermissionError(OSError):
+        pass
+
 WIN = platform.platform() == 'Windows'
 
 if WIN:


Test patch:
diff --git a/tests/recordings/test_core/test_append.yaml b/tests/recordings/test_core/test_append.yaml
index 8dca3db..cd71edc 100644
--- a/tests/recordings/test_core/test_append.yaml
+++ b/tests/recordings/test_core/test_append.yaml
@@ -14,15 +14,15 @@ interactions:
       Cache-Control: [no-cache]
       Content-Length: ['34']
       Content-Type: [application/json; charset=utf-8]
-      Date: ['Thu, 15 Sep 2016 22:02:42 GMT']
+      Date: ['Thu, 22 Sep 2016 17:25:10 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[5930a2bd-5921-4aec-9001-0ba8a7d0368f][ AuthTime::0::PostAuthTime::0
-          ][S-HdfsListStatus :: 00:00:006 ms]%0a[LISTSTATUS :: 00:00:006 ms]%0a']
+      Server-Perf: ['[52cdd20a-6dfe-4a2d-8199-952ced0c7fa7][ AuthTime::937.845196953906::PostAuthTime::226.228959958329
+          ][S-HdfsListStatus :: 00:00:007 ms]%0a[LISTSTATUS :: 00:00:008 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [5930a2bd-5921-4aec-9001-0ba8a7d0368f]
+      x-ms-request-id: [52cdd20a-6dfe-4a2d-8199-952ced0c7fa7]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 200, message: OK}
 - request:
@@ -34,27 +34,27 @@ interactions:
       Content-Length: ['3']
       User-Agent: [python-requests/2.11.1]
     method: PUT
-    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?OP=CREATE&overwrite=true&write=true
+    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?OP=CREATE&write=true&overwrite=true
   response:
     body: {string: ''}
     headers:
       Cache-Control: [no-cache]
       Content-Length: ['0']
       ContentLength: ['0']
-      Date: ['Thu, 15 Sep 2016 22:02:42 GMT']
+      Date: ['Thu, 22 Sep 2016 17:25:10 GMT']
       Expires: ['-1']
-      Location: ['https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?OP=CREATE&overwrite=true&write=true']
+      Location: ['https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?OP=CREATE&write=true&overwrite=true']
       Pragma: [no-cache]
-      Server-Perf: ['[9d3585ce-4e6b-4245-ace6-b30cf3b1a9ea][ AuthTime::0::PostAuthTime::0
-          ][S-HdfsGetFileStatusV2 :: 00:00:006 ms]%0a[S-HdfsCheckAccess :: 00:00:002
-          ms]%0a[S-FsDelete :: 00:00:006 ms]%0a[S-FsOpenStream :: 00:00:049 ms]%0a[S-FsAppendStream
-          :: 00:00:171 ms]%0a[BufferingTime :: 00:00:000 ms]%0a[WriteTime :: 00:00:171
-          ms]%0a[S-FsAppendStream :: 00:00:033 ms]%0a[S-FsCloseHandle :: 00:00:001
-          ms]%0a[CREATE :: 00:00:274 ms]%0a']
+      Server-Perf: ['[eff4ebee-c325-4c1c-b1ee-ed76c8a75c2e][ AuthTime::948.536952313994::PostAuthTime::210.405852361806
+          ][S-HdfsGetFileStatusV2 :: 00:00:006 ms]%0a[S-HdfsCheckAccess :: 00:00:003
+          ms]%0a[S-FsDelete :: 00:00:006 ms]%0a[S-FsOpenStream :: 00:00:027 ms]%0a[S-FsAppendStream
+          :: 00:00:130 ms]%0a[BufferingTime :: 00:00:000 ms]%0a[WriteTime :: 00:00:130
+          ms]%0a[S-FsAppendStream :: 00:00:017 ms]%0a[S-FsCloseHandle :: 00:00:001
+          ms]%0a[CREATE :: 00:00:208 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [9d3585ce-4e6b-4245-ace6-b30cf3b1a9ea]
+      x-ms-request-id: [eff4ebee-c325-4c1c-b1ee-ed76c8a75c2e]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 201, message: Created}
 - request:
@@ -67,20 +67,20 @@ interactions:
     method: GET
     uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir?OP=LISTSTATUS
   response:
-    body: {string: '{"FileStatuses":{"FileStatus":[{"length":3,"pathSuffix":"a","type":"FILE","blockSize":268435456,"accessTime":1473976962773,"modificationTime":1473976962904,"replication":1,"permission":"770","owner":"49b2f9ec-818a-49ca-9424-249e1f19f7d7","group":"49b2f9ec-818a-49ca-9424-249e1f19f7d7"}]}}'}
+    body: {string: '{"FileStatuses":{"FileStatus":[{"length":3,"pathSuffix":"a","type":"FILE","blockSize":268435456,"accessTime":1474565111424,"modificationTime":1474565111521,"replication":1,"permission":"770","owner":"49b2f9ec-818a-49ca-9424-249e1f19f7d7","group":"49b2f9ec-818a-49ca-9424-249e1f19f7d7"}]}}'}
     headers:
       Cache-Control: [no-cache]
       Content-Length: ['288']
       Content-Type: [application/json; charset=utf-8]
-      Date: ['Thu, 15 Sep 2016 22:02:42 GMT']
+      Date: ['Thu, 22 Sep 2016 17:25:12 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[5b52049c-f4f0-4479-8e11-eb50537eb7b0][ AuthTime::0::PostAuthTime::0
-          ][S-HdfsListStatus :: 00:00:046 ms]%0a[LISTSTATUS :: 00:00:046 ms]%0a']
+      Server-Perf: ['[bc6ebbcd-e407-4f40-ad36-acfd494cf87d][ AuthTime::977.615345567353::PostAuthTime::212.971322000237
+          ][S-HdfsListStatus :: 00:00:012 ms]%0a[LISTSTATUS :: 00:00:013 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [5b52049c-f4f0-4479-8e11-eb50537eb7b0]
+      x-ms-request-id: [bc6ebbcd-e407-4f40-ad36-acfd494cf87d]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 200, message: OK}
 - request:
@@ -92,24 +92,23 @@ interactions:
       Content-Length: ['3']
       User-Agent: [python-requests/2.11.1]
     method: POST
-    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?OP=APPEND&append=true
+    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?append=true&OP=APPEND&offset=3
   response:
     body: {string: ''}
     headers:
       Cache-Control: [no-cache]
       Content-Length: ['0']
-      Date: ['Thu, 15 Sep 2016 22:02:43 GMT']
+      Date: ['Thu, 22 Sep 2016 17:25:11 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[c63a6917-9a87-405b-a5a0-b315ec85f2ae][ AuthTime::0::PostAuthTime::0
-          ][S-FsOpenStream :: 00:00:010 ms]%0a[S-FsGetStreamLength :: 00:00:010 ms]%0a[S-FsAppendStream
-          :: 00:00:064 ms]%0a[BufferingTime :: 00:00:000 ms]%0a[WriteTime :: 00:00:064
-          ms]%0a[S-FsAppendStream :: 00:00:033 ms]%0a[S-FsCloseHandle :: 00:00:001
-          ms]%0a[APPEND :: 00:00:122 ms]%0a']
+      Server-Perf: ['[2f5f6b4b-7509-4883-a773-cc1333a6ee89][ AuthTime::942.122542644623::PostAuthTime::206.129398799232
+          ][S-FsOpenStream :: 00:00:011 ms]%0a[S-FsAppendStream :: 00:00:072 ms]%0a[BufferingTime
+          :: 00:00:000 ms]%0a[WriteTime :: 00:00:072 ms]%0a[S-FsAppendStream :: 00:00:033
+          ms]%0a[S-FsCloseHandle :: 00:00:001 ms]%0a[APPEND :: 00:00:119 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [c63a6917-9a87-405b-a5a0-b315ec85f2ae]
+      x-ms-request-id: [2f5f6b4b-7509-4883-a773-cc1333a6ee89]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 200, message: OK}
 - request:
@@ -122,20 +121,20 @@ interactions:
     method: GET
     uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir?OP=LISTSTATUS
   response:
-    body: {string: '{"FileStatuses":{"FileStatus":[{"length":6,"pathSuffix":"a","type":"FILE","blockSize":268435456,"accessTime":1473976962773,"modificationTime":1473976963576,"replication":1,"permission":"770","owner":"49b2f9ec-818a-49ca-9424-249e1f19f7d7","group":"49b2f9ec-818a-49ca-9424-249e1f19f7d7"}]}}'}
+    body: {string: '{"FileStatuses":{"FileStatus":[{"length":6,"pathSuffix":"a","type":"FILE","blockSize":268435456,"accessTime":1474565111424,"modificationTime":1474565112724,"replication":1,"permission":"770","owner":"49b2f9ec-818a-49ca-9424-249e1f19f7d7","group":"49b2f9ec-818a-49ca-9424-249e1f19f7d7"}]}}'}
     headers:
       Cache-Control: [no-cache]
       Content-Length: ['288']
       Content-Type: [application/json; charset=utf-8]
-      Date: ['Thu, 15 Sep 2016 22:02:43 GMT']
+      Date: ['Thu, 22 Sep 2016 17:25:12 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[aaa54e80-7ec5-4bc1-80d8-50ccf2a87678][ AuthTime::0::PostAuthTime::0
-          ][S-HdfsListStatus :: 00:00:012 ms]%0a[LISTSTATUS :: 00:00:012 ms]%0a']
+      Server-Perf: ['[1e1a7931-76f2-4c24-b35a-4bcf15af8df2][ AuthTime::903.63287786758::PostAuthTime::201.425028620743
+          ][S-HdfsListStatus :: 00:00:011 ms]%0a[LISTSTATUS :: 00:00:011 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [aaa54e80-7ec5-4bc1-80d8-50ccf2a87678]
+      x-ms-request-id: [1e1a7931-76f2-4c24-b35a-4bcf15af8df2]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 200, message: OK}
 - request:
@@ -146,23 +145,23 @@ interactions:
       Connection: [keep-alive]
       User-Agent: [python-requests/2.11.1]
     method: GET
-    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?OP=OPEN&offset=0&read=true&length=6
+    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?length=6&OP=OPEN&offset=0&read=true
   response:
     body: {string: '123456'}
     headers:
       Cache-Control: [no-cache]
       Content-Type: [application/octet-stream]
-      Date: ['Thu, 15 Sep 2016 22:02:44 GMT']
+      Date: ['Thu, 22 Sep 2016 17:25:13 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[d7c1f8b4-11bc-4813-b034-7c6e8b74306f][ AuthTime::0::PostAuthTime::0
-          ][S-FsOpenStream :: 00:00:013 ms]%0a[S-FsReadStream :: 00:00:013 ms]%0a[OPEN
-          :: 00:00:027 ms]%0a']
+      Server-Perf: ['[8dbd408c-30b1-4e62-8fcf-569331323d72][ AuthTime::841.62520906988::PostAuthTime::163.364242817426
+          ][S-FsOpenStream :: 00:00:013 ms]%0a[S-FsReadStream :: 00:00:024 ms]%0a[OPEN
+          :: 00:00:037 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       Transfer-Encoding: [chunked]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [d7c1f8b4-11bc-4813-b034-7c6e8b74306f]
+      x-ms-request-id: [8dbd408c-30b1-4e62-8fcf-569331323d72]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 200, message: OK}
 - request:
@@ -174,24 +173,23 @@ interactions:
       Content-Length: ['3']
       User-Agent: [python-requests/2.11.1]
     method: POST
-    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?OP=APPEND&append=true
+    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?append=true&OP=APPEND&offset=6
   response:
     body: {string: ''}
     headers:
       Cache-Control: [no-cache]
       Content-Length: ['0']
-      Date: ['Thu, 15 Sep 2016 22:02:44 GMT']
+      Date: ['Thu, 22 Sep 2016 17:25:13 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[2ca0ce0a-1e25-477d-8b75-1b677810687d][ AuthTime::0::PostAuthTime::0
-          ][S-FsOpenStream :: 00:00:010 ms]%0a[S-FsGetStreamLength :: 00:00:289 ms]%0a[S-FsAppendStream
-          :: 00:00:085 ms]%0a[BufferingTime :: 00:00:000 ms]%0a[WriteTime :: 00:00:085
-          ms]%0a[S-FsAppendStream :: 00:00:033 ms]%0a[S-FsCloseHandle :: 00:00:001
-          ms]%0a[APPEND :: 00:00:420 ms]%0a']
+      Server-Perf: ['[80b029d9-208d-4038-9a74-05870958c31e][ AuthTime::920.311776997166::PostAuthTime::209.550544018872
+          ][S-FsOpenStream :: 00:00:010 ms]%0a[S-FsAppendStream :: 00:00:064 ms]%0a[BufferingTime
+          :: 00:00:000 ms]%0a[WriteTime :: 00:00:064 ms]%0a[S-FsAppendStream :: 00:00:017
+          ms]%0a[S-FsCloseHandle :: 00:00:001 ms]%0a[APPEND :: 00:00:095 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [2ca0ce0a-1e25-477d-8b75-1b677810687d]
+      x-ms-request-id: [80b029d9-208d-4038-9a74-05870958c31e]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 200, message: OK}
 - request:
@@ -204,20 +202,20 @@ interactions:
     method: GET
     uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir?OP=LISTSTATUS
   response:
-    body: {string: '{"FileStatuses":{"FileStatus":[{"length":9,"pathSuffix":"a","type":"FILE","blockSize":268435456,"accessTime":1473976962773,"modificationTime":1473976964701,"replication":1,"permission":"770","owner":"49b2f9ec-818a-49ca-9424-249e1f19f7d7","group":"49b2f9ec-818a-49ca-9424-249e1f19f7d7"}]}}'}
+    body: {string: '{"FileStatuses":{"FileStatus":[{"length":9,"pathSuffix":"a","type":"FILE","blockSize":268435456,"accessTime":1474565111424,"modificationTime":1474565113506,"replication":1,"permission":"770","owner":"49b2f9ec-818a-49ca-9424-249e1f19f7d7","group":"49b2f9ec-818a-49ca-9424-249e1f19f7d7"}]}}'}
     headers:
       Cache-Control: [no-cache]
       Content-Length: ['288']
       Content-Type: [application/json; charset=utf-8]
-      Date: ['Thu, 15 Sep 2016 22:02:44 GMT']
+      Date: ['Thu, 22 Sep 2016 17:25:13 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[b6aed1e4-4108-4244-9853-dd9edede0711][ AuthTime::0::PostAuthTime::0
-          ][S-HdfsListStatus :: 00:00:067 ms]%0a[LISTSTATUS :: 00:00:067 ms]%0a']
+      Server-Perf: ['[e12c453b-93b0-490e-9714-0584cb4521b3][ AuthTime::939.985476839493::PostAuthTime::221.097584861701
+          ][S-HdfsListStatus :: 00:00:012 ms]%0a[LISTSTATUS :: 00:00:013 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [b6aed1e4-4108-4244-9853-dd9edede0711]
+      x-ms-request-id: [e12c453b-93b0-490e-9714-0584cb4521b3]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 200, message: OK}
 - request:
@@ -228,23 +226,23 @@ interactions:
       Connection: [keep-alive]
       User-Agent: [python-requests/2.11.1]
     method: GET
-    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?OP=OPEN&offset=0&read=true&length=9
+    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?length=9&OP=OPEN&offset=0&read=true
   response:
     body: {string: '123456789'}
     headers:
       Cache-Control: [no-cache]
       Content-Type: [application/octet-stream]
-      Date: ['Thu, 15 Sep 2016 22:02:44 GMT']
+      Date: ['Thu, 22 Sep 2016 17:25:13 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[63bbb4da-931c-4d5e-9fb5-9f4eae28ff7b][ AuthTime::0::PostAuthTime::0
-          ][S-FsOpenStream :: 00:00:015 ms]%0a[S-FsReadStream :: 00:00:018 ms]%0a[OPEN
-          :: 00:00:034 ms]%0a']
+      Server-Perf: ['[5e8456e5-2bbd-421f-9184-0f636f035774][ AuthTime::1365.07386666154::PostAuthTime::247.184428236331
+          ][S-FsOpenStream :: 00:00:013 ms]%0a[S-FsReadStream :: 00:00:017 ms]%0a[OPEN
+          :: 00:00:031 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       Transfer-Encoding: [chunked]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [63bbb4da-931c-4d5e-9fb5-9f4eae28ff7b]
+      x-ms-request-id: [5e8456e5-2bbd-421f-9184-0f636f035774]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 200, message: OK}
 - request:
@@ -256,22 +254,22 @@ interactions:
       Content-Length: ['0']
       User-Agent: [python-requests/2.11.1]
     method: DELETE
-    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?OP=DELETE&recursive=True
+    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?recursive=True&OP=DELETE
   response:
     body: {string: '{"boolean":true}'}
     headers:
       Cache-Control: [no-cache]
       Content-Length: ['16']
       Content-Type: [application/json; charset=utf-8]
-      Date: ['Thu, 15 Sep 2016 22:02:45 GMT']
+      Date: ['Thu, 22 Sep 2016 17:25:13 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[fe69bdb6-aa91-4547-850a-46a3d7574db8][ AuthTime::0::PostAuthTime::0
-          ][S-FsDelete :: 00:00:094 ms]%0a[DELETE :: 00:00:095 ms]%0a']
+      Server-Perf: ['[201d5c1f-bbcb-445f-95bd-22f9979c565a][ AuthTime::938.702913571335::PostAuthTime::216.393473470203
+          ][S-FsDelete :: 00:00:046 ms]%0a[DELETE :: 00:00:053 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [fe69bdb6-aa91-4547-850a-46a3d7574db8]
+      x-ms-request-id: [201d5c1f-bbcb-445f-95bd-22f9979c565a]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 200, message: OK}
 version: 1
diff --git a/tests/recordings/test_core/test_chmod.yaml b/tests/recordings/test_core/test_chmod.yaml
index 32bbc8c..26d47a4 100644
--- a/tests/recordings/test_core/test_chmod.yaml
+++ b/tests/recordings/test_core/test_chmod.yaml
@@ -8,26 +8,26 @@ interactions:
       Content-Length: ['0']
       User-Agent: [python-requests/2.11.1]
     method: PUT
-    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?OP=CREATE&overwrite=true&write=true
+    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?overwrite=true&OP=CREATE&write=true
   response:
     body: {string: ''}
     headers:
       Cache-Control: [no-cache]
       Content-Length: ['0']
       ContentLength: ['0']
-      Date: ['Thu, 15 Sep 2016 22:03:04 GMT']
+      Date: ['Thu, 22 Sep 2016 17:26:17 GMT']
       Expires: ['-1']
-      Location: ['https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?OP=CREATE&overwrite=true&write=true']
+      Location: ['https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?overwrite=true&OP=CREATE&write=true']
       Pragma: [no-cache]
-      Server-Perf: ['[4f7ad0b4-6bf9-4b83-be33-d2dedfb0ad94][ AuthTime::0::PostAuthTime::0
-          ][S-HdfsGetFileStatusV2 :: 00:00:010 ms]%0a[S-HdfsCheckAccess :: 00:00:006
+      Server-Perf: ['[99ddd83c-d47d-4cbf-b60a-ea3f27a1dd4b][ AuthTime::9475.11797924592::PostAuthTime::235.210096072633
+          ][S-HdfsGetFileStatusV2 :: 00:00:009 ms]%0a[S-HdfsCheckAccess :: 00:00:004
           ms]%0a[S-FsDelete :: 00:00:008 ms]%0a[S-FsOpenStream :: 00:00:052 ms]%0a[BufferingTime
-          :: 00:00:000 ms]%0a[WriteTime :: 00:00:000 ms]%0a[S-FsAppendStream :: 00:00:038
-          ms]%0a[S-FsCloseHandle :: 00:00:006 ms]%0a[CREATE :: 00:00:129 ms]%0a']
+          :: 00:00:000 ms]%0a[WriteTime :: 00:00:000 ms]%0a[S-FsAppendStream :: 00:00:043
+          ms]%0a[S-FsCloseHandle :: 00:00:002 ms]%0a[CREATE :: 00:00:188 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [4f7ad0b4-6bf9-4b83-be33-d2dedfb0ad94]
+      x-ms-request-id: [99ddd83c-d47d-4cbf-b60a-ea3f27a1dd4b]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 201, message: Created}
 - request:
@@ -40,20 +40,20 @@ interactions:
     method: GET
     uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir?OP=LISTSTATUS
   response:
-    body: {string: '{"FileStatuses":{"FileStatus":[{"length":0,"pathSuffix":"a","type":"FILE","blockSize":268435456,"accessTime":1473976984965,"modificationTime":1473976984965,"replication":1,"permission":"770","owner":"49b2f9ec-818a-49ca-9424-249e1f19f7d7","group":"49b2f9ec-818a-49ca-9424-249e1f19f7d7"}]}}'}
+    body: {string: '{"FileStatuses":{"FileStatus":[{"length":0,"pathSuffix":"a","type":"FILE","blockSize":268435456,"accessTime":1474565178086,"modificationTime":1474565178086,"replication":1,"permission":"770","owner":"49b2f9ec-818a-49ca-9424-249e1f19f7d7","group":"49b2f9ec-818a-49ca-9424-249e1f19f7d7"}]}}'}
     headers:
       Cache-Control: [no-cache]
       Content-Length: ['288']
       Content-Type: [application/json; charset=utf-8]
-      Date: ['Thu, 15 Sep 2016 22:03:04 GMT']
+      Date: ['Thu, 22 Sep 2016 17:26:18 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[af7f71ad-8204-4f92-9d07-75ac8d809809][ AuthTime::0::PostAuthTime::0
-          ][S-HdfsListStatus :: 00:00:049 ms]%0a[LISTSTATUS :: 00:00:049 ms]%0a']
+      Server-Perf: ['[5eeffd1b-395f-417f-9740-806cf8844706][ AuthTime::1194.86677705856::PostAuthTime::287.383849027685
+          ][S-HdfsListStatus :: 00:00:014 ms]%0a[LISTSTATUS :: 00:00:014 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [af7f71ad-8204-4f92-9d07-75ac8d809809]
+      x-ms-request-id: [5eeffd1b-395f-417f-9740-806cf8844706]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 200, message: OK}
 - request:
@@ -65,21 +65,21 @@ interactions:
       Content-Length: ['0']
       User-Agent: [python-requests/2.11.1]
     method: PUT
-    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?OP=SETPERMISSION&permission=0555
+    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?permission=0555&OP=SETPERMISSION
   response:
     body: {string: ''}
     headers:
       Cache-Control: [no-cache]
       Content-Length: ['0']
-      Date: ['Thu, 15 Sep 2016 22:03:04 GMT']
+      Date: ['Thu, 22 Sep 2016 17:26:19 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[c785adfb-1572-4463-8a5e-0e32124cab1a][ AuthTime::0::PostAuthTime::0
-          ][S-HdfsSetPermission :: 00:00:031 ms]%0a[SETPERMISSION :: 00:00:033 ms]%0a']
+      Server-Perf: ['[8789f155-60af-4551-82ee-8685e2f3f9eb][ AuthTime::934.852018827047::PostAuthTime::213.827085733542
+          ][S-HdfsSetPermission :: 00:00:021 ms]%0a[SETPERMISSION :: 00:00:024 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [c785adfb-1572-4463-8a5e-0e32124cab1a]
+      x-ms-request-id: [8789f155-60af-4551-82ee-8685e2f3f9eb]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 200, message: OK}
 - request:
@@ -92,20 +92,20 @@ interactions:
     method: GET
     uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir?OP=LISTSTATUS
   response:
-    body: {string: '{"FileStatuses":{"FileStatus":[{"length":0,"pathSuffix":"a","type":"FILE","blockSize":268435456,"accessTime":1473976984965,"modificationTime":1473976984965,"replication":1,"permission":"555","owner":"49b2f9ec-818a-49ca-9424-249e1f19f7d7","group":"49b2f9ec-818a-49ca-9424-249e1f19f7d7"}]}}'}
+    body: {string: '{"FileStatuses":{"FileStatus":[{"length":0,"pathSuffix":"a","type":"FILE","blockSize":268435456,"accessTime":1474565178086,"modificationTime":1474565178086,"replication":1,"permission":"555","owner":"49b2f9ec-818a-49ca-9424-249e1f19f7d7","group":"49b2f9ec-818a-49ca-9424-249e1f19f7d7"}]}}'}
     headers:
       Cache-Control: [no-cache]
       Content-Length: ['288']
       Content-Type: [application/json; charset=utf-8]
-      Date: ['Thu, 15 Sep 2016 22:03:05 GMT']
+      Date: ['Thu, 22 Sep 2016 17:26:19 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[5c6f6fef-a28e-4305-a62e-42828c244ea1][ AuthTime::0::PostAuthTime::0
-          ][S-HdfsListStatus :: 00:00:052 ms]%0a[LISTSTATUS :: 00:00:053 ms]%0a']
+      Server-Perf: ['[510632c1-841e-4fde-a741-4697cd290e00][ AuthTime::1052.4569159805::PostAuthTime::279.258173968006
+          ][S-HdfsListStatus :: 00:00:070 ms]%0a[LISTSTATUS :: 00:00:071 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [5c6f6fef-a28e-4305-a62e-42828c244ea1]
+      x-ms-request-id: [510632c1-841e-4fde-a741-4697cd290e00]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 200, message: OK}
 - request:
@@ -117,24 +117,24 @@ interactions:
       Content-Length: ['4']
       User-Agent: [python-requests/2.11.1]
     method: POST
-    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?OP=APPEND&append=true
+    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?offset=0&append=true&OP=APPEND
   response:
     body: {string: '{"RemoteException":{"exception":"AccessControlException","message":"Operation
         failed. failed with error 0x83090aa2 (Either the resource does not exist or
-        the current user is not authorized to perform the requested operation). [3d881627-792b-4b62-ab4a-8885703a0873][2016-09-15T15:03:06.1254451-07:00]","javaClassName":"org.apache.hadoop.security.AccessControlException"}}'}
+        the current user is not authorized to perform the requested operation). [ed9b7720-b939-45d5-99dd-76fc051c6076][2016-09-22T10:26:20.1195352-07:00]","javaClassName":"org.apache.hadoop.security.AccessControlException"}}'}
     headers:
       Cache-Control: [no-cache]
       Content-Length: ['370']
       Content-Type: [application/json; charset=utf-8]
-      Date: ['Thu, 15 Sep 2016 22:03:05 GMT']
+      Date: ['Thu, 22 Sep 2016 17:26:19 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[3d881627-792b-4b62-ab4a-8885703a0873][ AuthTime::0::PostAuthTime::0
-          ][S-FsOpenStream :: 00:00:005 ms]%0a[APPEND :: 00:00:009 ms]%0a']
+      Server-Perf: ['[ed9b7720-b939-45d5-99dd-76fc051c6076][ AuthTime::9665.85198442482::PostAuthTime::215.110324226426
+          ][S-FsOpenStream :: 00:00:007 ms]%0a[APPEND :: 00:00:022 ms]%0a']
       Status: ['0x83090AA2']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [3d881627-792b-4b62-ab4a-8885703a0873]
+      x-ms-request-id: [ed9b7720-b939-45d5-99dd-76fc051c6076]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 403, message: Forbidden}
 - request:
@@ -146,21 +146,21 @@ interactions:
       Content-Length: ['0']
       User-Agent: [python-requests/2.11.1]
     method: PUT
-    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?OP=SETPERMISSION&permission=0770
+    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?permission=0770&OP=SETPERMISSION
   response:
     body: {string: ''}
     headers:
       Cache-Control: [no-cache]
       Content-Length: ['0']
-      Date: ['Thu, 15 Sep 2016 22:03:05 GMT']
+      Date: ['Thu, 22 Sep 2016 17:26:19 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[3ca631ca-8e42-467e-88ab-b4054392613d][ AuthTime::0::PostAuthTime::0
-          ][S-HdfsSetPermission :: 00:00:023 ms]%0a[SETPERMISSION :: 00:00:025 ms]%0a']
+      Server-Perf: ['[dd9f3644-d08d-4e85-9583-b52efe1ecd96][ AuthTime::916.891719963136::PostAuthTime::210.833777025105
+          ][S-HdfsSetPermission :: 00:00:018 ms]%0a[SETPERMISSION :: 00:00:035 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [3ca631ca-8e42-467e-88ab-b4054392613d]
+      x-ms-request-id: [dd9f3644-d08d-4e85-9583-b52efe1ecd96]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 200, message: OK}
 - request:
@@ -173,20 +173,20 @@ interactions:
     method: GET
     uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir?OP=LISTSTATUS
   response:
-    body: {string: '{"FileStatuses":{"FileStatus":[{"length":0,"pathSuffix":"a","type":"FILE","blockSize":268435456,"accessTime":1473976984965,"modificationTime":1473976984965,"replication":1,"permission":"770","owner":"49b2f9ec-818a-49ca-9424-249e1f19f7d7","group":"49b2f9ec-818a-49ca-9424-249e1f19f7d7"}]}}'}
+    body: {string: '{"FileStatuses":{"FileStatus":[{"length":0,"pathSuffix":"a","type":"FILE","blockSize":268435456,"accessTime":1474565178086,"modificationTime":1474565178086,"replication":1,"permission":"770","owner":"49b2f9ec-818a-49ca-9424-249e1f19f7d7","group":"49b2f9ec-818a-49ca-9424-249e1f19f7d7"}]}}'}
     headers:
       Cache-Control: [no-cache]
       Content-Length: ['288']
       Content-Type: [application/json; charset=utf-8]
-      Date: ['Thu, 15 Sep 2016 22:03:05 GMT']
+      Date: ['Thu, 22 Sep 2016 17:26:19 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[f70b977f-3503-46fb-a15b-507e05125840][ AuthTime::0::PostAuthTime::0
-          ][S-HdfsListStatus :: 00:00:013 ms]%0a[LISTSTATUS :: 00:00:013 ms]%0a']
+      Server-Perf: ['[85d4d9c9-8049-48aa-bcb0-aaff876ce422][ AuthTime::1884.67435162199::PostAuthTime::712.900418460144
+          ][S-HdfsListStatus :: 00:00:013 ms]%0a[LISTSTATUS :: 00:00:014 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [f70b977f-3503-46fb-a15b-507e05125840]
+      x-ms-request-id: [85d4d9c9-8049-48aa-bcb0-aaff876ce422]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 200, message: OK}
 - request:
@@ -198,22 +198,22 @@ interactions:
       Content-Length: ['0']
       User-Agent: [python-requests/2.11.1]
     method: DELETE
-    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?OP=DELETE&recursive=False
+    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?recursive=False&OP=DELETE
   response:
     body: {string: '{"boolean":true}'}
     headers:
       Cache-Control: [no-cache]
       Content-Length: ['16']
       Content-Type: [application/json; charset=utf-8]
-      Date: ['Thu, 15 Sep 2016 22:03:06 GMT']
+      Date: ['Thu, 22 Sep 2016 17:26:20 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[9feb7979-fdf9-4c6f-9a21-87e12f89b642][ AuthTime::0::PostAuthTime::0
-          ][S-FsDelete :: 00:00:121 ms]%0a[DELETE :: 00:00:122 ms]%0a']
+      Server-Perf: ['[5221fe20-3a45-4f68-a2d3-9c9f5839b47e][ AuthTime::929.720566368321::PostAuthTime::221.952609910376
+          ][S-FsDelete :: 00:00:070 ms]%0a[DELETE :: 00:00:078 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [9feb7979-fdf9-4c6f-9a21-87e12f89b642]
+      x-ms-request-id: [5221fe20-3a45-4f68-a2d3-9c9f5839b47e]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 200, message: OK}
 - request:
@@ -232,15 +232,15 @@ interactions:
       Cache-Control: [no-cache]
       Content-Length: ['16']
       Content-Type: [application/json; charset=utf-8]
-      Date: ['Thu, 15 Sep 2016 22:03:06 GMT']
+      Date: ['Thu, 22 Sep 2016 17:26:21 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[0e93781c-14b2-46c0-bc5c-24a1e7b1a4e5][ AuthTime::0::PostAuthTime::0
-          ][S-HdfsMkdirs :: 00:00:033 ms]%0a[MKDIRS :: 00:00:034 ms]%0a']
+      Server-Perf: ['[d865f65d-9de6-4092-8921-cbd6f0c600e3][ AuthTime::949.393478693173::PostAuthTime::219.386871427747
+          ][S-HdfsMkdirs :: 00:00:009 ms]%0a[MKDIRS :: 00:00:013 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [0e93781c-14b2-46c0-bc5c-24a1e7b1a4e5]
+      x-ms-request-id: [d865f65d-9de6-4092-8921-cbd6f0c600e3]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 200, message: OK}
 - request:
@@ -252,26 +252,26 @@ interactions:
       Content-Length: ['0']
       User-Agent: [python-requests/2.11.1]
     method: PUT
-    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/deep/file?OP=CREATE&overwrite=true&write=true
+    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/deep/file?overwrite=true&OP=CREATE&write=true
   response:
     body: {string: ''}
     headers:
       Cache-Control: [no-cache]
       Content-Length: ['0']
       ContentLength: ['0']
-      Date: ['Thu, 15 Sep 2016 22:03:07 GMT']
+      Date: ['Thu, 22 Sep 2016 17:26:21 GMT']
       Expires: ['-1']
-      Location: ['https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/deep/file?OP=CREATE&overwrite=true&write=true']
+      Location: ['https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/deep/file?overwrite=true&OP=CREATE&write=true']
       Pragma: [no-cache]
-      Server-Perf: ['[3f44fdb7-1afa-46b3-bedc-32c71cc564f0][ AuthTime::0::PostAuthTime::0
+      Server-Perf: ['[1d663c6e-dd1a-4dda-a667-5e044e420d90][ AuthTime::929.294899099016::PostAuthTime::210.834047517632
           ][S-HdfsGetFileStatusV2 :: 00:00:006 ms]%0a[S-HdfsCheckAccess :: 00:00:002
-          ms]%0a[S-FsDelete :: 00:00:005 ms]%0a[S-FsOpenStream :: 00:00:056 ms]%0a[BufferingTime
-          :: 00:00:000 ms]%0a[WriteTime :: 00:00:000 ms]%0a[S-FsAppendStream :: 00:00:031
-          ms]%0a[S-FsCloseHandle :: 00:00:001 ms]%0a[CREATE :: 00:00:109 ms]%0a']
+          ms]%0a[S-FsDelete :: 00:00:005 ms]%0a[S-FsOpenStream :: 00:00:332 ms]%0a[BufferingTime
+          :: 00:00:000 ms]%0a[WriteTime :: 00:00:000 ms]%0a[S-FsAppendStream :: 00:00:034
+          ms]%0a[S-FsCloseHandle :: 00:00:001 ms]%0a[CREATE :: 00:00:393 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [3f44fdb7-1afa-46b3-bedc-32c71cc564f0]
+      x-ms-request-id: [1d663c6e-dd1a-4dda-a667-5e044e420d90]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 201, message: Created}
 - request:
@@ -283,21 +283,21 @@ interactions:
       Content-Length: ['0']
       User-Agent: [python-requests/2.11.1]
     method: PUT
-    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/deep?OP=SETPERMISSION&permission=660
+    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/deep?permission=660&OP=SETPERMISSION
   response:
     body: {string: ''}
     headers:
       Cache-Control: [no-cache]
       Content-Length: ['0']
-      Date: ['Thu, 15 Sep 2016 22:03:07 GMT']
+      Date: ['Thu, 22 Sep 2016 17:26:21 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[d9a27143-a1fe-4c67-b96c-c2f70ac473a0][ AuthTime::0::PostAuthTime::0
-          ][S-HdfsSetPermission :: 00:00:012 ms]%0a[SETPERMISSION :: 00:00:015 ms]%0a']
+      Server-Perf: ['[2c34850d-954b-4f73-8193-9fb9abbd73e8][ AuthTime::909.619644705218::PostAuthTime::209.122710983005
+          ][S-HdfsSetPermission :: 00:00:007 ms]%0a[SETPERMISSION :: 00:00:010 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [d9a27143-a1fe-4c67-b96c-c2f70ac473a0]
+      x-ms-request-id: [2c34850d-954b-4f73-8193-9fb9abbd73e8]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 200, message: OK}
 - request:
@@ -312,22 +312,22 @@ interactions:
   response:
     body: {string: '{"RemoteException":{"exception":"AccessControlException","message":"ListStatus
         failed with error 0x83090aa2 (Either the resource does not exist or the current
-        user is not authorized to perform the requested operation). [1fe99c01-cb00-4ac3-818a-955349707d41][2016-09-15T15:03:09.3105410-07:00]","javaClassName":"org.apache.hadoop.security.AccessControlException"}}'}
+        user is not authorized to perform the requested operation). [9a329262-c9d9-4de2-8126-ef83b7926934][2016-09-22T10:26:23.4072586-07:00]","javaClassName":"org.apache.hadoop.security.AccessControlException"}}'}
     headers:
       Cache-Control: [no-cache]
       Content-Length: ['363']
       Content-Type: [application/json; charset=utf-8]
-      Date: ['Thu, 15 Sep 2016 22:03:09 GMT']
+      Date: ['Thu, 22 Sep 2016 17:26:23 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[1fe99c01-cb00-4ac3-818a-955349707d41][ AuthTime::0::PostAuthTime::0
+      Server-Perf: ['[9a329262-c9d9-4de2-8126-ef83b7926934][ AuthTime::903.63287786758::PostAuthTime::185.601831043318
           ][S-HdfsListStatus :: 00:00:006 ms]%0a[S-HdfsListStatus :: 00:00:006 ms]%0a[S-HdfsListStatus
           :: 00:00:006 ms]%0a[S-HdfsListStatus :: 00:00:006 ms]%0a[S-HdfsListStatus
-          :: 00:00:005 ms]%0a[LISTSTATUS :: 00:01:248 ms]%0a']
+          :: 00:00:006 ms]%0a[LISTSTATUS :: 00:01:257 ms]%0a']
       Status: ['0x83090AA2']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [1fe99c01-cb00-4ac3-818a-955349707d41]
+      x-ms-request-id: [9a329262-c9d9-4de2-8126-ef83b7926934]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 403, message: Forbidden}
 - request:
@@ -339,21 +339,21 @@ interactions:
       Content-Length: ['0']
       User-Agent: [python-requests/2.11.1]
     method: PUT
-    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/deep?OP=SETPERMISSION&permission=770
+    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/deep?permission=770&OP=SETPERMISSION
   response:
     body: {string: ''}
     headers:
       Cache-Control: [no-cache]
       Content-Length: ['0']
-      Date: ['Thu, 15 Sep 2016 22:03:09 GMT']
+      Date: ['Thu, 22 Sep 2016 17:26:23 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[dc6427a9-3bec-4738-af07-08b83c791316][ AuthTime::0::PostAuthTime::0
-          ][S-HdfsSetPermission :: 00:00:027 ms]%0a[SETPERMISSION :: 00:00:027 ms]%0a']
+      Server-Perf: ['[ea2a2969-823f-4cf3-806b-b5500a71bbe1][ AuthTime::0::PostAuthTime::0
+          ][S-HdfsSetPermission :: 00:00:021 ms]%0a[SETPERMISSION :: 00:00:021 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [dc6427a9-3bec-4738-af07-08b83c791316]
+      x-ms-request-id: [ea2a2969-823f-4cf3-806b-b5500a71bbe1]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 200, message: OK}
 - request:
@@ -366,20 +366,20 @@ interactions:
     method: GET
     uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir?OP=LISTSTATUS
   response:
-    body: {string: '{"FileStatuses":{"FileStatus":[{"length":0,"pathSuffix":"deep","type":"DIRECTORY","blockSize":0,"accessTime":1473976987201,"modificationTime":1473976987526,"replication":0,"permission":"770","owner":"49b2f9ec-818a-49ca-9424-249e1f19f7d7","group":"49b2f9ec-818a-49ca-9424-249e1f19f7d7"}]}}'}
+    body: {string: '{"FileStatuses":{"FileStatus":[{"length":0,"pathSuffix":"deep","type":"DIRECTORY","blockSize":0,"accessTime":1474565181120,"modificationTime":1474565181660,"replication":0,"permission":"770","owner":"49b2f9ec-818a-49ca-9424-249e1f19f7d7","group":"49b2f9ec-818a-49ca-9424-249e1f19f7d7"}]}}'}
     headers:
       Cache-Control: [no-cache]
       Content-Length: ['288']
       Content-Type: [application/json; charset=utf-8]
-      Date: ['Thu, 15 Sep 2016 22:03:09 GMT']
+      Date: ['Thu, 22 Sep 2016 17:26:23 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[03ffce62-9926-4c59-8df5-60fb90aac6ad][ AuthTime::0::PostAuthTime::0
-          ][S-HdfsListStatus :: 00:00:007 ms]%0a[LISTSTATUS :: 00:00:008 ms]%0a']
+      Server-Perf: ['[6339da02-e518-4824-8046-c97be79a312c][ AuthTime::853.169342353978::PostAuthTime::182.180521224458
+          ][S-HdfsListStatus :: 00:00:006 ms]%0a[LISTSTATUS :: 00:00:007 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [03ffce62-9926-4c59-8df5-60fb90aac6ad]
+      x-ms-request-id: [6339da02-e518-4824-8046-c97be79a312c]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 200, message: OK}
 - request:
@@ -391,22 +391,22 @@ interactions:
       Content-Length: ['0']
       User-Agent: [python-requests/2.11.1]
     method: DELETE
-    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/deep?OP=DELETE&recursive=True
+    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/deep?recursive=True&OP=DELETE
   response:
     body: {string: '{"boolean":true}'}
     headers:
       Cache-Control: [no-cache]
       Content-Length: ['16']
       Content-Type: [application/json; charset=utf-8]
-      Date: ['Thu, 15 Sep 2016 22:03:09 GMT']
+      Date: ['Thu, 22 Sep 2016 17:26:23 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[2b7efbfb-a6cc-4dc6-b959-0e4a8a82c533][ AuthTime::0::PostAuthTime::0
-          ][S-FsDelete :: 00:00:045 ms]%0a[DELETE :: 00:00:046 ms]%0a']
+      Server-Perf: ['[05164205-0afa-4669-aebf-aec027f48737][ AuthTime::935.281272906266::PostAuthTime::224.946478988887
+          ][S-FsDelete :: 00:00:054 ms]%0a[DELETE :: 00:00:064 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [2b7efbfb-a6cc-4dc6-b959-0e4a8a82c533]
+      x-ms-request-id: [05164205-0afa-4669-aebf-aec027f48737]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 200, message: OK}
 - request:
@@ -418,23 +418,23 @@ interactions:
       Content-Length: ['4']
       User-Agent: [python-requests/2.11.1]
     method: POST
-    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?OP=APPEND&append=true
+    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?offset=0&append=true&OP=APPEND
   response:
     body: {string: '{"RemoteException":{"exception":"FileNotFoundException","message":"Operation
-        failed. failed with error 0x8309000a (Stream not found). [7f0e5641-29ef-4a67-87f9-97c8b72f4e51][2016-09-15T15:03:10.3712624-07:00]","javaClassName":"java.io.FileNotFoundException"}}'}
+        failed. failed with error 0x8309000a (Stream not found). [3cbc2496-6cc2-4875-a41b-e8fa6a30e142][2016-09-22T10:26:24.2909766-07:00]","javaClassName":"java.io.FileNotFoundException"}}'}
     headers:
       Cache-Control: [no-cache]
       Content-Length: ['258']
       Content-Type: [application/json; charset=utf-8]
-      Date: ['Thu, 15 Sep 2016 22:03:09 GMT']
+      Date: ['Thu, 22 Sep 2016 17:26:23 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[7f0e5641-29ef-4a67-87f9-97c8b72f4e51][ AuthTime::0::PostAuthTime::0
-          ][S-FsOpenStream :: 00:00:006 ms]%0a[APPEND :: 00:00:006 ms]%0a']
+      Server-Perf: ['[3cbc2496-6cc2-4875-a41b-e8fa6a30e142][ AuthTime::829.223211578505::PostAuthTime::157.377071614693
+          ][S-FsOpenStream :: 00:00:006 ms]%0a[APPEND :: 00:00:011 ms]%0a']
       Status: ['0x8309000A']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [7f0e5641-29ef-4a67-87f9-97c8b72f4e51]
+      x-ms-request-id: [3cbc2496-6cc2-4875-a41b-e8fa6a30e142]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 404, message: Not Found}
 version: 1
diff --git a/tests/recordings/test_core/test_delimiters_dash.yaml b/tests/recordings/test_core/test_delimiters_dash.yaml
index a27f46d..6dbaeda 100644
--- a/tests/recordings/test_core/test_delimiters_dash.yaml
+++ b/tests/recordings/test_core/test_delimiters_dash.yaml
@@ -8,27 +8,27 @@ interactions:
       Content-Length: ['5']
       User-Agent: [python-requests/2.11.1]
     method: PUT
-    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?OP=CREATE&overwrite=true&write=true
+    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?overwrite=true&OP=CREATE&write=true
   response:
     body: {string: ''}
     headers:
       Cache-Control: [no-cache]
       Content-Length: ['0']
       ContentLength: ['0']
-      Date: ['Thu, 15 Sep 2016 22:03:02 GMT']
+      Date: ['Thu, 22 Sep 2016 17:26:59 GMT']
       Expires: ['-1']
-      Location: ['https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?OP=CREATE&overwrite=true&write=true']
+      Location: ['https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?overwrite=true&OP=CREATE&write=true']
       Pragma: [no-cache]
-      Server-Perf: ['[5b95c94d-a0fe-4769-9a4f-701b33318388][ AuthTime::0::PostAuthTime::0
-          ][S-HdfsGetFileStatusV2 :: 00:00:006 ms]%0a[S-HdfsCheckAccess :: 00:00:002
-          ms]%0a[S-FsDelete :: 00:00:005 ms]%0a[S-FsOpenStream :: 00:00:072 ms]%0a[S-FsAppendStream
-          :: 00:00:450 ms]%0a[BufferingTime :: 00:00:000 ms]%0a[WriteTime :: 00:00:450
+      Server-Perf: ['[8a0b505d-7508-4a84-b926-3b7a09a80771][ AuthTime::1069.13634310895::PostAuthTime::274.981867447621
+          ][S-HdfsGetFileStatusV2 :: 00:00:007 ms]%0a[S-HdfsCheckAccess :: 00:00:003
+          ms]%0a[S-FsDelete :: 00:00:006 ms]%0a[S-FsOpenStream :: 00:00:058 ms]%0a[S-FsAppendStream
+          :: 00:00:121 ms]%0a[BufferingTime :: 00:00:000 ms]%0a[WriteTime :: 00:00:121
           ms]%0a[S-FsAppendStream :: 00:00:033 ms]%0a[S-FsCloseHandle :: 00:00:001
-          ms]%0a[CREATE :: 00:00:576 ms]%0a']
+          ms]%0a[CREATE :: 00:00:236 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [5b95c94d-a0fe-4769-9a4f-701b33318388]
+      x-ms-request-id: [8a0b505d-7508-4a84-b926-3b7a09a80771]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 201, message: Created}
 - request:
@@ -41,20 +41,20 @@ interactions:
     method: GET
     uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir?OP=LISTSTATUS
   response:
-    body: {string: '{"FileStatuses":{"FileStatus":[{"length":5,"pathSuffix":"a","type":"FILE","blockSize":268435456,"accessTime":1473976982129,"modificationTime":1473976982572,"replication":1,"permission":"770","owner":"49b2f9ec-818a-49ca-9424-249e1f19f7d7","group":"49b2f9ec-818a-49ca-9424-249e1f19f7d7"}]}}'}
+    body: {string: '{"FileStatuses":{"FileStatus":[{"length":5,"pathSuffix":"a","type":"FILE","blockSize":268435456,"accessTime":1474565219213,"modificationTime":1474565219310,"replication":1,"permission":"770","owner":"49b2f9ec-818a-49ca-9424-249e1f19f7d7","group":"49b2f9ec-818a-49ca-9424-249e1f19f7d7"}]}}'}
     headers:
       Cache-Control: [no-cache]
       Content-Length: ['288']
       Content-Type: [application/json; charset=utf-8]
-      Date: ['Thu, 15 Sep 2016 22:03:02 GMT']
+      Date: ['Thu, 22 Sep 2016 17:26:58 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[09e96669-fa51-4e9a-a192-6cfbf35e1489][ AuthTime::0::PostAuthTime::0
-          ][S-HdfsListStatus :: 00:00:011 ms]%0a[LISTSTATUS :: 00:00:011 ms]%0a']
+      Server-Perf: ['[9640250c-6808-425c-a434-c44713249df4][ AuthTime::970.347315058815::PostAuthTime::232.643869278094
+          ][S-HdfsListStatus :: 00:00:012 ms]%0a[LISTSTATUS :: 00:00:012 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [09e96669-fa51-4e9a-a192-6cfbf35e1489]
+      x-ms-request-id: [9640250c-6808-425c-a434-c44713249df4]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 200, message: OK}
 - request:
@@ -65,23 +65,23 @@ interactions:
       Connection: [keep-alive]
       User-Agent: [python-requests/2.11.1]
     method: GET
-    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?OP=OPEN&offset=0&read=true&length=5
+    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?length=5&read=true&OP=OPEN&offset=0
   response:
     body: {string: 123--}
     headers:
       Cache-Control: [no-cache]
       Content-Type: [application/octet-stream]
-      Date: ['Thu, 15 Sep 2016 22:03:03 GMT']
+      Date: ['Thu, 22 Sep 2016 17:26:58 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[2bd0f359-622e-43a7-87b5-dc7ba9e36aa2][ AuthTime::0::PostAuthTime::0
-          ][S-FsOpenStream :: 00:00:014 ms]%0a[S-FsReadStream :: 00:00:040 ms]%0a[OPEN
-          :: 00:00:055 ms]%0a']
+      Server-Perf: ['[1220fd48-2d7b-4ad4-b082-6c68c91bf557][ AuthTime::1488.23778960765::PostAuthTime::219.814432143199
+          ][S-FsOpenStream :: 00:00:014 ms]%0a[S-FsReadStream :: 00:00:017 ms]%0a[OPEN
+          :: 00:00:031 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       Transfer-Encoding: [chunked]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [2bd0f359-622e-43a7-87b5-dc7ba9e36aa2]
+      x-ms-request-id: [1220fd48-2d7b-4ad4-b082-6c68c91bf557]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 200, message: OK}
 - request:
@@ -93,24 +93,24 @@ interactions:
       Content-Length: ['5']
       User-Agent: [python-requests/2.11.1]
     method: POST
-    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?OP=APPEND&append=true
+    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?append=true&OP=APPEND
   response:
     body: {string: ''}
     headers:
       Cache-Control: [no-cache]
       Content-Length: ['0']
-      Date: ['Thu, 15 Sep 2016 22:03:03 GMT']
+      Date: ['Thu, 22 Sep 2016 17:26:59 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[e65fe050-b000-4cd9-992a-46f072d5c8a1][ AuthTime::0::PostAuthTime::0
-          ][S-FsOpenStream :: 00:00:010 ms]%0a[S-FsGetStreamLength :: 00:00:009 ms]%0a[S-FsAppendStream
-          :: 00:00:066 ms]%0a[BufferingTime :: 00:00:000 ms]%0a[WriteTime :: 00:00:066
-          ms]%0a[S-FsAppendStream :: 00:00:017 ms]%0a[S-FsCloseHandle :: 00:00:001
-          ms]%0a[APPEND :: 00:00:106 ms]%0a']
+      Server-Perf: ['[e7302618-0532-49e4-8dc1-b3cc85facbee][ AuthTime::1259.01549606878::PostAuthTime::295.937066331385
+          ][S-FsOpenStream :: 00:00:013 ms]%0a[S-FsGetStreamLength :: 00:00:009 ms]%0a[S-FsAppendStream
+          :: 00:00:377 ms]%0a[BufferingTime :: 00:00:000 ms]%0a[WriteTime :: 00:00:377
+          ms]%0a[S-FsAppendStream :: 00:00:033 ms]%0a[S-FsCloseHandle :: 00:00:001
+          ms]%0a[APPEND :: 00:00:437 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [e65fe050-b000-4cd9-992a-46f072d5c8a1]
+      x-ms-request-id: [e7302618-0532-49e4-8dc1-b3cc85facbee]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 200, message: OK}
 - request:
@@ -122,24 +122,23 @@ interactions:
       Content-Length: ['3']
       User-Agent: [python-requests/2.11.1]
     method: POST
-    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?OP=APPEND&append=true
+    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?append=true&OP=APPEND&offset=10
   response:
     body: {string: ''}
     headers:
       Cache-Control: [no-cache]
       Content-Length: ['0']
-      Date: ['Thu, 15 Sep 2016 22:03:03 GMT']
+      Date: ['Thu, 22 Sep 2016 17:27:00 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[2a43de68-405f-4bb3-8eec-1201c2033dbe][ AuthTime::0::PostAuthTime::0
-          ][S-FsOpenStream :: 00:00:010 ms]%0a[S-FsGetStreamLength :: 00:00:009 ms]%0a[S-FsAppendStream
-          :: 00:00:063 ms]%0a[BufferingTime :: 00:00:000 ms]%0a[WriteTime :: 00:00:063
-          ms]%0a[S-FsAppendStream :: 00:00:017 ms]%0a[S-FsCloseHandle :: 00:00:001
-          ms]%0a[APPEND :: 00:00:104 ms]%0a']
+      Server-Perf: ['[3bba5c29-27ce-4dbf-bcb7-a340ea65cf90][ AuthTime::982.749706308372::PostAuthTime::233.926931832324
+          ][S-FsOpenStream :: 00:00:011 ms]%0a[S-FsAppendStream :: 00:00:066 ms]%0a[BufferingTime
+          :: 00:00:000 ms]%0a[WriteTime :: 00:00:067 ms]%0a[S-FsAppendStream :: 00:00:033
+          ms]%0a[S-FsCloseHandle :: 00:00:001 ms]%0a[APPEND :: 00:00:115 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [2a43de68-405f-4bb3-8eec-1201c2033dbe]
+      x-ms-request-id: [3bba5c29-27ce-4dbf-bcb7-a340ea65cf90]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 200, message: OK}
 - request:
@@ -152,20 +151,20 @@ interactions:
     method: GET
     uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir?OP=LISTSTATUS
   response:
-    body: {string: '{"FileStatuses":{"FileStatus":[{"length":13,"pathSuffix":"a","type":"FILE","blockSize":268435456,"accessTime":1473976982129,"modificationTime":1473976983807,"replication":1,"permission":"770","owner":"49b2f9ec-818a-49ca-9424-249e1f19f7d7","group":"49b2f9ec-818a-49ca-9424-249e1f19f7d7"}]}}'}
+    body: {string: '{"FileStatuses":{"FileStatus":[{"length":13,"pathSuffix":"a","type":"FILE","blockSize":268435456,"accessTime":1474565219213,"modificationTime":1474565220998,"replication":1,"permission":"770","owner":"49b2f9ec-818a-49ca-9424-249e1f19f7d7","group":"49b2f9ec-818a-49ca-9424-249e1f19f7d7"}]}}'}
     headers:
       Cache-Control: [no-cache]
       Content-Length: ['289']
       Content-Type: [application/json; charset=utf-8]
-      Date: ['Thu, 15 Sep 2016 22:03:03 GMT']
+      Date: ['Thu, 22 Sep 2016 17:27:01 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[c78e2edb-17ec-407f-a375-c2379e5e8334][ AuthTime::0::PostAuthTime::0
-          ][S-HdfsListStatus :: 00:00:012 ms]%0a[LISTSTATUS :: 00:00:013 ms]%0a']
+      Server-Perf: ['[7f1fb1e4-95fd-43cf-9045-02b31f05c754][ AuthTime::925.870489321484::PostAuthTime::212.543941428535
+          ][S-HdfsListStatus :: 00:00:012 ms]%0a[LISTSTATUS :: 00:00:012 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [c78e2edb-17ec-407f-a375-c2379e5e8334]
+      x-ms-request-id: [7f1fb1e4-95fd-43cf-9045-02b31f05c754]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 200, message: OK}
 - request:
@@ -176,23 +175,23 @@ interactions:
       Connection: [keep-alive]
       User-Agent: [python-requests/2.11.1]
     method: GET
-    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?OP=OPEN&offset=0&read=true&length=13
+    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?length=13&read=true&OP=OPEN&offset=0
   response:
     body: {string: 123--456--789}
     headers:
       Cache-Control: [no-cache]
       Content-Type: [application/octet-stream]
-      Date: ['Thu, 15 Sep 2016 22:03:03 GMT']
+      Date: ['Thu, 22 Sep 2016 17:27:01 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[ab167687-47a9-4d73-99b4-609357e6dd70][ AuthTime::0::PostAuthTime::0
-          ][S-FsOpenStream :: 00:00:013 ms]%0a[S-FsReadStream :: 00:00:020 ms]%0a[OPEN
-          :: 00:00:034 ms]%0a']
+      Server-Perf: ['[7480abfc-e2db-486b-b5de-2b470cebcadb][ AuthTime::1024.65983303519::PostAuthTime::264.290390991547
+          ][S-FsOpenStream :: 00:00:015 ms]%0a[S-FsReadStream :: 00:00:043 ms]%0a[OPEN
+          :: 00:00:060 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       Transfer-Encoding: [chunked]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [ab167687-47a9-4d73-99b4-609357e6dd70]
+      x-ms-request-id: [7480abfc-e2db-486b-b5de-2b470cebcadb]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 200, message: OK}
 - request:
@@ -211,15 +210,15 @@ interactions:
       Cache-Control: [no-cache]
       Content-Length: ['16']
       Content-Type: [application/json; charset=utf-8]
-      Date: ['Thu, 15 Sep 2016 22:03:04 GMT']
+      Date: ['Thu, 22 Sep 2016 17:27:01 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[5a14e236-e946-4444-b6c7-4f59a12b607f][ AuthTime::0::PostAuthTime::0
-          ][S-FsDelete :: 00:00:094 ms]%0a[DELETE :: 00:00:095 ms]%0a']
+      Server-Perf: ['[23d05587-c727-4452-bef5-871b7523b3fa][ AuthTime::1038.34388426999::PostAuthTime::250.605237307337
+          ][S-FsDelete :: 00:00:070 ms]%0a[DELETE :: 00:00:070 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [5a14e236-e946-4444-b6c7-4f59a12b607f]
+      x-ms-request-id: [23d05587-c727-4452-bef5-871b7523b3fa]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 200, message: OK}
 version: 1
diff --git a/tests/recordings/test_core/test_delimiters_newline.yaml b/tests/recordings/test_core/test_delimiters_newline.yaml
index 5aa0e59..61a6b54 100644
--- a/tests/recordings/test_core/test_delimiters_newline.yaml
+++ b/tests/recordings/test_core/test_delimiters_newline.yaml
@@ -10,27 +10,27 @@ interactions:
       Content-Length: ['4']
       User-Agent: [python-requests/2.11.1]
     method: PUT
-    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?OP=CREATE&overwrite=true&write=true
+    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?overwrite=true&OP=CREATE&write=true
   response:
     body: {string: ''}
     headers:
       Cache-Control: [no-cache]
       Content-Length: ['0']
       ContentLength: ['0']
-      Date: ['Thu, 15 Sep 2016 22:02:59 GMT']
+      Date: ['Thu, 22 Sep 2016 17:26:47 GMT']
       Expires: ['-1']
-      Location: ['https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?OP=CREATE&overwrite=true&write=true']
+      Location: ['https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?overwrite=true&OP=CREATE&write=true']
       Pragma: [no-cache]
-      Server-Perf: ['[3468f47f-3a22-4b3c-b8ab-c0bd8351ed34][ AuthTime::0::PostAuthTime::0
-          ][S-HdfsGetFileStatusV2 :: 00:00:006 ms]%0a[S-HdfsCheckAccess :: 00:00:002
-          ms]%0a[S-FsDelete :: 00:00:005 ms]%0a[S-FsOpenStream :: 00:00:066 ms]%0a[S-FsAppendStream
-          :: 00:00:422 ms]%0a[BufferingTime :: 00:00:000 ms]%0a[WriteTime :: 00:00:422
-          ms]%0a[S-FsAppendStream :: 00:00:033 ms]%0a[S-FsCloseHandle :: 00:00:001
-          ms]%0a[CREATE :: 00:00:542 ms]%0a']
+      Server-Perf: ['[b4ff5326-06a7-49db-9d87-262f3302232c][ AuthTime::1427.93911052095::PostAuthTime::403.278401084532
+          ][S-HdfsGetFileStatusV2 :: 00:00:008 ms]%0a[S-HdfsCheckAccess :: 00:00:003
+          ms]%0a[S-FsDelete :: 00:00:008 ms]%0a[S-FsOpenStream :: 00:00:048 ms]%0a[S-FsAppendStream
+          :: 00:00:138 ms]%0a[BufferingTime :: 00:00:000 ms]%0a[WriteTime :: 00:00:140
+          ms]%0a[S-FsAppendStream :: 00:00:030 ms]%0a[S-FsCloseHandle :: 00:00:002
+          ms]%0a[CREATE :: 00:00:257 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [3468f47f-3a22-4b3c-b8ab-c0bd8351ed34]
+      x-ms-request-id: [b4ff5326-06a7-49db-9d87-262f3302232c]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 201, message: Created}
 - request:
@@ -43,20 +43,20 @@ interactions:
     method: GET
     uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir?OP=LISTSTATUS
   response:
-    body: {string: '{"FileStatuses":{"FileStatus":[{"length":4,"pathSuffix":"a","type":"FILE","blockSize":268435456,"accessTime":1473976978898,"modificationTime":1473976979178,"replication":1,"permission":"770","owner":"49b2f9ec-818a-49ca-9424-249e1f19f7d7","group":"49b2f9ec-818a-49ca-9424-249e1f19f7d7"}]}}'}
+    body: {string: '{"FileStatuses":{"FileStatus":[{"length":4,"pathSuffix":"a","type":"FILE","blockSize":268435456,"accessTime":1474565207746,"modificationTime":1474565207873,"replication":1,"permission":"770","owner":"49b2f9ec-818a-49ca-9424-249e1f19f7d7","group":"49b2f9ec-818a-49ca-9424-249e1f19f7d7"}]}}'}
     headers:
       Cache-Control: [no-cache]
       Content-Length: ['288']
       Content-Type: [application/json; charset=utf-8]
-      Date: ['Thu, 15 Sep 2016 22:02:59 GMT']
+      Date: ['Thu, 22 Sep 2016 17:26:47 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[df0820eb-e785-44cb-b196-00a2c0d1b896][ AuthTime::0::PostAuthTime::0
-          ][S-HdfsListStatus :: 00:00:043 ms]%0a[LISTSTATUS :: 00:00:043 ms]%0a']
+      Server-Perf: ['[4bd98882-2c80-414b-aad6-a7cb03d6c1d1][ AuthTime::869.422417841078::PostAuthTime::205.702008352956
+          ][S-HdfsListStatus :: 00:00:023 ms]%0a[LISTSTATUS :: 00:00:023 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [df0820eb-e785-44cb-b196-00a2c0d1b896]
+      x-ms-request-id: [4bd98882-2c80-414b-aad6-a7cb03d6c1d1]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 200, message: OK}
 - request:
@@ -67,7 +67,7 @@ interactions:
       Connection: [keep-alive]
       User-Agent: [python-requests/2.11.1]
     method: GET
-    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?OP=OPEN&offset=0&read=true&length=4
+    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?read=true&length=4&OP=OPEN&offset=0
   response:
     body: {string: '123
 
@@ -75,17 +75,18 @@ interactions:
     headers:
       Cache-Control: [no-cache]
       Content-Type: [application/octet-stream]
-      Date: ['Thu, 15 Sep 2016 22:02:59 GMT']
+      Date: ['Thu, 22 Sep 2016 17:26:47 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[b66716fb-47e0-4665-9019-e938c4505793][ AuthTime::0::PostAuthTime::0
-          ][S-FsOpenStream :: 00:00:012 ms]%0a[S-FsReadStream :: 00:00:032 ms]%0a[OPEN
-          :: 00:00:045 ms]%0a']
+      Server-Perf: ['[84be60d5-353b-41ee-9ee9-bee7a748f054][ AuthTime::945.11612312511::PostAuthTime::209.978287988429
+          ][S-FsReadStream :: 00:00:004 ms]%0a[S-FsCloseHandle :: 00:00:001 ms]%0a[S-FsOpenStream
+          :: 00:00:013 ms]%0a[S-FsReadStream :: 00:00:014 ms]%0a[OPEN :: 00:00:033
+          ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       Transfer-Encoding: [chunked]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [b66716fb-47e0-4665-9019-e938c4505793]
+      x-ms-request-id: [84be60d5-353b-41ee-9ee9-bee7a748f054]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 200, message: OK}
 - request:
@@ -105,18 +106,18 @@ interactions:
     headers:
       Cache-Control: [no-cache]
       Content-Length: ['0']
-      Date: ['Thu, 15 Sep 2016 22:02:59 GMT']
+      Date: ['Thu, 22 Sep 2016 17:26:49 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[f0c87027-d206-44f2-81b0-9764fbff65b5][ AuthTime::0::PostAuthTime::0
-          ][S-FsOpenStream :: 00:00:010 ms]%0a[S-FsGetStreamLength :: 00:00:038 ms]%0a[S-FsAppendStream
-          :: 00:00:076 ms]%0a[BufferingTime :: 00:00:000 ms]%0a[WriteTime :: 00:00:076
-          ms]%0a[S-FsAppendStream :: 00:00:033 ms]%0a[S-FsCloseHandle :: 00:00:001
-          ms]%0a[APPEND :: 00:00:161 ms]%0a']
+      Server-Perf: ['[d3120b12-1e1c-4dd9-8dab-e234a934b51a][ AuthTime::939.983868884652::PostAuthTime::217.248319105279
+          ][S-FsOpenStream :: 00:00:010 ms]%0a[S-FsGetStreamLength :: 00:00:009 ms]%0a[S-FsAppendStream
+          :: 00:00:059 ms]%0a[BufferingTime :: 00:00:000 ms]%0a[WriteTime :: 00:00:059
+          ms]%0a[S-FsAppendStream :: 00:00:034 ms]%0a[S-FsCloseHandle :: 00:00:001
+          ms]%0a[APPEND :: 00:00:116 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [f0c87027-d206-44f2-81b0-9764fbff65b5]
+      x-ms-request-id: [d3120b12-1e1c-4dd9-8dab-e234a934b51a]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 200, message: OK}
 - request:
@@ -128,24 +129,23 @@ interactions:
       Content-Length: ['3']
       User-Agent: [python-requests/2.11.1]
     method: POST
-    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?OP=APPEND&append=true
+    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?offset=8&OP=APPEND&append=true
   response:
     body: {string: ''}
     headers:
       Cache-Control: [no-cache]
       Content-Length: ['0']
-      Date: ['Thu, 15 Sep 2016 22:03:00 GMT']
+      Date: ['Thu, 22 Sep 2016 17:26:49 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[77837b1a-c9de-4720-8fd3-f9a7aad83bad][ AuthTime::0::PostAuthTime::0
-          ][S-FsOpenStream :: 00:00:011 ms]%0a[S-FsGetStreamLength :: 00:00:009 ms]%0a[S-FsAppendStream
-          :: 00:00:202 ms]%0a[BufferingTime :: 00:00:000 ms]%0a[WriteTime :: 00:00:202
-          ms]%0a[S-FsAppendStream :: 00:00:033 ms]%0a[S-FsCloseHandle :: 00:00:001
-          ms]%0a[APPEND :: 00:00:258 ms]%0a']
+      Server-Perf: ['[915ea582-8aaf-48b1-825a-8907e22849ae][ AuthTime::0::PostAuthTime::0
+          ][S-FsOpenStream :: 00:00:012 ms]%0a[S-FsAppendStream :: 00:00:067 ms]%0a[BufferingTime
+          :: 00:00:000 ms]%0a[WriteTime :: 00:00:067 ms]%0a[S-FsAppendStream :: 00:00:033
+          ms]%0a[S-FsCloseHandle :: 00:00:003 ms]%0a[APPEND :: 00:00:120 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [77837b1a-c9de-4720-8fd3-f9a7aad83bad]
+      x-ms-request-id: [915ea582-8aaf-48b1-825a-8907e22849ae]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 200, message: OK}
 - request:
@@ -158,20 +158,20 @@ interactions:
     method: GET
     uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir?OP=LISTSTATUS
   response:
-    body: {string: '{"FileStatuses":{"FileStatus":[{"length":11,"pathSuffix":"a","type":"FILE","blockSize":268435456,"accessTime":1473976978898,"modificationTime":1473976980788,"replication":1,"permission":"770","owner":"49b2f9ec-818a-49ca-9424-249e1f19f7d7","group":"49b2f9ec-818a-49ca-9424-249e1f19f7d7"}]}}'}
+    body: {string: '{"FileStatuses":{"FileStatus":[{"length":11,"pathSuffix":"a","type":"FILE","blockSize":268435456,"accessTime":1474565207746,"modificationTime":1474565209358,"replication":1,"permission":"770","owner":"49b2f9ec-818a-49ca-9424-249e1f19f7d7","group":"49b2f9ec-818a-49ca-9424-249e1f19f7d7"}]}}'}
     headers:
       Cache-Control: [no-cache]
       Content-Length: ['289']
       Content-Type: [application/json; charset=utf-8]
-      Date: ['Thu, 15 Sep 2016 22:03:01 GMT']
+      Date: ['Thu, 22 Sep 2016 17:26:48 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[1aa2d082-7c23-4438-9da0-af2d9978cee2][ AuthTime::0::PostAuthTime::0
-          ][S-HdfsListStatus :: 00:00:142 ms]%0a[LISTSTATUS :: 00:00:142 ms]%0a']
+      Server-Perf: ['[6599b907-b64c-46cb-9f3a-72670ca12a59][ AuthTime::897.219219137027::PostAuthTime::196.293432594802
+          ][S-HdfsListStatus :: 00:00:012 ms]%0a[LISTSTATUS :: 00:00:012 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [1aa2d082-7c23-4438-9da0-af2d9978cee2]
+      x-ms-request-id: [6599b907-b64c-46cb-9f3a-72670ca12a59]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 200, message: OK}
 - request:
@@ -182,7 +182,7 @@ interactions:
       Connection: [keep-alive]
       User-Agent: [python-requests/2.11.1]
     method: GET
-    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?OP=OPEN&offset=0&read=true&length=11
+    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?read=true&length=11&OP=OPEN&offset=0
   response:
     body: {string: '123
 
@@ -192,17 +192,17 @@ interactions:
     headers:
       Cache-Control: [no-cache]
       Content-Type: [application/octet-stream]
-      Date: ['Thu, 15 Sep 2016 22:03:01 GMT']
+      Date: ['Thu, 22 Sep 2016 17:26:49 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[881a9734-496b-4d27-aa99-fa2dc5efb037][ AuthTime::0::PostAuthTime::0
-          ][S-FsOpenStream :: 00:00:012 ms]%0a[S-FsReadStream :: 00:00:015 ms]%0a[OPEN
-          :: 00:00:027 ms]%0a']
+      Server-Perf: ['[b8c119f4-2fa0-46af-a71f-cce6b98ee32a][ AuthTime::942.979867700566::PostAuthTime::224.091360850384
+          ][S-FsOpenStream :: 00:00:013 ms]%0a[S-FsReadStream :: 00:00:026 ms]%0a[OPEN
+          :: 00:00:039 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       Transfer-Encoding: [chunked]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [881a9734-496b-4d27-aa99-fa2dc5efb037]
+      x-ms-request-id: [b8c119f4-2fa0-46af-a71f-cce6b98ee32a]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 200, message: OK}
 - request:
@@ -221,15 +221,15 @@ interactions:
       Cache-Control: [no-cache]
       Content-Length: ['16']
       Content-Type: [application/json; charset=utf-8]
-      Date: ['Thu, 15 Sep 2016 22:03:01 GMT']
+      Date: ['Thu, 22 Sep 2016 17:26:49 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[019b2891-2e07-491d-82d2-268961387631][ AuthTime::0::PostAuthTime::0
-          ][S-FsDelete :: 00:00:071 ms]%0a[DELETE :: 00:00:073 ms]%0a']
+      Server-Perf: ['[8362c403-6b73-4a79-9b72-d47331d2480d][ AuthTime::0::PostAuthTime::0
+          ][S-FsDelete :: 00:00:082 ms]%0a[DELETE :: 00:00:090 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [019b2891-2e07-491d-82d2-268961387631]
+      x-ms-request-id: [8362c403-6b73-4a79-9b72-d47331d2480d]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 200, message: OK}
 version: 1
diff --git a/tests/recordings/test_core/test_write_blocks.yaml b/tests/recordings/test_core/test_write_blocks.yaml
index cfdc502..8c684d5 100644
--- a/tests/recordings/test_core/test_write_blocks.yaml
+++ b/tests/recordings/test_core/test_write_blocks.yaml
@@ -15,20 +15,20 @@ interactions:
       Cache-Control: [no-cache]
       Content-Length: ['0']
       ContentLength: ['0']
-      Date: ['Thu, 15 Sep 2016 22:02:46 GMT']
+      Date: ['Thu, 22 Sep 2016 17:25:36 GMT']
       Expires: ['-1']
       Location: ['https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?OP=CREATE&overwrite=true&write=true']
       Pragma: [no-cache]
-      Server-Perf: ['[f4145160-ca39-4c02-b9f0-a23d0b1a4f69][ AuthTime::0::PostAuthTime::0
-          ][S-HdfsGetFileStatusV2 :: 00:00:007 ms]%0a[S-HdfsCheckAccess :: 00:00:002
-          ms]%0a[S-FsDelete :: 00:00:006 ms]%0a[S-FsOpenStream :: 00:00:075 ms]%0a[S-FsAppendStream
-          :: 00:00:216 ms]%0a[BufferingTime :: 00:00:000 ms]%0a[WriteTime :: 00:00:216
-          ms]%0a[S-FsAppendStream :: 00:00:033 ms]%0a[S-FsCloseHandle :: 00:00:001
-          ms]%0a[CREATE :: 00:00:346 ms]%0a']
+      Server-Perf: ['[c8fad1e0-4391-40ec-96c7-611833aa59b3][ AuthTime::839.912433569299::PostAuthTime::165.502093580101
+          ][S-HdfsGetFileStatusV2 :: 00:00:006 ms]%0a[S-HdfsCheckAccess :: 00:00:002
+          ms]%0a[S-FsDelete :: 00:00:006 ms]%0a[S-FsOpenStream :: 00:00:047 ms]%0a[S-FsAppendStream
+          :: 00:00:169 ms]%0a[BufferingTime :: 00:00:000 ms]%0a[WriteTime :: 00:00:169
+          ms]%0a[S-FsAppendStream :: 00:00:032 ms]%0a[S-FsCloseHandle :: 00:00:001
+          ms]%0a[CREATE :: 00:00:276 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [f4145160-ca39-4c02-b9f0-a23d0b1a4f69]
+      x-ms-request-id: [c8fad1e0-4391-40ec-96c7-611833aa59b3]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 201, message: Created}
 - request:
@@ -40,24 +40,23 @@ interactions:
       Content-Length: ['1']
       User-Agent: [python-requests/2.11.1]
     method: POST
-    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?OP=APPEND&append=true
+    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?OP=APPEND&offset=5&append=true
   response:
     body: {string: ''}
     headers:
       Cache-Control: [no-cache]
       Content-Length: ['0']
-      Date: ['Thu, 15 Sep 2016 22:02:47 GMT']
+      Date: ['Thu, 22 Sep 2016 17:25:36 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[ad6da152-dfc0-4d7e-9d05-90a98fe7cf81][ AuthTime::0::PostAuthTime::0
-          ][S-FsOpenStream :: 00:00:014 ms]%0a[S-FsGetStreamLength :: 00:00:282 ms]%0a[S-FsAppendStream
-          :: 00:00:187 ms]%0a[BufferingTime :: 00:00:000 ms]%0a[WriteTime :: 00:00:188
-          ms]%0a[S-FsAppendStream :: 00:00:033 ms]%0a[S-FsCloseHandle :: 00:00:006
-          ms]%0a[APPEND :: 00:00:528 ms]%0a']
+      Server-Perf: ['[598dfe00-2b91-42d6-b81d-d4e3dee406fc][ AuthTime::921.168661106583::PostAuthTime::214.68276131639
+          ][S-FsOpenStream :: 00:00:010 ms]%0a[S-FsAppendStream :: 00:00:061 ms]%0a[BufferingTime
+          :: 00:00:000 ms]%0a[WriteTime :: 00:00:061 ms]%0a[S-FsAppendStream :: 00:00:033
+          ms]%0a[S-FsCloseHandle :: 00:00:001 ms]%0a[APPEND :: 00:00:107 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [ad6da152-dfc0-4d7e-9d05-90a98fe7cf81]
+      x-ms-request-id: [598dfe00-2b91-42d6-b81d-d4e3dee406fc]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 200, message: OK}
 - request:
@@ -69,24 +68,23 @@ interactions:
       Content-Length: ['3']
       User-Agent: [python-requests/2.11.1]
     method: POST
-    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?OP=APPEND&append=true
+    uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?OP=APPEND&offset=6&append=true
   response:
     body: {string: ''}
     headers:
       Cache-Control: [no-cache]
       Content-Length: ['0']
-      Date: ['Thu, 15 Sep 2016 22:02:47 GMT']
+      Date: ['Thu, 22 Sep 2016 17:25:36 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[8fdbd508-a9ce-4190-b57b-ff2075f9ad56][ AuthTime::0::PostAuthTime::0
-          ][S-FsOpenStream :: 00:00:010 ms]%0a[S-FsGetStreamLength :: 00:00:009 ms]%0a[S-FsAppendStream
-          :: 00:00:062 ms]%0a[BufferingTime :: 00:00:000 ms]%0a[WriteTime :: 00:00:063
-          ms]%0a[S-FsAppendStream :: 00:00:033 ms]%0a[S-FsCloseHandle :: 00:00:001
-          ms]%0a[APPEND :: 00:00:119 ms]%0a']
+      Server-Perf: ['[ac0cefa5-5596-48c6-b74c-2c6d1684477c][ AuthTime::0::PostAuthTime::0
+          ][S-FsOpenStream :: 00:00:010 ms]%0a[S-FsAppendStream :: 00:00:053 ms]%0a[BufferingTime
+          :: 00:00:000 ms]%0a[WriteTime :: 00:00:054 ms]%0a[S-FsAppendStream :: 00:00:032
+          ms]%0a[S-FsCloseHandle :: 00:00:001 ms]%0a[APPEND :: 00:00:098 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [8fdbd508-a9ce-4190-b57b-ff2075f9ad56]
+      x-ms-request-id: [ac0cefa5-5596-48c6-b74c-2c6d1684477c]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 200, message: OK}
 - request:
@@ -99,20 +97,20 @@ interactions:
     method: GET
     uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir/a?OP=LISTSTATUS
   response:
-    body: {string: '{"FileStatuses":{"FileStatus":[{"length":9,"pathSuffix":"","type":"FILE","blockSize":268435456,"accessTime":1473976967207,"modificationTime":1473976968639,"replication":1,"permission":"770","owner":"49b2f9ec-818a-49ca-9424-249e1f19f7d7","group":"49b2f9ec-818a-49ca-9424-249e1f19f7d7"}]}}'}
+    body: {string: '{"FileStatuses":{"FileStatus":[{"length":9,"pathSuffix":"","type":"FILE","blockSize":268435456,"accessTime":1474565136602,"modificationTime":1474565137580,"replication":1,"permission":"770","owner":"49b2f9ec-818a-49ca-9424-249e1f19f7d7","group":"49b2f9ec-818a-49ca-9424-249e1f19f7d7"}]}}'}
     headers:
       Cache-Control: [no-cache]
       Content-Length: ['287']
       Content-Type: [application/json; charset=utf-8]
-      Date: ['Thu, 15 Sep 2016 22:02:48 GMT']
+      Date: ['Thu, 22 Sep 2016 17:25:37 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[ed6d9f2e-67f0-4b8e-a690-add553e8f1a0][ AuthTime::0::PostAuthTime::0
-          ][S-HdfsListStatus :: 00:00:009 ms]%0a[LISTSTATUS :: 00:00:010 ms]%0a']
+      Server-Perf: ['[e58f478b-92bd-4414-b49e-ff80d0013040][ AuthTime::1122.16550572715::PostAuthTime::246.329013452301
+          ][S-HdfsListStatus :: 00:00:065 ms]%0a[LISTSTATUS :: 00:00:065 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [ed6d9f2e-67f0-4b8e-a690-add553e8f1a0]
+      x-ms-request-id: [e58f478b-92bd-4414-b49e-ff80d0013040]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 200, message: OK}
 - request:
@@ -125,20 +123,20 @@ interactions:
     method: GET
     uri: https://fakestore.azuredatalakestore.net/webhdfs/v1/azure_test_dir?OP=LISTSTATUS
   response:
-    body: {string: '{"FileStatuses":{"FileStatus":[{"length":9,"pathSuffix":"a","type":"FILE","blockSize":268435456,"accessTime":1473976967207,"modificationTime":1473976968639,"replication":1,"permission":"770","owner":"49b2f9ec-818a-49ca-9424-249e1f19f7d7","group":"49b2f9ec-818a-49ca-9424-249e1f19f7d7"}]}}'}
+    body: {string: '{"FileStatuses":{"FileStatus":[{"length":9,"pathSuffix":"a","type":"FILE","blockSize":268435456,"accessTime":1474565136602,"modificationTime":1474565137580,"replication":1,"permission":"770","owner":"49b2f9ec-818a-49ca-9424-249e1f19f7d7","group":"49b2f9ec-818a-49ca-9424-249e1f19f7d7"}]}}'}
     headers:
       Cache-Control: [no-cache]
       Content-Length: ['288']
       Content-Type: [application/json; charset=utf-8]
-      Date: ['Thu, 15 Sep 2016 22:02:48 GMT']
+      Date: ['Thu, 22 Sep 2016 17:25:37 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[45f65a84-9f70-4b9c-a721-17a33b27b91a][ AuthTime::0::PostAuthTime::0
-          ][S-HdfsListStatus :: 00:00:012 ms]%0a[LISTSTATUS :: 00:00:012 ms]%0a']
+      Server-Perf: ['[1f4fb44e-035d-4792-9999-793bf9653f40][ AuthTime::880.539185918215::PostAuthTime::201.424942480563
+          ][S-HdfsListStatus :: 00:00:011 ms]%0a[LISTSTATUS :: 00:00:012 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [45f65a84-9f70-4b9c-a721-17a33b27b91a]
+      x-ms-request-id: [1f4fb44e-035d-4792-9999-793bf9653f40]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 200, message: OK}
 - request:
@@ -157,15 +155,15 @@ interactions:
       Cache-Control: [no-cache]
       Content-Length: ['16']
       Content-Type: [application/json; charset=utf-8]
-      Date: ['Thu, 15 Sep 2016 22:02:49 GMT']
+      Date: ['Thu, 22 Sep 2016 17:25:38 GMT']
       Expires: ['-1']
       Pragma: [no-cache]
-      Server-Perf: ['[f1cf1b88-499d-4925-8802-08e7f76501ec][ AuthTime::0::PostAuthTime::0
-          ][S-FsDelete :: 00:00:098 ms]%0a[DELETE :: 00:00:099 ms]%0a']
+      Server-Perf: ['[53d291bc-b35b-4c98-b65f-2263b4815167][ AuthTime::1484.81718829851::PostAuthTime::505.060224475963
+          ][S-FsDelete :: 00:00:078 ms]%0a[DELETE :: 00:00:087 ms]%0a']
       Status: ['0x0']
       Strict-Transport-Security: [max-age=15724800; includeSubDomains]
       X-Content-Type-Options: [nosniff]
-      x-ms-request-id: [f1cf1b88-499d-4925-8802-08e7f76501ec]
+      x-ms-request-id: [53d291bc-b35b-4c98-b65f-2263b4815167]
       x-ms-webhdfs-version: [16.07.18.01]
     status: {code: 200, message: OK}
 version: 1
diff --git a/tests/test_transfer.py b/tests/test_transfer.py
index 0474ae0..f160380 100644
--- a/tests/test_transfer.py
+++ b/tests/test_transfer.py
@@ -6,11 +6,13 @@
 # license information.
 # --------------------------------------------------------------------------
 
+import os
 import pytest
 import time
 
-from tests.testing import azure, posix
+from adlfs.core import AzureDLPath
 from adlfs.transfer import ADLTransferClient
+from tests.testing import azure, posix
 
 
 @pytest.mark.skipif(True, reason="skip until resolve timing issue")
@@ -18,6 +20,7 @@ def test_interrupt(azure):
     def transfer(adlfs, src, dst, offset, size, retries=5, shutdown_event=None):
         while shutdown_event and not shutdown_event.is_set():
             time.sleep(0.1)
+        return size, None
 
     client = ADLTransferClient(azure, 'foobar', transfer=transfer, chunksize=1,
                                tmp_path=None)
@@ -30,9 +33,45 @@ def test_interrupt(azure):
     assert client.progress[0].state != 'finished'
 
 
+def test_submit_and_run(azure):
+    def transfer(adlfs, src, dst, offset, size, retries=5, shutdown_event=None):
+        time.sleep(0.1)
+        return size, None
+
+    client = ADLTransferClient(azure, 'foobar', transfer=transfer, chunksize=8,
+                               tmp_path=None)
+
+    client.submit('foo', 'bar', 16)
+    client.submit('abc', '123', 8)
+
+    nfiles = len(client.progress)
+    assert nfiles == 2
+    assert len([client.progress[i].chunks for i in range(nfiles)])
+
+    assert all([client.progress[i].state == 'pending' for i in range(nfiles)])
+    assert all([chunk.state == 'pending' for f in client.progress
+                                         for chunk in f.chunks])
+
+    expected = {('bar', 0), ('bar', 8), ('123', 0)}
+    assert {(chunk.name, chunk.offset) for f in client.progress
+                                       for chunk in f.chunks} == expected
+
+    client.run()
+
+    assert all([client.progress[i].state == 'finished' for i in range(nfiles)])
+    assert all([chunk.state == 'finished' for f in client.progress
+                                          for chunk in f.chunks])
+    assert all([chunk.expected == chunk.actual for f in client.progress
+                                               for chunk in f.chunks])
+
+
 def test_temporary_path(azure):
     def transfer(adlfs, src, dst, offset, size):
-        pass
+        time.sleep(0.1)
+        return size, None
+
+    client = ADLTransferClient(azure, 'foobar', transfer=transfer, chunksize=8,
+                               tmp_unique=False)
+    client.submit('foo', AzureDLPath('bar'), 16)
 
-    client = ADLTransferClient(azure, 'foobar', transfer=transfer, tmp_unique=False)
-    assert posix(client.temporary_path) == '/tmp'
+    assert os.path.dirname(posix(client.progress[0].chunks[0].name)) == '/tmp'