org.eclipse.jgit.lfs.server.fs.LfsServerTest.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.jgit.lfs.server.fs.LfsServerTest.java

Source

/*
 * Copyright (C) 2015, Matthias Sohn <matthias.sohn@sap.com>
 * and other copyright owners as documented in the project's IP log.
 *
 * This program and the accompanying materials are made available
 * under the terms of the Eclipse Distribution License v1.0 which
 * accompanies this distribution, is reproduced below, and is
 * available at http://www.eclipse.org/org/documents/edl-v10.php
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the following
 * conditions are met:
 *
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above
 *   copyright notice, this list of conditions and the following
 *   disclaimer in the documentation and/or other materials provided
 *   with the distribution.
 *
 * - Neither the name of the Eclipse Foundation, Inc. nor the
 *   names of its contributors may be used to endorse or promote
 *   products derived from this software without specific prior
 *   written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package org.eclipse.jgit.lfs.server.fs;

import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.assertEquals;

import java.io.BufferedInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.security.DigestInputStream;
import java.security.SecureRandom;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jgit.junit.http.AppServer;
import org.eclipse.jgit.lfs.lib.AnyLongObjectId;
import org.eclipse.jgit.lfs.lib.Constants;
import org.eclipse.jgit.lfs.lib.LongObjectId;
import org.eclipse.jgit.lfs.test.LongObjectIdTestUtils;
import org.eclipse.jgit.util.FileUtils;
import org.eclipse.jgit.util.IO;
import org.junit.After;
import org.junit.Before;

public abstract class LfsServerTest {

    private static final long timeout = /* 10 sec */ 10 * 1000;

    protected static final int MiB = 1024 * 1024;

    /** In-memory application server; subclass must start. */
    protected AppServer server;

    private Path tmp;

    private Path dir;

    protected FileLfsRepository repository;

    protected FileLfsServlet servlet;

    public LfsServerTest() {
        super();
    }

    public Path getTempDirectory() {
        return tmp;
    }

    public Path getDir() {
        return dir;
    }

    @Before
    public void setup() throws Exception {
        tmp = Files.createTempDirectory("jgit_test_");
        server = new AppServer();
        ServletContextHandler app = server.addContext("/lfs");
        dir = Paths.get(tmp.toString(), "lfs");
        this.repository = new FileLfsRepository(null, dir);
        servlet = new FileLfsServlet(repository, timeout);
        app.addServlet(new ServletHolder(servlet), "/objects/*");
        server.setUp();
    }

    @After
    public void tearDown() throws Exception {
        server.tearDown();
        FileUtils.delete(tmp.toFile(), FileUtils.RECURSIVE | FileUtils.RETRY);
    }

    protected AnyLongObjectId putContent(String s) throws IOException, ClientProtocolException {
        AnyLongObjectId id = LongObjectIdTestUtils.hash(s);
        return putContent(id, s);
    }

    protected AnyLongObjectId putContent(AnyLongObjectId id, String s) throws ClientProtocolException, IOException {
        try (CloseableHttpClient client = HttpClientBuilder.create().build()) {
            HttpEntity entity = new StringEntity(s, ContentType.APPLICATION_OCTET_STREAM);
            String hexId = id.name();
            HttpPut request = new HttpPut(server.getURI() + "/lfs/objects/" + hexId);
            request.setEntity(entity);
            try (CloseableHttpResponse response = client.execute(request)) {
                StatusLine statusLine = response.getStatusLine();
                int status = statusLine.getStatusCode();
                if (status >= 400) {
                    throw new RuntimeException("Status: " + status + ". " + statusLine.getReasonPhrase());
                }
            }
            return id;
        }
    }

    protected LongObjectId putContent(Path f) throws FileNotFoundException, IOException {
        try (CloseableHttpClient client = HttpClientBuilder.create().build()) {
            LongObjectId id1, id2;
            String hexId1, hexId2;
            try (DigestInputStream in = new DigestInputStream(new BufferedInputStream(Files.newInputStream(f)),
                    Constants.newMessageDigest())) {
                InputStreamEntity entity = new InputStreamEntity(in, Files.size(f),
                        ContentType.APPLICATION_OCTET_STREAM);
                id1 = LongObjectIdTestUtils.hash(f);
                hexId1 = id1.name();
                HttpPut request = new HttpPut(server.getURI() + "/lfs/objects/" + hexId1);
                request.setEntity(entity);
                HttpResponse response = client.execute(request);
                checkResponseStatus(response);
                id2 = LongObjectId.fromRaw(in.getMessageDigest().digest());
                hexId2 = id2.name();
                assertEquals(hexId1, hexId2);
            }
            return id1;
        }
    }

    private void checkResponseStatus(HttpResponse response) {
        StatusLine statusLine = response.getStatusLine();
        int status = statusLine.getStatusCode();
        if (statusLine.getStatusCode() >= 400) {
            String error;
            try {
                ByteBuffer buf = IO.readWholeStream(new BufferedInputStream(response.getEntity().getContent()),
                        1024);
                if (buf.hasArray()) {
                    error = new String(buf.array(), buf.arrayOffset() + buf.position(), buf.remaining(), UTF_8);
                } else {
                    final byte[] b = new byte[buf.remaining()];
                    buf.duplicate().get(b);
                    error = new String(b, UTF_8);
                }
            } catch (IOException e) {
                error = statusLine.getReasonPhrase();
            }
            throw new RuntimeException("Status: " + status + " " + error);
        }
        assertEquals(200, status);
    }

    protected long getContent(AnyLongObjectId id, Path f) throws IOException {
        String hexId = id.name();
        return getContent(hexId, f);
    }

    protected long getContent(String hexId, Path f) throws IOException {
        try (CloseableHttpClient client = HttpClientBuilder.create().build()) {
            HttpGet request = new HttpGet(server.getURI() + "/lfs/objects/" + hexId);
            HttpResponse response = client.execute(request);
            checkResponseStatus(response);
            HttpEntity entity = response.getEntity();
            long pos = 0;
            try (InputStream in = entity.getContent();
                    ReadableByteChannel inChannel = Channels.newChannel(in);
                    FileChannel outChannel = FileChannel.open(f, StandardOpenOption.CREATE_NEW,
                            StandardOpenOption.WRITE)) {
                long transferred;
                do {
                    transferred = outChannel.transferFrom(inChannel, pos, MiB);
                    pos += transferred;
                } while (transferred > 0);
            }
            return pos;
        }
    }

    /**
     * Creates a file with random content, repeatedly writing a random string of
     * 4k length to the file until the file has at least the specified length.
     *
     * @param f
     *            file to fill
     * @param size
     *            size of the file to generate
     * @return length of the generated file in bytes
     * @throws IOException
     */
    protected long createPseudoRandomContentFile(Path f, long size) throws IOException {
        SecureRandom rnd = new SecureRandom();
        byte[] buf = new byte[4096];
        rnd.nextBytes(buf);
        ByteBuffer bytebuf = ByteBuffer.wrap(buf);
        try (FileChannel outChannel = FileChannel.open(f, StandardOpenOption.CREATE_NEW,
                StandardOpenOption.WRITE)) {
            long len = 0;
            do {
                len += outChannel.write(bytebuf);
                if (bytebuf.position() == 4096) {
                    bytebuf.rewind();
                }
            } while (len < size);
        }
        return Files.size(f);
    }
}