]> git.basschouten.com Git - openhab-addons.git/blob
394b45e0f778bdf4427ac92578bb3a1634af8178
[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             // Old tables do not exit --> resolves to new schema
104             assertEquals(ExpectedTableSchema.NEW, resolveMaybeLegacy(legacyService, executor));
105
106             // Write data using legacy tables
107             item.setState(new DecimalType(0));
108             legacyService.store(item);
109
110             // Since table exist now, DynamoDBTableNameResolver should resolve
111             waitForAssert(() -> {
112                 // Old tables are now there --> should resolve to old schema
113                 assertEquals(ExpectedTableSchema.LEGACY, resolveMaybeLegacy(legacyService, executor));
114             });
115
116             // Create 2 new services, with unknown schemas (MAYBE_LEGACY), pointing to same database
117             maybeLegacyService = newService(null, false, legacyService.getEndpointOverride(), null, null);
118             DynamoDBTableNameResolver maybeLegacyServiceTableNameResolver = maybeLegacyService.getTableNameResolver();
119             assertNotNull(maybeLegacyServiceTableNameResolver);
120             assert maybeLegacyServiceTableNameResolver != null; // to get rid of null warning...
121             assertEquals(ExpectedTableSchema.MAYBE_LEGACY, maybeLegacyServiceTableNameResolver.getTableSchema());
122             assertEquals(legacyService.getEndpointOverride(), maybeLegacyService.getEndpointOverride());
123
124             // maybeLegacyService2 still does not know the schema
125             assertEquals(ExpectedTableSchema.MAYBE_LEGACY, maybeLegacyServiceTableNameResolver.getTableSchema());
126             // ... but it will be resolved automatically on query
127             final DynamoDBPersistenceService maybeLegacyServiceFinal = maybeLegacyService;
128             waitForAssert(() -> {
129                 assertEquals(1, asList(maybeLegacyServiceFinal.query(criteria)).size());
130                 // also the schema gets resolved
131                 assertEquals(ExpectedTableSchema.LEGACY, maybeLegacyServiceTableNameResolver.getTableSchema());
132             });
133
134         } finally {
135             executor.shutdown();
136             if (maybeLegacyService != null) {
137                 maybeLegacyService.deactivate();
138             }
139             legacyService.deactivate();
140         }
141     }
142
143     /**
144      *
145      * @param legacyService service that has the client to use
146      * @param executor
147      * @return
148      */
149     private ExpectedTableSchema resolveMaybeLegacy(DynamoDBPersistenceService legacyService, ExecutorService executor) {
150         DynamoDBTableNameResolver resolver = new DynamoDBTableNameResolver(ExpectedTableSchema.MAYBE_LEGACY,
151                 DynamoDBConfig.DEFAULT_TABLE_NAME, DynamoDBConfig.DEFAULT_TABLE_PREFIX);
152         assertFalse(resolver.isFullyResolved());
153         try {
154             DynamoDbAsyncClient localClient = legacyService.getLowLevelClient();
155             if (localClient == null) {
156                 fail("local client is null");
157                 throw new RuntimeException();
158             }
159             boolean resolved = resolver
160                     .resolveSchema(localClient, b -> b.overrideConfiguration(legacyService::overrideConfig), executor)
161                     .get();
162             assertTrue(resolved);
163             return resolver.getTableSchema();
164         } catch (InterruptedException | ExecutionException e) {
165             fail(e.getMessage());
166             throw new IllegalStateException(); // Make compiler happy
167         }
168     }
169
170     private static <T> List<T> asList(Iterable<T> iterable) {
171         var items = new ArrayList<T>();
172         for (T item : iterable) {
173             items.add(item);
174         }
175         return items;
176     }
177 }