| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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 org.apache.ignite.internal.client.thin; |
| |
| import java.lang.reflect.Field; |
| import java.util.NoSuchElementException; |
| import java.util.Objects; |
| import com.google.common.collect.ImmutableList; |
| import org.apache.ignite.IgniteSet; |
| import org.apache.ignite.cache.CacheAtomicityMode; |
| import org.apache.ignite.cache.CacheMode; |
| import org.apache.ignite.client.ClientAutoCloseableIterator; |
| import org.apache.ignite.client.ClientCollectionConfiguration; |
| import org.apache.ignite.client.ClientException; |
| import org.apache.ignite.client.ClientIgniteSet; |
| import org.apache.ignite.client.IgniteClient; |
| import org.apache.ignite.configuration.ClientConfiguration; |
| import org.apache.ignite.configuration.CollectionConfiguration; |
| import org.apache.ignite.internal.processors.cache.GridCacheContext; |
| import org.apache.ignite.internal.processors.datastructures.GridCacheSetProxy; |
| import org.apache.ignite.testframework.GridTestUtils; |
| import org.junit.Test; |
| |
| /** |
| * Tests client set. |
| * Partition awareness tests are in {@link ThinClientPartitionAwarenessStableTopologyTest#testIgniteSet()}. |
| */ |
| @SuppressWarnings({"rawtypes", "ZeroLengthArrayAllocation", "ThrowableNotThrown"}) |
| public class IgniteSetTest extends AbstractThinClientTest { |
| /** Client. */ |
| static IgniteClient client; |
| |
| /** {@inheritDoc} */ |
| @Override protected void beforeTestsStarted() throws Exception { |
| super.beforeTestsStarted(); |
| |
| startGrids(1); |
| client = startClient(0); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override protected ClientConfiguration getClientConfiguration() { |
| return super.getClientConfiguration().setPartitionAwarenessEnabled(true); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override protected void afterTestsStopped() throws Exception { |
| client.close(); |
| stopAllGrids(); |
| |
| super.afterTestsStopped(); |
| } |
| |
| /** |
| * Tests that missing set returns null. |
| */ |
| @Test |
| public void testGetNonExistentSetReturnsNull() { |
| assertNull(client.set("non-existent", null)); |
| } |
| |
| /** |
| * Tests that closed set throws exceptions. |
| */ |
| @Test |
| public void testCloseThenUseThrowsException() { |
| ClientIgniteSet<Integer> set = client.set("testCloseThenUseThrowsException", new ClientCollectionConfiguration()); |
| ClientIgniteSet<Integer> set2 = client.set(set.name(), null); |
| |
| set.add(1); |
| set.close(); |
| |
| assertThrowsClosed(set); |
| assertThrowsClosed(set2); |
| |
| assertTrue(set.removed()); |
| assertTrue(set2.removed()); |
| } |
| |
| /** |
| * Tests creating a new set with the old name. |
| */ |
| @Test |
| public void testCloseAndCreateWithSameName() { |
| ClientIgniteSet<Integer> oldSet = client.set("testCreateCloseCreateRemovesOldData", new ClientCollectionConfiguration()); |
| |
| oldSet.add(1); |
| oldSet.close(); |
| |
| assertTrue(oldSet.removed()); |
| |
| ClientIgniteSet<Integer> newSet = client.set(oldSet.name(), new ClientCollectionConfiguration()); |
| |
| assertEquals(0, newSet.size()); |
| |
| // Set is identified by id, so it is no longer removed. |
| assertFalse(newSet.removed()); |
| assertFalse(oldSet.removed()); |
| } |
| |
| /** |
| * Tests basic usage. |
| */ |
| @Test |
| public void testAddRemoveContains() { |
| ClientIgniteSet<String> set = client.set("testBasicUsage", new ClientCollectionConfiguration()); |
| |
| assertTrue(set.isEmpty()); |
| |
| set.add("foo"); |
| set.add("bar"); |
| |
| assertTrue(set.contains("foo")); |
| assertTrue(set.contains("bar")); |
| assertFalse(set.contains("baz")); |
| |
| set.remove("foo"); |
| assertFalse(set.contains("foo")); |
| |
| assertEquals(1, set.size()); |
| assertEquals("bar", set.iterator().next()); |
| } |
| |
| /** |
| * Tests addAll. |
| */ |
| @Test |
| public void testAddAll() { |
| ClientIgniteSet<Integer> set = client.set("testAddAll", new ClientCollectionConfiguration()); |
| |
| assertTrue(set.addAll(ImmutableList.of(1, 3))); |
| assertTrue(set.contains(1)); |
| assertFalse(set.contains(2)); |
| assertTrue(set.contains(3)); |
| assertEquals(2, set.size()); |
| |
| assertTrue(set.addAll(ImmutableList.of(1, 2, 3))); |
| assertTrue(set.contains(1)); |
| assertTrue(set.contains(2)); |
| assertTrue(set.contains(3)); |
| assertEquals(3, set.size()); |
| |
| assertFalse(set.addAll(ImmutableList.of(2, 3))); |
| assertFalse(set.addAll(ImmutableList.of(3))); |
| assertFalse(set.addAll(ImmutableList.of())); |
| |
| assertEquals(3, set.size()); |
| } |
| |
| /** |
| * Tests containsAll. |
| */ |
| @Test |
| @SuppressWarnings("SuspiciousMethodCalls") |
| public void testContainsAll() { |
| ClientIgniteSet<Integer> set = client.set("testContainsAll", new ClientCollectionConfiguration()); |
| set.addAll(ImmutableList.of(1, 2, 3)); |
| |
| assertTrue(set.containsAll(ImmutableList.of(1))); |
| assertTrue(set.containsAll(ImmutableList.of(1, 2))); |
| assertTrue(set.containsAll(ImmutableList.of(2, 1))); |
| assertTrue(set.containsAll(ImmutableList.of(3, 1, 2))); |
| |
| assertFalse(set.containsAll(ImmutableList.of())); |
| assertFalse(set.containsAll(ImmutableList.of(0))); |
| assertFalse(set.containsAll(ImmutableList.of(0, 1))); |
| assertFalse(set.containsAll(ImmutableList.of(1, 2, 4))); |
| } |
| |
| /** |
| * Tests removeAll. |
| */ |
| @Test |
| @SuppressWarnings({"SlowAbstractSetRemoveAll", "SuspiciousMethodCalls"}) |
| public void testRemoveAll() { |
| ClientIgniteSet<Integer> set = client.set("testRemoveAll", new ClientCollectionConfiguration()); |
| set.addAll(ImmutableList.of(1, 2, 3)); |
| |
| assertFalse(set.removeAll(ImmutableList.of())); |
| assertFalse(set.removeAll(ImmutableList.of(0))); |
| assertFalse(set.removeAll(ImmutableList.of(0, 4))); |
| |
| assertEquals(3, set.size()); |
| |
| assertTrue(set.removeAll(ImmutableList.of(5, 4, 3, 1, 0))); |
| |
| assertEquals(1, set.size()); |
| assertTrue(set.contains(2)); |
| } |
| |
| /** |
| * Tests retainAll. |
| */ |
| @Test |
| @SuppressWarnings("SuspiciousMethodCalls") |
| public void testRetainAll() { |
| ClientIgniteSet<Integer> set = client.set("testRemoveAll", new ClientCollectionConfiguration()); |
| |
| assertFalse(set.retainAll(ImmutableList.of())); |
| |
| set.addAll(ImmutableList.of(1, 2, 3)); |
| |
| assertFalse(set.retainAll(ImmutableList.of(3, 2, 1, 4))); |
| assertFalse(set.retainAll(ImmutableList.of(1, 2, 3))); |
| assertEquals(3, set.size()); |
| |
| assertTrue(set.retainAll(ImmutableList.of(1, 4, 7))); |
| assertEquals(1, set.size()); |
| assertTrue(set.contains(1)); |
| |
| // retainAll with empty list: clear the collection and get a boolean value indicating if it was empty or not. |
| assertTrue(set.retainAll(ImmutableList.of())); |
| assertTrue(set.isEmpty()); |
| } |
| |
| /** |
| * Tests user object types as set values. |
| */ |
| @Test |
| public void testUserObject() { |
| ClientIgniteSet<UserObj> clientSet = client.set("testUserObject", new ClientCollectionConfiguration()); |
| |
| UserObj obj1 = new UserObj(1, "a"); |
| UserObj obj2 = new UserObj(2, "a"); |
| |
| clientSet.add(obj1); |
| clientSet.add(obj2); |
| |
| assertTrue(clientSet.contains(obj1)); |
| assertTrue(clientSet.contains(new UserObj(1, "a"))); |
| assertTrue(clientSet.containsAll(ImmutableList.of(obj1, obj2))); |
| |
| assertFalse(clientSet.contains(new UserObj(1, "b"))); |
| } |
| |
| /** |
| * Tests user object types as set values with server-side API interop. |
| */ |
| @Test |
| public void testUserObjectClientServer() { |
| ClientIgniteSet<UserObj> clientSet = client.set("testUserObjectClientServer", new ClientCollectionConfiguration()); |
| |
| // By default, Client sends obj as BinaryObject, resulting in a different behavior. |
| // When thick and thin APIs are used with the same user-defined classes together, |
| // it means that classes are available on the server, and we can deserialize the obj to enable matching behavior. |
| clientSet.serverKeepBinary(false); |
| |
| IgniteSet<UserObj> serverSet = ignite(0).set(clientSet.name(), null); |
| |
| clientSet.add(new UserObj(1, "client")); |
| serverSet.add(new UserObj(2, "server")); |
| |
| assertTrue(clientSet.contains(new UserObj(1, "client"))); |
| assertTrue(clientSet.contains(new UserObj(2, "server"))); |
| |
| assertTrue(serverSet.contains(new UserObj(1, "client"))); |
| assertTrue(serverSet.contains(new UserObj(2, "server"))); |
| |
| assertFalse(clientSet.contains(new UserObj(1, "x"))); |
| assertFalse(serverSet.contains(new UserObj(1, "x"))); |
| } |
| |
| /** |
| * Tests config propagation. |
| */ |
| @Test |
| public void testConfigPropagation() throws Exception { |
| String groupName = "grp-testConfigPropagation"; |
| |
| ClientCollectionConfiguration cfg = new ClientCollectionConfiguration() |
| .setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL) |
| .setCacheMode(CacheMode.PARTITIONED) |
| .setBackups(7) |
| .setColocated(true) |
| .setGroupName(groupName); |
| |
| CollectionConfiguration serverCfg = new CollectionConfiguration() |
| .setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL) |
| .setCacheMode(CacheMode.PARTITIONED) |
| .setBackups(7) |
| .setCollocated(true) |
| .setGroupName(groupName); |
| |
| ClientIgniteSet<UserObj> set = client.set("testConfigPropagation", cfg); |
| |
| GridCacheSetProxy serverSet = (GridCacheSetProxy)ignite(0).set(set.name(), serverCfg); |
| |
| Field field = GridCacheSetProxy.class.getDeclaredField("cctx"); |
| field.setAccessible(true); |
| GridCacheContext cctx = (GridCacheContext)field.get(serverSet); |
| |
| assertTrue(set.colocated()); |
| assertFalse(set.removed()); |
| assertEquals("testConfigPropagation", set.name()); |
| assertEquals(7, cctx.config().getBackups()); |
| assertEquals(CacheMode.PARTITIONED, cctx.config().getCacheMode()); |
| assertEquals(CacheAtomicityMode.TRANSACTIONAL, cctx.config().getAtomicityMode()); |
| assertEquals(groupName, cctx.config().getGroupName()); |
| } |
| |
| /** |
| * Tests different cache groups. |
| */ |
| @Test |
| public void testSameNameInDifferentGroups() { |
| String name = "testSameNameInDifferentGroups"; |
| ClientCollectionConfiguration cfg1 = new ClientCollectionConfiguration(); |
| |
| ClientCollectionConfiguration cfg2 = new ClientCollectionConfiguration() |
| .setGroupName("gp1"); |
| |
| ClientCollectionConfiguration cfg3 = new ClientCollectionConfiguration() |
| .setGroupName("gp2") |
| .setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL); |
| |
| ClientIgniteSet<Integer> set1 = client.set(name, cfg1); |
| ClientIgniteSet<Integer> set2 = client.set(name, cfg2); |
| ClientIgniteSet<Integer> set3 = client.set(name, cfg3); |
| |
| set1.add(1); |
| set2.add(2); |
| set3.add(3); |
| |
| assertTrue(set1.contains(1)); |
| assertTrue(set2.contains(2)); |
| assertTrue(set3.contains(3)); |
| |
| assertFalse(set1.contains(2)); |
| assertFalse(set2.contains(3)); |
| assertFalse(set3.contains(1)); |
| } |
| |
| /** |
| * Tests same set name with different options. |
| */ |
| @Test |
| public void testSameNameDifferentOptions() { |
| String name = "testSameNameDifferentOptions"; |
| ClientCollectionConfiguration cfg1 = new ClientCollectionConfiguration() |
| .setGroupName("gp1"); |
| |
| ClientCollectionConfiguration cfg2 = new ClientCollectionConfiguration() |
| .setGroupName("gp1") |
| .setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL); |
| |
| ClientIgniteSet<Integer> set1 = client.set(name, cfg1); |
| ClientIgniteSet<Integer> set2 = client.set(name, cfg2); |
| |
| set1.add(2); |
| set2.add(3); |
| |
| assertTrue(set1.contains(2)); |
| assertTrue(set2.contains(3)); |
| |
| assertFalse(set1.contains(3)); |
| assertFalse(set2.contains(1)); |
| } |
| |
| /** |
| * Tests iterator over an empty set. |
| */ |
| @Test |
| public void testIteratorEmpty() { |
| ClientIgniteSet<Integer> set = client.set("testIteratorEmpty", new ClientCollectionConfiguration()); |
| |
| ClientAutoCloseableIterator<Integer> iterator = set.iterator(); |
| |
| assertEquals(1024, set.pageSize()); |
| assertFalse(iterator.hasNext()); |
| GridTestUtils.assertThrows(null, iterator::next, NoSuchElementException.class, null); |
| } |
| |
| /** |
| * Tests that iterator closes itself when the last page is retrieved. |
| */ |
| @Test |
| public void testIteratorClosesOnLastPage() throws Exception { |
| ClientIgniteSet<Integer> set = client.set("testCloseBeforeEnd", new ClientCollectionConfiguration()); |
| set.pageSize(1); |
| |
| ImmutableList<Integer> keys = ImmutableList.of(1, 2, 3); |
| set.addAll(keys); |
| |
| ClientAutoCloseableIterator<Integer> iter = set.iterator(); |
| |
| assertFalse(isIteratorClosed(iter)); |
| assertTrue(iter.hasNext()); |
| |
| iter.next(); |
| |
| assertFalse(isIteratorClosed(iter)); |
| assertTrue(iter.hasNext()); |
| |
| iter.next(); |
| |
| assertTrue(isIteratorClosed(iter)); |
| assertTrue(iter.hasNext()); |
| |
| iter.next(); |
| |
| assertFalse(iter.hasNext()); |
| } |
| |
| /** |
| * Tests closing the iterator before it is finished. |
| */ |
| @Test |
| public void testCloseBeforeEnd() throws Exception { |
| ClientIgniteSet<Integer> set = client.set("testCloseBeforeEnd", new ClientCollectionConfiguration()); |
| set.pageSize(1); |
| |
| ImmutableList<Integer> keys = ImmutableList.of(1, 2, 3); |
| set.addAll(keys); |
| |
| ClientAutoCloseableIterator<Integer> iter = set.iterator(); |
| |
| assertTrue(iter.hasNext()); |
| iter.close(); |
| |
| assertFalse(iter.hasNext()); |
| } |
| |
| /** |
| * Tests iterator in a foreach loop. |
| */ |
| @Test |
| public void testIteratorForeach() { |
| ClientIgniteSet<Integer> set = client.set("testIteratorForeach", new ClientCollectionConfiguration()); |
| set.pageSize(2); |
| |
| ImmutableList<Integer> keys = ImmutableList.of(1, 2, 3); |
| set.addAll(keys); |
| |
| int count = 0; |
| |
| for (Integer k : set) { |
| assertTrue(keys.contains(k)); |
| count++; |
| } |
| |
| assertEquals(keys.size(), count); |
| } |
| |
| /** |
| * Tests iterator with data modifications. |
| */ |
| @Test |
| public void testModifyWhileIterating() { |
| ClientIgniteSet<Integer> set = client.set("testModifyWhileIterating", new ClientCollectionConfiguration()); |
| set.pageSize(1); |
| |
| ImmutableList<Integer> keys = ImmutableList.of(1, 2, 3); |
| set.addAll(keys); |
| |
| ClientAutoCloseableIterator<Integer> iterator = set.iterator(); |
| |
| set.remove(3); |
| assertTrue(keys.contains(iterator.next())); |
| |
| set.remove(2); |
| assertTrue(keys.contains(iterator.next())); |
| |
| assertFalse(iterator.hasNext()); |
| } |
| |
| /** |
| * Tests toArray on empty set. |
| */ |
| @Test |
| public void testToArrayEmpty() { |
| ClientIgniteSet<Integer> set = client.set("testToArrayEmpty", new ClientCollectionConfiguration()); |
| |
| assertEquals(0, set.toArray().length); |
| assertEquals(0, set.toArray(new Integer[0]).length); |
| } |
| |
| /** |
| * Tests toArray. |
| */ |
| @Test |
| public void testToArray() { |
| for (int i = 1; i < 10; i++) |
| testToArray(i); |
| } |
| |
| /** |
| * Tests toArray. |
| */ |
| public void testToArray(int pageSize) { |
| ClientIgniteSet<Integer> set = client.set("testToArray", new ClientCollectionConfiguration()); |
| set.pageSize(pageSize); |
| |
| ImmutableList<Integer> keys = ImmutableList.of(1, 2, 3, 4, 5); |
| set.addAll(keys); |
| |
| Integer[] resTyped = set.toArray(new Integer[0]); |
| |
| assertEquals(5, resTyped.length); |
| |
| for (Integer k : resTyped) |
| assertTrue(keys.contains(k)); |
| |
| Object[] resObjects = set.toArray(); |
| |
| assertEquals(5, resObjects.length); |
| |
| for (Object k : resObjects) |
| assertTrue(keys.contains((Integer)k)); |
| } |
| |
| /** |
| * Asserts that usage throws closed exception. |
| */ |
| @SuppressWarnings("ThrowableNotThrown") |
| private static void assertThrowsClosed(ClientIgniteSet<Integer> set) { |
| String msg = "IgniteSet with name '" + set.name() + "' does not exist."; |
| GridTestUtils.assertThrows(null, set::size, ClientException.class, msg); |
| } |
| |
| /** |
| * Returns a value indicating whether iterator resources are closed. |
| * |
| * @param iter Iterator. |
| * @return Whether iterator resources are closed. |
| */ |
| private static boolean isIteratorClosed(ClientAutoCloseableIterator<Integer> iter) throws Exception { |
| Field field = iter.getClass().getDeclaredField("resourceId"); |
| field.setAccessible(true); |
| |
| return field.get(iter) == null; |
| } |
| |
| /** |
| * Custom user class. |
| */ |
| private static class UserObj { |
| /** */ |
| public final int id; |
| |
| /** */ |
| public final String val; |
| |
| /** */ |
| public UserObj(int id, String val) { |
| this.id = id; |
| this.val = val; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override public boolean equals(Object o) { |
| if (this == o) { |
| return true; |
| } |
| if (o == null || getClass() != o.getClass()) { |
| return false; |
| } |
| UserObj userObj = (UserObj)o; |
| return id == userObj.id && Objects.equals(val, userObj.val); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override public int hashCode() { |
| return Objects.hash(id, val); |
| } |
| } |
| } |