]> git.basschouten.com Git - openhab-addons.git/blob
d6ff9dc9b9e00ce550613638bd712beab1d1309a
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.persistence.dynamodb.internal;
14
15 import static org.junit.jupiter.api.Assertions.*;
16 import static org.junit.jupiter.api.Assumptions.assumeTrue;
17
18 import java.util.ArrayList;
19 import java.util.List;
20 import java.util.concurrent.ExecutionException;
21 import java.util.concurrent.ExecutorService;
22 import java.util.concurrent.Executors;
23
24 import org.eclipse.jdt.annotation.NonNull;
25 import org.eclipse.jdt.annotation.NonNullByDefault;
26 import org.junit.jupiter.api.Test;
27 import org.openhab.core.library.items.NumberItem;
28 import org.openhab.core.library.types.DecimalType;
29 import org.openhab.core.persistence.FilterCriteria;
30
31 import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
32
33 /**
34  *
35  * @author Sami Salonen - Initial contribution
36  *
37  */
38 @NonNullByDefault
39 public class DynamoDBTableNameResolverTest extends BaseIntegrationTest {
40
41     public static final boolean LEGACY_MODE = false; // not relevant for these tests but required by BaseIntegrationTest
42
43     @Test
44     public void testLegacyWithDynamoDBBigDecimalItem() {
45         assertEquals("integration-tests-bigdecimal",
46                 new DynamoDBTableNameResolver(ExpectedTableSchema.LEGACY, "", "integration-tests-")
47                         .fromItem(new DynamoDBBigDecimalItem()));
48     }
49
50     @Test
51     public void testLegacyWithDynamoDBStringItem() {
52         assertEquals("integration-tests-string",
53                 new DynamoDBTableNameResolver(ExpectedTableSchema.LEGACY, "", "integration-tests-")
54                         .fromItem(new DynamoDBStringItem()));
55     }
56
57     @Test
58     public void testWithDynamoDBBigDecimalItem() {
59         assertEquals("integration-tests",
60                 new DynamoDBTableNameResolver(ExpectedTableSchema.NEW, "integration-tests", "")
61                         .fromItem(new DynamoDBBigDecimalItem()));
62     }
63
64     @Test
65     public void testWithDynamoDBStringItem() {
66         assertEquals("integration-tests",
67                 new DynamoDBTableNameResolver(ExpectedTableSchema.NEW, "integration-tests", "")
68                         .fromItem(new DynamoDBStringItem()));
69     }
70
71     @Test
72     public void testBothLegacyAndNewParametersNeedToBeSpecifiedWithUnclearTableSchema() {
73         assertThrows(IllegalArgumentException.class, () -> {
74             assertEquals("integration-tests",
75                     new DynamoDBTableNameResolver(ExpectedTableSchema.MAYBE_LEGACY, "integration-tests", "")
76                             .fromItem(new DynamoDBStringItem()));
77         });
78         assertThrows(IllegalArgumentException.class, () -> {
79             assertEquals("integration-tests", new DynamoDBTableNameResolver(ExpectedTableSchema.MAYBE_LEGACY, "", "bb")
80                     .fromItem(new DynamoDBStringItem()));
81         });
82     }
83
84     @Test
85     public void testResolveLegacyTablesPresent() throws InterruptedException {
86         // Run test only with embedded server. Otherwise there is risk of writing data using default table names
87         assumeTrue(embeddedServer != null);
88         ExecutorService executor = Executors.newFixedThreadPool(2);
89
90         DynamoDBPersistenceService maybeLegacyService = null;
91         final DynamoDBPersistenceService legacyService = newService(true, true, null, DynamoDBConfig.DEFAULT_TABLE_NAME,
92                 DynamoDBConfig.DEFAULT_TABLE_PREFIX);
93         DynamoDBTableNameResolver tableNameResolver = legacyService.getTableNameResolver();
94         assertNotNull(tableNameResolver);
95         assert tableNameResolver != null; // to get rid of null warning...
96         assertEquals(ExpectedTableSchema.LEGACY, tableNameResolver.getTableSchema());
97
98         NumberItem item = (@NonNull NumberItem) ITEMS.get("number");
99         final FilterCriteria criteria = new FilterCriteria();
100         criteria.setItemName(item.getName());
101
102         try {
103
104             // Old tables do not exit --> resolves to new schema
105             assertEquals(ExpectedTableSchema.NEW, resolveMaybeLegacy(legacyService, executor));
106
107             // Write data using legacy tables
108             item.setState(new DecimalType(0));
109             legacyService.store(item);
110
111             // Since table exist now, DynamoDBTableNameResolver should resolve
112             waitForAssert(() -> {
113                 // Old tables are now there --> should resolve to old schema
114                 assertEquals(ExpectedTableSchema.LEGACY, resolveMaybeLegacy(legacyService, executor));
115             });
116
117             // Create 2 new services, with unknown schemas (MAYBE_LEGACY), pointing to same database
118             maybeLegacyService = newService(null, false, legacyService.getEndpointOverride(), null, null);
119             DynamoDBTableNameResolver maybeLegacyServiceTableNameResolver = maybeLegacyService.getTableNameResolver();
120             assertNotNull(maybeLegacyServiceTableNameResolver);
121             assert maybeLegacyServiceTableNameResolver != null; // to get rid of null warning...
122             assertEquals(ExpectedTableSchema.MAYBE_LEGACY, maybeLegacyServiceTableNameResolver.getTableSchema());
123             assertEquals(legacyService.getEndpointOverride(), maybeLegacyService.getEndpointOverride());
124
125             // maybeLegacyService2 still does not know the schema
126             assertEquals(ExpectedTableSchema.MAYBE_LEGACY, maybeLegacyServiceTableNameResolver.getTableSchema());
127             // ... but it will be resolved automatically on query
128             final DynamoDBPersistenceService maybeLegacyServiceFinal = maybeLegacyService;
129             waitForAssert(() -> {
130                 assertEquals(1, asList(maybeLegacyServiceFinal.query(criteria)).size());
131                 // also the schema gets resolved
132                 assertEquals(ExpectedTableSchema.LEGACY, maybeLegacyServiceTableNameResolver.getTableSchema());
133             });
134
135         } finally {
136             executor.shutdown();
137             if (maybeLegacyService != null) {
138                 maybeLegacyService.deactivate();
139             }
140             legacyService.deactivate();
141         }
142     }
143
144     /**
145      *
146      * @param legacyService service that has the client to use
147      * @param executor
148      * @return
149      */
150     private ExpectedTableSchema resolveMaybeLegacy(DynamoDBPersistenceService legacyService, ExecutorService executor) {
151         DynamoDBTableNameResolver resolver = new DynamoDBTableNameResolver(ExpectedTableSchema.MAYBE_LEGACY,
152                 DynamoDBConfig.DEFAULT_TABLE_NAME, DynamoDBConfig.DEFAULT_TABLE_PREFIX);
153         assertFalse(resolver.isFullyResolved());
154         try {
155             DynamoDbAsyncClient localClient = legacyService.getLowLevelClient();
156             if (localClient == null) {
157                 fail("local client is null");
158                 throw new RuntimeException();
159             }
160             boolean resolved = resolver
161                     .resolveSchema(localClient, b -> b.overrideConfiguration(legacyService::overrideConfig), executor)
162                     .get();
163             assertTrue(resolved);
164             return resolver.getTableSchema();
165         } catch (InterruptedException | ExecutionException e) {
166             fail(e.getMessage());
167             throw new IllegalStateException(); // Make compiler happy
168         }
169     }
170
171     private static <T> List<T> asList(Iterable<T> iterable) {
172         var items = new ArrayList<T>();
173         for (T item : iterable) {
174             items.add(item);
175         }
176         return items;
177     }
178 }