/* * 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.nifi.controller.state.providers; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.util.Collections; import java.util.HashMap; import java.util.Map; import org.apache.nifi.components.state.StateMap; import org.apache.nifi.components.state.StateProvider; import org.junit.Test; /** * <p> * Abstract class that provides a suite of test for State Providers. Each State Provider implementation can simply extend this class, * implement the getProvider() method, and have the entire suite of tests run against the provider. * </p> * * <p> * It is recommended that implementations create a new provider in a method annotated with @Before and cleanup in a method annotated with @After. * </p> */ public abstract class AbstractTestStateProvider { protected final String componentId = "111111111-1111-1111-1111-111111111111"; @Test public void testSetAndGet() throws IOException { getProvider().setState(Collections.singletonMap("testSetAndGet", "value"), componentId); assertEquals("value", getProvider().getState(componentId).get("testSetAndGet")); } @Test public void testReplaceSuccessful() throws IOException { final String key = "testReplaceSuccessful"; final StateProvider provider = getProvider(); StateMap map = provider.getState(componentId); assertNotNull(map); assertEquals(-1, map.getVersion()); assertNotNull(map.toMap()); assertTrue(map.toMap().isEmpty()); provider.setState(Collections.singletonMap(key, "value1"), componentId); map = provider.getState(componentId); assertNotNull(map); assertEquals(0, map.getVersion()); assertEquals("value1", map.get(key)); assertEquals("value1", map.toMap().get(key)); final Map<String, String> newMap = new HashMap<>(map.toMap()); newMap.put(key, "value2"); assertTrue(provider.replace(map, newMap, componentId)); map = provider.getState(componentId); assertEquals("value2", map.get(key)); assertEquals(1L, map.getVersion()); } @Test public void testReplaceWithWrongVersion() throws IOException { final String key = "testReplaceWithWrongVersion"; final StateProvider provider = getProvider(); provider.setState(Collections.singletonMap(key, "value1"), componentId); StateMap stateMap = provider.getState(componentId); assertNotNull(stateMap); assertEquals("value1", stateMap.get(key)); assertEquals(0, stateMap.getVersion()); provider.setState(Collections.singletonMap(key, "intermediate value"), componentId); assertFalse(provider.replace(stateMap, Collections.singletonMap(key, "value2"), componentId)); stateMap = provider.getState(componentId); assertEquals(key, stateMap.toMap().keySet().iterator().next()); assertEquals(1, stateMap.toMap().size()); assertEquals("intermediate value", stateMap.get(key)); assertEquals(1, stateMap.getVersion()); } @Test public void testToMap() throws IOException { final String key = "testKeySet"; final StateProvider provider = getProvider(); Map<String, String> map = provider.getState(componentId).toMap(); assertNotNull(map); assertTrue(map.isEmpty()); provider.setState(Collections.singletonMap(key, "value"), componentId); map = provider.getState(componentId).toMap(); assertNotNull(map); assertEquals(1, map.size()); assertEquals("value", map.get(key)); provider.setState(Collections.<String, String> emptyMap(), componentId); final StateMap stateMap = provider.getState(componentId); map = stateMap.toMap(); assertNotNull(map); assertTrue(map.isEmpty()); assertEquals(1, stateMap.getVersion()); } @Test public void testClear() throws IOException { final StateProvider provider = getProvider(); StateMap stateMap = provider.getState(componentId); assertNotNull(stateMap); assertEquals(-1L, stateMap.getVersion()); assertTrue(stateMap.toMap().isEmpty()); provider.setState(Collections.singletonMap("testClear", "value"), componentId); stateMap = provider.getState(componentId); assertNotNull(stateMap); assertEquals(0, stateMap.getVersion()); assertEquals("value", stateMap.get("testClear")); provider.clear(componentId); stateMap = provider.getState(componentId); assertNotNull(stateMap); assertEquals(1L, stateMap.getVersion()); assertTrue(stateMap.toMap().isEmpty()); } @Test public void testReplaceWithNonExistingValue() throws Exception { final StateProvider provider = getProvider(); StateMap stateMap = provider.getState(componentId); assertNotNull(stateMap); final Map<String, String> newValue = new HashMap<>(); newValue.put("value", "value"); final boolean replaced = provider.replace(stateMap, newValue, componentId); assertFalse(replaced); } @Test public void testReplaceWithNonExistingValueAndVersionGreaterThanNegativeOne() throws Exception { final StateProvider provider = getProvider(); final StateMap stateMap = new StateMap() { @Override public long getVersion() { return 4; } @Override public String get(String key) { return null; } @Override public Map<String, String> toMap() { return Collections.emptyMap(); } }; final Map<String, String> newValue = new HashMap<>(); newValue.put("value", "value"); final boolean replaced = provider.replace(stateMap, newValue, componentId); assertFalse(replaced); } @Test public void testOnComponentRemoved() throws IOException, InterruptedException { final StateProvider provider = getProvider(); final Map<String, String> newValue = new HashMap<>(); newValue.put("value", "value"); provider.setState(newValue, componentId); final StateMap stateMap = provider.getState(componentId); assertEquals(0L, stateMap.getVersion()); provider.onComponentRemoved(componentId); // wait for the background process to complete Thread.sleep(1000L); final StateMap stateMapAfterRemoval = provider.getState(componentId); // version should be -1 because the state has been removed entirely. assertEquals(-1L, stateMapAfterRemoval.getVersion()); } protected abstract StateProvider getProvider(); }