TiagoMSSantos/MobileRT

View on GitHub
app/src/androidTest/java/puscas/mobilertapp/system/NativeMemoryTest.java

Summary

Maintainability
A
0 mins
Test Coverage
package puscas.mobilertapp.system;

import static puscas.mobilertapp.ConstantsAndroidTests.NOT_ENOUGH_MEMORY_MESSAGE;

import android.os.Debug;

import org.junit.Assert;
import org.junit.Test;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Locale;
import java.util.logging.Logger;

import puscas.mobilertapp.AbstractTest;
import puscas.mobilertapp.constants.Constants;

/**
 * The Android tests for memory behaviour in the system.
 * <p>
 * These tests are useful to test the behaviour of allocating and freeing
 * native heap memory, as the Android unit tests only have Java heap and not a
 * native heap memory available.
 */
public final class NativeMemoryTest extends AbstractTest {

    /**
     * Logger for this class.
     */
    private static final Logger logger = Logger.getLogger(NativeMemoryTest.class.getSimpleName());

    /**
     * Tests that allocating heap memory from native memory, makes the available memory decrease as expected.
     */
    @Test
    public void testAllocatingHeapMemoryNative() {
        Runtime.getRuntime().gc();

        // Dummy array to hold the allocated memory.
        final Collection<ByteBuffer> dummyArrays = new ArrayList<>(1);
        final long firstAvailableMemoryMB = getAvailableNativeMemoryInMB();

        final long expectedAvailableMemory = 2L;
        final int megaBytesToAllocate = 50;
        final int maxMegaBytesToAllocate = 80; // Max heap around 80MB.
        int numAllocatedByteBuffers = 0;

        for(long memAllocated = 0L; getAvailableNativeMemoryInMB() > 0L && firstAvailableMemoryMB > getAvailableNativeMemoryInMB() + 2L * megaBytesToAllocate && memAllocated < maxMegaBytesToAllocate; memAllocated += megaBytesToAllocate) {
            // Force garbage collection now, before retrieving available memory
            // of the before and after allocating memory.
            Runtime.getRuntime().gc();

            Assert.assertTrue(NOT_ENOUGH_MEMORY_MESSAGE + firstAvailableMemoryMB + " >= " + expectedAvailableMemory, firstAvailableMemoryMB >= expectedAvailableMemory);

            final long beforeAvailableMemoryMB = getAvailableNativeMemoryInMB();
            dummyArrays.add(ByteBuffer.allocateDirect((megaBytesToAllocate * Constants.BYTES_IN_MEGABYTE)));
            final long afterAvailableMemory = getAvailableNativeMemoryInMB();
            Assert.assertTrue(NOT_ENOUGH_MEMORY_MESSAGE + afterAvailableMemory + " <= " + beforeAvailableMemoryMB, afterAvailableMemory <= beforeAvailableMemoryMB);

            ++numAllocatedByteBuffers;
        }

        Assert.assertEquals( "The number of allocated `ByteBuffer` is not the expected.", numAllocatedByteBuffers, dummyArrays.size());
    }

    /**
     * Helper method that calculates the available memory in the native Heap.
     * The returned value are in mega bytes.
     *
     * @return The available memory in the native Heap, in mega bytes.
     */
    private static long getAvailableNativeMemoryInMB() {
        final String template = "%s: %dKB (%dMB)";
        final long nativeHeapSizeBytes = Debug.getNativeHeapSize();
        final String sizeNativeHeap = String.format(Locale.US, template,
                "The size of the native heap",
                convertBytesToKiloBytes(nativeHeapSizeBytes),
                convertBytesToMegaBytes(nativeHeapSizeBytes)
        );
        logger.info(sizeNativeHeap);


        final long nativeHeapAllocatedSizeBytes = Debug.getNativeHeapAllocatedSize();
        final String sizeNativeAllocatedHeap = String.format(Locale.US, template,
                "Allocated memory in the native heap",
                convertBytesToKiloBytes(nativeHeapAllocatedSizeBytes),
                convertBytesToMegaBytes(nativeHeapAllocatedSizeBytes)
        );
        logger.info(sizeNativeAllocatedHeap);


        final long nativeHeapFreeSizeBytes = Debug.getNativeHeapFreeSize();
        final long availableMemoryMb = convertBytesToMegaBytes(nativeHeapFreeSizeBytes);
        final String sizeNativeHeapFree = String.format(Locale.US, template,
                "Available native heap memory",
                convertBytesToKiloBytes(nativeHeapFreeSizeBytes),
                availableMemoryMb
        );
        logger.info(sizeNativeHeapFree);

        return availableMemoryMb;
    }

    /**
     * Helper method that converts a number of bytes into kilobytes.
     *
     * @param bytes The number of bytes.
     * @return The number of kilobytes.
     */
    private static long convertBytesToKiloBytes(final long bytes) {
        return bytes / 1024L;
    }

    /**
     * Helper method that converts a number of bytes into megabytes.
     *
     * @param bytes The number of bytes.
     * @return The number of megabytes.
     */
    private static long convertBytesToMegaBytes(final long bytes) {
        return bytes / (long) Constants.BYTES_IN_MEGABYTE;
    }

}