protected String getNodeId(final Path file, final int chunksize) throws BackgroundException {
        if(file.isRoot()) {
            return ROOT_NODE_ID;
        }
        try {
            final String type;
            if(file.isDirectory()) {
                type = "room:folder";
            }
            else {
                type = "file";
            }
            // Top-level nodes only

            int offset = 0;
            NodeList nodes;
            do {
                if(StringUtils.isNoneBlank(file.getParent().attributes().getVersionId())) {
                    nodes = new NodesApi(session.getClient()).searchNodes(
                            URIEncoder.encode(normalizer.normalize(file.getName()).toString()),
                            StringUtils.EMPTY, 0, Long.valueOf(file.getParent().attributes().getVersionId()),
                            String.format("type:eq:%s", type),
                            null, offset, chunksize, null);
                }
                else {
                    nodes = new NodesApi(session.getClient()).searchNodes(
                            URIEncoder.encode(normalizer.normalize(file.getName()).toString()),
                            StringUtils.EMPTY, -1, null,
                            String.format("type:eq:%s|parentPath:eq:%s/", type, file.getParent().isRoot() ? StringUtils.EMPTY : file.getParent().getAbsolute()),
                            null, offset, chunksize, null);
                }
                for(Node node : nodes.getItems()) {
                    // Case-insensitive
                    if(node.getName().equalsIgnoreCase(normalizer.normalize(file.getName()).toString())) {
                        if(log.isInfoEnabled()) {
                            log.info(String.format("Return node %s for file %s", node.getId(), file));
                        }
                        return this.cache(file, node.getId().toString());
                    }
                }
                offset += chunksize;
            }
            while(nodes.getItems().size() == chunksize);
            throw new NotfoundException(file.getAbsolute());
        }
        catch(ApiException e) {
            throw new SDSExceptionMappingService(this).map("Failure to read attributes of {0}", e, file);
        }
    }
@Test
    public void getFileIdFile() throws Exception {
        final SDSNodeIdProvider nodeid = new SDSNodeIdProvider(session);
        final Path room = new SDSDirectoryFeature(session, nodeid).mkdir(new Path(new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory, Path.Type.volume)), new TransferStatus());
        final String name = String.format("%s%s", new AlphanumericRandomStringService().random(), new AlphanumericRandomStringService().random());
        final Path file = new SDSTouchFeature(session, nodeid).touch(new Path(room, name, EnumSet.of(Path.Type.file)), new TransferStatus());
        nodeid.clear();
        final String nodeId = nodeid.getNodeId(new Path(room, name, EnumSet.of(Path.Type.file)), 1);
        assertNotNull(nodeId);
        assertEquals(nodeId, nodeid.getNodeId(new Path(room.withAttributes(PathAttributes.EMPTY), name, EnumSet.of(Path.Type.file)), 1));
        assertEquals(nodeId, nodeid.getNodeId(new Path(room, StringUtils.upperCase(name), EnumSet.of(Path.Type.file)), 1));
        assertEquals(nodeId, nodeid.getNodeId(new Path(room, StringUtils.lowerCase(name), EnumSet.of(Path.Type.file)), 1));
        try {
            assertNull(nodeid.getNodeId(new Path(room, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)), 1));
            fail();
        }
        catch(NotfoundException e) {
            // Expected
        }
        try {
            assertNull(nodeid.getNodeId(new Path(room, name, EnumSet.of(Path.Type.directory)), 1));
            fail();
        }
        catch(NotfoundException e) {
            // Expected
        }
        new SDSDeleteFeature(session, nodeid).delete(Arrays.asList(file, room), new DisabledLoginCallback(), new Delete.DisabledCallback());
    }