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;