org.eclipse.che.api.vfs.TarArchiverTest.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.che.api.vfs.TarArchiverTest.java

Source

/*******************************************************************************
 * Copyright (c) 2012-2017 Codenvy, S.A.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *   Codenvy, S.A. - initial API and implementation
 *******************************************************************************/
package org.eclipse.che.api.vfs;

import com.google.common.io.ByteStreams;

import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.eclipse.che.api.core.ConflictException;
import org.eclipse.che.api.core.ForbiddenException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.util.FileCleaner;
import org.eclipse.che.api.vfs.impl.file.LocalVirtualFileSystem;
import org.eclipse.che.api.vfs.search.Searcher;
import org.eclipse.che.api.vfs.search.SearcherProvider;
import org.eclipse.che.commons.lang.IoUtil;
import org.eclipse.che.commons.lang.NameGenerator;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;

import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.newHashMap;
import static java.util.stream.Collectors.toMap;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class TarArchiverTest {
    @Rule
    public ExpectedException thrown = ExpectedException.none();

    private static final String TEST_CONTENT = "___TEST___";
    private static final byte[] TEST_CONTENT_BYTES = TEST_CONTENT.getBytes();

    private File testDirectory;
    private VirtualFile vfsRoot;

    @Before
    public void setUp() throws Exception {
        File targetDir = new File(Thread.currentThread().getContextClassLoader().getResource(".").getPath())
                .getParentFile();
        testDirectory = new File(targetDir, NameGenerator.generate("fs-", 4));
        assertTrue(testDirectory.mkdir());

        SearcherProvider searcherProvider = mock(SearcherProvider.class);
        Searcher searcher = mock(Searcher.class);
        VirtualFileSystem virtualFileSystem = new LocalVirtualFileSystem(testDirectory, mock(ArchiverFactory.class),
                searcherProvider, mock(AbstractVirtualFileSystemProvider.CloseCallback.class));
        when(searcherProvider.getSearcher(eq(virtualFileSystem), eq(true))).thenReturn(searcher);
        when(searcherProvider.getSearcher(eq(virtualFileSystem))).thenReturn(searcher);
        vfsRoot = virtualFileSystem.getRoot();
    }

    @After
    public void tearDown() throws Exception {
        IoUtil.deleteRecursive(testDirectory);
        FileCleaner.stop();
    }

    @Test
    public void compressesFolderToArchive() throws Exception {
        VirtualFile folder = createFileTreeForArchiving();
        ByteArrayOutputStream compressedFolder = new ByteArrayOutputStream();
        Map<String, String> entries = getFileTreeAsList(folder).stream()
                .collect(toMap(f -> getTarEntryName(folder, f), this::readContentUnchecked));

        new TarArchiver(folder).compress(compressedFolder);
        assertThatTarArchiveContainsAllEntries(new ByteArrayInputStream(compressedFolder.toByteArray()), entries);
    }

    @Test
    public void compressesFolderToArchiveWithFilter() throws Exception {
        VirtualFile folder = createFileTreeForArchiving();
        ByteArrayOutputStream compressedFolder = new ByteArrayOutputStream();
        Map<String, String> entries = getFileTreeAsList(folder).stream()
                .filter(f -> f.isFolder() || f.getName().equals("_a.txt"))
                .collect(toMap(f -> getTarEntryName(folder, f), this::readContentUnchecked));

        new TarArchiver(folder).compress(compressedFolder, f -> f.isFolder() || f.getName().equals("_a.txt"));
        assertThatTarArchiveContainsAllEntries(new ByteArrayInputStream(compressedFolder.toByteArray()), entries);
    }

    @Test
    public void extractsArchiveToFolder() throws Exception {
        byte[] archive = createTestTarArchive();
        VirtualFile folder = vfsRoot.createFolder("folder");
        new TarArchiver(folder).extract(new ByteArrayInputStream(archive), false, 0);

        Map<String, String> entries = getFileTreeAsList(folder).stream()
                .collect(toMap(f -> getTarEntryName(folder, f), this::readContentUnchecked));

        assertEquals(readArchiveEntries(new ByteArrayInputStream(archive)), entries);
    }

    @Test
    public void extractsArchiveToFolderAndSkipsRootFolderFromArchive() throws Exception {
        byte[] archive = createTestTarArchive();
        VirtualFile folder = vfsRoot.createFolder("folder");
        new TarArchiver(folder).extract(new ByteArrayInputStream(archive), false, 1);

        Map<String, String> entries = getFileTreeAsList(folder).stream()
                .collect(toMap(f -> getTarEntryName(folder, f), this::readContentUnchecked));

        Map<String, String> originalArchiveEntriesWithoutFirstPathSegment = readArchiveEntries(
                new ByteArrayInputStream(archive)).entrySet().stream().filter(e -> !"arc/".equals(e.getKey()))
                        .collect(toMap(e -> e.getKey().replace("arc/", ""), Map.Entry::getValue));
        assertEquals(originalArchiveEntriesWithoutFirstPathSegment, entries);
    }

    @Test
    public void extractsArchiveToFolderAndOverwriteExistedFiles() throws Exception {
        byte[] archive = createTestTarArchive();
        VirtualFile folder = vfsRoot.createFolder("folder");
        VirtualFile arc = folder.createFolder("arc");
        VirtualFile fileOne = arc.createFolder("a").createFile("_a.txt", "xxx");
        VirtualFile fileTwo = arc.createFolder("b").createFile("_b.txt", "zzz");
        new TarArchiver(folder).extract(new ByteArrayInputStream(archive), true, 0);

        Map<String, String> entries = getFileTreeAsList(folder).stream()
                .collect(toMap(f -> getTarEntryName(folder, f), this::readContentUnchecked));

        assertEquals(readArchiveEntries(new ByteArrayInputStream(archive)), entries);
        assertEquals(TEST_CONTENT, fileOne.getContentAsString());
        assertEquals(TEST_CONTENT, fileTwo.getContentAsString());
    }

    @Test
    public void failsExtractArchiveToFolderWhenItContainsItemWithSameNameAndOverwritingIsDisabled()
            throws Exception {
        byte[] archive = createTestTarArchive();
        VirtualFile folder = vfsRoot.createFolder("folder");
        VirtualFile arc = folder.createFolder("arc");
        VirtualFile lockedFile = arc.createFolder("a").createFile("_a.txt", "xxx");

        try {
            new TarArchiver(folder).extract(new ByteArrayInputStream(archive), false, 0);
            thrown.expect(ConflictException.class);
        } catch (ConflictException expected) {
            assertEquals("xxx", lockedFile.getContentAsString());
        }
    }

    @Test
    public void failsExtractArchiveToFolderWhenItContainsLockedFile() throws Exception {
        byte[] archive = createTestTarArchive();
        VirtualFile folder = vfsRoot.createFolder("folder");
        VirtualFile arc = folder.createFolder("arc");
        VirtualFile lockedFile = arc.createFolder("a").createFile("_a.txt", "xxx");
        lockedFile.lock(0);

        try {
            new TarArchiver(folder).extract(new ByteArrayInputStream(archive), true, 0);
            thrown.expect(ForbiddenException.class);
        } catch (ForbiddenException expected) {
            assertEquals("xxx", lockedFile.getContentAsString());
        }
    }

    private Map<String, String> readArchiveEntries(InputStream archive) throws Exception {
        Map<String, String> entries = newHashMap();
        try (TarArchiveInputStream tarIn = new TarArchiveInputStream(archive)) {
            TarArchiveEntry tarArchiveEntry;
            while ((tarArchiveEntry = tarIn.getNextTarEntry()) != null) {
                String name = tarArchiveEntry.getName();
                String content = tarArchiveEntry.isDirectory() ? "<none>"
                        : new String(ByteStreams.toByteArray(tarIn));
                entries.put(name, content);
            }
        }
        return entries;
    }

    private String readContentUnchecked(VirtualFile virtualFile) {
        if (virtualFile.isFolder()) {
            return "<none>";
        }
        try {
            return virtualFile.getContentAsString();
        } catch (ForbiddenException | ServerException e) {
            throw new RuntimeException(e);
        }
    }

    private String getTarEntryName(VirtualFile folderForArchiving, VirtualFile archiveItem) {
        String entryName = archiveItem.getPath().subPath(folderForArchiving.getPath()).toString();
        if (archiveItem.isFolder()) {
            entryName += "/";
        }
        return entryName;
    }

    private VirtualFile createFileTreeForArchiving() throws Exception {
        VirtualFile arc = vfsRoot.createFolder("arc");
        arc.createFolder("a").createFile("_a.txt", TEST_CONTENT);
        arc.createFolder("b").createFile("_b.txt", TEST_CONTENT);
        arc.createFolder("c").createFile("_c.txt", TEST_CONTENT);
        return arc;
    }

    private byte[] createTestTarArchive() throws IOException {
        ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
        TarArchiveOutputStream tarOut = new TarArchiveOutputStream(byteOut);
        addDirectoryEntry(tarOut, new TarArchiveEntry("arc/"));
        addDirectoryEntry(tarOut, new TarArchiveEntry("arc/a/"));
        addFileEntry(tarOut, "arc/a/_a.txt");
        addDirectoryEntry(tarOut, new TarArchiveEntry("arc/b/"));
        addFileEntry(tarOut, "arc/b/_b.txt");
        addDirectoryEntry(tarOut, new TarArchiveEntry("arc/c/"));
        addFileEntry(tarOut, "arc/c/_c.txt");
        tarOut.close();
        return byteOut.toByteArray();
    }

    private void addDirectoryEntry(TarArchiveOutputStream tarOut, TarArchiveEntry archiveEntry) throws IOException {
        tarOut.putArchiveEntry(archiveEntry);
        tarOut.closeArchiveEntry();
    }

    private void addFileEntry(TarArchiveOutputStream tarOut, String name) throws IOException {
        TarArchiveEntry entryA = new TarArchiveEntry(name);
        entryA.setSize(TEST_CONTENT_BYTES.length);
        tarOut.putArchiveEntry(entryA);
        tarOut.write(TEST_CONTENT_BYTES);
        tarOut.closeArchiveEntry();
    }

    private List<VirtualFile> getFileTreeAsList(VirtualFile rootOfTree) throws Exception {
        List<VirtualFile> list = newArrayList();

        VirtualFileVisitor treeWalker = new VirtualFileVisitor() {
            @Override
            public void visit(VirtualFile virtualFile) throws ServerException {
                list.add(virtualFile);
                if (virtualFile.isFolder()) {
                    for (VirtualFile child : virtualFile.getChildren()) {
                        child.accept(this);
                    }
                }
            }
        };

        for (VirtualFile child : rootOfTree.getChildren()) {
            child.accept(treeWalker);
        }

        return list;
    }

    private void assertThatTarArchiveContainsAllEntries(InputStream in, Map<String, String> entries)
            throws Exception {
        try (TarArchiveInputStream tarIn = new TarArchiveInputStream(in)) {
            TarArchiveEntry tarArchiveEntry;
            while ((tarArchiveEntry = tarIn.getNextTarEntry()) != null) {
                String name = tarArchiveEntry.getName();
                assertTrue(String.format("Unexpected entry %s in TAR", name), entries.containsKey(name));
                if (!tarArchiveEntry.isDirectory()) {
                    String content = new String(ByteStreams.toByteArray(tarIn));
                    assertEquals(String.format("Invalid content of file %s", name), entries.get(name), content);
                }
                entries.remove(name);
            }
        }
        assertTrue(String.format("Expected but were not found in TAR %s", entries), entries.isEmpty());
    }
}