@Override
    public AttributedList<Path> list(final Path file, final ListProgressListener listener) throws BackgroundException {
        if(file.isDirectory()) {
            return AttributedList.emptyList();
        }
        try {
            final AttributedList<Path> versions = new AttributedList<>();
            String page = null;
            do {
                final RevisionList list = session.getClient().revisions().list(fileid.getFileId(file))
                        .setFields(DEFAULT_FIELDS)
                        .setPageSize(new HostPreferences(session.getHost()).getInteger("googledrive.list.limit"))
                        .setPageToken(page).execute();
                for(Iterator<Revision> iter = list.getRevisions().iterator(); iter.hasNext(); ) {
                    final Revision revision = iter.next();
                    if(!iter.hasNext()) {
                        // Skip latest revision equals current version
                        if(revision.getMd5Checksum().equals(file.attributes().getChecksum().hash)) {
                            continue;
                        }
                    }
                    if(log.isDebugEnabled()) {
                        log.debug(String.format("Found revision %s", revision));
                    }
                    versions.add(new Path(file).withAttributes(this.toAttributes(revision)));
                    listener.chunk(file.getParent(), versions);
                }
                page = list.getNextPageToken();
            }
            while(page != null);
            return versions.filter(new TimestampComparator(false));
        }
        catch(IOException e) {
            throw new DriveExceptionMappingService(fileid).map("Failure to read attributes of {0}", e, file);
        }
    }
@Test
    public void testList() throws Exception {
        final DriveFileIdProvider fileid = new DriveFileIdProvider(session);
        final Path room = new DriveDirectoryFeature(session, fileid).mkdir(
                new Path(MYDRIVE_FOLDER, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)), new TransferStatus());
        final DriveAttributesFinderFeature attr = new DriveAttributesFinderFeature(session, fileid);
        final Path test = new DriveTouchFeature(session, fileid).touch(new Path(room, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)), new TransferStatus());
        assertEquals(test.attributes().getVersionId(), attr.find(test).getVersionId());
        final DriveVersioningFeature feature = new DriveVersioningFeature(session, fileid);
        assertEquals(0, feature.list(test, new DisabledListProgressListener()).size());
        final PathAttributes initialAttributes = new PathAttributes(test.attributes());
        {
            final byte[] content = RandomUtils.nextBytes(32769);
            final TransferStatus status = new TransferStatus();
            status.setLength(content.length);
            status.setExists(true);
            final DriveWriteFeature writer = new DriveWriteFeature(session, fileid);
            final StatusOutputStream<File> out = writer.write(test, status, new DisabledConnectionCallback());
            new StreamCopier(status, status).transfer(new ByteArrayInputStream(content), out);
            assertNull(attr.toAttributes(out.getStatus()).getVersionId());
            final AttributedList<Path> versions = feature.list(test.withAttributes(attr.toAttributes(out.getStatus())), new DisabledListProgressListener());
            assertEquals(1, versions.size());
            assertEquals(initialAttributes.getChecksum(), versions.get(0).attributes().getChecksum());
            final PathAttributes updated = attr.find(test.withAttributes(attr.toAttributes(out.getStatus())));
            assertNotEquals(initialAttributes.getChecksum(), updated.getChecksum());
        }
        {
            final byte[] content = RandomUtils.nextBytes(1647);
            final TransferStatus status = new TransferStatus();
            status.setLength(content.length);
            status.setExists(true);
            final DriveWriteFeature writer = new DriveWriteFeature(session, fileid);
            final StatusOutputStream<File> out = writer.write(test, status, new DisabledConnectionCallback());
            new StreamCopier(status, status).transfer(new ByteArrayInputStream(content), out);
            assertNull(attr.toAttributes(out.getStatus()).getVersionId());
            final List<Path> versions = feature.list(test.withAttributes(attr.toAttributes(out.getStatus())), new DisabledListProgressListener()).toList();
            assertEquals(32769L, versions.get(0).attributes().getSize());
            assertEquals(0L, versions.get(1).attributes().getSize());
        }
        // Delete versions permanently
        final AttributedList<Path> versions = feature.list(test.withAttributes(attr.find(test)), new DisabledListProgressListener());
        for(Path d : versions.toList()) {
            assertTrue(new DriveThresholdDeleteFeature(session, fileid).isSupported(d));
            assertTrue(new DriveBatchDeleteFeature(session, fileid).isSupported(d));
            assertTrue(new DriveDeleteFeature(session, fileid).isSupported(d));
        }
        new DriveDeleteFeature(session, fileid).delete(versions.toList(), new DisabledPasswordCallback(), new Delete.DisabledCallback());
        for(Path version : new DriveListService(session, fileid).list(room, new DisabledListProgressListener())) {
            new DriveDeleteFeature(session, fileid).delete(Collections.singletonList(version), new DisabledLoginCallback(), new Delete.DisabledCallback());
        }
        new DriveDeleteFeature(session, fileid).delete(Collections.singletonList(room), new DisabledLoginCallback(), new Delete.DisabledCallback());
    }