diff --git a/backend/config/urls.py b/backend/config/urls.py
index 6f3c82b21..526c4fea2 100644
--- a/backend/config/urls.py
+++ b/backend/config/urls.py
@@ -16,7 +16,6 @@
from metagrid.api_proxy.views import (
do_citation,
do_globus_auth,
- do_globus_get_endpoint,
do_globus_logout,
do_globus_search_endpoints,
do_search,
@@ -58,11 +57,6 @@ class KeycloakLogin(SocialLoginView):
path("", include("social_django.urls", namespace="social")),
path("proxy/globus-logout/", do_globus_logout, name="globus-logout"),
path("proxy/globus-auth/", do_globus_auth, name="globus-auth"),
- path(
- "proxy/globus-get-endpoint/",
- do_globus_get_endpoint,
- name="globus-get-endpoint",
- ),
path(
"proxy/globus-search-endpoints/",
do_globus_search_endpoints,
diff --git a/backend/metagrid/api_proxy/tests/test_views.py b/backend/metagrid/api_proxy/tests/test_views.py
index 365a1d12b..9a256dcb0 100644
--- a/backend/metagrid/api_proxy/tests/test_views.py
+++ b/backend/metagrid/api_proxy/tests/test_views.py
@@ -23,14 +23,6 @@ def test_globus_auth_begin(self):
)
self.assertEqual(response.status_code, 302)
- def test_do_globus_get_endpoint(self):
- url = reverse("globus-get-endpoint")
-
- data = {"endpoint_id": "0247816e-cc0d-4e03-a509-10903f6dde11"}
- response = self.client.get(url, data)
- print(response.status_code)
- assert response.status_code == status.HTTP_200_OK
-
def test_do_globus_search_endpoints(self):
url = reverse("globus-search-endpoints")
diff --git a/backend/metagrid/api_proxy/views.py b/backend/metagrid/api_proxy/views.py
index 331d26396..963fc2b13 100644
--- a/backend/metagrid/api_proxy/views.py
+++ b/backend/metagrid/api_proxy/views.py
@@ -51,27 +51,6 @@ def do_globus_logout(request):
return redirect(homepage_url)
-@api_view()
-@permission_classes([])
-def do_globus_get_endpoint(request):
- endpoint_id = request.GET.get("endpoint_id", None)
- if request.user.is_authenticated:
- tc = load_transfer_client(request.user) # pragma: no cover
- else:
- client = globus_sdk.ConfidentialAppAuthClient(
- settings.SOCIAL_AUTH_GLOBUS_KEY, settings.SOCIAL_AUTH_GLOBUS_SECRET
- )
- token_response = client.oauth2_client_credentials_tokens()
- globus_transfer_data = token_response.by_resource_server[
- "transfer.api.globus.org"
- ]
- globus_transfer_token = globus_transfer_data["access_token"]
- authorizer = globus_sdk.AccessTokenAuthorizer(globus_transfer_token)
- tc = globus_sdk.TransferClient(authorizer=authorizer)
- endpoint = tc.get_endpoint(endpoint_id)
- return Response(endpoint.data)
-
-
@api_view()
@permission_classes([])
def do_globus_search_endpoints(request):
diff --git a/frontend/src/components/Globus/DatasetDownload.test.tsx b/frontend/src/components/Globus/DatasetDownload.test.tsx
index 581b6f8f6..d25db37cb 100644
--- a/frontend/src/components/Globus/DatasetDownload.test.tsx
+++ b/frontend/src/components/Globus/DatasetDownload.test.tsx
@@ -1,12 +1,11 @@
import React from 'react';
import userEvent from '@testing-library/user-event';
-import { act, waitFor, within, screen } from '@testing-library/react';
+import { act, within, screen } from '@testing-library/react';
import customRender from '../../test/custom-render';
import { rest, server } from '../../test/mock/server';
import { getSearchFromUrl } from '../../common/utils';
import { ActiveSearchQuery, RawSearchResults } from '../Search/types';
import {
- getRowName,
globusReadyNode,
makeCartItem,
mockConfig,
@@ -23,7 +22,6 @@ import {
globusEndpointFixture,
globusAccessTokenFixture,
globusTransferTokenFixture,
- userCartFixture,
} from '../../test/mock/fixtures';
import apiRoutes from '../../api/routes';
import DatasetDownloadForm, { GlobusGoals } from './DatasetDownload';
@@ -883,507 +881,54 @@ describe('DatasetDownload form tests', () => {
'Submitted: 11/30/2023, 3:10:00 PM'
);
});
-});
-
-xit('If endpoint URL is available, process it and continue to Transfer process', async () => {
- // Setting the tokens so that the sign-in step should be completed
- mockSaveValue(CartStateKeys.cartItemSelections, userCartFixture());
- mockSaveValue(GlobusStateKeys.accessToken, 'accessToken');
- mockSaveValue(GlobusStateKeys.transferToken, {
- id_token: '',
- resource_server: '',
- other_tokens: { refresh_token: 'something', transfer_token: 'something' },
- created_on: Math.floor(Date.now() / 1000),
- expires_in: Math.floor(Date.now() / 1000) + 100,
- access_token: '',
- refresh_expires_in: 0,
- refresh_token: 'something',
- scope:
- 'openid profile email offline_access urn:globus:auth:scope:transfer.api.globus.org:all',
- token_type: '',
- } as GlobusTokenResponse);
-
- const { getByTestId, getByRole, getByText, getAllByText } = customRender(
-
- );
-
- // Wait for results to load
- await waitFor(() =>
- expect(getByText('results found for', { exact: false })).toBeTruthy()
- );
-
- // Check first row renders and click the checkbox
- const firstRow = getByRole('row', {
- name: getRowName('plus', 'check', 'foo', '3', '1', '1', true),
- });
-
- // Check first row has add button and click it
- const addBtn = within(firstRow).getByRole('img', { name: 'plus' });
- expect(addBtn).toBeTruthy();
- await act(async () => {
- await user.click(addBtn);
- });
-
- // Check 'Added items(s) to the cart' message appears
- const addText = await waitFor(
- () => getAllByText('Added item(s) to your cart')[0]
- );
- expect(addText).toBeTruthy();
-
- // Set endpoint in url
- Object.defineProperty(window, 'location', {
- value: {
- assign: () => {},
- pathname: '/cart/items',
- href:
- 'https://localhost:3000/cart/items?endpoint=dummyEndpoint&label=dummy&path=nowhere&globfs=empty&endpointid=endpoint1',
- search:
- '?endpoint=dummyEndpoint&label=dummy&path=nowhere&globfs=empty&endpointid=endpoint1',
- replace: () => {},
- },
- });
-
- // Switch to the cart page
- const cartBtn = getByTestId('cartPageLink');
- await act(async () => {
- await user.click(cartBtn);
- });
-
- // A popup should come asking if user wishes to save endpoint as default
- const saveEndpointDialog = getByRole('dialog');
- expect(saveEndpointDialog).toBeTruthy();
- expect(saveEndpointDialog).toBeVisible();
- expect(saveEndpointDialog).toHaveTextContent(
- 'Do you want to save this endpoint as default?'
- );
-
- // Click Yes to save the endpoint as default
- const yesBtn = within(saveEndpointDialog).getByText('Yes');
- expect(yesBtn).toBeTruthy();
- await act(async () => {
- await user.click(yesBtn);
- });
-
- // Next step should be to start the Transfer
- const globusTransferDialog = getByRole('dialog');
- expect(globusTransferDialog).toBeTruthy();
-
- // Select the final transfer step in the dialog
- const transferStep = within(globusTransferDialog).getByText(
- 'Start Globus transfer.',
- {
- exact: false,
- }
- );
- // The transfer step should be the next step to perform
- expect(transferStep.innerHTML).toMatch(/-> {2}Start Globus transfer./i);
-
- // Click Yes to continue transfer steps
- const startBtn = within(globusTransferDialog).getByText('Yes');
- expect(startBtn).toBeTruthy();
- await act(async () => {
- await user.click(startBtn);
- });
-
- // Check 'Globus transfer task submitted successfully!' message appears
- const taskMsg = await waitFor(() =>
- getByText('Globus transfer task submitted successfully!', {
- exact: false,
- })
- );
- expect(taskMsg).toBeTruthy();
-
- // Clear all task items
- const submitHistory = getByText('Task Submit History', { exact: false });
- expect(submitHistory).toBeTruthy();
- const clearAllBtn = within(submitHistory).getByText('Clear All');
- expect(clearAllBtn).toBeTruthy();
- await act(async () => {
- await user.click(clearAllBtn);
- });
-});
-
-xit('If endpoint URL is set, and sign in tokens in URL, continue to select endpoint', async () => {
- // Setting the tokens so that the sign-in step should be completed
-
- const { getByTestId, getByRole, getByText, getAllByText } = customRender(
-
- );
-
- // Wait for results to load
- await waitFor(() =>
- expect(getByText('results found for', { exact: false })).toBeTruthy()
- );
-
- // Check first row renders and click the checkbox
- const firstRow = getByRole('row', {
- name: getRowName('plus', 'check', 'foo', '3', '1', '1', true),
- });
-
- // Check first row has add button and click it
- const addBtn = within(firstRow).getByRole('img', { name: 'plus' });
- expect(addBtn).toBeTruthy();
- await act(async () => {
- await user.click(addBtn);
- });
-
- // Check 'Added items(s) to the cart' message appears
- const addText = await waitFor(
- () => getAllByText('Added item(s) to your cart')[0]
- );
- expect(addText).toBeTruthy();
-
- // Switch to the cart page
- const cartBtn = getByTestId('cartPageLink');
- await act(async () => {
- await user.click(cartBtn);
- });
- // Select item for globus transfer
- const firstCheckBox = getByRole('checkbox');
- expect(firstCheckBox).toBeTruthy();
- await act(async () => {
- await user.click(firstCheckBox);
- });
-
- // Click Transfer button
- const globusTransferBtn = getByRole('button', {
- name: /download transfer/i,
- });
- expect(globusTransferBtn).toBeTruthy();
- await act(async () => {
- await user.click(globusTransferBtn);
- });
-
- // Get the transfer dialog popup component
- const popupModal = getByRole('dialog');
- expect(popupModal).toBeTruthy();
-
- // The dialog should be visible
- expect(popupModal).toBeVisible();
-
- // Select the sign-in step in the dialog
- const signInStep = within(popupModal).getByText(
- 'Redirect to obtain transfer permission from Globus',
- {
- exact: false,
- }
- );
- // It should have a -> symbol next to it to indicate it's the next step
- expect(signInStep.innerHTML).toMatch(
- '-> Redirect to obtain transfer permission from Globus.'
- );
-
- // Select the endpoint step in the dialog
- const selectEndpointStep = within(
- popupModal
- ).getByText('Redirect to select an endpoint in Globus', { exact: false });
- // It should NOT have a -> symbol next to it to indicate it's the next step
- expect(selectEndpointStep.innerHTML).toMatch(
- 'Redirect to select an endpoint in Globus.'
- );
-
- // Click Yes to start next transfer steps
- const yesBtn = getByText('Yes');
- expect(yesBtn).toBeTruthy();
- await act(async () => {
- await user.click(yesBtn);
- });
-
- // Expect the dialog to not be visible
- expect(popupModal).not.toBeVisible();
-});
-
-xit('Perform Transfer process when sign in tokens and endpoint are BOTH ready', async () => {
- // Setting the tokens so that the sign-in step should be completed
- mockSaveValue(CartStateKeys.cartItemSelections, userCartFixture());
- mockSaveValue(GlobusStateKeys.accessToken, 'accessToken');
- mockSaveValue(GlobusStateKeys.transferToken, {
- id_token: '',
- resource_server: '',
- other_tokens: { refresh_token: 'something', transfer_token: 'something' },
- created_on: Math.floor(Date.now() / 1000),
- expires_in: Math.floor(Date.now() / 1000) + 100,
- access_token: '',
- refresh_expires_in: 0,
- refresh_token: 'something',
- scope:
- 'openid profile email offline_access urn:globus:auth:scope:transfer.api.globus.org:all',
- token_type: '',
- } as GlobusTokenResponse);
-
- const { getByTestId, getByRole, getByText, getAllByText } = customRender(
-
- );
-
- // Wait for results to load
- await waitFor(() =>
- expect(getByText('results found for', { exact: false })).toBeTruthy()
- );
-
- // Check first row renders and click the checkbox
- const firstRow = getByRole('row', {
- name: getRowName('plus', 'check', 'foo', '3', '1', '1', true),
- });
-
- // Check first row has add button and click it
- const addBtn = within(firstRow).getByRole('img', { name: 'plus' });
- expect(addBtn).toBeTruthy();
- await act(async () => {
- await user.click(addBtn);
- });
-
- // Check 'Added items(s) to the cart' message appears
- const addText = await waitFor(
- () => getAllByText('Added item(s) to your cart')[0]
- );
- expect(addText).toBeTruthy();
-
- // Switch to the cart page
- const cartBtn = getByTestId('cartPageLink');
- await act(async () => {
- await user.click(cartBtn);
- });
-
- // Check 'Globus transfer task submitted successfully!' message appears
- const taskMsg = await waitFor(() =>
- getByText('Globus transfer task submitted successfully!', {
- exact: false,
- })
- );
- expect(taskMsg).toBeTruthy();
-
- // Clear all task items
- const submitHistory = getByText('Task Submit History', { exact: false });
- expect(submitHistory).toBeTruthy();
- const clearAllBtn = within(submitHistory).getByText('Clear All');
- expect(clearAllBtn).toBeTruthy();
- await act(async () => {
- await user.click(clearAllBtn);
- });
-});
-
-xdescribe('Testing globus transfer related failures', () => {
- beforeAll(() => {
- jest.spyOn(console, 'error').mockImplementation(jest.fn());
- tempStorageSetMock('pkce-pass', false);
- jest.resetModules();
- });
-
- it('Shows an error message if transfer task fails', async () => {
+ it('Shows an alert when a collection search fails in the manage collections form', async () => {
server.use(
- rest.post(apiRoutes.globusTransfer.path, (_req, res, ctx) =>
- res(ctx.status(404))
+ rest.get(apiRoutes.globusSearchEndpoints.path, (_req, res, ctx) =>
+ res(ctx.status(500))
)
);
- // Setting the tokens so that the sign-in step should be completed
- mockSaveValue(CartStateKeys.cartItemSelections, userCartFixture());
- mockSaveValue(GlobusStateKeys.accessToken, 'globusAccessToken');
- mockSaveValue(GlobusStateKeys.transferToken, {
- id_token: '',
- resource_server: '',
- other_tokens: { refresh_token: 'something', transfer_token: 'something' },
- created_on: Math.floor(Date.now() / 1000),
- expires_in: Math.floor(Date.now() / 1000) + 100,
- access_token: '',
- refresh_expires_in: 0,
- refresh_token: 'something',
- scope: 'openid profile email offline_access ',
- token_type: '',
- } as GlobusTokenResponse);
-
- const { getByTestId, getByRole, getByText, getAllByText } = customRender(
-
- );
-
- // Wait for results to load
- await waitFor(() =>
- expect(getByText('results found for', { exact: false })).toBeTruthy()
- );
-
- // Check first row renders and click the checkbox
- const firstRow = getByRole('row', {
- name: getRowName('plus', 'check', 'foo', '3', '1', '1', true),
- });
-
- // Check first row has add button and click it
- const addBtn = within(firstRow).getByRole('img', { name: 'plus' });
- expect(addBtn).toBeTruthy();
- await act(async () => {
- await user.click(addBtn);
- });
-
- // Check 'Added items(s) to the cart' message appears
- const addText = await waitFor(
- () => getAllByText('Added item(s) to your cart')[0]
- );
- expect(addText).toBeTruthy();
-
- // Switch to the cart page
- const cartBtn = getByTestId('cartPageLink');
- await act(async () => {
- await user.click(cartBtn);
+ await initializeComponentForTest({
+ ...defaultTestConfig,
+ savedEndpoints: [],
+ chosenEndpoint: null,
});
- // Check 'Globus transfer task failed' message appears
- const taskMsg = await waitFor(() =>
- getByText('Globus transfer task failed', {
- exact: false,
- })
- );
- expect(taskMsg).toBeTruthy();
- });
-
- // TODO: Figure a reliable way to mock the GlobusAuth.exchangeForAccessToken output values.
- /** Until that is done, this test will fail and will need to use istanbul ignore statements
- * for the mean time.
- */
- xit('Shows error message if url tokens are not valid for transfer', async () => {
- // Setting the tokens so that the sign-in step should be skipped
- mockSaveValue(CartStateKeys.cartItemSelections, userCartFixture());
-
- tempStorageSetMock('pkce-pass', false);
-
- const { getByTestId, getByRole, getByText, getAllByText } = customRender(
-
- );
-
- // Wait for results to load
- await waitFor(() =>
- expect(getByText('results found for', { exact: false })).toBeTruthy()
+ // Open download dropdown
+ const collectionDropdown = await screen.findByTestId(
+ 'searchCollectionInput'
);
-
- // Check first row renders and click the checkbox
- const firstRow = getByRole('row', {
- name: getRowName('plus', 'check', 'foo', '3', '1', '1', true),
- });
-
- // Check first row has add button and click it
- const addBtn = within(firstRow).getByRole('img', { name: 'plus' });
- expect(addBtn).toBeTruthy();
- await act(async () => {
- await user.click(addBtn);
- });
-
- // Check 'Added items(s) to the cart' message appears
- const addText = await waitFor(
- () => getAllByText('Added item(s) to your cart')[0]
+ const selectEndpoint = await within(collectionDropdown).findByRole(
+ 'combobox'
);
- expect(addText).toBeTruthy();
-
- // Set the tokens in the url
- Object.defineProperty(window, 'location', {
- value: {
- assign: () => {},
- pathname: '/cart/items',
- href:
- 'https://localhost:3000/cart/items?code=12kj3kjh4&state=testingTransferTokens',
- search: '?code=12kj3kjh4&state=testingTransferTokens',
- replace: () => {},
- },
- });
-
- tempStorageSetMock('pkce-pass', false);
+ await openDropdownList(user, selectEndpoint);
- // Switch to the cart page
- const cartBtn = getByTestId('cartPageLink');
+ // Select manage collections
+ const manageEndpointsBtn = await screen.findByText('Manage Collections');
+ expect(manageEndpointsBtn).toBeTruthy();
await act(async () => {
- await user.click(cartBtn);
+ await user.click(manageEndpointsBtn);
});
- const accessToken = await mockLoadValue(GlobusStateKeys.accessToken);
- const transferToken = await mockLoadValue(GlobusStateKeys.transferToken);
-
- expect(accessToken).toBeFalsy();
- expect(transferToken).toBeFalsy();
-
- // Check 'Error occurred when obtaining transfer permission!' message appears
- const taskMsg = await waitFor(
- () =>
- getAllByText('Error occured when obtaining transfer permissions.', {
- exact: false,
- })[0]
- );
- expect(taskMsg).toBeTruthy();
- });
-});
-
-xdescribe('Testing wget transfer related failures', () => {
- it('Wget transfer fails and failure message pops up.', async () => {
- server.use(
- rest.post(apiRoutes.wget.path, (_req, res, ctx) => res(ctx.status(404)))
- );
-
- const { getByTestId, getByRole, getByText, getAllByText } = customRender(
-
- );
-
- // Wait for results to load
- await waitFor(() =>
- expect(getByText('results found for', { exact: false })).toBeTruthy()
+ const manageCollectionsForm = await screen.findByTestId(
+ 'manageCollectionsForm'
);
+ expect(manageCollectionsForm).toBeTruthy();
- // Check first row renders and click the checkbox
- const firstRow = getByRole('row', {
- name: getRowName('plus', 'check', 'foo', '3', '1', '1', true),
- });
-
- // Check first row has add button and click it
- const addBtn = within(firstRow).getByRole('img', { name: 'plus' });
- expect(addBtn).toBeTruthy();
- await act(async () => {
- await user.click(addBtn);
- });
-
- // Check 'Added items(s) to the cart' message appears
- const addText = await waitFor(
- () => getAllByText('Added item(s) to your cart')[0]
+ // Type in endpoint search text
+ const endpointSearchInput = await screen.findByPlaceholderText(
+ 'Search for a Globus Collection'
);
- expect(addText).toBeTruthy();
-
- // Switch to the cart page
- const cartBtn = getByTestId('cartPageLink');
- await act(async () => {
- await user.click(cartBtn);
- });
-
- // Select item for globus transfer
- const firstCheckBox = getByRole('checkbox');
- expect(firstCheckBox).toBeTruthy();
- await act(async () => {
- await user.click(firstCheckBox);
- });
-
- // Open download dropdown
- const globusTransferDropdown = within(
- getByTestId('downloadTypeSelector')
- ).getByRole('combobox');
-
- await openDropdownList(user, globusTransferDropdown);
-
- // Select wget
- const wgetOption = getAllByText(/wget/i)[2];
- expect(wgetOption).toBeTruthy();
- await act(async () => {
- await user.click(wgetOption);
- });
-
- // Start wget download
- const downloadBtn = getByText('Download');
- expect(downloadBtn).toBeTruthy();
+ expect(endpointSearchInput).toBeTruthy();
await act(async () => {
- await user.click(downloadBtn);
+ await user.type(endpointSearchInput, 'lc public{enter}');
});
- // Expect error message to show
- await waitFor(() =>
- expect(
- getAllByText(
- 'The requested resource at the ESGF wget API service was invalid.',
- { exact: false }
- )
- ).toBeTruthy()
+ // Expect an alert to show up
+ const alertPopup = await screen.findByText(
+ 'An error occurred while searching for collections. Please try again later.'
);
+ expect(alertPopup).toBeTruthy();
});
});
diff --git a/frontend/src/components/Globus/DatasetDownload.tsx b/frontend/src/components/Globus/DatasetDownload.tsx
index 7e8c23731..c0ccef210 100644
--- a/frontend/src/components/Globus/DatasetDownload.tsx
+++ b/frontend/src/components/Globus/DatasetDownload.tsx
@@ -542,6 +542,17 @@ const DatasetDownloadForm: React.FC> = () => {
} catch (error) {
// eslint-disable-next-line no-console
console.error(error);
+ setAlertPopupState({
+ content:
+ 'An error occurred while searching for collections. Please try again later.',
+ onCancelAction: () => {
+ setAlertPopupState({ ...alertPopupState, show: false });
+ },
+ onOkAction: () => {
+ setAlertPopupState({ ...alertPopupState, show: false });
+ },
+ show: true,
+ });
} finally {
setLoadingEndpointSearchResults(false);
}
diff --git a/frontend/src/components/Search/Table.test.tsx b/frontend/src/components/Search/Table.test.tsx
index c8d71b610..72fd120fe 100644
--- a/frontend/src/components/Search/Table.test.tsx
+++ b/frontend/src/components/Search/Table.test.tsx
@@ -10,7 +10,7 @@ import apiRoutes from '../../api/routes';
import customRender from '../../test/custom-render';
import Table, { Props } from './Table';
import { QualityFlag } from './Tabs';
-import { getRowName } from '../../test/jestTestFunctions';
+import { getRowName, mockConfig } from '../../test/jestTestFunctions';
const user = userEvent.setup();
@@ -451,6 +451,27 @@ describe('test main table UI', () => {
);
expect(errorMsg).toBeTruthy();
});
+
+ it('does not render Globus Ready column when globusEnabledNodes is empty', async () => {
+ // Set names of the globus enabled nodes
+ mockConfig.globusEnabledNodes = [];
+
+ customRender();
+
+ // Check table exists
+ const table = await screen.findByRole('table');
+ expect(table).toBeTruthy();
+
+ // Check first row exists
+ const firstRow = await screen.findByRole('row', {
+ name: getRowName('plus', 'question', 'foo', '3', '1', '1'),
+ });
+ expect(firstRow).toBeTruthy();
+
+ // Check Globus Ready column does not exist
+ const globusReadyColumn = screen.queryByText('Globus Ready');
+ expect(globusReadyColumn).toBeNull();
+ });
});
describe('test QualityFlag', () => {