/*
* 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.kafka.streams.state.internals;
import org.apache.kafka.streams.KeyValue;
import org.apache.kafka.streams.errors.InvalidStateStoreException;
import org.apache.kafka.streams.kstream.Windowed;
import org.apache.kafka.streams.kstream.internals.SessionWindow;
import org.apache.kafka.streams.state.KeyValueIterator;
import org.apache.kafka.streams.state.QueryableStoreTypes;
import org.apache.kafka.test.ReadOnlySessionStoreStub;
import org.apache.kafka.test.StateStoreProviderStub;
import org.junit.Before;
import org.junit.Test;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static org.apache.kafka.test.StreamsTestUtils.toList;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
public class CompositeReadOnlySessionStoreTest {
private final String storeName = "session-store";
private final StateStoreProviderStub stubProviderOne = new StateStoreProviderStub(false);
private final StateStoreProviderStub stubProviderTwo = new StateStoreProviderStub(false);
private final ReadOnlySessionStoreStub<String, Long> underlyingSessionStore = new ReadOnlySessionStoreStub<>();
private final ReadOnlySessionStoreStub<String, Long> otherUnderlyingStore = new ReadOnlySessionStoreStub<>();
private CompositeReadOnlySessionStore<String, Long> sessionStore;
@Before
public void before() {
stubProviderOne.addStore(storeName, underlyingSessionStore);
stubProviderOne.addStore("other-session-store", otherUnderlyingStore);
sessionStore = new CompositeReadOnlySessionStore<>(
new WrappingStoreProvider(Arrays.<StateStoreProvider>asList(stubProviderOne, stubProviderTwo)),
QueryableStoreTypes.<String, Long>sessionStore(), storeName);
}
@Test
public void shouldFetchResulstFromUnderlyingSessionStore() throws Exception {
underlyingSessionStore.put(new Windowed<>("a", new SessionWindow(0, 0)), 1L);
underlyingSessionStore.put(new Windowed<>("a", new SessionWindow(10, 10)), 2L);
final List<KeyValue<Windowed<String>, Long>> results = toList(sessionStore.fetch("a"));
assertEquals(Arrays.asList(KeyValue.pair(new Windowed<>("a", new SessionWindow(0, 0)), 1L),
KeyValue.pair(new Windowed<>("a", new SessionWindow(10, 10)), 2L)),
results);
}
@Test
public void shouldReturnEmptyIteratorIfNoData() throws Exception {
final KeyValueIterator<Windowed<String>, Long> result = sessionStore.fetch("b");
assertFalse(result.hasNext());
}
@Test
public void shouldFindValueForKeyWhenMultiStores() throws Exception {
final ReadOnlySessionStoreStub<String, Long> secondUnderlying = new
ReadOnlySessionStoreStub<>();
stubProviderTwo.addStore(storeName, secondUnderlying);
final Windowed<String> keyOne = new Windowed<>("key-one", new SessionWindow(0, 0));
final Windowed<String> keyTwo = new Windowed<>("key-two", new SessionWindow(0, 0));
underlyingSessionStore.put(keyOne, 0L);
secondUnderlying.put(keyTwo, 10L);
final List<KeyValue<Windowed<String>, Long>> keyOneResults = toList(sessionStore.fetch("key-one"));
final List<KeyValue<Windowed<String>, Long>> keyTwoResults = toList(sessionStore.fetch("key-two"));
assertEquals(Collections.singletonList(KeyValue.pair(keyOne, 0L)), keyOneResults);
assertEquals(Collections.singletonList(KeyValue.pair(keyTwo, 10L)), keyTwoResults);
}
@Test
public void shouldNotGetValueFromOtherStores() throws Exception {
final Windowed<String> expectedKey = new Windowed<>("foo", new SessionWindow(0, 0));
otherUnderlyingStore.put(new Windowed<>("foo", new SessionWindow(10, 10)), 10L);
underlyingSessionStore.put(expectedKey, 1L);
final KeyValueIterator<Windowed<String>, Long> result = sessionStore.fetch("foo");
assertEquals(KeyValue.pair(expectedKey, 1L), result.next());
assertFalse(result.hasNext());
}
@Test(expected = InvalidStateStoreException.class)
public void shouldThrowInvalidStateStoreExceptionOnRebalance() throws Exception {
final CompositeReadOnlySessionStore<String, String> store
= new CompositeReadOnlySessionStore<>(new StateStoreProviderStub(true),
QueryableStoreTypes.<String, String>sessionStore(),
"whateva");
store.fetch("a");
}
@Test(expected = InvalidStateStoreException.class)
public void shouldThrowInvalidStateStoreExceptionIfFetchThrows() throws Exception {
underlyingSessionStore.setOpen(false);
underlyingSessionStore.fetch("key");
}
}