From a051559b43840cc56c936e8420a2d6c54147ad67 Mon Sep 17 00:00:00 2001 From: alexandreferris Date: Tue, 1 Oct 2024 16:46:37 +0200 Subject: [PATCH 1/4] feat(get-domain-from-backend) Use new Helium API to fetch backend domain * Update Helium to 1.4.1 * Add assertions to major tests * Remove Consts.java from tests * Add call to get api version and default domain --- .../wire/bots/hold/NotificationProcessor.java | 80 ++++++------------- src/main/java/com/wire/bots/hold/Service.java | 11 ++- .../bots/hold/healthchecks/SanityCheck.java | 21 ++++- .../wire/bots/hold/model/Notification.java | 20 ----- .../bots/hold/model/NotificationList.java | 18 ----- .../bots/hold/resource/ConfirmResource.java | 10 ++- .../hold/resource/ConversationResource.java | 2 + .../java/com/wire/bots/hold/utils/Cache.java | 20 +++-- .../com/wire/bots/hold/utils/TestCache.java | 19 +++++ 9 files changed, 93 insertions(+), 108 deletions(-) delete mode 100644 src/main/java/com/wire/bots/hold/model/Notification.java delete mode 100644 src/main/java/com/wire/bots/hold/model/NotificationList.java diff --git a/src/main/java/com/wire/bots/hold/NotificationProcessor.java b/src/main/java/com/wire/bots/hold/NotificationProcessor.java index 3cf36c2..b9fc760 100644 --- a/src/main/java/com/wire/bots/hold/NotificationProcessor.java +++ b/src/main/java/com/wire/bots/hold/NotificationProcessor.java @@ -3,39 +3,34 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.wire.bots.hold.DAO.AccessDAO; -import com.wire.bots.hold.model.Config; import com.wire.bots.hold.model.LHAccess; -import com.wire.bots.hold.model.Notification; -import com.wire.bots.hold.model.NotificationList; +import com.wire.helium.API; import com.wire.helium.LoginClient; import com.wire.helium.models.Access; +import com.wire.helium.models.Event; +import com.wire.helium.models.NotificationList; import com.wire.xenon.backend.models.Payload; import com.wire.xenon.exceptions.AuthException; import com.wire.xenon.exceptions.HttpException; import com.wire.xenon.tools.Logger; import javax.ws.rs.client.Client; -import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.Cookie; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; import java.util.List; import java.util.UUID; import java.util.logging.Level; public class NotificationProcessor implements Runnable { + private static final int DEFAULT_NOTIFICATION_SIZE = 100; + private final Client client; private final AccessDAO accessDAO; private final HoldMessageResource messageResource; - private final WebTarget api; - NotificationProcessor(Client client, AccessDAO accessDAO, Config config, HoldMessageResource messageResource) { + NotificationProcessor(Client client, AccessDAO accessDAO, HoldMessageResource messageResource) { this.client = client; this.accessDAO = accessDAO; this.messageResource = messageResource; - - api = client.target(config.apiHost); } @Override @@ -59,7 +54,11 @@ private Access getAccess(Cookie cookie) throws HttpException { private void process(LHAccess device) { UUID userId = device.userId; + try { + // todo get exception + final API api = new API(client, null, device.token); + Logger.debug("`GET /notifications`: user: %s, last: %s", userId, device.last); String cookieValue = device.cookie; @@ -77,10 +76,13 @@ private void process(LHAccess device) { device.token = access.getAccessToken(); - NotificationList notificationList = retrieveNotifications(device); + NotificationList notificationList = api.retrieveNotifications( + device.clientId, + device.last, + DEFAULT_NOTIFICATION_SIZE + ); process(userId, notificationList); - } catch (AuthException e) { accessDAO.disable(userId); Logger.info("Disabled LH device for user: %s, error: %s", userId, e.getMessage()); @@ -89,27 +91,21 @@ private void process(LHAccess device) { } } - private static String bearer(String token) { - return token == null ? null : String.format("Bearer %s", token); - } - private void process(UUID userId, NotificationList notificationList) { - - for (Notification notif : notificationList.notifications) { - for (Payload payload : notif.payload) { - if (!process(userId, payload, notif.id)) { - Logger.error("Failed to process: user: %s, notif: %s", userId, notif.id); - //return; + for (Event event : notificationList.notifications) { + for (Payload payload : event.payload) { + if (!process(userId, payload, event.id)) { + Logger.error("Failed to process: user: %s, event: %s", userId, event.id); } else { - Logger.debug("Processed: `%s` conv: %s, user: %s, notifId: %s", + Logger.debug("Processed: `%s` conv: %s, user: %s, eventId: %s", payload.type, payload.conversation, userId, - notif.id); + event.id); } } - accessDAO.updateLast(userId, notif.id); + accessDAO.updateLast(userId, event.id); } } @@ -123,13 +119,13 @@ private boolean process(UUID userId, Payload payload, UUID id) { if (payload.from == null || payload.data == null) return true; - final boolean b = messageResource.onNewMessage(userId, id, payload); + final boolean wasMessageSent = messageResource.onNewMessage(userId, id, payload); - if (!b) { + if (!wasMessageSent) { Logger.error("process: `%s` user: %s, from: %s:%s, error: %s", payload.type, userId, payload.from, payload.data.sender); } - return b; + return wasMessageSent; } private void trace(Payload payload) { @@ -142,30 +138,4 @@ private void trace(Payload payload) { } } } - - //TODO remove this and use retrieveNotifications provided by Helium - private NotificationList retrieveNotifications(LHAccess access) throws HttpException { - Response response = api.path("notifications").queryParam("client", access.clientId).queryParam("since", access.last).queryParam("size", 100).request(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON).header(HttpHeaders.AUTHORIZATION, bearer(access.token)).get(); - - int status = response.getStatus(); - - if (status == 200) { - return response.readEntity(NotificationList.class); - } - - if (status == 404) { //todo what??? - return response.readEntity(NotificationList.class); - } - - if (status == 401) { //todo nginx returns text/html for 401. Cannot deserialize as json - response.readEntity(String.class); - throw new AuthException(status); - } - - if (status == 403) { - throw response.readEntity(AuthException.class); - } - - throw response.readEntity(HttpException.class); - } } diff --git a/src/main/java/com/wire/bots/hold/Service.java b/src/main/java/com/wire/bots/hold/Service.java index 568fdf7..5075545 100644 --- a/src/main/java/com/wire/bots/hold/Service.java +++ b/src/main/java/com/wire/bots/hold/Service.java @@ -27,14 +27,18 @@ import com.wire.bots.hold.monitoring.RequestMdcFactoryFilter; import com.wire.bots.hold.monitoring.StatusResource; import com.wire.bots.hold.resource.*; +import com.wire.bots.hold.utils.Cache; import com.wire.bots.hold.utils.HoldClientRepo; import com.wire.bots.hold.utils.ImagesBundle; import com.wire.helium.LoginClient; +import com.wire.helium.models.BackendConfiguration; import com.wire.xenon.Const; import com.wire.xenon.backend.models.QualifiedId; import com.wire.xenon.crypto.CryptoDatabase; import com.wire.xenon.crypto.storage.JdbiStorage; +import com.wire.xenon.exceptions.HttpException; import com.wire.xenon.factories.CryptoFactory; +import com.wire.xenon.tools.Logger; import io.dropwizard.Application; import io.dropwizard.assets.AssetsBundle; import io.dropwizard.client.JerseyClientBuilder; @@ -131,10 +135,9 @@ public void run(Config config, Environment environment) { environment.healthChecks().register("SanityCheck", new SanityCheck(accessDAO, httpClient)); final HoldClientRepo repo = new HoldClientRepo(jdbi, cf, httpClient); - final LoginClient loginClient = new LoginClient(httpClient); final HoldMessageResource holdMessageResource = new HoldMessageResource(new MessageHandler(jdbi), repo); - final NotificationProcessor notificationProcessor = new NotificationProcessor(httpClient, accessDAO, config, holdMessageResource); + final NotificationProcessor notificationProcessor = new NotificationProcessor(httpClient, accessDAO, holdMessageResource); environment.lifecycle() .scheduledExecutorService("notifications") @@ -144,10 +147,6 @@ public void run(Config config, Environment environment) { CollectorRegistry.defaultRegistry.register(new DropwizardExports(metrics)); environment.getApplicationContext().addServlet(MetricsServlet.class, "/metrics"); - - // todo here - // String res = loginClient.getBackendConfiguration(); - // handle res ^ } public Config getConfig() { diff --git a/src/main/java/com/wire/bots/hold/healthchecks/SanityCheck.java b/src/main/java/com/wire/bots/hold/healthchecks/SanityCheck.java index 80df73a..eb8afeb 100644 --- a/src/main/java/com/wire/bots/hold/healthchecks/SanityCheck.java +++ b/src/main/java/com/wire/bots/hold/healthchecks/SanityCheck.java @@ -3,8 +3,11 @@ import com.codahale.metrics.health.HealthCheck; import com.wire.bots.hold.DAO.AccessDAO; import com.wire.bots.hold.model.LHAccess; +import com.wire.bots.hold.utils.Cache; import com.wire.helium.API; +import com.wire.helium.models.BackendConfiguration; import com.wire.xenon.backend.models.QualifiedId; +import com.wire.xenon.exceptions.HttpException; import com.wire.xenon.tools.Logger; import javax.ws.rs.client.Client; @@ -30,14 +33,18 @@ protected Result check() { API api = new API(client, null, single.token); + fetchAndStoreApiVersion(api); + String created = single.created; List accessList = accessDAO.list(100, created); while (!accessList.isEmpty()) { Logger.info("SanityCheck: checking %d devices, created: %s", accessList.size(), created); for (LHAccess access : accessList) { + // TODO(WPB-11287): Use user domain if exists, otherwise default + // TODO: String domain = (access.domain != null) ? access.domain : Cache.DEFAULT_DOMAIN; boolean hasDevice = api.hasDevice( - new QualifiedId(access.userId, null), // TODO(WPB-11287): Change null to default domain + new QualifiedId(access.userId, Cache.getDefaultDomain()), // TODO(WPB-11287): Change null to default domain access.clientId ); @@ -61,4 +68,16 @@ protected Result check() { Logger.debug("Finished SanityCheck"); } } + + private void fetchAndStoreApiVersion(API api) { + if (Cache.getDefaultDomain() != null) { return; } + + try { + BackendConfiguration apiVersionResponse = api.getBackendConfiguration(); + + Cache.setDefaultDomain(apiVersionResponse.domain); + } catch (HttpException exception) { + Logger.exception(exception, "Service.getApiVersion, exception: %s", exception.getMessage()); + } + } } diff --git a/src/main/java/com/wire/bots/hold/model/Notification.java b/src/main/java/com/wire/bots/hold/model/Notification.java deleted file mode 100644 index 5bfba19..0000000 --- a/src/main/java/com/wire/bots/hold/model/Notification.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.wire.bots.hold.model; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.wire.xenon.backend.models.Payload; - -import javax.validation.constraints.NotNull; -import java.util.List; -import java.util.UUID; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class Notification { - @JsonProperty - @NotNull - public List payload; - - @JsonProperty - @NotNull - public UUID id; -} diff --git a/src/main/java/com/wire/bots/hold/model/NotificationList.java b/src/main/java/com/wire/bots/hold/model/NotificationList.java deleted file mode 100644 index 76a31f8..0000000 --- a/src/main/java/com/wire/bots/hold/model/NotificationList.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.wire.bots.hold.model; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -import javax.validation.constraints.NotNull; -import java.util.ArrayList; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class NotificationList { - @JsonProperty("has_more") - @NotNull - public Boolean hasMore; - - @JsonProperty - @NotNull - public ArrayList notifications; -} diff --git a/src/main/java/com/wire/bots/hold/resource/ConfirmResource.java b/src/main/java/com/wire/bots/hold/resource/ConfirmResource.java index 352f489..9cea782 100644 --- a/src/main/java/com/wire/bots/hold/resource/ConfirmResource.java +++ b/src/main/java/com/wire/bots/hold/resource/ConfirmResource.java @@ -33,9 +33,13 @@ public ConfirmResource(AccessDAO accessDAO) { @ApiResponse(code = 200, message = "Legal Hold Device enabled")}) public Response confirm(@ApiParam @Valid @NotNull ConfirmPayload payload) { try { - int insert = accessDAO.insert(payload.userId, - payload.clientId, - payload.refreshToken); + int insert = accessDAO.insert( + // TODO(WPB-11287): Add new column in DB for domain + // TODO(WPB-11287): + Use default domain for v0 + payload.userId, + payload.clientId, + payload.refreshToken + ); if (0 == insert) { Logger.error("ConfirmResource: Failed to insert Access %s:%s", diff --git a/src/main/java/com/wire/bots/hold/resource/ConversationResource.java b/src/main/java/com/wire/bots/hold/resource/ConversationResource.java index 6a7c649..ed226e3 100644 --- a/src/main/java/com/wire/bots/hold/resource/ConversationResource.java +++ b/src/main/java/com/wire/bots/hold/resource/ConversationResource.java @@ -67,6 +67,8 @@ public Response list(@ApiParam @PathParam("conversationId") UUID conversationId, try { List events = eventsDAO.listAllAsc(conversationId); + // TODO(WPB-11287) Verify default domain + testAPI(); Cache cache = new Cache(api, assetsDAO); diff --git a/src/main/java/com/wire/bots/hold/utils/Cache.java b/src/main/java/com/wire/bots/hold/utils/Cache.java index e0e55c2..b41101a 100644 --- a/src/main/java/com/wire/bots/hold/utils/Cache.java +++ b/src/main/java/com/wire/bots/hold/utils/Cache.java @@ -13,10 +13,11 @@ import java.util.concurrent.ConcurrentHashMap; public class Cache { - // TODO(WPB-11287): Add default domain here - private static final ConcurrentHashMap assets = new ConcurrentHashMap<>();// - private static final ConcurrentHashMap users = new ConcurrentHashMap<>();// - private static final ConcurrentHashMap profiles = new ConcurrentHashMap<>();// + private static String DEFAULT_DOMAIN = null; + + private static final ConcurrentHashMap assets = new ConcurrentHashMap<>(); // + private static final ConcurrentHashMap users = new ConcurrentHashMap<>(); // + private static final ConcurrentHashMap profiles = new ConcurrentHashMap<>(); // private final API api; private final AssetsDAO assetsDAO; @@ -25,6 +26,16 @@ public Cache(API api, AssetsDAO assetsDAO) { this.assetsDAO = assetsDAO; } + public static void setDefaultDomain(String domain) { + if (DEFAULT_DOMAIN == null) { + DEFAULT_DOMAIN = domain; + } + } + + public static String getDefaultDomain() { + return DEFAULT_DOMAIN; + } + @Nullable public File getAssetFile(UUID messageId) { @@ -57,7 +68,6 @@ public File getProfileImage(User user) { } public User getUser(QualifiedId userId) { - // TODO(WPB-11287): Fetch first in map then check API return users.computeIfAbsent(userId, k -> { try { return api.getUser(userId); diff --git a/src/test/java/com/wire/bots/hold/utils/TestCache.java b/src/test/java/com/wire/bots/hold/utils/TestCache.java index 0c36fb2..1ea23e8 100644 --- a/src/test/java/com/wire/bots/hold/utils/TestCache.java +++ b/src/test/java/com/wire/bots/hold/utils/TestCache.java @@ -2,6 +2,7 @@ import com.wire.xenon.backend.models.QualifiedId; import com.wire.xenon.backend.models.User; +import org.junit.Test; import java.io.File; import java.util.UUID; @@ -32,4 +33,22 @@ public User getUser(QualifiedId userId) { return dummyUser; } + + @Test + public void verifyDefaultDomainIsSetCorrectly() { + String firstDomain = Cache.getDefaultDomain(); + assert firstDomain == null; + + Cache.setDefaultDomain("dummy_domain"); + String secondDomain = Cache.getDefaultDomain(); + + assert secondDomain != null; + assert secondDomain.equals("dummy_domain"); + + Cache.setDefaultDomain("dummy_domain_3"); + String thirdDomain = Cache.getDefaultDomain(); + + assert thirdDomain != null; + assert thirdDomain.equals("dummy_domain"); + } } From 84673c0bd947fde6d01b95455e17a2c04e892d8e Mon Sep 17 00:00:00 2001 From: alexandreferris Date: Mon, 7 Oct 2024 12:29:05 +0200 Subject: [PATCH 2/4] feat(get-domain-from-backend) Use new Helium API to fetch backend domain * Update Helium to 1.4.1 * Add assertions to major tests * Remove Consts.java from tests * Add call to get api version and default domain * Persist fallback domain to database * Add FallbackDomainFetcher to handle fetch from cache, database and API --- pom.xml | 6 ++ .../com/wire/bots/hold/DAO/MetadataDAO.java | 20 ++++ .../hold/DAO/MetadataResultSetMapper.java | 19 ++++ .../wire/bots/hold/FallbackDomainFetcher.java | 59 ++++++++++ .../wire/bots/hold/NotificationProcessor.java | 3 +- src/main/java/com/wire/bots/hold/Service.java | 23 ++-- .../bots/hold/healthchecks/SanityCheck.java | 18 +--- .../com/wire/bots/hold/model/Metadata.java | 11 ++ .../java/com/wire/bots/hold/utils/Cache.java | 12 +-- .../db/migration/V107__add_metadata_table.sql | 4 + .../java/com/wire/bots/hold/DatabaseTest.java | 18 ++++ .../bots/hold/FallbackDomainFetcherTest.java | 102 ++++++++++++++++++ .../com/wire/bots/hold/utils/CacheTest.java | 38 +++++++ .../com/wire/bots/hold/utils/TestCache.java | 18 ---- 14 files changed, 302 insertions(+), 49 deletions(-) create mode 100644 src/main/java/com/wire/bots/hold/DAO/MetadataDAO.java create mode 100644 src/main/java/com/wire/bots/hold/DAO/MetadataResultSetMapper.java create mode 100644 src/main/java/com/wire/bots/hold/FallbackDomainFetcher.java create mode 100644 src/main/java/com/wire/bots/hold/model/Metadata.java create mode 100644 src/main/resources/db/migration/V107__add_metadata_table.sql create mode 100644 src/test/java/com/wire/bots/hold/FallbackDomainFetcherTest.java create mode 100644 src/test/java/com/wire/bots/hold/utils/CacheTest.java diff --git a/pom.xml b/pom.xml index b5e93dc..c255d0e 100644 --- a/pom.xml +++ b/pom.xml @@ -135,6 +135,12 @@ simpleclient_servlet ${prometheus.version} + + org.mockito + mockito-all + 1.10.19 + test + diff --git a/src/main/java/com/wire/bots/hold/DAO/MetadataDAO.java b/src/main/java/com/wire/bots/hold/DAO/MetadataDAO.java new file mode 100644 index 0000000..933d83e --- /dev/null +++ b/src/main/java/com/wire/bots/hold/DAO/MetadataDAO.java @@ -0,0 +1,20 @@ +package com.wire.bots.hold.DAO; + +import com.wire.bots.hold.model.Metadata; +import org.jdbi.v3.sqlobject.config.RegisterColumnMapper; +import org.jdbi.v3.sqlobject.customizer.Bind; +import org.jdbi.v3.sqlobject.statement.SqlQuery; +import org.jdbi.v3.sqlobject.statement.SqlUpdate; + +public interface MetadataDAO { + String FALLBACK_DOMAIN_KEY = "FALLBACK_DOMAIN_KEY"; + + @SqlUpdate("INSERT INTO Metadata (key, value)" + + "VALUES (:key, :value)" + + "ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value") + int insert(@Bind("key") String key, @Bind("value") String value); + + @SqlQuery("SELECT key, value FROM Metadata WHERE key = :key LIMIT 1") + @RegisterColumnMapper(MetadataResultSetMapper.class) + Metadata get(@Bind("key") String key); +} diff --git a/src/main/java/com/wire/bots/hold/DAO/MetadataResultSetMapper.java b/src/main/java/com/wire/bots/hold/DAO/MetadataResultSetMapper.java new file mode 100644 index 0000000..526985e --- /dev/null +++ b/src/main/java/com/wire/bots/hold/DAO/MetadataResultSetMapper.java @@ -0,0 +1,19 @@ +package com.wire.bots.hold.DAO; + +import com.wire.bots.hold.model.Metadata; +import org.jdbi.v3.core.mapper.ColumnMapper; +import org.jdbi.v3.core.statement.StatementContext; + +import java.sql.ResultSet; +import java.sql.SQLException; + +public class MetadataResultSetMapper implements ColumnMapper { + + @Override + public Metadata map(ResultSet rs, int columnNumber, StatementContext ctx) throws SQLException { + return new Metadata( + rs.getString("key"), + rs.getString("value") + ); + } +} diff --git a/src/main/java/com/wire/bots/hold/FallbackDomainFetcher.java b/src/main/java/com/wire/bots/hold/FallbackDomainFetcher.java new file mode 100644 index 0000000..58e7a40 --- /dev/null +++ b/src/main/java/com/wire/bots/hold/FallbackDomainFetcher.java @@ -0,0 +1,59 @@ +package com.wire.bots.hold; + +import com.wire.bots.hold.DAO.MetadataDAO; +import com.wire.bots.hold.model.Metadata; +import com.wire.bots.hold.utils.Cache; +import com.wire.helium.LoginClient; +import com.wire.helium.models.BackendConfiguration; +import com.wire.xenon.exceptions.HttpException; +import com.wire.xenon.tools.Logger; + +public class FallbackDomainFetcher implements Runnable { + + private final LoginClient loginClient; + private final MetadataDAO metadataDAO; + + /** + * Fetcher and handler for fallback domain. + *

+ * Fetches from API and compares against database value (if any), then inserts into database and updates cache value. + * If value received from the API is different from what is saved in the database, a [RuntimeException] is thrown. + *

+ * @param loginClient [{@link LoginClient}] as API to get backend configuration containing default domain. + * @param metadataDAO [{@link MetadataDAO}] as DAO to get/insert default domain to database. + * + * @throws RuntimeException if received domain from API is different from the one saved in the database. + */ + FallbackDomainFetcher(LoginClient loginClient, MetadataDAO metadataDAO) { + this.loginClient = loginClient; + this.metadataDAO = metadataDAO; + } + + @Override + public void run() { + if (Cache.getFallbackDomain() != null) { return; } + + Metadata metadata = metadataDAO.get(MetadataDAO.FALLBACK_DOMAIN_KEY); + try { + BackendConfiguration apiVersionResponse = loginClient.getBackendConfiguration(); + + if (metadata == null) { + metadataDAO.insert(MetadataDAO.FALLBACK_DOMAIN_KEY, apiVersionResponse.domain); + Cache.setFallbackDomain(apiVersionResponse.domain); + } else { + if (metadata.value.equals(apiVersionResponse.domain)) { + Cache.setFallbackDomain(apiVersionResponse.domain); + } else { + String formattedExceptionMessage = String.format( + "Database already has a default domain as %s and instead we got %s from the Backend API.", + metadata.value, + apiVersionResponse.domain + ); + throw new RuntimeException(formattedExceptionMessage); + } + } + } catch (HttpException exception) { + Logger.exception(exception, "FallbackDomainFetcher.run, exception: %s", exception.getMessage()); + } + } +} diff --git a/src/main/java/com/wire/bots/hold/NotificationProcessor.java b/src/main/java/com/wire/bots/hold/NotificationProcessor.java index b9fc760..1f504cf 100644 --- a/src/main/java/com/wire/bots/hold/NotificationProcessor.java +++ b/src/main/java/com/wire/bots/hold/NotificationProcessor.java @@ -56,7 +56,6 @@ private void process(LHAccess device) { UUID userId = device.userId; try { - // todo get exception final API api = new API(client, null, device.token); Logger.debug("`GET /notifications`: user: %s, last: %s", userId, device.last); @@ -86,6 +85,8 @@ private void process(LHAccess device) { } catch (AuthException e) { accessDAO.disable(userId); Logger.info("Disabled LH device for user: %s, error: %s", userId, e.getMessage()); + } catch (HttpException e) { + Logger.exception(e, "NotificationProcessor: Couldn't retrieve notifications, error: %s", e.getMessage()); } catch (Exception e) { Logger.exception(e, "NotificationProcessor: user: %s, last: %s, error: %s", userId, device.last, e.getMessage()); } diff --git a/src/main/java/com/wire/bots/hold/Service.java b/src/main/java/com/wire/bots/hold/Service.java index 5075545..4b2615f 100644 --- a/src/main/java/com/wire/bots/hold/Service.java +++ b/src/main/java/com/wire/bots/hold/Service.java @@ -21,24 +21,21 @@ import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider; import com.wire.bots.hold.DAO.AccessDAO; import com.wire.bots.hold.DAO.EventsDAO; +import com.wire.bots.hold.DAO.MetadataDAO; import com.wire.bots.hold.filters.ServiceAuthenticationFilter; import com.wire.bots.hold.healthchecks.SanityCheck; import com.wire.bots.hold.model.Config; import com.wire.bots.hold.monitoring.RequestMdcFactoryFilter; import com.wire.bots.hold.monitoring.StatusResource; import com.wire.bots.hold.resource.*; -import com.wire.bots.hold.utils.Cache; import com.wire.bots.hold.utils.HoldClientRepo; import com.wire.bots.hold.utils.ImagesBundle; import com.wire.helium.LoginClient; -import com.wire.helium.models.BackendConfiguration; import com.wire.xenon.Const; import com.wire.xenon.backend.models.QualifiedId; import com.wire.xenon.crypto.CryptoDatabase; import com.wire.xenon.crypto.storage.JdbiStorage; -import com.wire.xenon.exceptions.HttpException; import com.wire.xenon.factories.CryptoFactory; -import com.wire.xenon.tools.Logger; import io.dropwizard.Application; import io.dropwizard.assets.AssetsBundle; import io.dropwizard.client.JerseyClientBuilder; @@ -63,7 +60,6 @@ public class Service extends Application { public static Service instance; public static MetricRegistry metrics; - public static String API_DOMAIN; protected Config config; protected Environment environment; protected Jdbi jdbi; @@ -113,6 +109,7 @@ public void run(Config config, Environment environment) { final AccessDAO accessDAO = jdbi.onDemand(AccessDAO.class); final EventsDAO eventsDAO = jdbi.onDemand(EventsDAO.class); + final MetadataDAO metadataDAO = jdbi.onDemand(MetadataDAO.class); // Monitoring resources addResource(new StatusResource()); @@ -132,7 +129,21 @@ public void run(Config config, Environment environment) { addResource(ServiceAuthenticationFilter.ServiceAuthenticationFeature.class); - environment.healthChecks().register("SanityCheck", new SanityCheck(accessDAO, httpClient)); + environment + .lifecycle() + .executorService("fallback_domain_fetcher") + .build() + .execute( + new FallbackDomainFetcher( + new LoginClient(httpClient), + metadataDAO + ) + ); + + environment.healthChecks().register( + "SanityCheck", + new SanityCheck(accessDAO, httpClient) + ); final HoldClientRepo repo = new HoldClientRepo(jdbi, cf, httpClient); diff --git a/src/main/java/com/wire/bots/hold/healthchecks/SanityCheck.java b/src/main/java/com/wire/bots/hold/healthchecks/SanityCheck.java index eb8afeb..94df99a 100644 --- a/src/main/java/com/wire/bots/hold/healthchecks/SanityCheck.java +++ b/src/main/java/com/wire/bots/hold/healthchecks/SanityCheck.java @@ -5,9 +5,7 @@ import com.wire.bots.hold.model.LHAccess; import com.wire.bots.hold.utils.Cache; import com.wire.helium.API; -import com.wire.helium.models.BackendConfiguration; import com.wire.xenon.backend.models.QualifiedId; -import com.wire.xenon.exceptions.HttpException; import com.wire.xenon.tools.Logger; import javax.ws.rs.client.Client; @@ -33,8 +31,6 @@ protected Result check() { API api = new API(client, null, single.token); - fetchAndStoreApiVersion(api); - String created = single.created; List accessList = accessDAO.list(100, created); @@ -44,7 +40,7 @@ protected Result check() { // TODO(WPB-11287): Use user domain if exists, otherwise default // TODO: String domain = (access.domain != null) ? access.domain : Cache.DEFAULT_DOMAIN; boolean hasDevice = api.hasDevice( - new QualifiedId(access.userId, Cache.getDefaultDomain()), // TODO(WPB-11287): Change null to default domain + new QualifiedId(access.userId, Cache.getFallbackDomain()), // TODO(WPB-11287): Change null to default domain access.clientId ); @@ -68,16 +64,4 @@ protected Result check() { Logger.debug("Finished SanityCheck"); } } - - private void fetchAndStoreApiVersion(API api) { - if (Cache.getDefaultDomain() != null) { return; } - - try { - BackendConfiguration apiVersionResponse = api.getBackendConfiguration(); - - Cache.setDefaultDomain(apiVersionResponse.domain); - } catch (HttpException exception) { - Logger.exception(exception, "Service.getApiVersion, exception: %s", exception.getMessage()); - } - } } diff --git a/src/main/java/com/wire/bots/hold/model/Metadata.java b/src/main/java/com/wire/bots/hold/model/Metadata.java new file mode 100644 index 0000000..f145827 --- /dev/null +++ b/src/main/java/com/wire/bots/hold/model/Metadata.java @@ -0,0 +1,11 @@ +package com.wire.bots.hold.model; + +public class Metadata { + public String key; + public String value; + + public Metadata(String key, String value) { + this.key = key; + this.value = value; + } +} diff --git a/src/main/java/com/wire/bots/hold/utils/Cache.java b/src/main/java/com/wire/bots/hold/utils/Cache.java index b41101a..95b4ee4 100644 --- a/src/main/java/com/wire/bots/hold/utils/Cache.java +++ b/src/main/java/com/wire/bots/hold/utils/Cache.java @@ -13,7 +13,7 @@ import java.util.concurrent.ConcurrentHashMap; public class Cache { - private static String DEFAULT_DOMAIN = null; + private static String FALLBACK_DOMAIN = null; private static final ConcurrentHashMap assets = new ConcurrentHashMap<>(); // private static final ConcurrentHashMap users = new ConcurrentHashMap<>(); // @@ -26,14 +26,12 @@ public Cache(API api, AssetsDAO assetsDAO) { this.assetsDAO = assetsDAO; } - public static void setDefaultDomain(String domain) { - if (DEFAULT_DOMAIN == null) { - DEFAULT_DOMAIN = domain; - } + public static void setFallbackDomain(String domain) { + FALLBACK_DOMAIN = domain; } - public static String getDefaultDomain() { - return DEFAULT_DOMAIN; + public static String getFallbackDomain() { + return FALLBACK_DOMAIN; } @Nullable diff --git a/src/main/resources/db/migration/V107__add_metadata_table.sql b/src/main/resources/db/migration/V107__add_metadata_table.sql new file mode 100644 index 0000000..86e2406 --- /dev/null +++ b/src/main/resources/db/migration/V107__add_metadata_table.sql @@ -0,0 +1,4 @@ +CREATE TABLE Metadata ( + key VARCHAR NOT NULL UNIQUE, + value VARCHAR NOT NULL +); diff --git a/src/test/java/com/wire/bots/hold/DatabaseTest.java b/src/test/java/com/wire/bots/hold/DatabaseTest.java index 8ee64b9..833b28f 100644 --- a/src/test/java/com/wire/bots/hold/DatabaseTest.java +++ b/src/test/java/com/wire/bots/hold/DatabaseTest.java @@ -5,9 +5,11 @@ import com.wire.bots.hold.DAO.AccessDAO; import com.wire.bots.hold.DAO.AssetsDAO; import com.wire.bots.hold.DAO.EventsDAO; +import com.wire.bots.hold.DAO.MetadataDAO; import com.wire.bots.hold.model.Config; import com.wire.bots.hold.model.Event; import com.wire.bots.hold.model.LHAccess; +import com.wire.bots.hold.model.Metadata; import com.wire.xenon.backend.models.QualifiedId; import com.wire.xenon.models.TextMessage; import io.dropwizard.testing.ConfigOverride; @@ -28,6 +30,7 @@ public class DatabaseTest { private static AssetsDAO assetsDAO; private static EventsDAO eventsDAO; private static AccessDAO accessDAO; + private static MetadataDAO metadataDAO; @BeforeClass public static void init() throws Exception { @@ -37,6 +40,7 @@ public static void init() throws Exception { eventsDAO = app.getJdbi().onDemand(EventsDAO.class); assetsDAO = app.getJdbi().onDemand(AssetsDAO.class); accessDAO = app.getJdbi().onDemand(AccessDAO.class); + metadataDAO = app.getJdbi().onDemand(MetadataDAO.class); } @AfterClass @@ -116,4 +120,18 @@ public void accessTests() { assert lhAccess2 != null; assert lhAccess2.created.equals(lhAccess.created); } + + @Test + public void metadataTests() { + String dummyKey = MetadataDAO.FALLBACK_DOMAIN_KEY + UUID.randomUUID(); + + Metadata nullMetadata = metadataDAO.get(dummyKey); + assert nullMetadata == null; + + int insert = metadataDAO.insert(dummyKey, "dummy_domain"); + Metadata metadata = metadataDAO.get(dummyKey); + + assert metadata != null; + assert metadata.value.equals("dummy_domain"); + } } diff --git a/src/test/java/com/wire/bots/hold/FallbackDomainFetcherTest.java b/src/test/java/com/wire/bots/hold/FallbackDomainFetcherTest.java new file mode 100644 index 0000000..0b83ffe --- /dev/null +++ b/src/test/java/com/wire/bots/hold/FallbackDomainFetcherTest.java @@ -0,0 +1,102 @@ +package com.wire.bots.hold; + +import com.wire.bots.hold.DAO.MetadataDAO; +import com.wire.bots.hold.model.Metadata; +import com.wire.bots.hold.utils.Cache; +import com.wire.helium.LoginClient; +import com.wire.helium.models.BackendConfiguration; +import com.wire.xenon.exceptions.HttpException; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.times; + +public class FallbackDomainFetcherTest { + + private MetadataDAO metadataDAO; + private LoginClient loginClient; + private FallbackDomainFetcher fallbackDomainFetcher; + + @Before + public void before() { + // Clears cached domain + Cache.setFallbackDomain(null); + metadataDAO = mock(MetadataDAO.class); + loginClient = mock(LoginClient.class); + fallbackDomainFetcher = new FallbackDomainFetcher(loginClient, metadataDAO); + } + + @After + public void after() { + // Clears cached domain + Cache.setFallbackDomain(null); + } + + @Test + public void givenNoFallbackDomainInCacheAndDatabase_whenExecuting_thenFetchFromApiAndStoreInCacheAndDatabase() throws HttpException { + // given + BackendConfiguration backendConfiguration = new BackendConfiguration(); + backendConfiguration.domain = "dummy_domain_3"; + + when(metadataDAO.get(MetadataDAO.FALLBACK_DOMAIN_KEY)).thenReturn(null); + when(metadataDAO.insert(any(), any())).thenReturn(1); + when(loginClient.getBackendConfiguration()).thenReturn(backendConfiguration); + + // when + fallbackDomainFetcher.run(); + + // then + assert Cache.getFallbackDomain().equals("dummy_domain_3"); + verify(metadataDAO, times(1)).insert(MetadataDAO.FALLBACK_DOMAIN_KEY, backendConfiguration.domain); + } + + @Test + public void givenNoFallbackDomainInCache_whenExecuting_thenFetchFromAPIAndCompareWithDatabase() throws HttpException { + // given + BackendConfiguration backendConfiguration = new BackendConfiguration(); + backendConfiguration.domain = "dummy_domain_2"; + + Metadata metadata = new Metadata(MetadataDAO.FALLBACK_DOMAIN_KEY, "dummy_domain_2"); + + when(metadataDAO.get(MetadataDAO.FALLBACK_DOMAIN_KEY)).thenReturn(metadata); + when(loginClient.getBackendConfiguration()).thenReturn(backendConfiguration); + + // when + fallbackDomainFetcher.run(); + + // then + assert Cache.getFallbackDomain().equals("dummy_domain_2"); + } + + @Test(expected=RuntimeException.class) + public void givenNoFallbackDomainInCache_whenExecutingAndApiReturnsDifferentDomainFromDatabase_thenThrowRuntimeException() throws HttpException, RuntimeException { + // given + BackendConfiguration backendConfiguration = new BackendConfiguration(); + backendConfiguration.domain = "dummy_domain_1"; + + Metadata metadata = new Metadata(MetadataDAO.FALLBACK_DOMAIN_KEY, "dummy_domain_2"); + + when(metadataDAO.get(MetadataDAO.FALLBACK_DOMAIN_KEY)).thenReturn(metadata); + when(loginClient.getBackendConfiguration()).thenReturn(backendConfiguration); + + // when + fallbackDomainFetcher.run(); + } + + @Test + public void givenFallbackDomainInCache_whenExecuting_thenReturnAndIgnoreDatabaseAndApiCalls() { + // given + Cache.setFallbackDomain("dummy_domain_0"); + + // when + fallbackDomainFetcher.run(); + + // then + assert Cache.getFallbackDomain().equals("dummy_domain_0"); + } +} diff --git a/src/test/java/com/wire/bots/hold/utils/CacheTest.java b/src/test/java/com/wire/bots/hold/utils/CacheTest.java new file mode 100644 index 0000000..ddbf2dd --- /dev/null +++ b/src/test/java/com/wire/bots/hold/utils/CacheTest.java @@ -0,0 +1,38 @@ +package com.wire.bots.hold.utils; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class CacheTest { + + @Before + public void before() { + // Clears cached domain + Cache.setFallbackDomain(null); + } + + @After + public void after() { + // Clears cached domain + Cache.setFallbackDomain(null); + } + + @Test + public void verifyDefaultDomainIsSetCorrectly() { + String firstDomain = Cache.getFallbackDomain(); + assert firstDomain == null; + + Cache.setFallbackDomain("dummy_domain"); + String secondDomain = Cache.getFallbackDomain(); + + assert secondDomain != null; + assert secondDomain.equals("dummy_domain"); + + Cache.setFallbackDomain("dummy_domain_3"); + String thirdDomain = Cache.getFallbackDomain(); + + assert thirdDomain != null; + assert thirdDomain.equals("dummy_domain_3"); + } +} diff --git a/src/test/java/com/wire/bots/hold/utils/TestCache.java b/src/test/java/com/wire/bots/hold/utils/TestCache.java index 1ea23e8..3a16723 100644 --- a/src/test/java/com/wire/bots/hold/utils/TestCache.java +++ b/src/test/java/com/wire/bots/hold/utils/TestCache.java @@ -33,22 +33,4 @@ public User getUser(QualifiedId userId) { return dummyUser; } - - @Test - public void verifyDefaultDomainIsSetCorrectly() { - String firstDomain = Cache.getDefaultDomain(); - assert firstDomain == null; - - Cache.setDefaultDomain("dummy_domain"); - String secondDomain = Cache.getDefaultDomain(); - - assert secondDomain != null; - assert secondDomain.equals("dummy_domain"); - - Cache.setDefaultDomain("dummy_domain_3"); - String thirdDomain = Cache.getDefaultDomain(); - - assert thirdDomain != null; - assert thirdDomain.equals("dummy_domain"); - } } From b2137d607415eb451b23ff39b95cfd2a9fd9617a Mon Sep 17 00:00:00 2001 From: alexandreferris Date: Mon, 7 Oct 2024 14:59:51 +0200 Subject: [PATCH 3/4] feat(get-domain-from-backend) Use new Helium API to fetch backend domain * Update Helium to 1.4.1 * Add assertions to major tests * Remove Consts.java from tests * Add call to get api version and default domain * Persist fallback domain to database * Add FallbackDomainFetcher to handle fetch from cache, database and API * Properly receive thrown exception from dropwizard task execution * Add Mockito for testing mocks * Add JavaDoc for FallbackDomainFetcher --- pom.xml | 4 +-- .../wire/bots/hold/FallbackDomainFetcher.java | 9 +++++ src/main/java/com/wire/bots/hold/Service.java | 36 +++++++++++++++---- .../db/migration/V107__add_metadata_table.sql | 4 +-- .../bots/hold/FallbackDomainFetcherTest.java | 2 +- 5 files changed, 43 insertions(+), 12 deletions(-) diff --git a/pom.xml b/pom.xml index c255d0e..33772e3 100644 --- a/pom.xml +++ b/pom.xml @@ -137,8 +137,8 @@ org.mockito - mockito-all - 1.10.19 + mockito-core + 5.14.1 test diff --git a/src/main/java/com/wire/bots/hold/FallbackDomainFetcher.java b/src/main/java/com/wire/bots/hold/FallbackDomainFetcher.java index 58e7a40..40741e9 100644 --- a/src/main/java/com/wire/bots/hold/FallbackDomainFetcher.java +++ b/src/main/java/com/wire/bots/hold/FallbackDomainFetcher.java @@ -19,6 +19,12 @@ public class FallbackDomainFetcher implements Runnable { * Fetches from API and compares against database value (if any), then inserts into database and updates cache value. * If value received from the API is different from what is saved in the database, a [RuntimeException] is thrown. *

+ *

+ * This fallback domain is necessary for LegalHold to work with Federation (as it needs id@domain) and not just the ID anymore. + * In case there is a mismatch we are throwing a RuntimeException so it stops the execution of this app, so in an event + * of already having a defined default domain saved in the database and this app restarts with a different domain + * we don't get mismatching domains. + *

* @param loginClient [{@link LoginClient}] as API to get backend configuration containing default domain. * @param metadataDAO [{@link MetadataDAO}] as DAO to get/insert default domain to database. * @@ -41,9 +47,12 @@ public void run() { metadataDAO.insert(MetadataDAO.FALLBACK_DOMAIN_KEY, apiVersionResponse.domain); Cache.setFallbackDomain(apiVersionResponse.domain); } else { + System.out.println("EEEEEEEE -> " + apiVersionResponse.domain); if (metadata.value.equals(apiVersionResponse.domain)) { + System.out.println("EEEEEEEE -> p1"); Cache.setFallbackDomain(apiVersionResponse.domain); } else { + System.out.println("EEEEEEEE -> p2"); String formattedExceptionMessage = String.format( "Database already has a default domain as %s and instead we got %s from the Backend API.", metadata.value, diff --git a/src/main/java/com/wire/bots/hold/Service.java b/src/main/java/com/wire/bots/hold/Service.java index 4b2615f..61a1ed8 100644 --- a/src/main/java/com/wire/bots/hold/Service.java +++ b/src/main/java/com/wire/bots/hold/Service.java @@ -55,6 +55,8 @@ import org.jdbi.v3.sqlobject.SqlObjectPlugin; import javax.ws.rs.client.Client; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; public class Service extends Application { @@ -92,7 +94,7 @@ protected SwaggerBundleConfiguration getSwaggerBundleConfiguration(Config config } @Override - public void run(Config config, Environment environment) { + public void run(Config config, Environment environment) throws ExecutionException, InterruptedException { this.config = config; this.environment = environment; Service.metrics = environment.metrics(); @@ -129,17 +131,37 @@ public void run(Config config, Environment environment) { addResource(ServiceAuthenticationFilter.ServiceAuthenticationFeature.class); - environment - .lifecycle() - .executorService("fallback_domain_fetcher") - .build() - .execute( +// environment +// .lifecycle() +// .executorService("fallback_domain_fetcher") +// .build() +// .submit( +// new FallbackDomainFetcher( +// new LoginClient(httpClient), +// metadataDAO +// ) +// ); + + Runnable run = new Runnable() { + @Override + public void run(){ new FallbackDomainFetcher( new LoginClient(httpClient), metadataDAO - ) + ).run(); + } + }; + + final Future fallbackDomainFetcher = environment + .lifecycle() + .executorService("fallback_domain_fetcher") + .build() + .submit( + run ); + fallbackDomainFetcher.get(); + environment.healthChecks().register( "SanityCheck", new SanityCheck(accessDAO, httpClient) diff --git a/src/main/resources/db/migration/V107__add_metadata_table.sql b/src/main/resources/db/migration/V107__add_metadata_table.sql index 86e2406..ef255d4 100644 --- a/src/main/resources/db/migration/V107__add_metadata_table.sql +++ b/src/main/resources/db/migration/V107__add_metadata_table.sql @@ -1,4 +1,4 @@ CREATE TABLE Metadata ( - key VARCHAR NOT NULL UNIQUE, - value VARCHAR NOT NULL + key VARCHAR(255) PRIMARY KEY, + value VARCHAR(255) NOT NULL ); diff --git a/src/test/java/com/wire/bots/hold/FallbackDomainFetcherTest.java b/src/test/java/com/wire/bots/hold/FallbackDomainFetcherTest.java index 0b83ffe..26f9c4c 100644 --- a/src/test/java/com/wire/bots/hold/FallbackDomainFetcherTest.java +++ b/src/test/java/com/wire/bots/hold/FallbackDomainFetcherTest.java @@ -10,7 +10,7 @@ import org.junit.Before; import org.junit.Test; -import static org.mockito.Matchers.any; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.mockito.Mockito.verify; From c7e416cda9beeec7ad1581fa703ff6dc902fac8c Mon Sep 17 00:00:00 2001 From: alexandreferris Date: Mon, 7 Oct 2024 14:59:51 +0200 Subject: [PATCH 4/4] feat(get-domain-from-backend) Use new Helium API to fetch backend domain * Update Helium to 1.4.1 * Add assertions to major tests * Remove Consts.java from tests * Add call to get api version and default domain * Persist fallback domain to database * Add FallbackDomainFetcher to handle fetch from cache, database and API * Properly receive thrown exception from dropwizard task execution * Add Mockito for testing mocks * Add JavaDoc for FallbackDomainFetcher --- pom.xml | 4 +-- .../wire/bots/hold/FallbackDomainFetcher.java | 9 +++++++ src/main/java/com/wire/bots/hold/Service.java | 25 +++++++++++++------ .../db/migration/V107__add_metadata_table.sql | 4 +-- .../bots/hold/FallbackDomainFetcherTest.java | 2 +- 5 files changed, 32 insertions(+), 12 deletions(-) diff --git a/pom.xml b/pom.xml index c255d0e..33772e3 100644 --- a/pom.xml +++ b/pom.xml @@ -137,8 +137,8 @@ org.mockito - mockito-all - 1.10.19 + mockito-core + 5.14.1 test diff --git a/src/main/java/com/wire/bots/hold/FallbackDomainFetcher.java b/src/main/java/com/wire/bots/hold/FallbackDomainFetcher.java index 58e7a40..40741e9 100644 --- a/src/main/java/com/wire/bots/hold/FallbackDomainFetcher.java +++ b/src/main/java/com/wire/bots/hold/FallbackDomainFetcher.java @@ -19,6 +19,12 @@ public class FallbackDomainFetcher implements Runnable { * Fetches from API and compares against database value (if any), then inserts into database and updates cache value. * If value received from the API is different from what is saved in the database, a [RuntimeException] is thrown. *

+ *

+ * This fallback domain is necessary for LegalHold to work with Federation (as it needs id@domain) and not just the ID anymore. + * In case there is a mismatch we are throwing a RuntimeException so it stops the execution of this app, so in an event + * of already having a defined default domain saved in the database and this app restarts with a different domain + * we don't get mismatching domains. + *

* @param loginClient [{@link LoginClient}] as API to get backend configuration containing default domain. * @param metadataDAO [{@link MetadataDAO}] as DAO to get/insert default domain to database. * @@ -41,9 +47,12 @@ public void run() { metadataDAO.insert(MetadataDAO.FALLBACK_DOMAIN_KEY, apiVersionResponse.domain); Cache.setFallbackDomain(apiVersionResponse.domain); } else { + System.out.println("EEEEEEEE -> " + apiVersionResponse.domain); if (metadata.value.equals(apiVersionResponse.domain)) { + System.out.println("EEEEEEEE -> p1"); Cache.setFallbackDomain(apiVersionResponse.domain); } else { + System.out.println("EEEEEEEE -> p2"); String formattedExceptionMessage = String.format( "Database already has a default domain as %s and instead we got %s from the Backend API.", metadata.value, diff --git a/src/main/java/com/wire/bots/hold/Service.java b/src/main/java/com/wire/bots/hold/Service.java index 4b2615f..dcae767 100644 --- a/src/main/java/com/wire/bots/hold/Service.java +++ b/src/main/java/com/wire/bots/hold/Service.java @@ -55,6 +55,8 @@ import org.jdbi.v3.sqlobject.SqlObjectPlugin; import javax.ws.rs.client.Client; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; public class Service extends Application { @@ -92,7 +94,7 @@ protected SwaggerBundleConfiguration getSwaggerBundleConfiguration(Config config } @Override - public void run(Config config, Environment environment) { + public void run(Config config, Environment environment) throws ExecutionException, InterruptedException { this.config = config; this.environment = environment; Service.metrics = environment.metrics(); @@ -129,17 +131,26 @@ public void run(Config config, Environment environment) { addResource(ServiceAuthenticationFilter.ServiceAuthenticationFeature.class); - environment - .lifecycle() - .executorService("fallback_domain_fetcher") - .build() - .execute( + Runnable run = new Runnable() { + @Override + public void run(){ new FallbackDomainFetcher( new LoginClient(httpClient), metadataDAO - ) + ).run(); + } + }; + + final Future fallbackDomainFetcher = environment + .lifecycle() + .executorService("fallback_domain_fetcher") + .build() + .submit( + run ); + fallbackDomainFetcher.get(); + environment.healthChecks().register( "SanityCheck", new SanityCheck(accessDAO, httpClient) diff --git a/src/main/resources/db/migration/V107__add_metadata_table.sql b/src/main/resources/db/migration/V107__add_metadata_table.sql index 86e2406..ef255d4 100644 --- a/src/main/resources/db/migration/V107__add_metadata_table.sql +++ b/src/main/resources/db/migration/V107__add_metadata_table.sql @@ -1,4 +1,4 @@ CREATE TABLE Metadata ( - key VARCHAR NOT NULL UNIQUE, - value VARCHAR NOT NULL + key VARCHAR(255) PRIMARY KEY, + value VARCHAR(255) NOT NULL ); diff --git a/src/test/java/com/wire/bots/hold/FallbackDomainFetcherTest.java b/src/test/java/com/wire/bots/hold/FallbackDomainFetcherTest.java index 0b83ffe..26f9c4c 100644 --- a/src/test/java/com/wire/bots/hold/FallbackDomainFetcherTest.java +++ b/src/test/java/com/wire/bots/hold/FallbackDomainFetcherTest.java @@ -10,7 +10,7 @@ import org.junit.Before; import org.junit.Test; -import static org.mockito.Matchers.any; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.mockito.Mockito.verify;