Skip to content

Commit

Permalink
Merge branch 'main' into bug/WP-319--rt-email-confirmation
Browse files Browse the repository at this point in the history
  • Loading branch information
rstijerina authored Oct 10, 2023
2 parents 7e69a37 + e47ea96 commit c4f2258
Show file tree
Hide file tree
Showing 10 changed files with 258 additions and 10 deletions.
13 changes: 13 additions & 0 deletions client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
"stylelint": "^14.4.0",
"stylelint-config-recommended": "^7.0.0",
"stylelint-config-standard": "^25.0.0",
"timekeeper": "^2.3.1",
"typescript": "^4.4.3",
"vite": "^2.9.16",
"weak-key": "^1.0.1"
Expand Down
1 change: 1 addition & 0 deletions client/src/components/Applications/AppForm/AppForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,7 @@ export const AppSchemaForm = ({ app }) => {
targetDir: isTargetPathField(k) ? v : null,
};
})
.filter((v) => v) //filter nulls
.reduce((acc, entry) => {
// merge input field and targetPath fields into one.
const key = getInputFieldFromTargetPathField(entry.name);
Expand Down
171 changes: 169 additions & 2 deletions client/src/components/Applications/AppForm/AppForm.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react';
import { render, waitFor } from '@testing-library/react';
import { fireEvent, render, waitFor } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import { Provider } from 'react-redux';
import configureStore from 'redux-mock-store';
import { BrowserRouter } from 'react-router-dom';
Expand All @@ -15,11 +16,16 @@ import {
appTrayExpectedFixture,
} from '../../../redux/sagas/fixtures/apptray.fixture';
import { initialAppState } from '../../../redux/reducers/apps.reducers';
import { helloWorldAppFixture } from './fixtures/AppForm.app.fixture';
import {
helloWorldAppFixture,
helloWorldAppSubmissionPayloadFixture,
} from './fixtures/AppForm.app.fixture';
import systemsFixture from '../../DataFiles/fixtures/DataFiles.systems.fixture';
import { projectsFixture } from '../../../redux/sagas/fixtures/projects.fixture';
import '@testing-library/jest-dom/extend-expect';
import timekeeper from 'timekeeper';

const frozenDate = '2023-10-01';
const mockStore = configureStore();
const initialMockState = {
allocations: allocationsFixture,
Expand Down Expand Up @@ -56,6 +62,11 @@ function renderAppSchemaFormComponent(store, app) {
}

describe('AppSchemaForm', () => {
beforeAll(() => {
// Lock Time
timekeeper.freeze(new Date(frozenDate));
});

it('renders the AppSchemaForm', async () => {
const store = mockStore({
...initialMockState,
Expand Down Expand Up @@ -257,6 +268,162 @@ describe('AppSchemaForm', () => {
expect(getByText(/Activate your Application Name license/)).toBeDefined();
});
});

it('job submission with file input mode FIXED', async () => {
const store = mockStore({
...initialMockState,
});

const { getByText, container } = renderAppSchemaFormComponent(store, {
...helloWorldAppFixture,
definition: {
...helloWorldAppFixture.definition,
jobAttributes: {
...helloWorldAppFixture.definition.jobAttributes,
fileInputs: [
{
name: 'File to copy',
description: 'A fixed file used by the app',
inputMode: 'FIXED',
autoMountLocal: true,
sourceUrl:
'tapis://corral-tacc/tacc/aci/secure-test/rallyGolf.jpg',
targetPath: 'rallyGolf.jpg',
},
],
},
},
});
const hiddenFileInput = container.querySelector(
'input[name="fileInputs.File to copy"]'
);
// FIXED fields are still shown in UI but not submitted.
expect(hiddenFileInput).toBeInTheDocument();

const submitButton = getByText(/Submit/);
fireEvent.click(submitButton);
const payload = {
...helloWorldAppSubmissionPayloadFixture,
job: {
...helloWorldAppSubmissionPayloadFixture.job,
name: 'hello-world-0.0.1_' + frozenDate + 'T00:00:00',
},
};

await waitFor(() => {
expect(store.getActions()).toEqual([
{ type: 'GET_SYSTEM_MONITOR' },
{ type: 'SUBMIT_JOB', payload: payload },
]);
});
});

it('job submission with file input hidden', async () => {
const store = mockStore({
...initialMockState,
});

const { getByText, container } = renderAppSchemaFormComponent(store, {
...helloWorldAppFixture,
definition: {
...helloWorldAppFixture.definition,
jobAttributes: {
...helloWorldAppFixture.definition.jobAttributes,
fileInputs: [
{
name: 'File to copy',
description: 'A fixed file used by the app',
inputMode: 'REQUIRED',
autoMountLocal: true,
sourceUrl:
'tapis://corral-tacc/tacc/aci/secure-test/rallyGolf.jpg',
targetPath: 'rallyGolf.jpg',
notes: {
isHidden: true,
},
},
],
},
},
});

const hiddenFileInput = container.querySelector(
'input[name="fileInputs.File to copy"]'
);
expect(hiddenFileInput).not.toBeInTheDocument();

const submitButton = getByText(/Submit/);
fireEvent.click(submitButton);
const payload = {
...helloWorldAppSubmissionPayloadFixture,
job: {
...helloWorldAppSubmissionPayloadFixture.job,
name: 'hello-world-0.0.1_' + frozenDate + 'T00:00:00',
},
};

await waitFor(() => {
expect(store.getActions()).toEqual([
{ type: 'GET_SYSTEM_MONITOR' },
{ type: 'SUBMIT_JOB', payload: payload },
]);
});
});

it('job submission with custom target path', async () => {
const store = mockStore({
...initialMockState,
});
const { getByText, container } = renderAppSchemaFormComponent(store, {
...helloWorldAppFixture,
definition: {
...helloWorldAppFixture.definition,
notes: {
...helloWorldAppFixture.definition.notes,
showTargetPath: true,
},
},
});

const fileInput = container.querySelector(
'input[name="fileInputs.File to modify"]'
);
const file = 'tapis://foo/bar.txt';
const targetPathForFile = 'baz.txt';
fireEvent.change(fileInput, { target: { value: file } });
const targetPathInput = container.querySelector(
'input[name="fileInputs._TargetPath_File to modify"]'
);
fireEvent.change(targetPathInput, { target: { value: targetPathForFile } });

const submitButton = getByText(/Submit/);
fireEvent.click(submitButton);
const payload = {
...helloWorldAppSubmissionPayloadFixture,
job: {
...helloWorldAppSubmissionPayloadFixture.job,
fileInputs: [
{
name: 'File to modify',
sourceUrl: file,
targetPath: targetPathForFile,
},
],
name: 'hello-world-0.0.1_' + frozenDate + 'T00:00:00',
},
};

await waitFor(() => {
expect(store.getActions()).toEqual([
{ type: 'GET_SYSTEM_MONITOR' },
{ type: 'SUBMIT_JOB', payload: payload },
]);
});
});

afterAll(() => {
timekeeper.reset();
});
});

describe('AppDetail', () => {
Expand Down
9 changes: 4 additions & 5 deletions client/src/components/Applications/AppForm/AppFormSchema.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,10 @@ const FormSchema = (app) => {
app.definition.notes.showTargetPath ?? false;
(app.definition.jobAttributes.fileInputs || []).forEach((i) => {
const input = i;
/* TODOv3 consider hidden file inputs https://jira.tacc.utexas.edu/browse/WP-102
if (input.name.startsWith('_') || !input.value.visible) { // TODOv3 visible or hidden
return;
}
*/
if (input.notes?.isHidden) {
return;
}

const field = {
label: input.name,
description: input.description,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,3 +237,49 @@ export const helloWorldAppFixture = {
type: null,
},
};

export const helloWorldAppSubmissionPayloadFixture = {
job: {
fileInputs: [],
parameterSet: {
appArgs: [
{
name: 'Greeting',
arg: 'hello',
},
{
name: 'Target',
arg: 'world',
},
{
name: 'Sleep Time',
arg: '30',
},
],
containerArgs: [],
schedulerOptions: [
{
name: 'TACC Allocation',
description: 'The TACC allocation associated with this job execution',
include: true,
arg: '-A TACC-ACI',
},
],
envVariables: [],
},
name: 'hello-world-0.0.1',
nodeCount: 1,
coresPerNode: 1,
maxMinutes: 10,
archiveSystemId: 'frontera',
archiveSystemDir:
'HOST_EVAL($HOME)/tapis-jobs-archive/${JobCreateDate}/${JobName}-${JobUUID}',
archiveOnAppError: true,
appId: 'hello-world',
appVersion: '0.0.1',
execSystemId: 'frontera',
execSystemLogicalQueue: 'development',
},
licenseType: null,
isInteractive: false,
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ import { bool, func, string } from 'prop-types';
import './JobsSessionModal.global.scss';
import styles from './JobsSessionModal.module.scss';

const JobsSessionModal = ({ isOpen, toggle, interactiveSessionLink }) => {
const JobsSessionModal = ({
isOpen,
toggle,
interactiveSessionLink,
message,
}) => {
return (
<Modal isOpen={isOpen} toggle={toggle} contentClassName="session-modal">
<ModalHeader
Expand All @@ -18,6 +23,7 @@ const JobsSessionModal = ({ isOpen, toggle, interactiveSessionLink }) => {
<span>
Click the button below to connect to the interactive session.
</span>
{message && <b>{message}</b>}
<span>To end the job, quit the application within the session.</span>
<span>
Files may take some time to appear in the output location after the
Expand Down
3 changes: 3 additions & 0 deletions client/src/components/Jobs/JobsStatus/JobsStatus.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ function JobsStatus({ status, fancy, jobUuid }) {

const notifs = useSelector((state) => state.notifications.list.notifs);
let interactiveSessionLink;
let message;

const jobConcluded = isTerminalState(status) || status === 'ARCHIVING';

Expand All @@ -85,6 +86,7 @@ function JobsStatus({ status, fancy, jobUuid }) {
);
const notif = interactiveNotifs.find((n) => n.extra.uuid === jobUuid);
interactiveSessionLink = notif ? notif.action_link : null;
message = notif ? notif.message : null;
}

return (
Expand All @@ -109,6 +111,7 @@ function JobsStatus({ status, fancy, jobUuid }) {
toggle={toggleModal}
isOpen={modal}
interactiveSessionLink={interactiveSessionLink}
message={message}
/>
</>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,11 @@ def migrate_project(project_id):

for co_pi in v2_project.co_pis.all():
v2_role = get_role(project_id, co_pi.username)
v3_role = ROLE_MAP[v2_role]
try:
v3_role = ROLE_MAP[v2_role]
except KeyError:
print(f'ERROR: No role found for: {v2_role}')
v3_role = "reader"
try:
add_user_to_workspace(client, project_id, co_pi.username, v3_role)
except NotFoundError:
Expand All @@ -71,7 +75,11 @@ def migrate_project(project_id):

for team_member in v2_project.team_members.all():
v2_role = get_role(project_id, team_member.username)
v3_role = ROLE_MAP[v2_role]
try:
v3_role = ROLE_MAP[v2_role]
except KeyError:
print(f'ERROR: No role found for: {v2_role}')
v3_role = "reader"
try:
add_user_to_workspace(client, project_id, team_member.username, v3_role)
except NotFoundError:
Expand Down
Loading

0 comments on commit c4f2258

Please sign in to comment.