/*
* Copyright 2014 Cask Data, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package co.cask.cdap.data2.dataset2.lib.table.inmemory;
import co.cask.cdap.api.common.Bytes;
import co.cask.cdap.data2.dataset2.lib.table.PutValue;
import co.cask.cdap.data2.dataset2.lib.table.Update;
import co.cask.tephra.Transaction;
import com.google.common.collect.Maps;
import org.junit.Assert;
import org.junit.Test;
import java.util.NavigableMap;
/**
*
*/
public class InMemoryTableServiceTest {
@Test
public void testInternalsNotLeaking() {
// Test that there's no way to break the state of InMemoryTableService by changing parameters of update
// methods (after method invocation) or by changing returned values "in-place"
InMemoryTableService.create("table");
// verify writing thru merge is guarded
NavigableMap<byte[], NavigableMap<byte[], Update>> updates = Maps.newTreeMap(Bytes.BYTES_COMPARATOR);
NavigableMap<byte[], Update> rowUpdate = Maps.newTreeMap(Bytes.BYTES_COMPARATOR);
byte[] rowParam = new byte[] {1};
byte[] columnParam = new byte[] {2};
byte[] valParam = new byte[] {3};
rowUpdate.put(columnParam, new PutValue(valParam));
updates.put(rowParam, rowUpdate);
InMemoryTableService.merge("table", updates, 1L);
verify123();
updates.remove(rowParam);
rowUpdate.remove(columnParam);
rowParam[0]++;
columnParam[0]++;
valParam[0]++;
verify123();
// verify changing returned data from get doesn't affect the stored data
NavigableMap<byte[], NavigableMap<Long, byte[]>> rowFromGet =
InMemoryTableService.get("table", new byte[]{1}, new Transaction(1L, 2L, new long[0], new long[0], 1L));
Assert.assertEquals(1, rowFromGet.size());
byte[] columnFromGet = rowFromGet.firstEntry().getKey();
Assert.assertArrayEquals(new byte[] {2}, columnFromGet);
byte[] valFromGet = rowFromGet.firstEntry().getValue().get(1L);
Assert.assertArrayEquals(new byte[] {3}, valFromGet);
rowFromGet.firstEntry().getValue().remove(1L);
rowFromGet.remove(columnFromGet);
columnFromGet[0]++;
valFromGet[0]++;
verify123();
// verify changing returned data doesn't affect the stored data
NavigableMap<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>> fromGetRange =
InMemoryTableService.getRowRange("table", null, null, new Transaction(1L, 2L, new long[0], new long[0], 1L));
Assert.assertEquals(1, fromGetRange.size());
byte[] keyFromGetRange = fromGetRange.firstEntry().getKey();
Assert.assertArrayEquals(new byte[] {1}, keyFromGetRange);
NavigableMap<byte[], NavigableMap<Long, byte[]>> rowFromGetRange = fromGetRange.get(new byte[] {1});
Assert.assertEquals(1, rowFromGetRange.size());
byte[] columnFromGetRange = rowFromGetRange.firstEntry().getKey();
Assert.assertArrayEquals(new byte[] {2}, columnFromGetRange);
byte[] valFromGetRange = rowFromGetRange.firstEntry().getValue().get(1L);
Assert.assertArrayEquals(new byte[] {3}, valFromGetRange);
rowFromGetRange.firstEntry().getValue().remove(1L);
rowFromGetRange.remove(columnFromGetRange);
fromGetRange.remove(keyFromGetRange);
keyFromGetRange[0]++;
columnFromGetRange[0]++;
valFromGet[0]++;
verify123();
}
private void verify123() {
NavigableMap<byte[], NavigableMap<Long, byte[]>> rowFromGet =
InMemoryTableService.get("table", new byte[]{1}, new Transaction(1L, 2L, new long[0], new long[0], 1L));
Assert.assertEquals(1, rowFromGet.size());
Assert.assertArrayEquals(new byte[] {2}, rowFromGet.firstEntry().getKey());
Assert.assertArrayEquals(new byte[] {3}, rowFromGet.firstEntry().getValue().get(1L));
}
}