diff --git a/.github/workflows/maven-publish.yml b/.github/workflows/maven-publish.yml index 88bdf3e..d4a4449 100644 --- a/.github/workflows/maven-publish.yml +++ b/.github/workflows/maven-publish.yml @@ -1,20 +1,19 @@ # This workflow will build a package using Maven and then publish it to GitHub packages when a release is created # For more information see: https://github.com/actions/setup-java#apache-maven-with-a-settings-path - -name: Maven Package +name: Maven Deploy to GitHub Packages on: release: types: [created] +env: + PLUGGY_CLIENT_ID: "ccd5b9be-3be6-45fe-9512-5907f1619db0" + PLUGGY_CLIENT_SECRET: ${{ secrets.PLUGGY_CLIENT_SECRET }} + PLUGGY_BASE_URL: "https://dev-pluggy-api.herokuapp.com" + jobs: build: - runs-on: ubuntu-latest - env: - PLUGGY_CLIENT_ID: "ccd5b9be-3be6-45fe-9512-5907f1619db0" - PLUGGY_CLIENT_SECRET: ${{ secrets.PLUGGY_CLIENT_SECRET }} - PLUGGY_BASE_URL: "https://dev-pluggy-api.herokuapp.com" steps: - uses: actions/checkout@v2 - name: Set up JDK 1.8 @@ -23,11 +22,29 @@ jobs: java-version: 1.8 server-id: github # Value of the distributionManagement/repository/id field of the pom.xml settings-path: ${{ github.workspace }} # location for the settings.xml file - - name: Check Test Env Variables - run: echo PLUGGY_CLIENT_ID $PLUGGY_CLIENT_ID PLUGGY_BASE_URL $PLUGGY_BASE_URL - name: Build with Maven run: mvn -B package --file pom.xml + test: + needs: build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Check Test Env Variables + run: echo PLUGGY_CLIENT_ID $PLUGGY_CLIENT_ID PLUGGY_BASE_URL $PLUGGY_BASE_URL + - name: Integration Tests + run: mvn -B verify --file pom.xml + deploy: + runs-on: ubuntu-latest + needs: [build, test] + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 1.8 + uses: actions/setup-java@v1 + with: + java-version: 1.8 + server-id: github # Value of the distributionManagement/repository/id field of the pom.xml + settings-path: ${{ github.workspace }} # location for the settings.xml file - name: Publish to GitHub Packages Apache Maven - run: mvn deploy -s $GITHUB_WORKSPACE/settings.xml + run: mvn deploy -Dmaven.test.skip.exec -s $GITHUB_WORKSPACE/settings.xml # skip tests in this step env: GITHUB_TOKEN: ${{ github.token }} diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 1a8af85..18406f9 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -8,23 +8,30 @@ on: pull_request: branches: [ master, development ] +env: + PLUGGY_CLIENT_ID: "ccd5b9be-3be6-45fe-9512-5907f1619db0" + PLUGGY_CLIENT_SECRET: ${{ secrets.PLUGGY_CLIENT_SECRET }} + PLUGGY_BASE_URL: "https://dev-pluggy-api.herokuapp.com" + jobs: build: - runs-on: ubuntu-latest - env: - PLUGGY_CLIENT_ID: "ccd5b9be-3be6-45fe-9512-5907f1619db0" - PLUGGY_CLIENT_SECRET: ${{ secrets.PLUGGY_CLIENT_SECRET }} - PLUGGY_BASE_URL: "https://dev-pluggy-api.herokuapp.com" steps: - uses: actions/checkout@v2 - name: Set up JDK 1.8 uses: actions/setup-java@v1 with: java-version: 1.8 - - name: Check Test Env Variables - run: echo PLUGGY_CLIENT_ID $PLUGGY_CLIENT_ID PLUGGY_BASE_URL $PLUGGY_BASE_URL + server-id: github # Value of the distributionManagement/repository/id field of the pom.xml + settings-path: ${{ github.workspace }} # location for the settings.xml file - name: Build with Maven run: mvn -B package --file pom.xml + test: + needs: build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Check Test Env Variables + run: echo PLUGGY_CLIENT_ID $PLUGGY_CLIENT_ID PLUGGY_BASE_URL $PLUGGY_BASE_URL - name: Integration Tests run: mvn -B verify --file pom.xml diff --git a/pom.xml b/pom.xml index c9cbae7..28c1ef9 100644 --- a/pom.xml +++ b/pom.xml @@ -116,9 +116,9 @@ - + org.apache.maven.plugins maven-release-plugin @@ -142,6 +142,19 @@ + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar + + + + diff --git a/src/main/java/ai/pluggy/client/response/ItemError.java b/src/main/java/ai/pluggy/client/response/ItemError.java new file mode 100644 index 0000000..a1ce408 --- /dev/null +++ b/src/main/java/ai/pluggy/client/response/ItemError.java @@ -0,0 +1,10 @@ +package ai.pluggy.client.response; + +import lombok.Data; + +@Data +public class ItemError { + + String message; + String code; +} diff --git a/src/main/java/ai/pluggy/client/response/ItemResponse.java b/src/main/java/ai/pluggy/client/response/ItemResponse.java index c56326a..73147cf 100644 --- a/src/main/java/ai/pluggy/client/response/ItemResponse.java +++ b/src/main/java/ai/pluggy/client/response/ItemResponse.java @@ -17,5 +17,5 @@ public class ItemResponse { String executionStatus; Date lastUpdatedAt; String webhookUrl; - ErrorResponse error = null; + ItemError error = null; } diff --git a/src/test/java/ai/pluggy/client/integration/CreateItemTest.java b/src/test/java/ai/pluggy/client/integration/CreateItemTest.java index c52d3f8..3991752 100644 --- a/src/test/java/ai/pluggy/client/integration/CreateItemTest.java +++ b/src/test/java/ai/pluggy/client/integration/CreateItemTest.java @@ -1,11 +1,13 @@ package ai.pluggy.client.integration; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import ai.pluggy.client.request.CreateItemRequest; import ai.pluggy.client.request.ParametersMap; +import ai.pluggy.client.response.ErrorResponse; import ai.pluggy.client.response.ItemResponse; import lombok.SneakyThrows; import org.junit.jupiter.api.Test; @@ -30,7 +32,7 @@ void createItem_withValidParams_responseOk() { Response itemRequestResponse = createItemRequestCall.execute(); assertTrue(itemRequestResponse.isSuccessful()); ItemResponse itemResponse1 = itemRequestResponse.body(); - + assertNotNull(itemResponse1); assertEquals(itemResponse1.getConnectorId(), connectorId); @@ -41,8 +43,30 @@ void createItem_withValidParams_responseOk() { Response itemRequestWithWebhookResponse = client.service() .createItem(createItemRequestWithWebhook).execute(); ItemResponse itemResponse2 = itemRequestWithWebhookResponse.body(); - + assertNotNull(itemResponse2); assertEquals(itemResponse2.getConnectorId(), connectorId); } + + @SneakyThrows + @Test + void createItem_withInvalidParams_responseError400() { + // create item params + ParametersMap parametersMap = ParametersMap + .map("bad-param-key", "asd") + .with("other-bad-param-key", "qwe"); + Integer connectorId = 0; + + // run request with 'connectorId', 'parameters' params + CreateItemRequest createItemRequest = new CreateItemRequest(connectorId, parametersMap); + + Call createItemRequestCall = client.service().createItem(createItemRequest); + Response itemRequestResponse = createItemRequestCall.execute(); + + assertFalse(itemRequestResponse.isSuccessful()); + + ErrorResponse errorResponse = client.parseError(itemRequestResponse); + assertNotNull(errorResponse); + assertEquals(errorResponse.getCode(), 400); + } } diff --git a/src/test/java/ai/pluggy/client/integration/GetItemTest.java b/src/test/java/ai/pluggy/client/integration/GetItemTest.java index 98fa00f..5b85cd0 100644 --- a/src/test/java/ai/pluggy/client/integration/GetItemTest.java +++ b/src/test/java/ai/pluggy/client/integration/GetItemTest.java @@ -1,13 +1,19 @@ package ai.pluggy.client.integration; +import static ai.pluggy.client.integration.helper.ItemHelper.ITEM_FINISH_STATUSES; import static ai.pluggy.client.integration.helper.ItemHelper.NON_EXISTING_ITEM_ID; import static ai.pluggy.client.integration.helper.ItemHelper.createItem; +import static ai.pluggy.client.integration.helper.ItemHelper.getItemStatus; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import ai.pluggy.client.integration.util.Poller; +import ai.pluggy.client.request.ParametersMap; import ai.pluggy.client.response.ErrorResponse; import ai.pluggy.client.response.ItemResponse; import java.io.IOException; +import lombok.SneakyThrows; import org.junit.jupiter.api.Test; import retrofit2.Response; @@ -30,10 +36,45 @@ void getItem_existingItem_ok() throws IOException { assertEquals(itemResponse.getId(), createdItemId); } + @SneakyThrows + @Test + void getItem_validItemWithInvalidCredentials_finishesWithLoginError() throws IOException { + // precondition: ensure item with bad credentials params exists + Integer connectorId = 0; + ParametersMap validParametersBadCredentialsMap = ParametersMap + .map("user", "_bad_user_") + .with("password", "_bad_password_"); + + ItemResponse itemWithBadCredentials = createItem(client, connectorId, + validParametersBadCredentialsMap); + assertNotNull(itemWithBadCredentials); + + // wait for item execution to finish. + Poller.pollRequestUntil( + () -> getItemStatus(client, itemWithBadCredentials.getId()), + (ItemResponse itemStatusResponse) -> + ITEM_FINISH_STATUSES.indexOf(itemStatusResponse.getStatus()) > 0, + 500, 35000 + ); + + // expect item to be finished with login error status & code + String expectedItemStatus = "LOGIN_ERROR"; + String expectedLoginErrorCode = "INVALID_CREDENTIALS"; + + Response getItemFinishedResponse = client.service() + .getItem(itemWithBadCredentials.getId()).execute(); + assertTrue(getItemFinishedResponse.isSuccessful()); + + ItemResponse itemFinishedResponse = getItemFinishedResponse.body(); + assertNotNull(itemFinishedResponse); + assertEquals(itemFinishedResponse.getStatus(), expectedItemStatus); + + assertNotNull(itemFinishedResponse.getError()); + assertEquals(itemFinishedResponse.getError().getCode(), expectedLoginErrorCode); + } + @Test void getItem_nonExistingItem_errorResponse404() throws IOException { - // TODO using the following returns an error 400 "Invalid id, not an uuid" (not 404) - check why... - // String nonExistingItemId = UUID.nameUUIDFromBytes("non-existing-item-id".getBytes()).toString(); Response getItemResponse = client.service().getItem(NON_EXISTING_ITEM_ID) .execute(); ErrorResponse errorResponse = client.parseError(getItemResponse); diff --git a/src/test/java/ai/pluggy/client/integration/GetTransactionTest.java b/src/test/java/ai/pluggy/client/integration/GetTransactionTest.java index cba2408..78eeefe 100644 --- a/src/test/java/ai/pluggy/client/integration/GetTransactionTest.java +++ b/src/test/java/ai/pluggy/client/integration/GetTransactionTest.java @@ -13,7 +13,6 @@ public class GetTransactionTest extends BaseApiIntegrationTest { - @Disabled // TODO enable again once it's working... @SneakyThrows @Test void getTransaction_byExistingId_ok() { diff --git a/src/test/java/ai/pluggy/client/integration/GetTransactionsTest.java b/src/test/java/ai/pluggy/client/integration/GetTransactionsTest.java index 221577c..1b3db99 100644 --- a/src/test/java/ai/pluggy/client/integration/GetTransactionsTest.java +++ b/src/test/java/ai/pluggy/client/integration/GetTransactionsTest.java @@ -6,7 +6,9 @@ import ai.pluggy.client.request.DateFilters; import ai.pluggy.client.response.TransactionsResponse; +import java.util.stream.Collectors; import lombok.SneakyThrows; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import retrofit2.Response; @@ -31,6 +33,7 @@ void getTransactions_byExistingAccountId_ok() { assertTrue(transactions.getResults().size() > 0); } + @Disabled @SneakyThrows @Test void getTransactions_byExistingAccountId_withDateFilters_ok() { @@ -62,12 +65,23 @@ void getTransactions_byExistingAccountId_withDateFilters_ok() { assertNotNull(transactionsFiltered); assertNotNull(transactionsFiltered.getResults()); int transactionsFilteredCount = transactionsFiltered.getResults().size(); - assertTrue(transactionsFilteredCount > 0); + + // build error string in case of no transactions filtered result. + String allTxsString = allTransactions.getResults().stream() + .map(transaction -> String.format( + "{id=%s, date=%s}", transaction.getId(), transaction.getDate().substring(0, 10))) + .collect(Collectors.joining(", ")); + String expectedTransactionsFilteredMsg = String.format( + "Expected at least 1 tx between '%s' (out of total '%d' txs) for account id '%s', all txs: '%s'", + dateFilters, + allTransactions.getResults().size(), firstAccountId, allTxsString); + + assertTrue(transactionsFilteredCount > 0, expectedTransactionsFilteredMsg); // expect filtered transactions count to be less than total transactions count assertTrue(transactionsFilteredCount < allTransactionsCount, String.format( - "Transations filtered result: %d should be less than all transactions result: %d, using date filters '%s'", + "Transactions filtered result: %d should be less than all transactions result: %d, using date filters '%s'", transactionsFilteredCount, allTransactionsCount, dateFilters)); } } diff --git a/src/test/java/ai/pluggy/client/integration/helper/ItemHelper.java b/src/test/java/ai/pluggy/client/integration/helper/ItemHelper.java index cc21b56..4821726 100644 --- a/src/test/java/ai/pluggy/client/integration/helper/ItemHelper.java +++ b/src/test/java/ai/pluggy/client/integration/helper/ItemHelper.java @@ -9,6 +9,8 @@ import ai.pluggy.client.request.ParametersMap; import ai.pluggy.client.response.ErrorResponse; import ai.pluggy.client.response.ItemResponse; +import java.util.Arrays; +import java.util.List; import lombok.SneakyThrows; import lombok.extern.log4j.Log4j2; import retrofit2.Response; @@ -21,6 +23,10 @@ public class ItemHelper { public static final Integer PLUGGY_BANK_CONNECTOR_ID = 0; + // Possible item statuses that indicate execution finished + public static final List ITEM_FINISH_STATUSES = Arrays + .asList("FINISHED", "OUTDATED", "LOGIN_ERROR"); + @SneakyThrows public static ItemResponse createItem(PluggyClient client, Integer connectorId) { ParametersMap invalidParametersMap = ParametersMap.map("user", "asd") @@ -51,7 +57,6 @@ public static ItemResponse createItem(PluggyClient client, Integer connectorId, } public static ItemResponse createPluggyBankItem(PluggyClient client) { - // TODO: remove PluggyBank credentials from source code? ParametersMap parametersMap = ParametersMap .map("user", "user-ok") .with("password", "password-ok");