Repository: incubator-geode
Updated Branches:
  refs/heads/develop 5eeb3313c -> aad3ef739


GEODE-783: add unit test for SyncChunkStack


Project: http://git-wip-us.apache.org/repos/asf/incubator-geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-geode/commit/aad3ef73
Tree: http://git-wip-us.apache.org/repos/asf/incubator-geode/tree/aad3ef73
Diff: http://git-wip-us.apache.org/repos/asf/incubator-geode/diff/aad3ef73

Branch: refs/heads/develop
Commit: aad3ef73974236c3ab2abb8fe116c9b2462e8df5
Parents: 5eeb331
Author: Darrel Schneider <dschnei...@pivotal.io>
Authored: Mon Jan 18 16:42:40 2016 -0800
Committer: Darrel Schneider <dschnei...@pivotal.io>
Committed: Tue Jan 19 10:42:17 2016 -0800

----------------------------------------------------------------------
 .../internal/offheap/SyncChunkStack.java        |  13 +-
 .../offheap/SyncChunkStackJUnitTest.java        | 273 +++++++++++++++++++
 2 files changed, 285 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/aad3ef73/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/SyncChunkStack.java
----------------------------------------------------------------------
diff --git 
a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/SyncChunkStack.java
 
b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/SyncChunkStack.java
index a615af0..7ba28a2 100644
--- 
a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/SyncChunkStack.java
+++ 
b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/SyncChunkStack.java
@@ -87,6 +87,7 @@ public class SyncChunkStack {
       while (addr != 0L) {
         int curSize = Chunk.getSize(addr);
         addr = Chunk.getNext(addr);
+        testHookDoConcurrentModification();
         long curHead = this.topAddr;
         if (curHead != headAddr) {
           headAddr = curHead;
@@ -97,7 +98,7 @@ public class SyncChunkStack {
           break;
         }
         // TODO construct a single log msg
-        // that gets reset on the concurrent mad.
+        // that gets reset when concurrentModDetected.
         lw.info(msg + curSize);
       }
     } while (concurrentModDetected);
@@ -114,6 +115,7 @@ public class SyncChunkStack {
       while (addr != 0L) {
         result += Chunk.getSize(addr);
         addr = Chunk.getNext(addr);
+        testHookDoConcurrentModification();
         long curHead = this.topAddr;
         if (curHead != headAddr) {
           headAddr = curHead;
@@ -127,4 +129,13 @@ public class SyncChunkStack {
     } while (concurrentModDetected);
     return result;
   }
+  
+  /**
+   * This method allows tests to override it
+   * and do a concurrent modification to the stack.
+   * For production code it will be a noop.
+   */
+  protected void testHookDoConcurrentModification() {
+    // nothing needed in production code
+  }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/aad3ef73/gemfire-core/src/test/java/com/gemstone/gemfire/internal/offheap/SyncChunkStackJUnitTest.java
----------------------------------------------------------------------
diff --git 
a/gemfire-core/src/test/java/com/gemstone/gemfire/internal/offheap/SyncChunkStackJUnitTest.java
 
b/gemfire-core/src/test/java/com/gemstone/gemfire/internal/offheap/SyncChunkStackJUnitTest.java
new file mode 100644
index 0000000..f8e93a7
--- /dev/null
+++ 
b/gemfire-core/src/test/java/com/gemstone/gemfire/internal/offheap/SyncChunkStackJUnitTest.java
@@ -0,0 +1,273 @@
+package com.gemstone.gemfire.internal.offheap;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.mockito.listeners.InvocationListener;
+import org.mockito.listeners.MethodInvocationReport;
+
+import com.gemstone.gemfire.LogWriter;
+import com.gemstone.gemfire.test.junit.categories.UnitTest;
+
+@Category(UnitTest.class)
+public class SyncChunkStackJUnitTest {
+  static {
+    ClassLoader.getSystemClassLoader().setDefaultAssertionStatus(true);
+  }
+
+  @BeforeClass
+  public static void setUpBeforeClass() throws Exception {
+  }
+
+  @AfterClass
+  public static void tearDownAfterClass() throws Exception {
+  }
+
+  @Before
+  public void setUp() throws Exception {
+  }
+
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  @Test
+  public void addressZeroCausesStackToBeEmpty() {
+    SyncChunkStack stack = new SyncChunkStack(0L);
+    assertEquals(true, stack.isEmpty());
+  }
+
+  @Test
+  public void defaultStackIsEmpty() {
+    SyncChunkStack stack = new SyncChunkStack();
+    assertEquals(true, stack.isEmpty());
+  }
+
+  @Test
+  public void defaultStackReturnsZeroFromTop() {
+    SyncChunkStack stack = new SyncChunkStack();
+    assertEquals(0L, stack.getTopAddress());
+  }
+  
+  @Test
+  public void defaultStackReturnsZeroFromPoll() {
+    SyncChunkStack stack = new SyncChunkStack();
+    assertEquals(0L, stack.poll());
+  }
+  
+  @Test
+  public void defaultStackReturnsZeroFromClear() {
+    SyncChunkStack stack = new SyncChunkStack();
+    assertEquals(0L, stack.clear());
+    assertEquals(true, stack.isEmpty());
+  }
+  
+  @Test
+  public void defaultStackLogsNothing() {
+    SyncChunkStack stack = new SyncChunkStack();
+    LogWriter lw = mock(LogWriter.class, 
withSettings().invocationListeners(new InvocationListener() {
+      @Override
+      public void reportInvocation(MethodInvocationReport 
methodInvocationReport) {
+        fail("Unexpected invocation");
+      }
+    }));
+    stack.logSizes(lw, "should not be used");
+  }
+  
+  @Test
+  public void defaultStackComputeSizeIsZero() {
+    SyncChunkStack stack = new SyncChunkStack();
+    assertEquals(0L, stack.computeTotalSize());
+  }
+  
+  @Test
+  public void stackCreatedWithAddressIsNotEmpty() {
+    UnsafeMemoryChunk slab = new UnsafeMemoryChunk(1024);
+    try {
+      SimpleMemoryAllocatorImpl ma = SimpleMemoryAllocatorImpl.create(new 
NullOutOfOffHeapMemoryListener(), new NullOffHeapMemoryStats(), new 
UnsafeMemoryChunk[]{slab});
+      Chunk chunk = (Chunk) ma.allocate(100, null);
+
+      SyncChunkStack stack = new SyncChunkStack(chunk.getMemoryAddress());
+      assertEquals(false, stack.isEmpty());
+    } finally {
+      SimpleMemoryAllocatorImpl.freeOffHeapMemory();
+    }
+  }
+
+  @Test
+  public void stackWithChunkIsNotEmpty() {
+    UnsafeMemoryChunk slab = new UnsafeMemoryChunk(1024);
+    try {
+      SimpleMemoryAllocatorImpl ma = SimpleMemoryAllocatorImpl.create(new 
NullOutOfOffHeapMemoryListener(), new NullOffHeapMemoryStats(), new 
UnsafeMemoryChunk[]{slab});
+      Chunk chunk = (Chunk) ma.allocate(100, null);
+
+      SyncChunkStack stack = new SyncChunkStack();
+      stack.offer(chunk.getMemoryAddress());
+      assertEquals(false, stack.isEmpty());
+    } finally {
+      SimpleMemoryAllocatorImpl.freeOffHeapMemory();
+    }
+  }
+
+  @Test
+  public void stackWithChunkTopEqualsAddress() {
+    UnsafeMemoryChunk slab = new UnsafeMemoryChunk(1024);
+    try {
+      SimpleMemoryAllocatorImpl ma = SimpleMemoryAllocatorImpl.create(new 
NullOutOfOffHeapMemoryListener(), new NullOffHeapMemoryStats(), new 
UnsafeMemoryChunk[]{slab});
+      Chunk chunk = (Chunk) ma.allocate(100, null);
+
+      long addr = chunk.getMemoryAddress();
+      SyncChunkStack stack = new SyncChunkStack();
+      stack.offer(addr);
+      assertEquals(addr, stack.getTopAddress());
+    } finally {
+      SimpleMemoryAllocatorImpl.freeOffHeapMemory();
+    }
+  }
+
+  @Test
+  public void addressZeroOfferCausesFailedAssertion() {
+    SyncChunkStack stack = new SyncChunkStack(0L);
+    try {
+      stack.offer(0);
+      fail("expected AssertionError");
+    } catch (AssertionError expected) {
+    }
+  }
+
+
+  @Test
+  public void stackWithChunkClearReturnsAddressAndEmptiesStack() {
+    UnsafeMemoryChunk slab = new UnsafeMemoryChunk(1024);
+    try {
+      SimpleMemoryAllocatorImpl ma = SimpleMemoryAllocatorImpl.create(new 
NullOutOfOffHeapMemoryListener(), new NullOffHeapMemoryStats(), new 
UnsafeMemoryChunk[]{slab});
+      Chunk chunk = (Chunk) ma.allocate(100, null);
+
+      long addr = chunk.getMemoryAddress();
+      SyncChunkStack stack = new SyncChunkStack();
+      stack.offer(addr);
+      long clearAddr = stack.clear();
+      assertEquals(addr, clearAddr);
+      assertEquals(true, stack.isEmpty());
+    } finally {
+      SimpleMemoryAllocatorImpl.freeOffHeapMemory();
+    }
+  }
+
+  @Test
+  public void stackWithChunkPollReturnsAddressAndEmptiesStack() {
+    UnsafeMemoryChunk slab = new UnsafeMemoryChunk(1024);
+    try {
+      SimpleMemoryAllocatorImpl ma = SimpleMemoryAllocatorImpl.create(new 
NullOutOfOffHeapMemoryListener(), new NullOffHeapMemoryStats(), new 
UnsafeMemoryChunk[]{slab});
+      Chunk chunk = (Chunk) ma.allocate(100, null);
+
+      long addr = chunk.getMemoryAddress();
+      SyncChunkStack stack = new SyncChunkStack();
+      stack.offer(addr);
+      long pollAddr = stack.poll();
+      assertEquals(addr, pollAddr);
+      assertEquals(true, stack.isEmpty());
+    } finally {
+      SimpleMemoryAllocatorImpl.freeOffHeapMemory();
+    }
+  }
+
+  @Test
+  public void stackWithChunkTotalSizeIsChunkSize() {
+    UnsafeMemoryChunk slab = new UnsafeMemoryChunk(1024);
+    try {
+      SimpleMemoryAllocatorImpl ma = SimpleMemoryAllocatorImpl.create(new 
NullOutOfOffHeapMemoryListener(), new NullOffHeapMemoryStats(), new 
UnsafeMemoryChunk[]{slab});
+      Chunk chunk = (Chunk) ma.allocate(100, null);
+      int chunkSize = chunk.getSize();
+
+      long addr = chunk.getMemoryAddress();
+      SyncChunkStack stack = new SyncChunkStack();
+      stack.offer(addr);
+      assertEquals(chunkSize, stack.computeTotalSize());
+    } finally {
+      SimpleMemoryAllocatorImpl.freeOffHeapMemory();
+    }
+  }
+
+
+  @Test
+  public void stackWithChunkLogShowsMsgAndSize() {
+    UnsafeMemoryChunk slab = new UnsafeMemoryChunk(1024);
+    try {
+      SimpleMemoryAllocatorImpl ma = SimpleMemoryAllocatorImpl.create(new 
NullOutOfOffHeapMemoryListener(), new NullOffHeapMemoryStats(), new 
UnsafeMemoryChunk[]{slab});
+      Chunk chunk = (Chunk) ma.allocate(100, null);
+      int chunkSize = chunk.getSize();
+
+      long addr = chunk.getMemoryAddress();
+      SyncChunkStack stack = new SyncChunkStack();
+      stack.offer(addr);
+      LogWriter lw = mock(LogWriter.class);
+      stack.logSizes(lw, "foo");
+      verify(lw).info("foo"+chunkSize);
+    } finally {
+      SimpleMemoryAllocatorImpl.freeOffHeapMemory();
+    }
+  }
+  
+  private class TestableSyncChunkStack extends SyncChunkStack {
+    public boolean doConcurrentMod = true;
+    public int chunk2Size;
+    private SimpleMemoryAllocatorImpl ma;
+    TestableSyncChunkStack(SimpleMemoryAllocatorImpl ma) {
+      this.ma = ma;
+    }
+    @Override
+    protected void testHookDoConcurrentModification() {
+      if (doConcurrentMod) {
+        doConcurrentMod = false;
+        Chunk chunk2 = (Chunk) ma.allocate(50, null);
+        this.chunk2Size = chunk2.getSize();
+        this.offer(chunk2.getMemoryAddress());
+      }
+    }
+  }
+  @Test
+  public void stackWithChunkTotalSizeIsChunkSizeWithConcurrentMod() {
+    UnsafeMemoryChunk slab = new UnsafeMemoryChunk(1024);
+    try {
+      SimpleMemoryAllocatorImpl ma = SimpleMemoryAllocatorImpl.create(new 
NullOutOfOffHeapMemoryListener(), new NullOffHeapMemoryStats(), new 
UnsafeMemoryChunk[]{slab});
+      Chunk chunk = (Chunk) ma.allocate(100, null);
+      int chunkSize = chunk.getSize();
+
+      long addr = chunk.getMemoryAddress();
+      TestableSyncChunkStack stack = new TestableSyncChunkStack(ma);
+      stack.offer(addr);
+      long totalSize = stack.computeTotalSize();
+      assertEquals("chunkSize=" + chunkSize + " chunk2Size=" + 
stack.chunk2Size, chunkSize + stack.chunk2Size, totalSize);
+    } finally {
+      SimpleMemoryAllocatorImpl.freeOffHeapMemory();
+    }
+  }
+
+
+  @Test
+  public void stackWithChunkLogShowsMsgAndSizeWithConcurrentMod() {
+    UnsafeMemoryChunk slab = new UnsafeMemoryChunk(1024);
+    try {
+      SimpleMemoryAllocatorImpl ma = SimpleMemoryAllocatorImpl.create(new 
NullOutOfOffHeapMemoryListener(), new NullOffHeapMemoryStats(), new 
UnsafeMemoryChunk[]{slab});
+      Chunk chunk = (Chunk) ma.allocate(100, null);
+      int chunkSize = chunk.getSize();
+
+      long addr = chunk.getMemoryAddress();
+      TestableSyncChunkStack stack = new TestableSyncChunkStack(ma);
+      stack.offer(addr);
+      LogWriter lw = mock(LogWriter.class);
+      stack.logSizes(lw, "foo");
+      verify(lw).info("foo"+chunkSize);
+      verify(lw).info("foo"+stack.chunk2Size);
+    } finally {
+      SimpleMemoryAllocatorImpl.freeOffHeapMemory();
+    }
+  }
+}

Reply via email to