diff --git a/galasa-extensions-parent/dev.galasa.auth.couchdb/src/main/java/dev/galasa/auth/couchdb/internal/CouchdbAuthStore.java b/galasa-extensions-parent/dev.galasa.auth.couchdb/src/main/java/dev/galasa/auth/couchdb/internal/CouchdbAuthStore.java index 3704269c..3f31816a 100644 --- a/galasa-extensions-parent/dev.galasa.auth.couchdb/src/main/java/dev/galasa/auth/couchdb/internal/CouchdbAuthStore.java +++ b/galasa-extensions-parent/dev.galasa.auth.couchdb/src/main/java/dev/galasa/auth/couchdb/internal/CouchdbAuthStore.java @@ -13,7 +13,6 @@ import java.time.Instant; import java.util.ArrayList; import java.util.List; -import java.util.Optional; import org.apache.commons.logging.Log; import org.apache.http.HttpStatus; @@ -22,6 +21,8 @@ import org.apache.http.impl.client.CloseableHttpClient; import dev.galasa.auth.couchdb.internal.beans.AuthDBNameViewDesign; +import dev.galasa.auth.couchdb.internal.beans.FrontEndClient; +import dev.galasa.auth.couchdb.internal.beans.UserDoc; import dev.galasa.extensions.common.api.HttpClientFactory; import dev.galasa.extensions.common.api.LogFactory; import dev.galasa.extensions.common.couchdb.CouchdbException; @@ -32,11 +33,11 @@ import dev.galasa.extensions.common.api.HttpRequestFactory; import dev.galasa.framework.spi.auth.IInternalAuthToken; import dev.galasa.framework.spi.auth.IInternalUser; -import dev.galasa.framework.spi.auth.UserDoc; +import dev.galasa.framework.spi.auth.IUser; import dev.galasa.framework.spi.auth.IAuthStore; +import dev.galasa.framework.spi.auth.IFrontEndClient; import dev.galasa.framework.spi.utils.ITimeService; import dev.galasa.framework.spi.auth.AuthStoreException; -import dev.galasa.framework.spi.auth.FrontendClient; /** * When CouchDB is being used to store user-related information, including @@ -59,7 +60,7 @@ public class CouchdbAuthStore extends CouchdbStore implements IAuthStore { public static final String COUCHDB_AUTH_TYPE = "Basic"; public static final String TOKENS_DB_VIEW_NAME = "loginId-view"; - public static final String USERS_DB_VIEW_NAME = "users-loginId-view"; + public static final String USERS_DB_VIEW_NAME = "loginId-view"; private Log logger; private ITimeService timeService; @@ -173,11 +174,11 @@ private IInternalAuthToken getAuthTokenFromDocument(String documentId) throws Co } @Override - public List getAllUsers() throws AuthStoreException { + public List getAllUsers() throws AuthStoreException { logger.info("Retrieving all users from couchdb"); List userDocuments = new ArrayList<>(); - List users = new ArrayList<>(); + List users = new ArrayList<>(); try { userDocuments = getAllDocsFromDatabase(USERS_DATABASE_NAME); @@ -198,7 +199,13 @@ public List getAllUsers() throws AuthStoreException { @Override public void createUser(String loginId, String clientName) throws AuthStoreException { - String userJson = gson.toJson(new UserDoc(loginId, List.of(new FrontendClient(clientName, Instant.now())))); + + FrontEndClient client = new FrontEndClient(); + + client.setClientName(clientName); + client.setLastLogin(Instant.now()); + + String userJson = gson.toJson(new UserDoc(loginId, List.of(client))); try { createDocument(USERS_DATABASE_NAME, userJson); @@ -206,32 +213,38 @@ public void createUser(String loginId, String clientName) throws AuthStoreExcept String errorMessage = ERROR_FAILED_TO_CREATE_USER_DOCUMENT.getMessage(e.getMessage()); throw new AuthStoreException(errorMessage, e); } + + return; } @Override - public UserDoc getUserByLoginId(String loginId) throws AuthStoreException { + public IUser getUserByLoginId(String loginId) throws AuthStoreException { logger.info("Retrieving user by loginId from CouchDB"); - List userDocument = new ArrayList<>(); - List users = new ArrayList<>(); - - UserDoc user = null; - String revNumber = null; + List userDocument; + IUser user = null; try { - + // Fetch documents matching the loginId userDocument = getAllDocsByLoginId(USERS_DATABASE_NAME, loginId, USERS_DB_VIEW_NAME); - // Build up a list of all the tokens using the document IDs - for (ViewRow row : userDocument) { - users.add(getUserFromDocument(row.id)); + // Since loginIds are unique, there should be only one document. + if (!userDocument.isEmpty()) { + ViewRow row = userDocument.get(0); // Get the first entry since loginId is unique + + // Fetch the user document from the CouchDB using the ID from the row + UserDoc fetchedUser = getUserFromDocument(row.id); + logger.info("Fetched user: " + fetchedUser); if (row.value != null) { AuthDBNameViewDesign nameViewDesign = gson.fromJson(gson.toJson(row.value), - AuthDBNameViewDesign.class); - revNumber = nameViewDesign._rev; + AuthDBNameViewDesign.class); + fetchedUser.setVersion(nameViewDesign._rev); // Set the version from the CouchDB rev } + // Assign fetchedUser to the user variable + user = fetchedUser; } + logger.info("User retrieved from CouchDB OK"); } catch (CouchdbException e) { @@ -239,82 +252,91 @@ public UserDoc getUserByLoginId(String loginId) throws AuthStoreException { throw new AuthStoreException(errorMessage, e); } - // Always going to return one entry, as loginIds are unique. - // Hence, we can take out the first index - if (!users.isEmpty()) { - - user = users.get(0); - user.setUserNumber(userDocument.get(0).id); - user.setVersion(revNumber); - - } - return user; - } @Override - public void updateUserClientActivity(String loginId, String clientName) throws AuthStoreException { + public IUser updateUser(IUser user) throws AuthStoreException { + // Take a clone of the user we are passed, so we can guarantee we are using our bean which + // serialises to the correct format. + UserDoc userDoc = new UserDoc(user); + updateUserDoc(httpClient, storeUri, 0, userDoc); + return userDoc; + } - UserDoc user = getUserByLoginId(loginId); + private void updateUserDoc(CloseableHttpClient httpClient, URI couchdbUri, int attempts, UserDoc user) + throws AuthStoreException { - List clients = user.getClients(); + validateUserDoc(user); - Optional clientOptional = clients.stream() - .filter(client -> client.getClientName().equals(clientName)) - .findFirst(); + HttpEntityEnclosingRequestBase request = buildUpdateUserDocRequest(user, couchdbUri); - if (clientOptional.isPresent()) { - FrontendClient client = clientOptional.get(); - client.setLastLoggedIn(Instant.now()); - } else { - // User has used a new client. - FrontendClient newClient = new FrontendClient(clientName, Instant.now()); - clients.add(newClient); - } + PutPostResponse putResponse = sendPutRequestToCouchDb(request); + validateCouchdbResponseJson(user.getUserNumber(), putResponse); + + // The version of the document in couchdb has updated, so lets update our version in the doc we were sent, + // so that the same document could be used for another update. + user.setVersion(putResponse.rev); + } + + private PutPostResponse sendPutRequestToCouchDb(HttpEntityEnclosingRequestBase request) throws AuthStoreException { + PutPostResponse putResponse; try { - updateUserDoc(httpClient, storeUri, 0, user); + String entity = sendHttpRequest(request, HttpStatus.SC_CREATED); + putResponse = gson.fromJson(entity, PutPostResponse.class); + } catch (CouchdbException e) { - e.printStackTrace(); - throw new AuthStoreException(e); + String errorMessage = ERROR_FAILED_TO_UPDATE_USER_DOCUMENT.getMessage(e.getMessage()); + throw new AuthStoreException(errorMessage,e); } + return putResponse; } - private void updateUserDoc(CloseableHttpClient httpClient, URI couchdbUri, int attempts, UserDoc user) - throws CouchdbException { + private HttpEntityEnclosingRequestBase buildUpdateUserDocRequest(UserDoc user, URI couchdbUri) { + HttpEntityEnclosingRequestBase request; String jsonStructure = gson.toJson(user); - - HttpEntityEnclosingRequestBase request; - - if (user.getUserNumber() == null) { - request = httpRequestFactory.getHttpPostRequest(couchdbUri + "/" + USERS_DATABASE_NAME); - } else { - request = httpRequestFactory - .getHttpPutRequest(couchdbUri + "/" + USERS_DATABASE_NAME + "/" + user.getUserNumber()); - request.setHeader("If-Match", user.getVersion()); - - logger.info("Rev is: " + user.getVersion()); - } - + request = httpRequestFactory + .getHttpPutRequest(couchdbUri + "/" + USERS_DATABASE_NAME + "/" + user.getUserNumber()); + request.setHeader("If-Match", user.getVersion()); + request.setEntity(new StringEntity(jsonStructure, StandardCharsets.UTF_8)); + return request; + } - try { - String entity = sendHttpRequest(request, HttpStatus.SC_CREATED); - PutPostResponse putPostResponse = gson.fromJson(entity, PutPostResponse.class); - - if (putPostResponse.id == null || putPostResponse.rev == null) { - throw new CouchdbException("Unable to store the user structure - Invalid JSON response"); - } + private void validateCouchdbResponseJson(String expectedUserNumber , PutPostResponse putResponse) throws AuthStoreException { + if (putResponse.id == null || putResponse.rev == null) { + String errorMessage = ERROR_FAILED_TO_UPDATE_USER_DOCUMENT_INVALID_RESP.getMessage(); + throw new AuthStoreException(errorMessage); + } + if (!expectedUserNumber.equals(putResponse.id)) { + String errorMessage = ERROR_FAILED_TO_UPDATE_USER_DOCUMENT_MISMATCH_DOC_ID.getMessage(); + throw new AuthStoreException(errorMessage); + } + } - user.setUserNumber(putPostResponse.id); - user.setVersion(putPostResponse.rev); + private void validateUserDoc(UserDoc user) throws AuthStoreException { + if (user.getUserNumber() == null) { + String errorMessage = ERROR_FAILED_TO_UPDATE_USER_DOCUMENT_INPUT_INVALID_NULL_USER_NUMBER.getMessage(); + throw new AuthStoreException(errorMessage); + } + + if (user.getVersion() == null) { + String errorMessage = ERROR_FAILED_TO_UPDATE_USER_DOCUMENT_INPUT_INVALID_NULL_USER_VERSION.getMessage(); + throw new AuthStoreException(errorMessage); + } + } - } catch (CouchdbException e) { - throw new CouchdbException(e); - } + @Override + public void deleteUser(IUser user) throws AuthStoreException { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'deleteUser'"); + } + @Override + public IFrontEndClient createClient(String clientName) { + return new FrontEndClient(clientName, timeService.now()); } /** diff --git a/galasa-extensions-parent/dev.galasa.auth.couchdb/src/main/java/dev/galasa/auth/couchdb/internal/CouchdbAuthStoreValidator.java b/galasa-extensions-parent/dev.galasa.auth.couchdb/src/main/java/dev/galasa/auth/couchdb/internal/CouchdbAuthStoreValidator.java index a9378019..cbcfd03f 100644 --- a/galasa-extensions-parent/dev.galasa.auth.couchdb/src/main/java/dev/galasa/auth/couchdb/internal/CouchdbAuthStoreValidator.java +++ b/galasa-extensions-parent/dev.galasa.auth.couchdb/src/main/java/dev/galasa/auth/couchdb/internal/CouchdbAuthStoreValidator.java @@ -97,7 +97,7 @@ public void checkTokensDesignDocument(CloseableHttpClient httpClient, URI couchd AuthDBNameViewDesign tableDesign = parseTokenDesignFromJson(docJson); - boolean isDesignUpdated = updateDesignDocToDesiredDesignDoc(tableDesign); + boolean isDesignUpdated = updateDesignDocToDesiredDesignDoc(tableDesign, dbName); if (isDesignUpdated) { updateTokenDesignDocument(httpClient, couchdbUri, attempts, tableDesign, dbName); @@ -118,23 +118,27 @@ private AuthDBNameViewDesign parseTokenDesignFromJson(String docJson) throws Cou return tableDesign; } - private boolean updateDesignDocToDesiredDesignDoc(AuthDBNameViewDesign tableDesign) { + private boolean updateDesignDocToDesiredDesignDoc(AuthDBNameViewDesign tableDesign, String dbName) { boolean isUpdated = false; if (tableDesign.views == null) { isUpdated = true; - tableDesign.views = new TokenDBViews(); + tableDesign.views = new AuthStoreDBViews(); } if (tableDesign.views.loginIdView == null) { isUpdated = true; - tableDesign.views.loginIdView = new TokenDBLoginView(); + tableDesign.views.loginIdView = new AuthStoreDBLoginView(); } - if (tableDesign.views.loginIdView.map == null - || !DB_TABLE_TOKENS_DESIGN.equals(tableDesign.views.loginIdView.map)) { + if (tableDesign.views.loginIdView.map == null) { isUpdated = true; - tableDesign.views.loginIdView.map = DB_TABLE_TOKENS_DESIGN; + if(dbName.equals("galasa_tokens")){ + tableDesign.views.loginIdView.map = DB_TABLE_TOKENS_DESIGN; + } + else{ + tableDesign.views.loginIdView.map = DB_TABLE_USERS_DESIGN; + } } if (tableDesign.language == null || !tableDesign.language.equals("javascript")) { diff --git a/galasa-extensions-parent/dev.galasa.auth.couchdb/src/main/java/dev/galasa/auth/couchdb/internal/beans/AuthDBNameViewDesign.java b/galasa-extensions-parent/dev.galasa.auth.couchdb/src/main/java/dev/galasa/auth/couchdb/internal/beans/AuthDBNameViewDesign.java index 8a508382..77180e21 100644 --- a/galasa-extensions-parent/dev.galasa.auth.couchdb/src/main/java/dev/galasa/auth/couchdb/internal/beans/AuthDBNameViewDesign.java +++ b/galasa-extensions-parent/dev.galasa.auth.couchdb/src/main/java/dev/galasa/auth/couchdb/internal/beans/AuthDBNameViewDesign.java @@ -9,10 +9,10 @@ public class AuthDBNameViewDesign { public String _rev; public String _id; - public TokenDBViews views; + public AuthStoreDBViews views; public String language; - public AuthDBNameViewDesign(String _rev, String _id, TokenDBViews views, String language) { + public AuthDBNameViewDesign(String _rev, String _id, AuthStoreDBViews views, String language) { this._rev = _rev; this._id = _id; this.views = views; diff --git a/galasa-extensions-parent/dev.galasa.auth.couchdb/src/main/java/dev/galasa/auth/couchdb/internal/beans/TokenDBLoginView.java b/galasa-extensions-parent/dev.galasa.auth.couchdb/src/main/java/dev/galasa/auth/couchdb/internal/beans/AuthStoreDBLoginView.java similarity index 82% rename from galasa-extensions-parent/dev.galasa.auth.couchdb/src/main/java/dev/galasa/auth/couchdb/internal/beans/TokenDBLoginView.java rename to galasa-extensions-parent/dev.galasa.auth.couchdb/src/main/java/dev/galasa/auth/couchdb/internal/beans/AuthStoreDBLoginView.java index 95c92afe..53b4fe8c 100644 --- a/galasa-extensions-parent/dev.galasa.auth.couchdb/src/main/java/dev/galasa/auth/couchdb/internal/beans/TokenDBLoginView.java +++ b/galasa-extensions-parent/dev.galasa.auth.couchdb/src/main/java/dev/galasa/auth/couchdb/internal/beans/AuthStoreDBLoginView.java @@ -5,6 +5,6 @@ */ package dev.galasa.auth.couchdb.internal.beans; -public class TokenDBLoginView { +public class AuthStoreDBLoginView { public String map; } \ No newline at end of file diff --git a/galasa-extensions-parent/dev.galasa.auth.couchdb/src/main/java/dev/galasa/auth/couchdb/internal/beans/TokenDBViews.java b/galasa-extensions-parent/dev.galasa.auth.couchdb/src/main/java/dev/galasa/auth/couchdb/internal/beans/AuthStoreDBViews.java similarity index 75% rename from galasa-extensions-parent/dev.galasa.auth.couchdb/src/main/java/dev/galasa/auth/couchdb/internal/beans/TokenDBViews.java rename to galasa-extensions-parent/dev.galasa.auth.couchdb/src/main/java/dev/galasa/auth/couchdb/internal/beans/AuthStoreDBViews.java index d7af7ffb..a92c6567 100644 --- a/galasa-extensions-parent/dev.galasa.auth.couchdb/src/main/java/dev/galasa/auth/couchdb/internal/beans/TokenDBViews.java +++ b/galasa-extensions-parent/dev.galasa.auth.couchdb/src/main/java/dev/galasa/auth/couchdb/internal/beans/AuthStoreDBViews.java @@ -7,7 +7,7 @@ import com.google.gson.annotations.SerializedName; -public class TokenDBViews { +public class AuthStoreDBViews { @SerializedName("loginId-view") - public TokenDBLoginView loginIdView; + public AuthStoreDBLoginView loginIdView; } diff --git a/galasa-extensions-parent/dev.galasa.auth.couchdb/src/main/java/dev/galasa/auth/couchdb/internal/beans/FrontEndClient.java b/galasa-extensions-parent/dev.galasa.auth.couchdb/src/main/java/dev/galasa/auth/couchdb/internal/beans/FrontEndClient.java new file mode 100644 index 00000000..cb3085b2 --- /dev/null +++ b/galasa-extensions-parent/dev.galasa.auth.couchdb/src/main/java/dev/galasa/auth/couchdb/internal/beans/FrontEndClient.java @@ -0,0 +1,55 @@ +package dev.galasa.auth.couchdb.internal.beans; + +import com.google.gson.annotations.SerializedName; + +import dev.galasa.framework.spi.auth.IFrontEndClient; +import java.time.Instant; + +public class FrontEndClient implements IFrontEndClient{ + + @SerializedName("client-name") + private String clientName; + + @SerializedName("last-login") + private Instant lastLogin; + + // No-arg constructor + public FrontEndClient() {} + + // Parameterized constructor + public FrontEndClient(String clientName, Instant lastLoggedIn) { + this.clientName = clientName; + this.lastLogin = lastLoggedIn; + } + + public FrontEndClient(IFrontEndClient fClient){ + this.clientName = fClient.getClientName(); + this.lastLogin = fClient.getLastLogin(); + } + + // Getter and Setter for lastLoggedIn + public Instant getLastLogin() { + return lastLogin; + } + + @Override + public void setLastLogin(Instant lastLoginTime) { + this.lastLogin = lastLoginTime; + } + + // Getter and Setter for clientName + public String getClientName() { + return clientName; + } + + public void setClientName(String clientName) { + this.clientName = clientName; + } + + // toString method to display client details + @Override + public String toString() { + return "Client [clientName=" + clientName + ", lastLoggedIn=" + lastLogin + "]"; + } + +} diff --git a/galasa-extensions-parent/dev.galasa.auth.couchdb/src/main/java/dev/galasa/auth/couchdb/internal/beans/UserDoc.java b/galasa-extensions-parent/dev.galasa.auth.couchdb/src/main/java/dev/galasa/auth/couchdb/internal/beans/UserDoc.java new file mode 100644 index 00000000..c8005052 --- /dev/null +++ b/galasa-extensions-parent/dev.galasa.auth.couchdb/src/main/java/dev/galasa/auth/couchdb/internal/beans/UserDoc.java @@ -0,0 +1,114 @@ +package dev.galasa.auth.couchdb.internal.beans; + +import java.util.Collection; +import java.util.List; +import java.util.ArrayList; + + +import com.google.gson.annotations.SerializedName; + +import dev.galasa.framework.spi.auth.IFrontEndClient; +import dev.galasa.framework.spi.auth.IUser; + +public class UserDoc implements IUser{ + + @SerializedName("_id") + private String userNumber; + + @SerializedName("_rev") + private String version; + + @SerializedName("login-id") + private String loginId; + + @SerializedName("activity") + private List clients; + + public UserDoc(String loginId, List clients) { + this.loginId = loginId; + setClients( clients); + } + + public UserDoc(IUser user){ + this.loginId = user.getLoginId(); + this.version = user.getVersion(); + this.userNumber = user.getUserNumber(); + setClients(user.getClients()); + } + + @Override + public String getUserNumber(){ + return userNumber; + } + + public void setUserNumber(String userNumber){ + this.userNumber = userNumber; + } + + public String getVersion(){ + return version; + } + + public void setVersion(String version){ + this.version = version; + } + + @Override + public String getLoginId() { + return loginId; + } + + public void setLoginId(String loginId) { + this.loginId = loginId; + } + + @Override + public Collection getClients() { + Collection results = new ArrayList(); + for( FrontEndClient client : this.clients) { + results.add(client); + } + return results; + } + + public void setClients(List clients) { + this.clients = new ArrayList(); + if( clients != null) { + for (IFrontEndClient clientIn: clients) { + addClient(clientIn); + } + } + } + + // Setter for clients. Takes a deep copy of any clients it is passed. + public void setClients(Collection clients) { + + this.clients = new ArrayList(); + if( clients != null) { + for (IFrontEndClient clientIn: clients) { + addClient(clientIn); + } + } + } + + @Override + public IFrontEndClient getClient(String clientName) { + IFrontEndClient match = null; + if (clientName != null) { + for (FrontEndClient frontEndClient : clients) { + if(clientName.equals(frontEndClient.getClientName())){ + match = frontEndClient; + break; + } + } + } + return match; + } + + @Override + public void addClient(IFrontEndClient client) { + clients.add( new FrontEndClient(client)); + } + + +} diff --git a/galasa-extensions-parent/dev.galasa.auth.couchdb/src/test/java/dev/galasa/auth/couchdb/TestCouchdbAuthStore.java b/galasa-extensions-parent/dev.galasa.auth.couchdb/src/test/java/dev/galasa/auth/couchdb/internal/TestCouchdbAuthStore.java similarity index 64% rename from galasa-extensions-parent/dev.galasa.auth.couchdb/src/test/java/dev/galasa/auth/couchdb/TestCouchdbAuthStore.java rename to galasa-extensions-parent/dev.galasa.auth.couchdb/src/test/java/dev/galasa/auth/couchdb/internal/TestCouchdbAuthStore.java index 4faf6e28..00363247 100644 --- a/galasa-extensions-parent/dev.galasa.auth.couchdb/src/test/java/dev/galasa/auth/couchdb/TestCouchdbAuthStore.java +++ b/galasa-extensions-parent/dev.galasa.auth.couchdb/src/test/java/dev/galasa/auth/couchdb/internal/TestCouchdbAuthStore.java @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package dev.galasa.auth.couchdb; +package dev.galasa.auth.couchdb.internal; import static org.assertj.core.api.Assertions.*; @@ -17,11 +17,8 @@ import org.apache.http.HttpStatus; import org.junit.Test; -import dev.galasa.auth.couchdb.internal.CouchdbAuthStore; -import dev.galasa.auth.couchdb.internal.CouchdbAuthToken; -import dev.galasa.auth.couchdb.internal.CouchdbUser; -import dev.galasa.auth.couchdb.internal.beans.TokenDBViews; -import dev.galasa.auth.couchdb.internal.beans.AuthDBNameViewDesign; +import dev.galasa.auth.couchdb.internal.beans.FrontEndClient; +import dev.galasa.auth.couchdb.internal.beans.UserDoc; import dev.galasa.extensions.common.couchdb.pojos.IdRev; import dev.galasa.extensions.common.couchdb.pojos.PutPostResponse; import dev.galasa.extensions.common.couchdb.pojos.ViewResponse; @@ -35,9 +32,9 @@ import dev.galasa.extensions.mocks.MockTimeService; import dev.galasa.extensions.mocks.couchdb.MockCouchdbValidator; import dev.galasa.framework.spi.auth.AuthStoreException; -import dev.galasa.framework.spi.auth.FrontendClient; +import dev.galasa.framework.spi.auth.IFrontEndClient; import dev.galasa.framework.spi.auth.IInternalAuthToken; -import dev.galasa.framework.spi.auth.UserDoc; +import dev.galasa.framework.spi.auth.IUser; public class TestCouchdbAuthStore { @@ -50,7 +47,7 @@ public GetAllDocumentsInteraction(String expectedUri, int responseStatusCode, Vi @Override public void validateRequest(HttpHost host, HttpRequest request) throws RuntimeException { - super.validateRequest(host,request); + super.validateRequest(host, request); assertThat(request.getRequestLine().getMethod()).isEqualTo("GET"); } } @@ -64,7 +61,7 @@ public GetDocumentInteraction(String expectedUri, int responseStatusCode, T resp @Override public void validateRequest(HttpHost host, HttpRequest request) throws RuntimeException { - super.validateRequest(host,request); + super.validateRequest(host, request); assertThat(request.getRequestLine().getMethod()).isEqualTo("GET"); } } @@ -78,7 +75,7 @@ public DeleteTokenDocumentInteraction(String expectedUri, int responseStatusCode @Override public void validateRequest(HttpHost host, HttpRequest request) throws RuntimeException { - super.validateRequest(host,request); + super.validateRequest(host, request); assertThat(request.getRequestLine().getMethod()).isEqualTo("DELETE"); } } @@ -97,26 +94,26 @@ public CreateDocumentInteraction(String expectedUri, int responseStatusCode) { @Override public void validateRequest(HttpHost host, HttpRequest request) throws RuntimeException { - super.validateRequest(host,request); + super.validateRequest(host, request); assertThat(request.getRequestLine().getMethod()).isEqualTo("POST"); } } class UpdateDocumentInteraction extends BaseHttpInteraction { - public UpdateDocumentInteraction(String expectedUri, int responseStatusCode) { + public UpdateDocumentInteraction(String expectedUri, int responseStatusCode, String id, String rev) { super(expectedUri, responseStatusCode); PutPostResponse responseTransportBean = new PutPostResponse(); - responseTransportBean.id = "id"; + responseTransportBean.id = id; responseTransportBean.ok = true; - responseTransportBean.rev = "rev"; + responseTransportBean.rev = rev; setResponsePayload(responseTransportBean); } @Override public void validateRequest(HttpHost host, HttpRequest request) throws RuntimeException { - super.validateRequest(host,request); + super.validateRequest(host, request); assertThat(request.getRequestLine().getMethod()).isEqualTo("PUT"); } } @@ -128,14 +125,16 @@ public void testGetTokensReturnsTokensWithFailingRequestReturnsErrorDup() throws MockLogFactory logFactory = new MockLogFactory(); List interactions = new ArrayList(); - interactions.add(new GetAllDocumentsInteraction("https://my-auth-store/galasa_tokens/_all_docs", HttpStatus.SC_INTERNAL_SERVER_ERROR, null)); + interactions.add(new GetAllDocumentsInteraction("https://my-auth-store/galasa_tokens/_all_docs", + HttpStatus.SC_INTERNAL_SERVER_ERROR, null)); MockCloseableHttpClient mockHttpClient = new MockCloseableHttpClient(interactions); MockHttpClientFactory httpClientFactory = new MockHttpClientFactory(mockHttpClient); MockTimeService mockTimeService = new MockTimeService(Instant.now()); - CouchdbAuthStore authStore = new CouchdbAuthStore(authStoreUri, httpClientFactory, new HttpRequestFactoryImpl(), logFactory, new MockCouchdbValidator(), mockTimeService); + CouchdbAuthStore authStore = new CouchdbAuthStore(authStoreUri, httpClientFactory, new HttpRequestFactoryImpl(), + logFactory, new MockCouchdbValidator(), mockTimeService); // When... AuthStoreException thrown = catchThrowableOfType(() -> authStore.getTokens(), AuthStoreException.class); @@ -158,17 +157,21 @@ public void testGetTokensReturnsTokensFromCouchdbOK() throws Exception { ViewResponse mockAllDocsResponse = new ViewResponse(); mockAllDocsResponse.rows = mockDocs; - CouchdbAuthToken mockToken = new CouchdbAuthToken("token1", "dex-client", "my test token", Instant.now(), new CouchdbUser("johndoe", "dex-user-id")); + CouchdbAuthToken mockToken = new CouchdbAuthToken("token1", "dex-client", "my test token", Instant.now(), + new CouchdbUser("johndoe", "dex-user-id")); List interactions = new ArrayList(); - interactions.add(new GetAllDocumentsInteraction("https://my-auth-store/galasa_tokens/_all_docs", HttpStatus.SC_OK, mockAllDocsResponse)); - interactions.add(new GetDocumentInteraction("https://my-auth-store/galasa_tokens/token1", HttpStatus.SC_OK, mockToken)); + interactions.add(new GetAllDocumentsInteraction("https://my-auth-store/galasa_tokens/_all_docs", + HttpStatus.SC_OK, mockAllDocsResponse)); + interactions.add(new GetDocumentInteraction("https://my-auth-store/galasa_tokens/token1", + HttpStatus.SC_OK, mockToken)); MockCloseableHttpClient mockHttpClient = new MockCloseableHttpClient(interactions); MockHttpClientFactory httpClientFactory = new MockHttpClientFactory(mockHttpClient); MockTimeService mockTimeService = new MockTimeService(Instant.now()); - CouchdbAuthStore authStore = new CouchdbAuthStore(authStoreUri, httpClientFactory, new HttpRequestFactoryImpl(), logFactory, new MockCouchdbValidator(), mockTimeService); + CouchdbAuthStore authStore = new CouchdbAuthStore(authStoreUri, httpClientFactory, new HttpRequestFactoryImpl(), + logFactory, new MockCouchdbValidator(), mockTimeService); // When... List tokens = authStore.getTokens(); @@ -193,19 +196,26 @@ public void testGetTokensReturnsTokensByLoginIdFromCouchdbOK() throws Exception ViewResponse mockAllDocsResponse = new ViewResponse(); mockAllDocsResponse.rows = mockDocs; - CouchdbAuthToken mockToken = new CouchdbAuthToken("token1", "dex-client", "my test token", Instant.now(), new CouchdbUser("johndoe", "dex-user-id")); - CouchdbAuthToken mockToken2 = new CouchdbAuthToken("token2", "dex-client", "my test token", Instant.now(), new CouchdbUser("notJohnDoe", "dex-user-id")); + CouchdbAuthToken mockToken = new CouchdbAuthToken("token1", "dex-client", "my test token", Instant.now(), + new CouchdbUser("johndoe", "dex-user-id")); + CouchdbAuthToken mockToken2 = new CouchdbAuthToken("token2", "dex-client", "my test token", Instant.now(), + new CouchdbUser("notJohnDoe", "dex-user-id")); List interactions = new ArrayList(); - interactions.add(new GetAllDocumentsInteraction("https://my-auth-store/galasa_tokens/_design/docs/_view/loginId-view?key=%22johndoe%22", HttpStatus.SC_OK, mockAllDocsResponse)); - interactions.add(new GetDocumentInteraction("https://my-auth-store/galasa_tokens/token1", HttpStatus.SC_OK, mockToken)); - interactions.add(new GetDocumentInteraction("https://my-auth-store/galasa_tokens/token1", HttpStatus.SC_OK, mockToken2)); + interactions.add(new GetAllDocumentsInteraction( + "https://my-auth-store/galasa_tokens/_design/docs/_view/loginId-view?key=%22johndoe%22", + HttpStatus.SC_OK, mockAllDocsResponse)); + interactions.add(new GetDocumentInteraction("https://my-auth-store/galasa_tokens/token1", + HttpStatus.SC_OK, mockToken)); + interactions.add(new GetDocumentInteraction("https://my-auth-store/galasa_tokens/token1", + HttpStatus.SC_OK, mockToken2)); MockCloseableHttpClient mockHttpClient = new MockCloseableHttpClient(interactions); MockHttpClientFactory httpClientFactory = new MockHttpClientFactory(mockHttpClient); MockTimeService mockTimeService = new MockTimeService(Instant.now()); - CouchdbAuthStore authStore = new CouchdbAuthStore(authStoreUri, httpClientFactory, new HttpRequestFactoryImpl(), logFactory, new MockCouchdbValidator(), mockTimeService); + CouchdbAuthStore authStore = new CouchdbAuthStore(authStoreUri, httpClientFactory, new HttpRequestFactoryImpl(), + logFactory, new MockCouchdbValidator(), mockTimeService); // When... List tokens = authStore.getTokensByLoginId("johndoe"); @@ -223,17 +233,21 @@ public void testGetTokensReturnsTokensByLoginIdWithFailingRequestReturnsError() MockLogFactory logFactory = new MockLogFactory(); List interactions = new ArrayList(); - interactions.add(new GetAllDocumentsInteraction("https://my-auth-store/galasa_tokens/_design/docs/_view/loginId-view?key=%22johndoe%22", HttpStatus.SC_INTERNAL_SERVER_ERROR, null)); + interactions.add(new GetAllDocumentsInteraction( + "https://my-auth-store/galasa_tokens/_design/docs/_view/loginId-view?key=%22johndoe%22", + HttpStatus.SC_INTERNAL_SERVER_ERROR, null)); MockCloseableHttpClient mockHttpClient = new MockCloseableHttpClient(interactions); MockHttpClientFactory httpClientFactory = new MockHttpClientFactory(mockHttpClient); MockTimeService mockTimeService = new MockTimeService(Instant.now()); - CouchdbAuthStore authStore = new CouchdbAuthStore(authStoreUri, httpClientFactory, new HttpRequestFactoryImpl(), logFactory, new MockCouchdbValidator(), mockTimeService); + CouchdbAuthStore authStore = new CouchdbAuthStore(authStoreUri, httpClientFactory, new HttpRequestFactoryImpl(), + logFactory, new MockCouchdbValidator(), mockTimeService); // When... - AuthStoreException thrown = catchThrowableOfType(() -> authStore.getTokensByLoginId("johndoe"), AuthStoreException.class); + AuthStoreException thrown = catchThrowableOfType(() -> authStore.getTokensByLoginId("johndoe"), + AuthStoreException.class); // Then... assertThat(thrown).isNotNull(); @@ -254,12 +268,14 @@ public void testStoreTokenSendsRequestToCreateTokenDocumentOK() throws Exception MockHttpClientFactory httpClientFactory = new MockHttpClientFactory(mockHttpClient); MockTimeService mockTimeService = new MockTimeService(Instant.now()); - CouchdbAuthStore authStore = new CouchdbAuthStore(authStoreUri, httpClientFactory, new HttpRequestFactoryImpl(), logFactory, new MockCouchdbValidator(), mockTimeService); + CouchdbAuthStore authStore = new CouchdbAuthStore(authStoreUri, httpClientFactory, new HttpRequestFactoryImpl(), + logFactory, new MockCouchdbValidator(), mockTimeService); // When... authStore.storeToken("this-is-a-dex-id", "my token", new CouchdbUser("user1", "user1-id")); - // Then the assertions made in the create token document interaction shouldn't have failed. + // Then the assertions made in the create token document interaction shouldn't + // have failed. } @Test @@ -269,21 +285,26 @@ public void testStoreTokenWithFailingRequestToCreateTokenDocumentReturnsError() MockLogFactory logFactory = new MockLogFactory(); List interactions = new ArrayList(); - interactions.add(new CreateDocumentInteraction("https://my-auth-store/galasa_tokens", HttpStatus.SC_INTERNAL_SERVER_ERROR)); + interactions.add(new CreateDocumentInteraction("https://my-auth-store/galasa_tokens", + HttpStatus.SC_INTERNAL_SERVER_ERROR)); MockCloseableHttpClient mockHttpClient = new MockCloseableHttpClient(interactions); MockHttpClientFactory httpClientFactory = new MockHttpClientFactory(mockHttpClient); MockTimeService mockTimeService = new MockTimeService(Instant.now()); - CouchdbAuthStore authStore = new CouchdbAuthStore(authStoreUri, httpClientFactory, new HttpRequestFactoryImpl(), logFactory, new MockCouchdbValidator(), mockTimeService); + CouchdbAuthStore authStore = new CouchdbAuthStore(authStoreUri, httpClientFactory, new HttpRequestFactoryImpl(), + logFactory, new MockCouchdbValidator(), mockTimeService); // When... - AuthStoreException thrown = catchThrowableOfType(() -> authStore.storeToken("this-is-a-dex-id", "my token", new CouchdbUser("user1", "user1-id")), AuthStoreException.class); + AuthStoreException thrown = catchThrowableOfType( + () -> authStore.storeToken("this-is-a-dex-id", "my token", new CouchdbUser("user1", "user1-id")), + AuthStoreException.class); // Then... assertThat(thrown).isNotNull(); - assertThat(thrown.getMessage()).contains("GAL6102E", "Failed to store auth token in the CouchDB tokens database"); + assertThat(thrown.getMessage()).contains("GAL6102E", + "Failed to store auth token in the CouchDB tokens database"); } @Test @@ -296,9 +317,10 @@ public void testDeleteTokenSendsRequestToDeleteTokenDocumentOK() throws Exceptio IdRev mockIdRev = new IdRev(); mockIdRev._rev = "this-is-a-revision"; - + String expectedGetRequestUrl = "https://my-auth-store/galasa_tokens/" + tokenIdToDelete; - String expectedDeleteRequestUrl = "https://my-auth-store/galasa_tokens/" + tokenIdToDelete + "?rev=" + mockIdRev._rev; + String expectedDeleteRequestUrl = "https://my-auth-store/galasa_tokens/" + tokenIdToDelete + "?rev=" + + mockIdRev._rev; List interactions = new ArrayList(); interactions.add(new GetDocumentInteraction(expectedGetRequestUrl, HttpStatus.SC_OK, mockIdRev)); @@ -309,7 +331,8 @@ public void testDeleteTokenSendsRequestToDeleteTokenDocumentOK() throws Exceptio MockHttpClientFactory httpClientFactory = new MockHttpClientFactory(mockHttpClient); MockTimeService mockTimeService = new MockTimeService(Instant.now()); - CouchdbAuthStore authStore = new CouchdbAuthStore(authStoreUri, httpClientFactory, new HttpRequestFactoryImpl(), logFactory, new MockCouchdbValidator(), mockTimeService); + CouchdbAuthStore authStore = new CouchdbAuthStore(authStoreUri, httpClientFactory, new HttpRequestFactoryImpl(), + logFactory, new MockCouchdbValidator(), mockTimeService); // When... authStore.deleteToken(tokenIdToDelete); @@ -327,14 +350,16 @@ public void testDeleteTokenWithAcceptedRequestToDeleteTokenDocumentDoesNotError( IdRev mockIdRev = new IdRev(); mockIdRev._rev = "this-is-a-revision"; - + String expectedGetRequestUrl = "https://my-auth-store/galasa_tokens/" + tokenIdToDelete; - String expectedDeleteRequestUrl = "https://my-auth-store/galasa_tokens/" + tokenIdToDelete + "?rev=" + mockIdRev._rev; + String expectedDeleteRequestUrl = "https://my-auth-store/galasa_tokens/" + tokenIdToDelete + "?rev=" + + mockIdRev._rev; List interactions = new ArrayList(); interactions.add(new GetDocumentInteraction(expectedGetRequestUrl, HttpStatus.SC_OK, mockIdRev)); - // The DELETE request may return a 202 Accepted, which shouldn't be a problem for us + // The DELETE request may return a 202 Accepted, which shouldn't be a problem + // for us interactions.add(new DeleteTokenDocumentInteraction(expectedDeleteRequestUrl, HttpStatus.SC_ACCEPTED)); MockCloseableHttpClient mockHttpClient = new MockCloseableHttpClient(interactions); @@ -342,7 +367,8 @@ public void testDeleteTokenWithAcceptedRequestToDeleteTokenDocumentDoesNotError( MockHttpClientFactory httpClientFactory = new MockHttpClientFactory(mockHttpClient); MockTimeService mockTimeService = new MockTimeService(Instant.now()); - CouchdbAuthStore authStore = new CouchdbAuthStore(authStoreUri, httpClientFactory, new HttpRequestFactoryImpl(), logFactory, new MockCouchdbValidator(), mockTimeService); + CouchdbAuthStore authStore = new CouchdbAuthStore(authStoreUri, httpClientFactory, new HttpRequestFactoryImpl(), + logFactory, new MockCouchdbValidator(), mockTimeService); // When... authStore.deleteToken(tokenIdToDelete); @@ -360,22 +386,25 @@ public void testDeleteTokenWithFailingRequestToDeleteTokenDocumentThrowsError() IdRev mockIdRev = new IdRev(); mockIdRev._rev = "this-is-a-revision"; - + String expectedGetRequestUrl = "https://my-auth-store/galasa_tokens/" + tokenIdToDelete; - String expectedDeleteRequestUrl = "https://my-auth-store/galasa_tokens/" + tokenIdToDelete + "?rev=" + mockIdRev._rev; + String expectedDeleteRequestUrl = "https://my-auth-store/galasa_tokens/" + tokenIdToDelete + "?rev=" + + mockIdRev._rev; List interactions = new ArrayList(); interactions.add(new GetDocumentInteraction(expectedGetRequestUrl, HttpStatus.SC_OK, mockIdRev)); // Simulate an internal server error - interactions.add(new DeleteTokenDocumentInteraction(expectedDeleteRequestUrl, HttpStatus.SC_INTERNAL_SERVER_ERROR)); + interactions + .add(new DeleteTokenDocumentInteraction(expectedDeleteRequestUrl, HttpStatus.SC_INTERNAL_SERVER_ERROR)); MockCloseableHttpClient mockHttpClient = new MockCloseableHttpClient(interactions); MockHttpClientFactory httpClientFactory = new MockHttpClientFactory(mockHttpClient); MockTimeService mockTimeService = new MockTimeService(Instant.now()); - CouchdbAuthStore authStore = new CouchdbAuthStore(authStoreUri, httpClientFactory, new HttpRequestFactoryImpl(), logFactory, new MockCouchdbValidator(), mockTimeService); + CouchdbAuthStore authStore = new CouchdbAuthStore(authStoreUri, httpClientFactory, new HttpRequestFactoryImpl(), + logFactory, new MockCouchdbValidator(), mockTimeService); // When... AuthStoreException thrown = catchThrowableOfType(() -> { @@ -384,7 +413,8 @@ public void testDeleteTokenWithFailingRequestToDeleteTokenDocumentThrowsError() // Then... assertThat(thrown).isNotNull(); - assertThat(thrown.getMessage()).contains("GAL6104E", "Failed to delete auth token from the CouchDB tokens database"); + assertThat(thrown.getMessage()).contains("GAL6104E", + "Failed to delete auth token from the CouchDB tokens database"); assertThat(thrown.getMessage()).contains("GAL6007E", "Expected status code(s) [200, 202] but received 500"); } @@ -398,20 +428,22 @@ public void testDeleteTokenWithFailingRequestToGetTokenDocumentThrowsError() thr IdRev mockIdRev = new IdRev(); mockIdRev._rev = "this-is-a-revision"; - + String expectedGetRequestUrl = "https://my-auth-store/galasa_tokens/" + tokenIdToDelete; List interactions = new ArrayList(); // Simulate an internal server error - interactions.add(new GetDocumentInteraction(expectedGetRequestUrl, HttpStatus.SC_INTERNAL_SERVER_ERROR, mockIdRev)); + interactions.add(new GetDocumentInteraction(expectedGetRequestUrl, HttpStatus.SC_INTERNAL_SERVER_ERROR, + mockIdRev)); MockCloseableHttpClient mockHttpClient = new MockCloseableHttpClient(interactions); MockHttpClientFactory httpClientFactory = new MockHttpClientFactory(mockHttpClient); MockTimeService mockTimeService = new MockTimeService(Instant.now()); - CouchdbAuthStore authStore = new CouchdbAuthStore(authStoreUri, httpClientFactory, new HttpRequestFactoryImpl(), logFactory, new MockCouchdbValidator(), mockTimeService); + CouchdbAuthStore authStore = new CouchdbAuthStore(authStoreUri, httpClientFactory, new HttpRequestFactoryImpl(), + logFactory, new MockCouchdbValidator(), mockTimeService); // When... AuthStoreException thrown = catchThrowableOfType(() -> { @@ -420,7 +452,8 @@ public void testDeleteTokenWithFailingRequestToGetTokenDocumentThrowsError() thr // Then... assertThat(thrown).isNotNull(); - assertThat(thrown.getMessage()).contains("GAL6104E", "Failed to delete auth token from the CouchDB tokens database"); + assertThat(thrown.getMessage()).contains("GAL6104E", + "Failed to delete auth token from the CouchDB tokens database"); } @Test @@ -430,7 +463,7 @@ public void testDeleteTokenWithBadGetTokenDocumentResponseBodyThrowsError() thro MockLogFactory logFactory = new MockLogFactory(); String tokenIdToDelete = "my-old-token"; - + String expectedGetRequestUrl = "https://my-auth-store/galasa_tokens/" + tokenIdToDelete; List interactions = new ArrayList(); @@ -443,7 +476,8 @@ public void testDeleteTokenWithBadGetTokenDocumentResponseBodyThrowsError() thro MockHttpClientFactory httpClientFactory = new MockHttpClientFactory(mockHttpClient); MockTimeService mockTimeService = new MockTimeService(Instant.now()); - CouchdbAuthStore authStore = new CouchdbAuthStore(authStoreUri, httpClientFactory, new HttpRequestFactoryImpl(), logFactory, new MockCouchdbValidator(), mockTimeService); + CouchdbAuthStore authStore = new CouchdbAuthStore(authStoreUri, httpClientFactory, new HttpRequestFactoryImpl(), + logFactory, new MockCouchdbValidator(), mockTimeService); // When... AuthStoreException thrown = catchThrowableOfType(() -> { @@ -452,12 +486,14 @@ public void testDeleteTokenWithBadGetTokenDocumentResponseBodyThrowsError() thro // Then... assertThat(thrown).isNotNull(); - assertThat(thrown.getMessage()).contains("GAL6104E", "Failed to delete auth token from the CouchDB tokens database"); - assertThat(thrown.getMessage()).contains("GAL6011E", "Failed to get document with ID 'my-old-token' from the 'galasa_tokens' database"); + assertThat(thrown.getMessage()).contains("GAL6104E", + "Failed to delete auth token from the CouchDB tokens database"); + assertThat(thrown.getMessage()).contains("GAL6011E", + "Failed to get document with ID 'my-old-token' from the 'galasa_tokens' database"); } @Test - public void testGetAllUsersReturnsListOfUsersFroasmCouchdbOK() throws Exception { + public void testGetAllUsersReturnsListOfUsersFromCouchdbOK() throws Exception { // Given... URI authStoreUri = URI.create("couchdb:https://my-users-store"); MockLogFactory logFactory = new MockLogFactory(); @@ -468,7 +504,7 @@ public void testGetAllUsersReturnsListOfUsersFroasmCouchdbOK() throws Exception userDoc.id = "user1"; userDoc2.id = "user2"; - List mockDocs = List.of(userDoc,userDoc2); + List mockDocs = List.of(userDoc, userDoc2); ViewResponse mockAllDocsResponse = new ViewResponse(); mockAllDocsResponse.rows = mockDocs; @@ -476,18 +512,23 @@ public void testGetAllUsersReturnsListOfUsersFroasmCouchdbOK() throws Exception UserDoc mockUser = new UserDoc("user1", List.of()); UserDoc mockUser2 = new UserDoc("user2", List.of()); List interactions = new ArrayList(); - interactions.add(new GetAllDocumentsInteraction("https://my-users-store/galasa_users/_all_docs", HttpStatus.SC_OK, mockAllDocsResponse)); - interactions.add(new GetDocumentInteraction("https://my-users-store/galasa_users/user1", HttpStatus.SC_OK, mockUser)); - interactions.add(new GetDocumentInteraction("https://my-users-store/galasa_users/user2", HttpStatus.SC_OK, mockUser2)); + interactions.add(new GetAllDocumentsInteraction("https://my-users-store/galasa_users/_all_docs", + HttpStatus.SC_OK, mockAllDocsResponse)); + interactions.add(new GetDocumentInteraction("https://my-users-store/galasa_users/user1", + HttpStatus.SC_OK, mockUser)); + interactions.add(new GetDocumentInteraction("https://my-users-store/galasa_users/user2", + HttpStatus.SC_OK, mockUser2)); MockCloseableHttpClient mockHttpClient = new MockCloseableHttpClient(interactions); MockHttpClientFactory httpClientFactory = new MockHttpClientFactory(mockHttpClient); MockTimeService mockTimeService = new MockTimeService(Instant.now()); - CouchdbAuthStore authStore = new CouchdbAuthStore(authStoreUri, httpClientFactory, new HttpRequestFactoryImpl(), logFactory, new MockCouchdbValidator(), mockTimeService); + CouchdbAuthStore authStore = new CouchdbAuthStore(authStoreUri, + httpClientFactory, new HttpRequestFactoryImpl(), logFactory, new MockCouchdbValidator(), + mockTimeService); // When... - List users = authStore.getAllUsers(); + List users = authStore.getAllUsers(); // Then... assertThat(users).hasSize(2); @@ -500,25 +541,28 @@ public void testGetTokensReturnsTokensWithFailingRequestReturnsError() throws Ex MockLogFactory logFactory = new MockLogFactory(); List interactions = new ArrayList(); - interactions.add(new GetAllDocumentsInteraction("https://my-users-store/galasa_users/_all_docs", HttpStatus.SC_INTERNAL_SERVER_ERROR, null)); + interactions.add(new GetAllDocumentsInteraction("https://my-users-store/galasa_users/_all_docs", + HttpStatus.SC_INTERNAL_SERVER_ERROR, null)); MockCloseableHttpClient mockHttpClient = new MockCloseableHttpClient(interactions); MockHttpClientFactory httpClientFactory = new MockHttpClientFactory(mockHttpClient); MockTimeService mockTimeService = new MockTimeService(Instant.now()); - CouchdbAuthStore authStore = new CouchdbAuthStore(authStoreUri, httpClientFactory, new HttpRequestFactoryImpl(), logFactory, new MockCouchdbValidator(), mockTimeService); + CouchdbAuthStore authStore = new CouchdbAuthStore(authStoreUri, httpClientFactory, new HttpRequestFactoryImpl(), + logFactory, new MockCouchdbValidator(), mockTimeService); // When... AuthStoreException thrown = catchThrowableOfType(() -> authStore.getAllUsers(), AuthStoreException.class); // Then... assertThat(thrown).isNotNull(); - assertThat(thrown.getMessage()).contains("GAL6202E", "Failed to get user documents from the CouchDB users store."); + assertThat(thrown.getMessage()).contains("GAL6202E", + "Failed to get user documents from the CouchDB users store."); } @Test - public void testStoreTokenSendsRequestToasCreateTokenDocumentOK() throws Exception { + public void testStoreUserSendsRequestToCreateUserDocumentOK() throws Exception { // Given... URI authStoreUri = URI.create("couchdb:https://my-users-store"); MockLogFactory logFactory = new MockLogFactory(); @@ -531,12 +575,14 @@ public void testStoreTokenSendsRequestToasCreateTokenDocumentOK() throws Excepti MockHttpClientFactory httpClientFactory = new MockHttpClientFactory(mockHttpClient); MockTimeService mockTimeService = new MockTimeService(Instant.now()); - CouchdbAuthStore authStore = new CouchdbAuthStore(authStoreUri, httpClientFactory, new HttpRequestFactoryImpl(), logFactory, new MockCouchdbValidator(), mockTimeService); + CouchdbAuthStore authStore = new CouchdbAuthStore(authStoreUri, httpClientFactory, new HttpRequestFactoryImpl(), + logFactory, new MockCouchdbValidator(), mockTimeService); // When... authStore.createUser("this-is-a-login-id", "rest-api"); - // Then the assertions made in the create users document interaction shouldn't have failed. + // Then the assertions made in the create users document interaction shouldn't + // have failed. } @Test @@ -553,22 +599,33 @@ public void testGetUserReturnsUsersByLoginIdFromCouchdbOK() throws Exception { ViewResponse mockAllDocsResponse = new ViewResponse(); mockAllDocsResponse.rows = mockDocs; - UserDoc mockUser = new UserDoc("johndoe", List.of(new FrontendClient("web-ui", Instant.now()))); - + FrontEndClient client = new FrontEndClient(); + + client.setClientName("web-ui"); + client.setLastLogin(Instant.now()); + + UserDoc mockUser = new UserDoc("johndoe", List.of(client)); + List interactions = new ArrayList(); - interactions.add(new GetAllDocumentsInteraction("https://my-auth-store/galasa_users/_design/docs/_view/users-loginId-view?key=%22johndoe%22", HttpStatus.SC_OK, mockAllDocsResponse)); - interactions.add(new GetDocumentInteraction("https://my-auth-store/galasa_users/user1", HttpStatus.SC_OK, mockUser)); + interactions.add(new GetAllDocumentsInteraction( + "https://my-auth-store/galasa_users/_design/docs/_view/loginId-view?key=%22user1%22", + HttpStatus.SC_OK, mockAllDocsResponse)); + interactions.add(new GetDocumentInteraction("https://my-auth-store/galasa_users/user1", + HttpStatus.SC_OK, mockUser)); MockCloseableHttpClient mockHttpClient = new MockCloseableHttpClient(interactions); MockHttpClientFactory httpClientFactory = new MockHttpClientFactory(mockHttpClient); MockTimeService mockTimeService = new MockTimeService(Instant.now()); - CouchdbAuthStore authStore = new CouchdbAuthStore(authStoreUri, httpClientFactory, new HttpRequestFactoryImpl(), logFactory, new MockCouchdbValidator(), mockTimeService); + CouchdbAuthStore authStore = new CouchdbAuthStore(authStoreUri, httpClientFactory, new HttpRequestFactoryImpl(), + logFactory, new MockCouchdbValidator(), mockTimeService); // When... - UserDoc user = authStore.getUserByLoginId("johndoe"); + IUser user = authStore.getUserByLoginId("user1"); + assertThat(user).isInstanceOf(UserDoc.class); assertThat(user).isNotNull(); + assertThat(user.getLoginId()).isEqualTo("johndoe"); } @Test @@ -585,20 +642,25 @@ public void testGetUserReturnsCorrectUserByLoginIdFromCouchdbOK() throws Excepti ViewResponse mockAllDocsResponse = new ViewResponse(); mockAllDocsResponse.rows = mockDocs; - UserDoc mockUser = new UserDoc("johndoe", List.of(new FrontendClient("web-ui", Instant.now()))); - + UserDoc mockUser = new UserDoc("johndoe", List.of(new FrontEndClient("web-ui", Instant.now()))); + List interactions = new ArrayList(); - interactions.add(new GetAllDocumentsInteraction("https://my-auth-store/galasa_users/_design/docs/_view/users-loginId-view?key=%22notJohndoe%22", HttpStatus.SC_OK, mockAllDocsResponse)); - interactions.add(new GetDocumentInteraction("https://my-auth-store/galasa_users/user1", HttpStatus.SC_OK, mockUser)); + interactions.add(new GetAllDocumentsInteraction( + "https://my-auth-store/galasa_users/_design/docs/_view/loginId-view?key=%22notJohndoe%22", + HttpStatus.SC_OK, mockAllDocsResponse)); + interactions.add(new GetDocumentInteraction("https://my-auth-store/galasa_users/user1", + HttpStatus.SC_OK, mockUser)); MockCloseableHttpClient mockHttpClient = new MockCloseableHttpClient(interactions); MockHttpClientFactory httpClientFactory = new MockHttpClientFactory(mockHttpClient); MockTimeService mockTimeService = new MockTimeService(Instant.now()); - CouchdbAuthStore authStore = new CouchdbAuthStore(authStoreUri, httpClientFactory, new HttpRequestFactoryImpl(), logFactory, new MockCouchdbValidator(), mockTimeService); + CouchdbAuthStore authStore = new CouchdbAuthStore(authStoreUri, + httpClientFactory, new HttpRequestFactoryImpl(), logFactory, new MockCouchdbValidator(), + mockTimeService); // When... - UserDoc user = authStore.getUserByLoginId("notJohndoe"); + IUser user = authStore.getUserByLoginId("notJohndoe"); assertThat(user).usingRecursiveComparison().isNotEqualTo(mockUser); } @@ -606,68 +668,152 @@ public void testGetUserReturnsCorrectUserByLoginIdFromCouchdbOK() throws Excepti @Test public void testUpdateUserUpdatesExisitingClientOK() throws Exception { // Given... - URI authStoreUri = URI.create("couchdb:https://my-auth-store"); - MockLogFactory logFactory = new MockLogFactory(); + UserDoc mockUser = new UserDoc("johndoe", List.of(new FrontEndClient("web-ui", Instant.MIN))); + mockUser.setVersion("1"); + mockUser.setUserNumber("user1"); - ViewRow userDoc1 = new ViewRow(); + List interactions = new ArrayList(); + interactions.add(new UpdateDocumentInteraction("https://my-auth-store/galasa_users/user1", + HttpStatus.SC_CREATED, "user1", "2" )); - userDoc1.id = "user1"; - List mockDocs = List.of(userDoc1); + CouchdbAuthStore authStore = createAuthStoreToTest(interactions); - ViewResponse mockAllDocsResponse = new ViewResponse(); - mockAllDocsResponse.rows = mockDocs; + IUser userGotBack = authStore.updateUser(mockUser); + + assertThat(userGotBack.getVersion()).isEqualTo("2"); + } + + @Test + public void testUpdateUserCouchDBPassesBackANullVersionField() throws Exception { + // Given... + UserDoc mockUser = new UserDoc("johndoe", List.of(new FrontEndClient("rest-api", Instant.MIN))); + mockUser.setVersion("1"); + mockUser.setUserNumber("user1"); - UserDoc mockUser = new UserDoc("johndoe", List.of(new FrontendClient("web-ui", Instant.now()))); - List interactions = new ArrayList(); - interactions.add(new GetAllDocumentsInteraction("https://my-auth-store/galasa_users/_design/docs/_view/users-loginId-view?key=%22johndoe%22", HttpStatus.SC_OK, mockAllDocsResponse)); - interactions.add(new GetDocumentInteraction("https://my-auth-store/galasa_users/user1", HttpStatus.SC_OK, mockUser)); - interactions.add(new UpdateDocumentInteraction("https://my-auth-store/galasa_users/user1", HttpStatus.SC_CREATED)); + interactions.add( + new UpdateDocumentInteraction("https://my-auth-store/galasa_users/user1", HttpStatus.SC_CREATED, "user1" , null ) + ); - MockCloseableHttpClient mockHttpClient = new MockCloseableHttpClient(interactions); + CouchdbAuthStore authStore = createAuthStoreToTest(interactions); - MockHttpClientFactory httpClientFactory = new MockHttpClientFactory(mockHttpClient); - MockTimeService mockTimeService = new MockTimeService(Instant.now()); + AuthStoreException ex = catchThrowableOfType( ()-> authStore.updateUser(mockUser), AuthStoreException.class); - CouchdbAuthStore authStore = new CouchdbAuthStore(authStoreUri, httpClientFactory, new HttpRequestFactoryImpl(), logFactory, new MockCouchdbValidator(), mockTimeService); - - authStore.updateUserClientActivity("johndoe", "web-ui"); + assertThat(ex.getMessage()).contains("GAL6204E"); + } - // Then the assertions made in the updates users document interaction shouldn't have failed. + @Test + public void testUpdateUserCouchDBPassesBackADocIdWithWrongUserNumberField() throws Exception { + // Given... + UserDoc mockUser = new UserDoc("johndoe", List.of(new FrontEndClient("rest-api", Instant.MIN))); + mockUser.setVersion("1"); + mockUser.setUserNumber("user1"); + + List interactions = new ArrayList(); + interactions.add( + new UpdateDocumentInteraction("https://my-auth-store/galasa_users/user1", HttpStatus.SC_CREATED, "user2" , "2" ) + ); + + CouchdbAuthStore authStore = createAuthStoreToTest(interactions); + + AuthStoreException ex = catchThrowableOfType( ()-> authStore.updateUser(mockUser), AuthStoreException.class); + + assertThat(ex.getMessage()).contains("GAL6205E"); } @Test - public void testUpdateUserAddsNewClientToUserOK() throws Exception { + public void testUpdateUserCouchDBPassesBackADocIdWithMissingIdField() throws Exception { // Given... - URI authStoreUri = URI.create("couchdb:https://my-auth-store"); - MockLogFactory logFactory = new MockLogFactory(); - ViewRow userDoc1 = new ViewRow(); + UserDoc mockUser = new UserDoc("johndoe", List.of(new FrontEndClient("rest-api", Instant.MIN))); + mockUser.setVersion("1"); + mockUser.setUserNumber("user1"); - userDoc1.id = "user1"; - userDoc1.key = "admin"; - userDoc1.value = new AuthDBNameViewDesign("hello", "world", new TokenDBViews(), "javascript"); - List mockDocs = List.of(userDoc1); + List interactions = new ArrayList(); + interactions.add( + new UpdateDocumentInteraction("https://my-auth-store/galasa_users/user1", HttpStatus.SC_CREATED,null , "2" ) + ); - ViewResponse mockAllDocsResponse = new ViewResponse(); - mockAllDocsResponse.rows = mockDocs; + CouchdbAuthStore authStore = createAuthStoreToTest(interactions); + + AuthStoreException ex = catchThrowableOfType( ()-> authStore.updateUser(mockUser), AuthStoreException.class); + + assertThat(ex.getMessage()).contains("GAL6204E"); + } + + @Test + public void testUpdateUserCouchDBPassesBackAnUnexpectedServerError() throws Exception { + // Given... + UserDoc mockUser = new UserDoc("johndoe", List.of(new FrontEndClient("rest-api", Instant.MIN))); + mockUser.setVersion("1"); + mockUser.setUserNumber("user1"); - UserDoc mockUser = new UserDoc("johndoe", List.of(new FrontendClient("web-ui", Instant.now()))); - List interactions = new ArrayList(); - interactions.add(new GetAllDocumentsInteraction("https://my-auth-store/galasa_users/_design/docs/_view/users-loginId-view?key=%22johndoe%22", HttpStatus.SC_OK, mockAllDocsResponse)); - interactions.add(new GetDocumentInteraction("https://my-auth-store/galasa_users/user1", HttpStatus.SC_OK, mockUser)); - interactions.add(new UpdateDocumentInteraction("https://my-auth-store/galasa_users/user1", HttpStatus.SC_CREATED)); + interactions.add( + new UpdateDocumentInteraction("https://my-auth-store/galasa_users/user1", HttpStatus.SC_INTERNAL_SERVER_ERROR,null , "2" ) + ); - MockCloseableHttpClient mockHttpClient = new MockCloseableHttpClient(interactions); + CouchdbAuthStore authStore = createAuthStoreToTest(interactions); - MockHttpClientFactory httpClientFactory = new MockHttpClientFactory(mockHttpClient); - MockTimeService mockTimeService = new MockTimeService(Instant.now()); + AuthStoreException ex = catchThrowableOfType( ()-> authStore.updateUser(mockUser), AuthStoreException.class); + + assertThat(ex.getMessage()).contains("GAL6203E"); + } + + @Test + public void testUpdateUserWithBadUserNullIdFieldGetsDetectedAsError() throws Exception { + UserDoc mockUser = new UserDoc("johndoe", List.of(new FrontEndClient("rest-api", Instant.MIN))); + mockUser.setVersion("1"); + mockUser.setUserNumber(null); + + CouchdbAuthStore authStore = createAuthStoreToTest(); + + AuthStoreException ex = catchThrowableOfType( ()-> authStore.updateUser(mockUser), AuthStoreException.class); - CouchdbAuthStore authStore = new CouchdbAuthStore(authStoreUri, httpClientFactory, new HttpRequestFactoryImpl(), logFactory, new MockCouchdbValidator(), mockTimeService); - - authStore.updateUserClientActivity("johndoe", "rest-api"); + assertThat(ex.getMessage()).contains("GAL6206E"); + } + + @Test + public void testUpdateUserWithBadUserNullVersionFieldGetsDetectedAsError() throws Exception { + UserDoc mockUser = new UserDoc("johndoe", List.of(new FrontEndClient("rest-api", Instant.MIN))); + mockUser.setVersion(null); + mockUser.setUserNumber("user1"); + + CouchdbAuthStore authStore = createAuthStoreToTest(); + + AuthStoreException ex = catchThrowableOfType( ()-> authStore.updateUser(mockUser), AuthStoreException.class); + + assertThat(ex.getMessage()).contains("GAL6207E"); + } + + private CouchdbAuthStore createAuthStoreToTest() throws Exception { + List interactions = new ArrayList(); + return createAuthStoreToTest(interactions); + } - // Then the assertions made in the updates users document interaction shouldn't have failed. + private CouchdbAuthStore createAuthStoreToTest(List interactions) throws Exception { + URI authStoreUri = URI.create("couchdb:https://my-auth-store"); + MockLogFactory logFactory = new MockLogFactory(); + + MockCloseableHttpClient mockHttpClient = new + MockCloseableHttpClient(interactions); + + MockHttpClientFactory httpClientFactory = new + MockHttpClientFactory(mockHttpClient); + MockTimeService mockTimeService = new MockTimeService(Instant.MIN); + + CouchdbAuthStore authStore = new CouchdbAuthStore(authStoreUri, + httpClientFactory, new HttpRequestFactoryImpl(), logFactory, new + MockCouchdbValidator(), mockTimeService); + + return authStore; + } + + @Test + public void testCanCreateAClientDocument() throws Exception { + CouchdbAuthStore authStore = createAuthStoreToTest(); + IFrontEndClient client = authStore.createClient("myClientName"); + assertThat(client.getClientName()).isEqualTo("myClientName"); + assertThat(client.getLastLogin()).isEqualTo(Instant.MIN); } } diff --git a/galasa-extensions-parent/dev.galasa.auth.couchdb/src/test/java/dev/galasa/auth/couchdb/TestCouchdbAuthStoreRegistration.java b/galasa-extensions-parent/dev.galasa.auth.couchdb/src/test/java/dev/galasa/auth/couchdb/internal/TestCouchdbAuthStoreRegistration.java similarity index 95% rename from galasa-extensions-parent/dev.galasa.auth.couchdb/src/test/java/dev/galasa/auth/couchdb/TestCouchdbAuthStoreRegistration.java rename to galasa-extensions-parent/dev.galasa.auth.couchdb/src/test/java/dev/galasa/auth/couchdb/internal/TestCouchdbAuthStoreRegistration.java index 260c1eb3..13083c34 100644 --- a/galasa-extensions-parent/dev.galasa.auth.couchdb/src/test/java/dev/galasa/auth/couchdb/TestCouchdbAuthStoreRegistration.java +++ b/galasa-extensions-parent/dev.galasa.auth.couchdb/src/test/java/dev/galasa/auth/couchdb/internal/TestCouchdbAuthStoreRegistration.java @@ -3,12 +3,10 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package dev.galasa.auth.couchdb; +package dev.galasa.auth.couchdb.internal; import org.junit.Test; -import dev.galasa.auth.couchdb.internal.CouchdbAuthStore; -import dev.galasa.auth.couchdb.internal.CouchdbAuthStoreRegistration; import dev.galasa.extensions.common.impl.HttpRequestFactoryImpl; import dev.galasa.extensions.mocks.MockFrameworkInitialisation; import dev.galasa.extensions.mocks.MockHttpClientFactory; diff --git a/galasa-extensions-parent/dev.galasa.auth.couchdb/src/test/java/dev/galasa/auth/couchdb/TestCouchdbAuthStoreValidator.java b/galasa-extensions-parent/dev.galasa.auth.couchdb/src/test/java/dev/galasa/auth/couchdb/internal/TestCouchdbAuthStoreValidator.java similarity index 97% rename from galasa-extensions-parent/dev.galasa.auth.couchdb/src/test/java/dev/galasa/auth/couchdb/TestCouchdbAuthStoreValidator.java rename to galasa-extensions-parent/dev.galasa.auth.couchdb/src/test/java/dev/galasa/auth/couchdb/internal/TestCouchdbAuthStoreValidator.java index 4092c62a..e28a66c7 100644 --- a/galasa-extensions-parent/dev.galasa.auth.couchdb/src/test/java/dev/galasa/auth/couchdb/TestCouchdbAuthStoreValidator.java +++ b/galasa-extensions-parent/dev.galasa.auth.couchdb/src/test/java/dev/galasa/auth/couchdb/internal/TestCouchdbAuthStoreValidator.java @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package dev.galasa.auth.couchdb; +package dev.galasa.auth.couchdb.internal; import static org.assertj.core.api.Assertions.*; @@ -18,8 +18,6 @@ import org.apache.http.impl.client.CloseableHttpClient; import org.junit.Test; -import dev.galasa.auth.couchdb.internal.CouchdbAuthStore; -import dev.galasa.auth.couchdb.internal.CouchdbAuthStoreValidator; import dev.galasa.auth.couchdb.internal.beans.*; import dev.galasa.extensions.common.couchdb.CouchdbException; import dev.galasa.extensions.common.couchdb.pojos.PutPostResponse; @@ -135,9 +133,9 @@ public void testCheckCouchdbDatabaseIsValidWithValidDatabaseIsOK() throws Except // }, // "language": "javascript" // } - TokenDBLoginView view = new TokenDBLoginView(); + AuthStoreDBLoginView view = new AuthStoreDBLoginView(); view.map = "function (doc) {\n if (doc.owner && doc.owner.loginId) {\n emit(doc.owner.loginId, doc);\n }\n}"; - TokenDBViews views = new TokenDBViews(); + AuthStoreDBViews views = new AuthStoreDBViews(); views.loginIdView = view; AuthDBNameViewDesign designDocToPassBack = new AuthDBNameViewDesign(); designDocToPassBack.language = "javascript"; @@ -208,9 +206,9 @@ public void testCheckCouchdbDatabaseIsValidWithSuccessfulDatabaseCreationIsOK() interactions.add(new GetTokensDatabaseInteraction(couchdbUriStr + "/" + usersDatabaseName, HttpStatus.SC_NOT_FOUND)); interactions.add(new CreateDatabaseInteraction(couchdbUriStr + "/" + usersDatabaseName, HttpStatus.SC_CREATED)); - TokenDBLoginView view = new TokenDBLoginView(); + AuthStoreDBLoginView view = new AuthStoreDBLoginView(); view.map = "function (doc) {\n if (doc.owner && doc.owner.loginId) {\n emit(doc.owner.loginId, doc);\n }\n}"; - TokenDBViews views = new TokenDBViews(); + AuthStoreDBViews views = new AuthStoreDBViews(); views.loginIdView = view; AuthDBNameViewDesign designDocToPassBack = new AuthDBNameViewDesign(); designDocToPassBack.language = "javascript"; @@ -446,9 +444,9 @@ public void testCheckCouchdbDatabaseIsValidWithFailedDesignDocResponseThrowsErro // }, // "language": "javascript" // } - TokenDBLoginView view = new TokenDBLoginView(); + AuthStoreDBLoginView view = new AuthStoreDBLoginView(); view.map = "function (doc) {\n if (doc.owner && doc.owner.loginId) {\n emit(doc.owner.loginId, doc);\n }\n}"; - TokenDBViews views = new TokenDBViews(); + AuthStoreDBViews views = new AuthStoreDBViews(); views.loginIdView = view; AuthDBNameViewDesign designDocToPassBack = new AuthDBNameViewDesign(); designDocToPassBack.language = "javascript"; @@ -497,9 +495,9 @@ public void testCheckCouchdbDatabaseIsValidWithUpdateDesignDocResponseThrowsErro // }, // "language": "javascript" // } - TokenDBLoginView view = new TokenDBLoginView(); + AuthStoreDBLoginView view = new AuthStoreDBLoginView(); view.map = "function (doc) {\n if (doc.owner && doc.owner.loginId) {\n emit(doc.owner.loginId, doc);\n }\n}"; - TokenDBViews views = new TokenDBViews(); + AuthStoreDBViews views = new AuthStoreDBViews(); views.loginIdView = view; AuthDBNameViewDesign designDocToPassBack = new AuthDBNameViewDesign(); designDocToPassBack.language = "javascript"; diff --git a/galasa-extensions-parent/dev.galasa.auth.couchdb/src/test/java/dev/galasa/auth/couchdb/internal/beans/TestUserDoc.java b/galasa-extensions-parent/dev.galasa.auth.couchdb/src/test/java/dev/galasa/auth/couchdb/internal/beans/TestUserDoc.java new file mode 100644 index 00000000..7276035a --- /dev/null +++ b/galasa-extensions-parent/dev.galasa.auth.couchdb/src/test/java/dev/galasa/auth/couchdb/internal/beans/TestUserDoc.java @@ -0,0 +1,278 @@ +/* + * Copyright contributors to the Galasa project + * + * SPDX-License-Identifier: EPL-2.0 + */ +package dev.galasa.auth.couchdb.internal.beans; + +import static org.assertj.core.api.Assertions.*; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.junit.Test; + +import dev.galasa.framework.spi.auth.IFrontEndClient; +import dev.galasa.framework.spi.auth.IUser; + + +public class TestUserDoc { + + @Test + public void testCanConstructUserDocGivenAUserDoc() throws Exception { + UserDoc doc1 = new UserDoc("myLoginId",null); + assertThat(doc1.getLoginId()).isEqualTo("myLoginId"); + } + + @Test + public void testCanConstructUserDocGivenAUserDocWithClient() throws Exception { + UserDoc doc1 = new UserDoc("myLoginId",List.of(new FrontEndClient("myClient1",Instant.MIN))); + + IFrontEndClient clientGotBack = doc1.getClient("myClient1"); + assertThat(clientGotBack).isNotNull(); + assertThat(clientGotBack.getClientName()).isEqualTo("myClient1"); + assertThat(clientGotBack.getLastLogin()).isEqualTo(Instant.MIN); + } + + @Test + public void testCanLookForClientWhichIsntInTheUserDocReturnsNull() throws Exception { + UserDoc doc1 = new UserDoc("myLoginId",List.of(new FrontEndClient("myClient1",Instant.MIN))); + + IFrontEndClient clientGotBack = doc1.getClient("myClient2"); // Client2 isn't there! + assertThat(clientGotBack).isNull(); + } + + @Test + public void testCanTryLookingForClientWithNullNameShouldReturnNull() throws Exception { + UserDoc doc1 = new UserDoc("myLoginId",List.of(new FrontEndClient("myClient1",Instant.MIN))); + + IFrontEndClient clientGotBack = doc1.getClient(null); + assertThat(clientGotBack).isNull(); + } + + class MockIUser implements IUser { + private String userNumber; + private String loginId; + + private List clients; + + public MockIUser(String loginId, List clients) { + this.loginId = loginId; + this.clients = clients; + } + + @Override + public String getUserNumber(){ + return userNumber; + } + + @Override + public String getLoginId() { + return loginId; + } + + @Override + public IFrontEndClient getClient(String clientName) { + return null; + } + + @Override + public Collection getClients() { + return this.clients; + } + + @Override + public void addClient(IFrontEndClient client) { + clients.add( new FrontEndClient(client)); + } + + @Override + public String getVersion() { + return "0" ; + } + + } + + @Test + public void testCanCloneUserDocFromIUser() throws Exception { + MockIUser doc1 = new MockIUser("myLoginId",null); + + UserDoc doc2 = new UserDoc(doc1); + + assertThat(doc2).isNotNull(); + assertThat(doc2.getLoginId()).isEqualTo("myLoginId"); + } + + class MockIFrontEndClient implements IFrontEndClient { + + String name ; + Instant lastLogin ; + + public MockIFrontEndClient(String name, Instant lastLogin) { + this.name = name; + this.lastLogin = lastLogin; + } + + @Override + public String getClientName() { + return name; + } + + @Override + public Instant getLastLogin() { + return lastLogin; + } + + @Override + public void setLastLogin(Instant lastLoginTime) { + } + + } + + @Test + public void testCanSetIFrontEndClientsInAndGetThemBack() throws Exception { + UserDoc doc1 = new UserDoc("myLoginId",List.of(new FrontEndClient("myClient1",Instant.MIN))); + MockIFrontEndClient mockClient = new MockIFrontEndClient("client2", Instant.MIN.plusSeconds(2)); + + doc1.addClient(mockClient); + + + // Then... + IFrontEndClient gotBack = doc1.getClient("client2"); + assertThat(gotBack).isNotNull(); + assertThat(gotBack.getLastLogin()).isEqualTo(Instant.MIN.plusSeconds(2)); + } + + @Test + public void testCanGetClientsWhenClientsArePresent() throws Exception { + UserDoc doc1 = new UserDoc("myLoginId", List.of( + new FrontEndClient("client1", Instant.MIN), + new FrontEndClient("client2", Instant.now()) + )); + + Collection clients = doc1.getClients(); + + assertThat(clients).isNotNull(); + assertThat(clients).hasSize(2); + assertThat(clients).extracting("clientName").containsExactlyInAnyOrder("client1", "client2"); + } + + @Test + public void testCanGetClientsWhenNoClientsArePresent() throws Exception { + UserDoc doc1 = new UserDoc("myLoginId", List.of()); + + Collection clients = doc1.getClients(); + + assertThat(clients).isNotNull(); + assertThat(clients).isEmpty(); + } + + @Test + public void testCanSetAndGetUserNumber() throws Exception { + UserDoc doc1 = new UserDoc("myLoginId", List.of()); + doc1.setUserNumber("12345"); + + String userNumber = doc1.getUserNumber(); + + assertThat(userNumber).isNotNull(); + assertThat(userNumber).isEqualTo("12345"); + } + + @Test + public void testGetUserNumberReturnsNullWhenNotSet() throws Exception { + UserDoc doc1 = new UserDoc("myLoginId", List.of()); + + String userNumber = doc1.getUserNumber(); + + assertThat(userNumber).isNull(); + } + + @Test + public void testCanSetAndGetVersion() throws Exception { + UserDoc doc1 = new UserDoc("myLoginId", List.of()); + doc1.setVersion("1.0"); + + String version = doc1.getVersion(); + + assertThat(version).isNotNull(); + assertThat(version).isEqualTo("1.0"); + } + + @Test + public void testGetVersionReturnsNullWhenNotSet() throws Exception { + UserDoc doc1 = new UserDoc("myLoginId", List.of()); + + String version = doc1.getVersion(); + + assertThat(version).isNull(); + } + + @Test + public void testCanSetAndGetLoginId() throws Exception { + UserDoc doc1 = new UserDoc("myLoginId", List.of()); + doc1.setLoginId("newLoginId"); + + String loginId = doc1.getLoginId(); + + assertThat(loginId).isNotNull(); + assertThat(loginId).isEqualTo("newLoginId"); + } + + @Test + public void testGetLoginIdReturnsNullWhenNotSet() throws Exception { + UserDoc doc1 = new UserDoc(null, List.of()); + + String loginId = doc1.getLoginId(); + + assertThat(loginId).isNull(); + } + + @Test + public void testCanSetClientsSuccessfully() throws Exception { + UserDoc doc1 = new UserDoc("myLoginId", List.of()); + Collection clients = List.of( + new FrontEndClient("client1", Instant.MIN), + new FrontEndClient("client2", Instant.now()) + ); + + doc1.setClients(clients); + + Collection clientsGotBack = doc1.getClients(); + assertThat(clientsGotBack).isNotNull(); + assertThat(clientsGotBack).hasSize(2); + assertThat(clientsGotBack).extracting("clientName").containsExactlyInAnyOrder("client1", "client2"); + } + + @Test + public void testSetClientsDoesNotModifyOriginalCollection() throws Exception { + UserDoc doc1 = new UserDoc("myLoginId", List.of()); + List originalClients = new ArrayList<>(); + originalClients.add(new FrontEndClient("client1", Instant.MIN)); + + doc1.setClients(originalClients); + + // Modify the original collection after setting it + originalClients.add(new FrontEndClient("client2", Instant.now())); + + Collection clientsGotBack = doc1.getClients(); + assertThat(clientsGotBack).hasSize(1); // Should only contain the first client + assertThat(clientsGotBack).extracting("clientName").containsExactly("client1"); + } + + @Test + public void testSetClientsShouldInvokeAddClientForEachClient() throws Exception { + UserDoc doc1 = new UserDoc("myLoginId", List.of()); + Collection clients = List.of( + new FrontEndClient("client1", Instant.MIN), + new FrontEndClient("client2", Instant.now()) + ); + + doc1.setClients(clients); + + Collection clientsGotBack = doc1.getClients(); + assertThat(clientsGotBack).hasSize(2); + assertThat(clientsGotBack).extracting("clientName").contains("client1", "client2"); + } + +} diff --git a/galasa-extensions-parent/dev.galasa.extensions.common/src/main/java/dev/galasa/extensions/common/Errors.java b/galasa-extensions-parent/dev.galasa.extensions.common/src/main/java/dev/galasa/extensions/common/Errors.java index eb6cabcb..85803443 100644 --- a/galasa-extensions-parent/dev.galasa.extensions.common/src/main/java/dev/galasa/extensions/common/Errors.java +++ b/galasa-extensions-parent/dev.galasa.extensions.common/src/main/java/dev/galasa/extensions/common/Errors.java @@ -36,9 +36,14 @@ public enum Errors { ERROR_FAILED_TO_DELETE_TOKEN_DOCUMENT (6104,"GAL6104E: Failed to delete auth token from the CouchDB tokens database. Cause: {0}"), // CouchDB Users Store error - ERROR_FAILED_TO_INITIALISE_USERS_STORE (6200,"GAL6200E: Failed to initialise the Galasa CouchDB users store. Cause: {0}"), - ERROR_FAILED_TO_CREATE_USER_DOCUMENT (6201,"GAL6201E: Failed to store users token in the CouchDB users database. Cause: {0}"), - ERROR_FAILED_TO_RETRIEVE_USERS (6202,"GAL6202E: Failed to get user documents from the CouchDB users store. Cause: {0}"), + ERROR_FAILED_TO_INITIALISE_USERS_STORE (6200,"GAL6200E: Failed to initialise the Galasa CouchDB users store. Cause: {0}"), + ERROR_FAILED_TO_CREATE_USER_DOCUMENT (6201,"GAL6201E: Failed to store users token in the CouchDB users database. Cause: {0}"), + ERROR_FAILED_TO_RETRIEVE_USERS (6202,"GAL6202E: Failed to get user documents from the CouchDB users store. Cause: {0}"), + ERROR_FAILED_TO_UPDATE_USER_DOCUMENT (6203,"GAL6203E: Failed to update user document in the CouchDB users store. Cause: {0}"), + ERROR_FAILED_TO_UPDATE_USER_DOCUMENT_INVALID_RESP (6204,"GAL6204E: Failed to update user document in the CouchDB users store. Cause: Couchdb returned an unexpected json response with no _rev or _id field."), + ERROR_FAILED_TO_UPDATE_USER_DOCUMENT_MISMATCH_DOC_ID (6205,"GAL6205E: Failed to update user document in the CouchDB users store. Cause: Couchdb returned a document with an unexpected _id field."), + ERROR_FAILED_TO_UPDATE_USER_DOCUMENT_INPUT_INVALID_NULL_USER_NUMBER (6206,"GAL6206E: Failed to update user document in the CouchDB users store. Cause: Bad input. User number is invalid or null."), + ERROR_FAILED_TO_UPDATE_USER_DOCUMENT_INPUT_INVALID_NULL_USER_VERSION(6207,"GAL6207E: Failed to update user document in the CouchDB users store. Cause: Bad input. User document version is invalid or null."), // REST CPS errors ERROR_GALASA_WRONG_NUMBER_OF_PARAMETERS_IN_MESSAGE (6999,"GAL6999E: Failed to render message template. Not the expected number of parameters. Got ''{0}''. Expected ''{1}''"), diff --git a/galasa-extensions-parent/dev.galasa.extensions.common/src/main/java/dev/galasa/extensions/common/couchdb/CouchdbStore.java b/galasa-extensions-parent/dev.galasa.extensions.common/src/main/java/dev/galasa/extensions/common/couchdb/CouchdbStore.java index 17fcc363..ff27f116 100644 --- a/galasa-extensions-parent/dev.galasa.extensions.common/src/main/java/dev/galasa/extensions/common/couchdb/CouchdbStore.java +++ b/galasa-extensions-parent/dev.galasa.extensions.common/src/main/java/dev/galasa/extensions/common/couchdb/CouchdbStore.java @@ -183,6 +183,9 @@ protected List getAllDocsByLoginId(String dbName, String loginId, Strin protected T getDocumentFromDatabase(String dbName, String documentId, Class classOfObject) throws CouchdbException { HttpGet getDocumentRequest = httpRequestFactory.getHttpGetRequest(storeUri + "/" + dbName + "/" + documentId); + + System.out.println("Fetched Document = " + getDocumentRequest); + return gson.fromJson(sendHttpRequest(getDocumentRequest, HttpStatus.SC_OK), classOfObject); }