diff --git a/.gitignore b/.gitignore index f75d64309..4296bd98a 100644 --- a/.gitignore +++ b/.gitignore @@ -408,3 +408,4 @@ beacon/spring/out *.project *bin /a.json +/testbed/authentication/.idea/workspace.xml diff --git a/backend/src/integration/groovy/edu/internet2/tier/shibboleth/admin/ui/SeleniumSIDETest.groovy b/backend/src/integration/groovy/edu/internet2/tier/shibboleth/admin/ui/SeleniumSIDETest.groovy index 3d8536f98..9791f9af9 100644 --- a/backend/src/integration/groovy/edu/internet2/tier/shibboleth/admin/ui/SeleniumSIDETest.groovy +++ b/backend/src/integration/groovy/edu/internet2/tier/shibboleth/admin/ui/SeleniumSIDETest.groovy @@ -126,14 +126,17 @@ class SeleniumSIDETest extends Specification { 'SHIBUI-1407: Metadata provider comparison highlights' | '/SHIBUI-1407-2.side' 'SHIBUI-1503: Non-admin can create metadata source' | '/SHIBUI-1503-1.side' 'SHIBUI-1503: User can be deleted' | '/SHIBUI-1503-2.side' - 'SHIBUI-1503: User can be enabled' | '/SHIBUI-1503-3.side'*/ -// 'SHIBUI-1740: Group can be created, edited, deleted' | '/SHIBUI-1740-1.side' -// 'SHIBUI-1740: Verify dev profile group membership' | '/SHIBUI-1740-2.side' -// 'SHIBUI-1740: Verify admin-owned resource not visible to nonadmins' | '/SHIBUI-1740-3.side' -// 'SHIBUI-1740: Verify nonadmin-owned resource visibility' | '/SHIBUI-1740-4.side' -// 'SHIBUI-1742: Verify enabler role allows enabling' | '/SHIBUI-1742-1.side' -// 'SHIBUI-1742: Verify role CRUD operations' | '/SHIBUI-1742-2.side' + 'SHIBUI-1503: User can be enabled' | '/SHIBUI-1503-3.side' + 'SHIBUI-1740: Group can be created, edited, deleted' | '/SHIBUI-1740-1.side' + 'SHIBUI-1740: Verify dev profile group membership' | '/SHIBUI-1740-2.side' + 'SHIBUI-1740: Verify admin-owned resource not visible to nonadmins' | '/SHIBUI-1740-3.side' + 'SHIBUI-1740: Verify nonadmin-owned resource visibility' | '/SHIBUI-1740-4.side' + 'SHIBUI-1742: Verify enabler role allows enabling' | '/SHIBUI-1742-1.side' + 'SHIBUI-1742: Verify role CRUD operations' | '/SHIBUI-1742-2.side'*/ 'SHIBUI-1743: Verify group regex CRUD operations' | '/SHIBUI-1743-1.side' 'SHIBUI-1743: Verify nonadmin group regex validation' | '/SHIBUI-1743-2.side' + 'SHIBUI-1744: Verify attribute bundle CRUD operations' | '/SHIBUI-1744-1.side' + 'SHIBUI-1744: Verify attribute bundles in metadata sources' | '/SHIBUI-1744-2.side' + 'SHIBUI-1744: Verify attribute bundles in entity attribute filters' | '/SHIBUI-1744-3.side' } } \ No newline at end of file diff --git a/backend/src/integration/resources/SHIBUI-1744-1.side b/backend/src/integration/resources/SHIBUI-1744-1.side new file mode 100644 index 000000000..faaacee02 --- /dev/null +++ b/backend/src/integration/resources/SHIBUI-1744-1.side @@ -0,0 +1,477 @@ +{ + "id": "46b0fc77-1920-4123-93cc-f5a9f9c7f3ee", + "version": "2.0", + "name": "SHIBUI-1744-1", + "url": "http://localhost:10101", + "tests": [{ + "id": "6700238c-68c3-4875-aca6-5345b9035043", + "name": "SHIBUI-1744-1", + "commands": [{ + "id": "8e5baaed-149f-4825-87d1-b74ad5207af5", + "comment": "", + "command": "open", + "target": "/login", + "targets": [], + "value": "" + }, { + "id": "312af240-96f2-432e-9dd9-ad28dbacce9e", + "comment": "", + "command": "type", + "target": "id=username", + "targets": [ + ["id=username", "id"], + ["name=username", "name"], + ["css=#username", "css:finder"], + ["xpath=//input[@id='username']", "xpath:attributes"], + ["xpath=//input", "xpath:position"] + ], + "value": "admin" + }, { + "id": "225e1245-05be-479d-ae5a-47647f2423c7", + "comment": "", + "command": "type", + "target": "id=password", + "targets": [ + ["id=password", "id"], + ["name=password", "name"], + ["css=#password", "css:finder"], + ["xpath=//input[@id='password']", "xpath:attributes"], + ["xpath=//p[2]/input", "xpath:position"] + ], + "value": "adminpass" + }, { + "id": "284ce82d-3b9e-4306-a8af-f6aa1f904677", + "comment": "", + "command": "click", + "target": "css=.btn", + "targets": [ + ["css=.btn", "css:finder"], + ["xpath=//button[@type='submit']", "xpath:attributes"], + ["xpath=//button", "xpath:position"], + ["xpath=//button[contains(.,'Sign in')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "b88f58fc-bd07-4b76-9a8a-08e7a13030e8", + "comment": "", + "command": "open", + "target": "/api/heheheheheheheWipeout", + "targets": [], + "value": "" + }, { + "id": "8ac3a399-aae1-4d46-93d4-51944effada6", + "comment": "", + "command": "assertText", + "target": "css=body", + "targets": [], + "value": "yes, you did it" + }, { + "id": "7f9552d9-47f0-470a-9ebb-0150ac230d85", + "comment": "", + "command": "open", + "target": "/", + "targets": [], + "value": "" + }, { + "id": "81d8d630-f07c-4582-a5f6-f871d282ff8b", + "comment": "", + "command": "click", + "target": "id=advanced-nav-dropdown-toggle", + "targets": [ + ["id=advanced-nav-dropdown-toggle", "id"], + ["css=#advanced-nav-dropdown-toggle", "css:finder"], + ["xpath=//button[@id='advanced-nav-dropdown-toggle']", "xpath:attributes"], + ["xpath=//div[@id='advanced-nav-dropdown']/button", "xpath:idRelative"], + ["xpath=//div[3]/button", "xpath:position"], + ["xpath=//button[contains(.,'Advanced')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "8e03032c-223a-41be-add6-83e7f27d6f7c", + "comment": "", + "command": "click", + "target": "id=advanced-nav-dropdown-bundles", + "targets": [ + ["id=advanced-nav-dropdown-bundles", "id"], + ["linkText=Attribute bundles", "linkText"], + ["css=#advanced-nav-dropdown-bundles", "css:finder"], + ["xpath=//a[contains(text(),'Attribute bundles')]", "xpath:link"], + ["xpath=//a[@id='advanced-nav-dropdown-bundles']", "xpath:attributes"], + ["xpath=//div[@id='advanced-nav-dropdown']/div/a[2]", "xpath:idRelative"], + ["xpath=//a[contains(@href, '/metadata/attributes/bundles')]", "xpath:href"], + ["xpath=//a[2]", "xpath:position"], + ["xpath=//a[contains(.,'Attribute bundles')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "35fe0df3-3237-4e0c-b552-e3596dbb61b8", + "comment": "", + "command": "click", + "target": "linkText=Add bundle", + "targets": [ + ["linkText=Add bundle", "linkText"], + ["css=.btn-success", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/div/section/div/div[2]/div/a", "xpath:idRelative"], + ["xpath=//a[contains(@href, '/metadata/attributes/bundles/new')]", "xpath:href"], + ["xpath=//div[2]/div/a", "xpath:position"], + ["xpath=//a[contains(.,'  Add bundle')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "f0ee699d-0fcd-499d-a05a-9a624e67180e", + "comment": "", + "command": "type", + "target": "id=root_name", + "targets": [ + ["id=root_name", "id"], + ["css=#root_name", "css:finder"], + ["xpath=//input[@id='root_name']", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/div/section/div[2]/div/div[2]/div/form/div/div/div/div/div/div/div/div/input", "xpath:idRelative"], + ["xpath=//input", "xpath:position"] + ], + "value": "Bundle 1" + }, { + "id": "1d30d160-e4cd-43fc-ad02-97cff7e6f236", + "comment": "", + "command": "click", + "target": "css=#root_attributes_0", + "targets": [ + ["css=tr:nth-child(1) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/div/section/div[2]/div/div[2]/div/form/div/div/div/div[2]/div/div/div/fieldset/table/tbody/tr/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//fieldset/div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "6b9f6181-15aa-4a27-937e-77924b9ca4d2", + "comment": "", + "command": "click", + "target": "css=#root_attributes_2", + "targets": [ + ["css=tr:nth-child(3) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/div/section/div[2]/div/div[2]/div/form/div/div/div/div[2]/div/div/div/fieldset/table/tbody/tr[3]/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//tr[3]/td[2]/fieldset/div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "69d2c0f6-15b1-42c9-bbef-15c83e134131", + "comment": "", + "command": "click", + "target": "css=#root_attributes_4", + "targets": [ + ["css=tr:nth-child(5) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/div/section/div[2]/div/div[2]/div/form/div/div/div/div[2]/div/div/div/fieldset/table/tbody/tr[5]/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//tr[5]/td[2]/fieldset/div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "88b8795d-d2a6-430d-83a8-ed469cd3db89", + "comment": "", + "command": "click", + "target": "css=#root_attributes_6", + "targets": [ + ["css=tr:nth-child(5) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/div/section/div[2]/div/div[2]/div/form/div/div/div/div[2]/div/div/div/fieldset/table/tbody/tr[5]/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//tr[5]/td[2]/fieldset/div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "6877d801-df03-4bce-b41b-fde47fd8b7ea", + "comment": "", + "command": "click", + "target": "css=#root_attributes_8", + "targets": [ + ["css=tr:nth-child(9) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/div/section/div[2]/div/div[2]/div/form/div/div/div/div[2]/div/div/div/fieldset/table/tbody/tr[9]/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//tr[9]/td[2]/fieldset/div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "16872e65-8f3a-4421-a32c-7737d83e7c16", + "comment": "", + "command": "click", + "target": "css=#root_attributes_10", + "targets": [ + ["css=tr:nth-child(11) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/div/section/div[2]/div/div[2]/div/form/div/div/div/div[2]/div/div/div/fieldset/table/tbody/tr[11]/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//tr[11]/td[2]/fieldset/div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "2ecac668-119c-4708-a88f-999fdec36d73", + "comment": "", + "command": "click", + "target": "css=.btn-info", + "targets": [ + ["css=.btn-info", "css:finder"], + ["xpath=(//button[@type='button'])[5]", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/div/section/div[2]/div/div/button", "xpath:idRelative"], + ["xpath=//div[2]/div/div/button", "xpath:position"], + ["xpath=//button[contains(.,' Save')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "d0959425-5169-4579-8d17-a22b2273d1ea", + "comment": "", + "command": "pause", + "target": "2000", + "targets": [], + "value": "" + }, { + "id": "6ad79c13-1e24-4a8e-a4d4-ca76b72c77a8", + "comment": "", + "command": "assertText", + "target": "css=td:nth-child(1)", + "targets": [ + ["css=td:nth-child(1)", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/div/section/div/div[2]/div[2]/table/tbody/tr/td", "xpath:idRelative"], + ["xpath=//td", "xpath:position"], + ["xpath=//td[contains(.,'Bundle 1')]", "xpath:innerText"] + ], + "value": "Bundle 1" + }, { + "id": "a7cd7ab2-3309-4ca2-ae1b-0b566c161582", + "comment": "", + "command": "click", + "target": "css=.fa-edit", + "targets": [ + ["css=.fa-edit", "css:finder"] + ], + "value": "" + }, { + "id": "a225ba76-2795-4395-b004-27629b49ebff", + "comment": "", + "command": "assertChecked", + "target": "css=#root_attributes_0", + "targets": [], + "value": "" + }, { + "id": "93974fdc-1b6a-4c97-94df-6dc7fdcc8ed8", + "comment": "", + "command": "assertChecked", + "target": "css=#root_attributes_2", + "targets": [ + ["css=tr:nth-child(3) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/div/section/div[2]/div/div[2]/div/form/div/div/div/div[2]/div/div/div/fieldset/table/tbody/tr[3]/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//tr[3]/td[2]/fieldset/div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "b874734d-53d7-449c-acd9-206c95665d40", + "comment": "", + "command": "assertChecked", + "target": "css=#root_attributes_4", + "targets": [ + ["css=tr:nth-child(3) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/div/section/div[2]/div/div[2]/div/form/div/div/div/div[2]/div/div/div/fieldset/table/tbody/tr[3]/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//tr[3]/td[2]/fieldset/div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "bdf4b8a9-d7bb-4b1b-aa58-c2c85bbf869f", + "comment": "", + "command": "assertChecked", + "target": "css=#root_attributes_6", + "targets": [ + ["css=tr:nth-child(3) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/div/section/div[2]/div/div[2]/div/form/div/div/div/div[2]/div/div/div/fieldset/table/tbody/tr[3]/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//tr[3]/td[2]/fieldset/div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "656b1af9-0356-401b-b0cf-a046b3121b09", + "comment": "", + "command": "assertChecked", + "target": "css=#root_attributes_8", + "targets": [ + ["css=tr:nth-child(3) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/div/section/div[2]/div/div[2]/div/form/div/div/div/div[2]/div/div/div/fieldset/table/tbody/tr[3]/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//tr[3]/td[2]/fieldset/div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "34a9dc70-f8f2-4247-85b0-f2e8100c59df", + "comment": "", + "command": "assertChecked", + "target": "css=#root_attributes_10", + "targets": [ + ["css=tr:nth-child(3) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/div/section/div[2]/div/div[2]/div/form/div/div/div/div[2]/div/div/div/fieldset/table/tbody/tr[3]/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//tr[3]/td[2]/fieldset/div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "789c4351-3989-4519-b45a-78fcf83bae74", + "comment": "", + "command": "type", + "target": "id=root_name", + "targets": [], + "value": "" + }, { + "id": "0c4dbdcd-2687-45c3-bf1f-3699b579ffe0", + "comment": "", + "command": "type", + "target": "id=root_name", + "targets": [ + ["id=root_name", "id"], + ["css=#root_name", "css:finder"], + ["xpath=//input[@id='root_name']", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/div/section/div[2]/div/div[2]/div/form/div/div/div/div/div/div/div/div/input", "xpath:idRelative"], + ["xpath=//input", "xpath:position"] + ], + "value": "Bundle 1 Edited" + }, { + "id": "9abad691-e8cf-47d5-ba2a-99b0f654c0e0", + "comment": "", + "command": "click", + "target": "css=#root_attributes_2", + "targets": [ + ["css=tr:nth-child(3) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/div/section/div[2]/div/div[2]/div/form/div/div/div/div[2]/div/div/div/fieldset/table/tbody/tr[3]/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//tr[3]/td[2]/fieldset/div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "d547bab8-df07-457b-aa7c-263ca89e714c", + "comment": "", + "command": "click", + "target": "css=#root_attributes_6", + "targets": [ + ["css=tr:nth-child(7) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/div/section/div[2]/div/div[2]/div/form/div/div/div/div[2]/div/div/div/fieldset/table/tbody/tr[7]/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//tr[7]/td[2]/fieldset/div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "bc6858f6-01a3-497b-bb2c-8426534d776b", + "comment": "", + "command": "click", + "target": "css=#root_attributes_10", + "targets": [ + ["css=tr:nth-child(11) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/div/section/div[2]/div/div[2]/div/form/div/div/div/div[2]/div/div/div/fieldset/table/tbody/tr[11]/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//tr[11]/td[2]/fieldset/div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "2c68f4dc-0040-4385-b960-934bc12c6806", + "comment": "", + "command": "click", + "target": "css=.btn-info", + "targets": [ + ["css=.btn-info", "css:finder"], + ["xpath=(//button[@type='button'])[5]", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/div/section/div[2]/div/div/button", "xpath:idRelative"], + ["xpath=//div[2]/div/div/button", "xpath:position"], + ["xpath=//button[contains(.,' Save')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "9e6dbe30-d5d2-4f34-a78a-7c6eff257bd4", + "comment": "", + "command": "waitForElementVisible", + "target": "css=td:nth-child(1)", + "targets": [], + "value": "30000" + }, { + "id": "05fce0b8-196f-4cae-bd1b-ab15b885cbe2", + "comment": "", + "command": "assertText", + "target": "css=td:nth-child(1)", + "targets": [ + ["css=td:nth-child(1)", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/div/section/div/div[2]/div[2]/table/tbody/tr/td", "xpath:idRelative"], + ["xpath=//td", "xpath:position"], + ["xpath=//td[contains(.,'Bundle 1 Edited')]", "xpath:innerText"] + ], + "value": "Bundle 1 Edited" + }, { + "id": "8ea152c6-4509-4969-b499-95272cb6b92e", + "comment": "", + "command": "click", + "target": "css=.fa-edit", + "targets": [ + ["css=.fa-edit", "css:finder"] + ], + "value": "" + }, { + "id": "9152c2be-bf07-4807-a068-7e779abcf86d", + "comment": "", + "command": "assertChecked", + "target": "css=#root_attributes_0", + "targets": [], + "value": "" + }, { + "id": "042857bd-6b10-4ff3-9544-04465ae664ab", + "comment": "", + "command": "assertChecked", + "target": "css=#root_attributes_4", + "targets": [ + ["css=tr:nth-child(3) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/div/section/div[2]/div/div[2]/div/form/div/div/div/div[2]/div/div/div/fieldset/table/tbody/tr[3]/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//tr[3]/td[2]/fieldset/div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "223e1893-0a61-440f-998e-80e8d299a7b1", + "comment": "", + "command": "assertChecked", + "target": "css=#root_attributes_8", + "targets": [ + ["css=tr:nth-child(3) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/div/section/div[2]/div/div[2]/div/form/div/div/div/div[2]/div/div/div/fieldset/table/tbody/tr[3]/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//tr[3]/td[2]/fieldset/div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "d60b6a27-5aba-4a2e-8252-7ebe6eb4dc58", + "comment": "", + "command": "click", + "target": "css=.btn-secondary", + "targets": [ + ["css=.btn-secondary", "css:finder"], + ["xpath=(//button[@type='button'])[6]", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/div/section/div[2]/div/div/button[2]", "xpath:idRelative"], + ["xpath=//button[2]", "xpath:position"], + ["xpath=//button[contains(.,'Cancel')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "f87e8057-b3c1-4d9a-92bd-1899680f4cbc", + "comment": "", + "command": "click", + "target": "css=.fa-trash > path", + "targets": [ + ["css=.fa-trash > path", "css:finder"] + ], + "value": "" + }, { + "id": "ad356bcf-d8d1-4668-bd7b-12b5d005d669", + "comment": "", + "command": "click", + "target": "css=.btn-danger", + "targets": [ + ["css=.btn-danger", "css:finder"], + ["xpath=(//button[@type='button'])[7]", "xpath:attributes"], + ["xpath=//div[3]/div/div/div[3]/button", "xpath:position"] + ], + "value": "" + }, { + "id": "fa6844d2-358d-4142-a96b-9bf6c04858e9", + "comment": "", + "command": "verifyElementPresent", + "target": "xpath=//div[@role=\"alert\" and contains(., \"Bundle has been deleted.\")]", + "targets": [], + "value": "" + }] + }], + "suites": [{ + "id": "f081803d-04c9-4aea-bd5b-765885cb4739", + "name": "Default Suite", + "persistSession": false, + "parallel": false, + "timeout": 300, + "tests": ["6700238c-68c3-4875-aca6-5345b9035043"] + }], + "urls": ["http://localhost:10101/"], + "plugins": [] +} \ No newline at end of file diff --git a/backend/src/integration/resources/SHIBUI-1744-2.side b/backend/src/integration/resources/SHIBUI-1744-2.side new file mode 100644 index 000000000..9524fb82d --- /dev/null +++ b/backend/src/integration/resources/SHIBUI-1744-2.side @@ -0,0 +1,646 @@ +{ + "id": "3616248b-1c79-48db-8d12-c8fac193e50c", + "version": "2.0", + "name": "SHIBUI-1744-2", + "url": "http://localhost:10101", + "tests": [{ + "id": "d785839e-2982-4464-85ed-d529b3c0657a", + "name": "SHIBUI-1744-2", + "commands": [{ + "id": "bcf63821-1c37-41da-a412-70b3d3f6d7c3", + "comment": "", + "command": "open", + "target": "/login", + "targets": [], + "value": "" + }, { + "id": "1ab6b03b-557c-4f24-bd85-b73eb9c8b799", + "comment": "", + "command": "type", + "target": "id=username", + "targets": [ + ["id=username", "id"], + ["name=username", "name"], + ["css=#username", "css:finder"], + ["xpath=//input[@id='username']", "xpath:attributes"], + ["xpath=//input", "xpath:position"] + ], + "value": "admin" + }, { + "id": "284cb3be-f30b-4910-b9cd-37f32bec16b2", + "comment": "", + "command": "type", + "target": "id=password", + "targets": [ + ["id=password", "id"], + ["name=password", "name"], + ["css=#password", "css:finder"], + ["xpath=//input[@id='password']", "xpath:attributes"], + ["xpath=//p[2]/input", "xpath:position"] + ], + "value": "adminpass" + }, { + "id": "d0ec187e-aa72-43d5-bb44-bbdb41337128", + "comment": "", + "command": "click", + "target": "css=.btn", + "targets": [ + ["css=.btn", "css:finder"], + ["xpath=//button[@type='submit']", "xpath:attributes"], + ["xpath=//button", "xpath:position"], + ["xpath=//button[contains(.,'Sign in')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "8096864b-f997-4d71-a579-d5170f27fdea", + "comment": "", + "command": "open", + "target": "/api/heheheheheheheWipeout", + "targets": [], + "value": "" + }, { + "id": "6033215d-28e8-4ce1-9558-8e42cef9b345", + "comment": "", + "command": "assertText", + "target": "css=body", + "targets": [], + "value": "yes, you did it" + }, { + "id": "3429ed77-d2d9-4d10-af98-36f875be06ed", + "comment": "", + "command": "open", + "target": "/", + "targets": [], + "value": "" + }, { + "id": "29540d39-cf80-4397-8db9-5405a543106e", + "comment": "", + "command": "click", + "target": "id=advanced-nav-dropdown-toggle", + "targets": [ + ["id=advanced-nav-dropdown-toggle", "id"], + ["css=#advanced-nav-dropdown-toggle", "css:finder"], + ["xpath=//button[@id='advanced-nav-dropdown-toggle']", "xpath:attributes"], + ["xpath=//div[@id='advanced-nav-dropdown']/button", "xpath:idRelative"], + ["xpath=//div[3]/button", "xpath:position"], + ["xpath=//button[contains(.,'Advanced')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "0a1d91f2-2265-4854-8bc9-329c6a65c0df", + "comment": "", + "command": "click", + "target": "id=advanced-nav-dropdown-bundles", + "targets": [ + ["id=advanced-nav-dropdown-bundles", "id"], + ["linkText=Attribute bundles", "linkText"], + ["css=#advanced-nav-dropdown-bundles", "css:finder"], + ["xpath=//a[contains(text(),'Attribute bundles')]", "xpath:link"], + ["xpath=//a[@id='advanced-nav-dropdown-bundles']", "xpath:attributes"], + ["xpath=//div[@id='advanced-nav-dropdown']/div/a[2]", "xpath:idRelative"], + ["xpath=//a[contains(@href, '/metadata/attributes/bundles')]", "xpath:href"], + ["xpath=//a[2]", "xpath:position"], + ["xpath=//a[contains(.,'Attribute bundles')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "1e764021-9ccf-46aa-b472-4ea81f22a68e", + "comment": "", + "command": "click", + "target": "linkText=Add bundle", + "targets": [ + ["linkText=Add bundle", "linkText"], + ["css=.btn-success", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/div/section/div/div[2]/div/a", "xpath:idRelative"], + ["xpath=//a[contains(@href, '/metadata/attributes/bundles/new')]", "xpath:href"], + ["xpath=//div[2]/div/a", "xpath:position"], + ["xpath=//a[contains(.,'  Add bundle')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "65bd6d70-1232-497b-83c4-960910e8966f", + "comment": "", + "command": "click", + "target": "id=root_name", + "targets": [ + ["id=root_name", "id"], + ["css=#root_name", "css:finder"], + ["xpath=//input[@id='root_name']", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/div/section/div[2]/div/div[2]/div/form/div/div/div/div/div/div/div/div/input", "xpath:idRelative"], + ["xpath=//input", "xpath:position"] + ], + "value": "" + }, { + "id": "1c563723-ad9a-4cd5-a4fa-7d291ed9edae", + "comment": "", + "command": "type", + "target": "id=root_name", + "targets": [ + ["id=root_name", "id"], + ["css=#root_name", "css:finder"], + ["xpath=//input[@id='root_name']", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/div/section/div[2]/div/div[2]/div/form/div/div/div/div/div/div/div/div/input", "xpath:idRelative"], + ["xpath=//input", "xpath:position"] + ], + "value": "Test Bundle" + }, { + "id": "f72c10ce-2902-4dee-bb30-80f9f47ea44c", + "comment": "", + "command": "click", + "target": "css=#root_attributes_2", + "targets": [ + ["css=tr:nth-child(3) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/div/section/div[2]/div/div[2]/div/form/div/div/div/div[2]/div/div/div/fieldset/table/tbody/tr[3]/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//tr[3]/td[2]/fieldset/div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "35263126-51a0-4d7e-80a4-b820da2936d7", + "comment": "", + "command": "click", + "target": "css=#root_attributes_3", + "targets": [ + ["css=tr:nth-child(4) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/div/section/div[2]/div/div[2]/div/form/div/div/div/div[2]/div/div/div/fieldset/table/tbody/tr[4]/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//tr[4]/td[2]/fieldset/div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "e0349ad1-44e0-4674-ad46-5d41e0518314", + "comment": "", + "command": "click", + "target": "css=#root_attributes_4", + "targets": [ + ["css=tr:nth-child(5) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/div/section/div[2]/div/div[2]/div/form/div/div/div/div[2]/div/div/div/fieldset/table/tbody/tr[5]/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//tr[5]/td[2]/fieldset/div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "1bc79128-62d6-43f9-8349-e27db62b3d87", + "comment": "", + "command": "click", + "target": "css=.btn-info", + "targets": [ + ["css=.btn-info", "css:finder"], + ["xpath=(//button[@type='button'])[5]", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/div/section/div[2]/div/div/button", "xpath:idRelative"], + ["xpath=//div[2]/div/div/button", "xpath:position"], + ["xpath=//button[contains(.,' Save')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "4f0b2e6d-cb4f-4c1b-ae76-7b5e6bb2502c", + "comment": "", + "command": "click", + "target": "id=metadata-nav-dropdown-toggle", + "targets": [ + ["id=metadata-nav-dropdown-toggle", "id"], + ["css=#metadata-nav-dropdown-toggle", "css:finder"], + ["xpath=//button[@id='metadata-nav-dropdown-toggle']", "xpath:attributes"], + ["xpath=//div[@id='metadata-nav-dropdown']/button", "xpath:idRelative"], + ["xpath=//div[2]/button", "xpath:position"], + ["xpath=//button[contains(.,'Add New')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "c1085b25-7f35-459e-9ff7-739159e425b3", + "comment": "", + "command": "click", + "target": "id=metadata-nav-dropdown-source", + "targets": [ + ["id=metadata-nav-dropdown-source", "id"], + ["linkText=Add a new metadata source", "linkText"], + ["css=#metadata-nav-dropdown-source", "css:finder"], + ["xpath=//a[contains(text(),'Add a new metadata source')]", "xpath:link"], + ["xpath=//a[@id='metadata-nav-dropdown-source']", "xpath:attributes"], + ["xpath=//div[@id='metadata-nav-dropdown']/div/a", "xpath:idRelative"], + ["xpath=//a[contains(@href, '/metadata/source/new')]", "xpath:href"], + ["xpath=//div[2]/div/a", "xpath:position"], + ["xpath=//a[contains(.,'Add a new metadata source')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "13dfe241-089e-4d46-a477-f90b0eefb77d", + "comment": "", + "command": "pause", + "target": "1000", + "targets": [], + "value": "" + }, { + "id": "4efe6339-8015-4dfb-896c-3613f6b7da60", + "comment": "", + "command": "waitForElementEditable", + "target": "id=root_serviceProviderName", + "targets": [], + "value": "30000" + }, { + "id": "6046353f-0e67-4de7-b4cd-7c4e86d6a7cf", + "comment": "", + "command": "type", + "target": "id=root_serviceProviderName", + "targets": [ + ["id=root_serviceProviderName", "id"], + ["css=#root_serviceProviderName", "css:finder"], + ["xpath=//input[@id='root_serviceProviderName']", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div[3]/div/div/form/div/div/div/div/div/div/div/div/input", "xpath:idRelative"], + ["xpath=//input", "xpath:position"] + ], + "value": "Test" + }, { + "id": "e6954887-26d0-4907-a05a-223e80e52100", + "comment": "", + "command": "type", + "target": "id=root_entityId", + "targets": [ + ["id=root_entityId", "id"], + ["css=#root_entityId", "css:finder"], + ["xpath=//input[@id='root_entityId']", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div[3]/div/div/form/div/div/div/div/div/div[2]/div/div/input", "xpath:idRelative"], + ["xpath=//div[2]/div/div/input", "xpath:position"] + ], + "value": "Test" + }, { + "id": "1f113531-653a-4c8d-b526-db39b4cd38d8", + "comment": "", + "command": "click", + "target": "css=.next", + "targets": [ + ["css=.next", "css:finder"], + ["xpath=(//button[@type='button'])[6]", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div/nav/ul/li[3]/button", "xpath:idRelative"], + ["xpath=//li[3]/button", "xpath:position"] + ], + "value": "" + }, { + "id": "a7932ded-137d-49fa-995a-6f4c8660ce7d", + "comment": "", + "command": "click", + "target": "css=.next", + "targets": [ + ["css=.next", "css:finder"], + ["xpath=(//button[@type='button'])[6]", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div/nav/ul/li[3]/button", "xpath:idRelative"], + ["xpath=//li[3]/button", "xpath:position"] + ], + "value": "" + }, { + "id": "9844cb75-96cb-45ec-af56-fbada6166651", + "comment": "", + "command": "click", + "target": "css=.next", + "targets": [ + ["css=.next", "css:finder"], + ["xpath=(//button[@type='button'])[6]", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div/nav/ul/li[3]/button", "xpath:idRelative"], + ["xpath=//li[3]/button", "xpath:position"] + ], + "value": "" + }, { + "id": "2d7ab9d2-d434-418d-bd8c-bf2732fc0686", + "comment": "", + "command": "click", + "target": "css=.next", + "targets": [ + ["css=.next", "css:finder"], + ["xpath=(//button[@type='button'])[6]", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div/nav/ul/li[3]/button", "xpath:idRelative"], + ["xpath=//li[3]/button", "xpath:position"] + ], + "value": "" + }, { + "id": "6d46d001-c986-4e7a-8578-54e8ace0011c", + "comment": "", + "command": "click", + "target": "css=.next", + "targets": [ + ["css=.next", "css:finder"], + ["xpath=(//button[@type='button'])[6]", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div/nav/ul/li[3]/button", "xpath:idRelative"], + ["xpath=//li[3]/button", "xpath:position"] + ], + "value": "" + }, { + "id": "18c7bec1-def4-444c-957c-d6356d206f85", + "comment": "", + "command": "click", + "target": "css=.next", + "targets": [ + ["css=.next", "css:finder"], + ["xpath=(//button[@type='button'])[6]", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div/nav/ul/li[3]/button", "xpath:idRelative"], + ["xpath=//li[3]/button", "xpath:position"] + ], + "value": "" + }, { + "id": "38549a11-2bbc-4c13-a2a5-4bbad1b5abf1", + "comment": "", + "command": "click", + "target": "css=.next", + "targets": [ + ["css=.next", "css:finder"], + ["xpath=(//button[@type='button'])[6]", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div/nav/ul/li[3]/button", "xpath:idRelative"], + ["xpath=//li[3]/button", "xpath:position"] + ], + "value": "" + }, { + "id": "117ff672-cb22-47a5-9738-b95985efa774", + "comment": "", + "command": "click", + "target": "css=.next", + "targets": [ + ["css=.next", "css:finder"], + ["xpath=(//button[@type='button'])[6]", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div/nav/ul/li[3]/button", "xpath:idRelative"], + ["xpath=//li[3]/button", "xpath:position"] + ], + "value": "" + }, { + "id": "c82be982-6551-4d50-af85-b9e87610e000", + "comment": "", + "command": "waitForElementVisible", + "target": "css=fieldset > ul > li > strong", + "targets": [], + "value": "Bundle - Test Bundle" + }, { + "id": "e3b80e89-4278-4e2e-9aa4-d2cc03e86932", + "comment": "", + "command": "assertText", + "target": "css=fieldset > ul > li > strong", + "targets": [ + ["css=strong", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div[2]/div/div/form/div/div/div/div/div[10]/div/div/fieldset/ul/li/strong", "xpath:idRelative"], + ["xpath=//strong", "xpath:position"], + ["xpath=//strong[contains(.,'Bundle - Test Bundle')]", "xpath:innerText"] + ], + "value": "Bundle - Test Bundle" + }, { + "id": "421fdaa5-e42b-4ba3-be22-c5697624ee34", + "comment": "", + "command": "click", + "target": "css=.fa-check:nth-child(2)", + "targets": [ + ["css=.fa-check:nth-child(2)", "css:finder"] + ], + "value": "" + }, { + "id": "6f00d279-5573-45e7-a618-35dde6433739", + "comment": "", + "command": "assertChecked", + "target": "css=#root_attributeRelease_2", + "targets": [ + ["css=tr:nth-child(3) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div[2]/div/div/form/div/div/div/div/div[10]/div/div/fieldset/table/tbody/tr[3]/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//tr[3]/td[2]/fieldset/div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "3e4be95e-8bac-4b0f-bc52-7f76ae9e2018", + "comment": "", + "command": "assertChecked", + "target": "css=#root_attributeRelease_3", + "targets": [ + ["css=tr:nth-child(4) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div[2]/div/div/form/div/div/div/div/div[10]/div/div/fieldset/table/tbody/tr[4]/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//tr[4]/td[2]/fieldset/div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "0515e864-1888-403c-a57d-497c778b02ef", + "comment": "", + "command": "assertChecked", + "target": "css=#root_attributeRelease_4", + "targets": [ + ["css=tr:nth-child(5) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div[2]/div/div/form/div/div/div/div/div[10]/div/div/fieldset/table/tbody/tr[5]/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//tr[5]/td[2]/fieldset/div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "27846b08-eadf-49aa-9dab-4d421c3bbb84", + "comment": "", + "command": "assertNotChecked", + "target": "css=#root_attributeRelease_0", + "targets": [ + ["css=tr:nth-child(1) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div[2]/div/div/form/div/div/div/div/div[10]/div/div/fieldset/table/tbody/tr/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//label", "xpath:position"] + ], + "value": "" + }, { + "id": "02cc0231-a293-4941-9a2a-56ad09989eda", + "comment": "", + "command": "assertNotChecked", + "target": "css=#root_attributeRelease_1", + "targets": [ + ["css=tr:nth-child(2) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div[2]/div/div/form/div/div/div/div/div[10]/div/div/fieldset/table/tbody/tr[2]/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//tr[2]/td[2]/fieldset/div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "9fcfc15f-7891-4f80-8a44-1dff0f5ec9a4", + "comment": "", + "command": "assertNotChecked", + "target": "css=#root_attributeRelease_5", + "targets": [ + ["css=tr:nth-child(6) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div[2]/div/div/form/div/div/div/div/div[10]/div/div/fieldset/table/tbody/tr[6]/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//tr[6]/td[2]/fieldset/div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "998081ad-f8d8-4060-bfc6-80e99cd40255", + "comment": "", + "command": "assertNotChecked", + "target": "css=#root_attributeRelease_6", + "targets": [ + ["css=tr:nth-child(7) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div[2]/div/div/form/div/div/div/div/div[10]/div/div/fieldset/table/tbody/tr[7]/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//tr[7]/td[2]/fieldset/div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "92558421-b381-43fa-baac-e21c6e7520fe", + "comment": "", + "command": "assertNotChecked", + "target": "css=#root_attributeRelease_7", + "targets": [ + ["css=tr:nth-child(8) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div[2]/div/div/form/div/div/div/div/div[10]/div/div/fieldset/table/tbody/tr[8]/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//tr[8]/td[2]/fieldset/div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "9b123534-035e-482e-9add-0db8161f6308", + "comment": "", + "command": "assertNotChecked", + "target": "css=#root_attributeRelease_8", + "targets": [ + ["css=tr:nth-child(9) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div[2]/div/div/form/div/div/div/div/div[10]/div/div/fieldset/table/tbody/tr[9]/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//tr[9]/td[2]/fieldset/div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "c0b25e56-c086-4a55-b0ed-b92c3f299bb2", + "comment": "", + "command": "assertNotChecked", + "target": "css=#root_attributeRelease_9", + "targets": [ + ["css=tr:nth-child(10) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div[2]/div/div/form/div/div/div/div/div[10]/div/div/fieldset/table/tbody/tr[10]/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//tr[10]/td[2]/fieldset/div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "d227964f-3876-4d60-a83b-0dc1b21727f4", + "comment": "", + "command": "assertNotChecked", + "target": "css=#root_attributeRelease_10", + "targets": [ + ["css=tr:nth-child(11) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div[2]/div/div/form/div/div/div/div/div[10]/div/div/fieldset/table/tbody/tr[11]/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//tr[11]/td[2]/fieldset/div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "dc8a895a-d685-4d56-b273-690141abc2c7", + "comment": "", + "command": "assertNotChecked", + "target": "css=#root_attributeRelease_11", + "targets": [ + ["css=tr:nth-child(12) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div[2]/div/div/form/div/div/div/div/div[10]/div/div/fieldset/table/tbody/tr[12]/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//tr[12]/td[2]/fieldset/div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "676f417c-a86f-461b-91f7-d5079e60dd65", + "comment": "", + "command": "click", + "target": "css=.label:nth-child(1)", + "targets": [ + ["css=.label:nth-child(1)", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div/nav/ul/li[3]/button/span", "xpath:idRelative"], + ["xpath=//li[3]/button/span", "xpath:position"], + ["xpath=//span[contains(.,'10. Finished!')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "65fa1a68-1f57-458a-8289-7cc50a8081ed", + "comment": "", + "command": "assertText", + "target": "css=.d-flex:nth-child(3) > .py-2 > span", + "targets": [ + ["css=.d-flex:nth-child(3) > .py-2 > span", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div[3]/div/section[9]/div/div[2]/div[2]/div[3]/div/span", "xpath:idRelative"], + ["xpath=//div[2]/div[3]/div/span", "xpath:position"], + ["xpath=//span[contains(.,'True')]", "xpath:innerText"] + ], + "value": "True" + }, { + "id": "bfc6ef5f-aaf7-4945-bbc1-d89e95b8d3ac", + "comment": "", + "command": "assertText", + "target": "css=.d-flex:nth-child(4) > .py-2 > span", + "targets": [ + ["css=.d-flex:nth-child(4) > .py-2 > span", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div[3]/div/section[9]/div/div[2]/div[2]/div[4]/div/span", "xpath:idRelative"], + ["xpath=//div[2]/div[4]/div/span", "xpath:position"] + ], + "value": "True" + }, { + "id": "5225f1db-7bdc-432e-a422-c6684b9e8416", + "comment": "", + "command": "assertText", + "target": "css=.d-flex:nth-child(5) > .py-2 > span", + "targets": [ + ["css=.d-flex:nth-child(5) > .py-2 > span", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div[3]/div/section[9]/div/div[2]/div[2]/div[5]/div/span", "xpath:idRelative"], + ["xpath=//div[2]/div[5]/div/span", "xpath:position"] + ], + "value": "True" + }, { + "id": "2a14e2d4-31f1-4ae8-b977-b6edd94de02c", + "comment": "", + "command": "click", + "target": "css=.direction:nth-child(2)", + "targets": [ + ["css=.direction:nth-child(2)", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div/nav/ul/li[3]/button/span[2]", "xpath:idRelative"], + ["xpath=//li[3]/button/span[2]", "xpath:position"] + ], + "value": "" + }, { + "id": "71ed9006-b0fe-4598-8f68-1548270dc686", + "comment": "", + "command": "click", + "target": "linkText=Test", + "targets": [ + ["linkText=Test", "linkText"], + ["css=.align-middle > a", "css:finder"], + ["xpath=//a[contains(text(),'Test')]", "xpath:link"], + ["xpath=//div[@id='root']/div/main/div/section/div/div[2]/div/div/div/table/tbody/tr/td/a", "xpath:idRelative"], + ["xpath=//a[contains(@href, '/metadata/source/a46bea29-0e2b-4aac-8f03-be7647c8c35c/configuration/options')]", "xpath:href"], + ["xpath=//td/a", "xpath:position"], + ["xpath=//a[contains(.,'Test')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "405fdd78-8a38-47d7-a123-97f6c3661ef3", + "comment": "", + "command": "waitForElementVisible", + "target": "css=.d-flex:nth-child(3) > .py-2 > span", + "targets": [], + "value": "30000" + }, { + "id": "24e0c8da-54fe-4755-964a-8ab93f1117ec", + "comment": "", + "command": "assertText", + "target": "css=.d-flex:nth-child(3) > .py-2 > span", + "targets": [ + ["css=.d-flex:nth-child(4) > .py-2 > span", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div/div/section[8]/div/div[2]/div[2]/div[4]/div/span", "xpath:idRelative"], + ["xpath=//div[2]/div[4]/div/span", "xpath:position"], + ["xpath=//span[contains(.,'True')]", "xpath:innerText"] + ], + "value": "True" + }, { + "id": "09fa0157-7e1a-4886-969e-fe9519974923", + "comment": "", + "command": "assertText", + "target": "css=.d-flex:nth-child(4) > .py-2 > span", + "targets": [ + ["css=.d-flex:nth-child(4) > .py-2 > span", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div/div/section[8]/div/div[2]/div[2]/div[4]/div/span", "xpath:idRelative"], + ["xpath=//div[2]/div[4]/div/span", "xpath:position"], + ["xpath=//span[contains(.,'True')]", "xpath:innerText"] + ], + "value": "True" + }, { + "id": "95dd6769-d8b6-4c1e-a799-fb4c083a1b43", + "comment": "", + "command": "assertText", + "target": "css=.d-flex:nth-child(5) > .py-2 > span", + "targets": [ + ["css=.d-flex:nth-child(4) > .py-2 > span", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div/div/section[8]/div/div[2]/div[2]/div[4]/div/span", "xpath:idRelative"], + ["xpath=//div[2]/div[4]/div/span", "xpath:position"], + ["xpath=//span[contains(.,'True')]", "xpath:innerText"] + ], + "value": "True" + }] + }], + "suites": [{ + "id": "56040c8b-b45c-454e-b2ba-2a06056b397f", + "name": "Default Suite", + "persistSession": false, + "parallel": false, + "timeout": 300, + "tests": ["d785839e-2982-4464-85ed-d529b3c0657a"] + }], + "urls": ["http://localhost:10101/"], + "plugins": [] +} \ No newline at end of file diff --git a/backend/src/integration/resources/SHIBUI-1744-3.side b/backend/src/integration/resources/SHIBUI-1744-3.side new file mode 100644 index 000000000..1ecfdfff5 --- /dev/null +++ b/backend/src/integration/resources/SHIBUI-1744-3.side @@ -0,0 +1,678 @@ +{ + "id": "3616248b-1c79-48db-8d12-c8fac193e50c", + "version": "2.0", + "name": "SHIBUI-1744-3", + "url": "http://localhost:10101", + "tests": [{ + "id": "d785839e-2982-4464-85ed-d529b3c0657a", + "name": "SHIBUI-1744-3", + "commands": [{ + "id": "bcf63821-1c37-41da-a412-70b3d3f6d7c3", + "comment": "", + "command": "open", + "target": "/login", + "targets": [], + "value": "" + }, { + "id": "1ab6b03b-557c-4f24-bd85-b73eb9c8b799", + "comment": "", + "command": "type", + "target": "id=username", + "targets": [ + ["id=username", "id"], + ["name=username", "name"], + ["css=#username", "css:finder"], + ["xpath=//input[@id='username']", "xpath:attributes"], + ["xpath=//input", "xpath:position"] + ], + "value": "admin" + }, { + "id": "284cb3be-f30b-4910-b9cd-37f32bec16b2", + "comment": "", + "command": "type", + "target": "id=password", + "targets": [ + ["id=password", "id"], + ["name=password", "name"], + ["css=#password", "css:finder"], + ["xpath=//input[@id='password']", "xpath:attributes"], + ["xpath=//p[2]/input", "xpath:position"] + ], + "value": "adminpass" + }, { + "id": "d0ec187e-aa72-43d5-bb44-bbdb41337128", + "comment": "", + "command": "click", + "target": "css=.btn", + "targets": [ + ["css=.btn", "css:finder"], + ["xpath=//button[@type='submit']", "xpath:attributes"], + ["xpath=//button", "xpath:position"], + ["xpath=//button[contains(.,'Sign in')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "8096864b-f997-4d71-a579-d5170f27fdea", + "comment": "", + "command": "open", + "target": "/api/heheheheheheheWipeout", + "targets": [], + "value": "" + }, { + "id": "6033215d-28e8-4ce1-9558-8e42cef9b345", + "comment": "", + "command": "assertText", + "target": "css=body", + "targets": [], + "value": "yes, you did it" + }, { + "id": "3429ed77-d2d9-4d10-af98-36f875be06ed", + "comment": "", + "command": "open", + "target": "/", + "targets": [], + "value": "" + }, { + "id": "29540d39-cf80-4397-8db9-5405a543106e", + "comment": "", + "command": "click", + "target": "id=advanced-nav-dropdown-toggle", + "targets": [ + ["id=advanced-nav-dropdown-toggle", "id"], + ["css=#advanced-nav-dropdown-toggle", "css:finder"], + ["xpath=//button[@id='advanced-nav-dropdown-toggle']", "xpath:attributes"], + ["xpath=//div[@id='advanced-nav-dropdown']/button", "xpath:idRelative"], + ["xpath=//div[3]/button", "xpath:position"], + ["xpath=//button[contains(.,'Advanced')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "0a1d91f2-2265-4854-8bc9-329c6a65c0df", + "comment": "", + "command": "click", + "target": "id=advanced-nav-dropdown-bundles", + "targets": [ + ["id=advanced-nav-dropdown-bundles", "id"], + ["linkText=Attribute bundles", "linkText"], + ["css=#advanced-nav-dropdown-bundles", "css:finder"], + ["xpath=//a[contains(text(),'Attribute bundles')]", "xpath:link"], + ["xpath=//a[@id='advanced-nav-dropdown-bundles']", "xpath:attributes"], + ["xpath=//div[@id='advanced-nav-dropdown']/div/a[2]", "xpath:idRelative"], + ["xpath=//a[contains(@href, '/metadata/attributes/bundles')]", "xpath:href"], + ["xpath=//a[2]", "xpath:position"], + ["xpath=//a[contains(.,'Attribute bundles')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "1e764021-9ccf-46aa-b472-4ea81f22a68e", + "comment": "", + "command": "click", + "target": "linkText=Add bundle", + "targets": [ + ["linkText=Add bundle", "linkText"], + ["css=.btn-success", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/div/section/div/div[2]/div/a", "xpath:idRelative"], + ["xpath=//a[contains(@href, '/metadata/attributes/bundles/new')]", "xpath:href"], + ["xpath=//div[2]/div/a", "xpath:position"], + ["xpath=//a[contains(.,'  Add bundle')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "65bd6d70-1232-497b-83c4-960910e8966f", + "comment": "", + "command": "click", + "target": "id=root_name", + "targets": [ + ["id=root_name", "id"], + ["css=#root_name", "css:finder"], + ["xpath=//input[@id='root_name']", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/div/section/div[2]/div/div[2]/div/form/div/div/div/div/div/div/div/div/input", "xpath:idRelative"], + ["xpath=//input", "xpath:position"] + ], + "value": "" + }, { + "id": "1c563723-ad9a-4cd5-a4fa-7d291ed9edae", + "comment": "", + "command": "type", + "target": "id=root_name", + "targets": [ + ["id=root_name", "id"], + ["css=#root_name", "css:finder"], + ["xpath=//input[@id='root_name']", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/div/section/div[2]/div/div[2]/div/form/div/div/div/div/div/div/div/div/input", "xpath:idRelative"], + ["xpath=//input", "xpath:position"] + ], + "value": "Test Bundle" + }, { + "id": "f72c10ce-2902-4dee-bb30-80f9f47ea44c", + "comment": "", + "command": "click", + "target": "css=#root_attributes_2", + "targets": [ + ["css=tr:nth-child(3) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/div/section/div[2]/div/div[2]/div/form/div/div/div/div[2]/div/div/div/fieldset/table/tbody/tr[3]/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//tr[3]/td[2]/fieldset/div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "35263126-51a0-4d7e-80a4-b820da2936d7", + "comment": "", + "command": "click", + "target": "css=#root_attributes_3", + "targets": [ + ["css=tr:nth-child(4) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/div/section/div[2]/div/div[2]/div/form/div/div/div/div[2]/div/div/div/fieldset/table/tbody/tr[4]/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//tr[4]/td[2]/fieldset/div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "e0349ad1-44e0-4674-ad46-5d41e0518314", + "comment": "", + "command": "click", + "target": "css=#root_attributes_4", + "targets": [ + ["css=tr:nth-child(5) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/div/section/div[2]/div/div[2]/div/form/div/div/div/div[2]/div/div/div/fieldset/table/tbody/tr[5]/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//tr[5]/td[2]/fieldset/div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "1bc79128-62d6-43f9-8349-e27db62b3d87", + "comment": "", + "command": "click", + "target": "css=.btn-info", + "targets": [ + ["css=.btn-info", "css:finder"], + ["xpath=(//button[@type='button'])[5]", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/div/section/div[2]/div/div/button", "xpath:idRelative"], + ["xpath=//div[2]/div/div/button", "xpath:position"], + ["xpath=//button[contains(.,' Save')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "4f0b2e6d-cb4f-4c1b-ae76-7b5e6bb2502c", + "comment": "", + "command": "click", + "target": "id=metadata-nav-dropdown-toggle", + "targets": [ + ["id=metadata-nav-dropdown-toggle", "id"], + ["css=#metadata-nav-dropdown-toggle", "css:finder"], + ["xpath=//button[@id='metadata-nav-dropdown-toggle']", "xpath:attributes"], + ["xpath=//div[@id='metadata-nav-dropdown']/button", "xpath:idRelative"], + ["xpath=//div[2]/button", "xpath:position"], + ["xpath=//button[contains(.,'Add New')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "ddb94e33-dc34-4bc4-928f-919de2a5eca2", + "comment": "", + "command": "click", + "target": "id=metadata-nav-dropdown-provider", + "targets": [ + ["id=metadata-nav-dropdown-provider", "id"], + ["linkText=Add a new metadata provider", "linkText"], + ["css=#metadata-nav-dropdown-provider", "css:finder"], + ["xpath=//a[contains(text(),'Add a new metadata provider')]", "xpath:link"], + ["xpath=//a[@id='metadata-nav-dropdown-provider']", "xpath:attributes"], + ["xpath=//div[@id='metadata-nav-dropdown']/div/a[2]", "xpath:idRelative"], + ["xpath=//a[contains(@href, '/metadata/provider/new')]", "xpath:href"], + ["xpath=//a[2]", "xpath:position"], + ["xpath=//a[contains(.,'Add a new metadata provider')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "2f9779e5-b611-4a59-859c-9a57772eacda", + "comment": "", + "command": "type", + "target": "name=name", + "targets": [ + ["name=name", "name"], + ["css=.form-control", "css:finder"], + ["xpath=//input[@name='name']", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div/div/form/div/input", "xpath:idRelative"], + ["xpath=//input", "xpath:position"] + ], + "value": "Test" + }, { + "id": "5d7d9568-b7cc-4cec-b1cc-8df961abd76c", + "comment": "", + "command": "select", + "target": "name=type", + "targets": [], + "value": "label=DynamicHttpMetadataResolver" + }, { + "id": "4a060cc6-b5c6-440d-9985-b25d92a8b3c6", + "comment": "", + "command": "click", + "target": "css=.next", + "targets": [ + ["css=.label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/nav/ul/li[2]/button/span", "xpath:idRelative"], + ["xpath=//li[2]/button/span", "xpath:position"], + ["xpath=//span[contains(.,'2. Common Attributes')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "7cfab6d3-3982-423f-a99c-488e1d41e40b", + "comment": "", + "command": "type", + "target": "id=root_xmlId", + "targets": [ + ["id=root_xmlId", "id"], + ["css=#root_xmlId", "css:finder"], + ["xpath=//input[@id='root_xmlId']", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div[2]/div/div/form/div/div/div/div/div[3]/div/div/div/input", "xpath:idRelative"], + ["xpath=//input", "xpath:position"] + ], + "value": "Test" + }, { + "id": "003b8bbb-597d-4c08-beb7-7bdc8d7a9470", + "comment": "", + "command": "select", + "target": "id=root_metadataRequestURLConstructionScheme_@type", + "targets": [], + "value": "label=MetadataQueryProtocol" + }, { + "id": "4b5c2806-b2ec-47ae-b3bc-86173faa6252", + "comment": "", + "command": "type", + "target": "id=root_metadataRequestURLConstructionScheme_content", + "targets": [ + ["id=root_metadataRequestURLConstructionScheme_content", "id"], + ["css=#root_metadataRequestURLConstructionScheme_content", "css:finder"], + ["xpath=//input[@id='root_metadataRequestURLConstructionScheme_content']", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div[2]/div/div/form/div/div/div/div/div[3]/div[2]/div/div/div[2]/div/div/div/div/input", "xpath:idRelative"], + ["xpath=//div[2]/div/div/div/div/input", "xpath:position"] + ], + "value": "foo" + }, { + "id": "b7de5d35-d08e-4ffa-9a4f-2df1a69c0c3a", + "comment": "", + "command": "click", + "target": "css=.next", + "targets": [ + ["css=.label:nth-child(1)", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div/nav/ul/li[3]/button/span", "xpath:idRelative"], + ["xpath=//li[3]/button/span", "xpath:position"], + ["xpath=//span[contains(.,'3. Dynamic Attributes')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "2d26ec0b-b770-4491-9e0d-ffeffb2e5a4e", + "comment": "", + "command": "click", + "target": "css=.next", + "targets": [ + ["css=.label:nth-child(1)", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div/nav/ul/li[3]/button/span", "xpath:idRelative"], + ["xpath=//li[3]/button/span", "xpath:position"], + ["xpath=//span[contains(.,'4. Metadata Filter Plugins')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "104cb22a-0bb1-4fb0-839a-a8773448911e", + "comment": "", + "command": "click", + "target": "css=.next", + "targets": [ + ["css=.label:nth-child(1)", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div/nav/ul/li[3]/button/span", "xpath:idRelative"], + ["xpath=//li[3]/button/span", "xpath:position"], + ["xpath=//span[contains(.,'5. Finished!')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "ebaf0dd5-13ca-4f71-b91e-b6f0d89b5634", + "comment": "", + "command": "click", + "target": "css=.save", + "targets": [ + ["css=.direction:nth-child(2)", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div/nav/ul/li[3]/button/span[2]", "xpath:idRelative"], + ["xpath=//li[3]/button/span[2]", "xpath:position"] + ], + "value": "" + }, { + "id": "6d4af931-1e69-4c7d-b68c-6de43f30d6f5", + "comment": "", + "command": "click", + "target": "linkText=Test", + "targets": [ + ["linkText=Test", "linkText"], + ["css=.align-middle > a", "css:finder"], + ["xpath=//a[contains(text(),'Test')]", "xpath:link"], + ["xpath=//div[@id='root']/div/main/div/section/div/div[2]/div/div/div/table/tbody/tr/td[2]/a", "xpath:idRelative"], + ["xpath=//a[contains(@href, '/metadata/provider/7d626ff5-8bca-49ce-b4e5-6445ac1037bd/configuration/options')]", "xpath:href"], + ["xpath=//td[2]/a", "xpath:position"], + ["xpath=//a[contains(.,'Test')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "2415b904-780e-4fc4-80dc-b27167d60daf", + "comment": "", + "command": "click", + "target": "linkText=Add Filter", + "targets": [ + ["linkText=Add Filter", "linkText"], + ["css=#filters .btn", "css:finder"], + ["xpath=//div[@id='filters']/div/div/a", "xpath:idRelative"], + ["xpath=//a[contains(@href, '/metadata/provider/7d626ff5-8bca-49ce-b4e5-6445ac1037bd/filter/new')]", "xpath:href"], + ["xpath=//div[3]/div/div/a", "xpath:position"], + ["xpath=//a[contains(.,' Add Filter')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "29c69cce-2560-45b6-aa03-1891d28b8b1f", + "comment": "", + "command": "select", + "target": "name=type", + "targets": [], + "value": "label=EntityAttributes" + }, { + "id": "208a221d-db9c-4fa7-8116-24b5f425fc11", + "comment": "", + "command": "type", + "target": "id=root_name", + "targets": [ + ["id=root_name", "id"], + ["css=#root_name", "css:finder"], + ["xpath=//input[@id='root_name']", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div[2]/div/form/div/div/div/div/div/div/div/div/input", "xpath:idRelative"], + ["xpath=//input", "xpath:position"] + ], + "value": "Test Filter" + }, { + "id": "147ba1a9-3655-4624-bbf7-0d68d6ff3870", + "comment": "", + "command": "click", + "target": "id=dropdown-label.filter-target-type", + "targets": [ + ["id=dropdown-label.filter-target-type", "id"], + ["css=#dropdown-label\\.filter-target-type", "css:finder"], + ["xpath=//button[@id='dropdown-label.filter-target-type']", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div[2]/div/form/div/div/div/div[6]/div/div/div/fieldset/div/div/div/div/button", "xpath:idRelative"], + ["xpath=//fieldset/div/div/div/div/button", "xpath:position"], + ["xpath=//button[contains(.,'Entity ID ')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "2041d3fd-442d-44b4-ac7a-aac12cc8f9c0", + "comment": "", + "command": "click", + "target": "css=.show > .dropdown-item:nth-child(3)", + "targets": [ + ["css=.show > .dropdown-item:nth-child(3)", "css:finder"], + ["xpath=(//button[@type='button'])[17]", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div[2]/div/form/div/div/div/div[6]/div/div/div/fieldset/div/div/div/div/div/button[3]", "xpath:idRelative"], + ["xpath=//div/button[3]", "xpath:position"], + ["xpath=//button[contains(.,'Script')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "189c2e41-87f3-49dd-b2e7-9e9fe69448e0", + "comment": "", + "command": "click", + "target": "css=.npm__react-simple-code-editor__textarea", + "targets": [ + ["css=.npm__react-simple-code-editor__textarea", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div[2]/div/form/div/div/div/div[6]/div/div/div/fieldset/div/div/div[2]/div/div/div/div/textarea", "xpath:idRelative"], + ["xpath=//textarea", "xpath:position"] + ], + "value": "" + }, { + "id": "58dc0492-0777-4d33-a9a2-3f132becd2d0", + "comment": "", + "command": "type", + "target": "css=.npm__react-simple-code-editor__textarea", + "targets": [ + ["css=.npm__react-simple-code-editor__textarea", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div[2]/div/form/div/div/div/div[6]/div/div/div/fieldset/div/div/div[2]/div/div/div/div/textarea", "xpath:idRelative"], + ["xpath=//textarea", "xpath:position"] + ], + "value": "true;" + }, { + "id": "9b993510-7e7e-40d6-b05c-38c274113e44", + "comment": "", + "command": "click", + "target": "css=.nav-link:nth-child(3)", + "targets": [ + ["css=.nav-link:nth-child(3)", "css:finder"], + ["xpath=(//button[@type='button'])[11]", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div/nav/button[3]", "xpath:idRelative"], + ["xpath=//button[3]", "xpath:position"], + ["xpath=//button[contains(.,'Attributes')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "e8a2f501-0efa-43a3-bbf2-b86e5ec8f6d1", + "comment": "", + "command": "waitForElementVisible", + "target": "css=fieldset > ul > li > strong", + "targets": [], + "value": "30000" + }, { + "id": "cc36c580-3d53-483a-a813-2a6c8fb95792", + "comment": "", + "command": "assertText", + "target": "css=fieldset > ul > li > strong", + "targets": [ + ["css=strong", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div[2]/div/form/div/div/div/div[8]/div/div/div/fieldset/ul/li/strong", "xpath:idRelative"], + ["xpath=//strong", "xpath:position"], + ["xpath=//strong[contains(.,'Bundle - Test Bundle')]", "xpath:innerText"] + ], + "value": "Bundle - Test Bundle" + }, { + "id": "caabc3c1-7ac7-4251-9885-fe2e3b7c4c10", + "comment": "", + "command": "click", + "target": "css=fieldset > ul > li > button", + "targets": [ + ["css=.fa-check:nth-child(2) > path", "css:finder"] + ], + "value": "" + }, { + "id": "5cd2df54-e975-4657-9d4b-390c87901f88", + "comment": "", + "command": "assertChecked", + "target": "css=#root_attributeRelease_2", + "targets": [ + ["css=tr:nth-child(3) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div[2]/div/form/div/div/div/div[8]/div/div/div/fieldset/table/tbody/tr[3]/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//tr[3]/td[2]/fieldset/div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "c3e555b8-56f6-4f1c-a6ef-0df32ae8cdcb", + "comment": "", + "command": "assertChecked", + "target": "css=#root_attributeRelease_3", + "targets": [ + ["css=tr:nth-child(4) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div[2]/div/form/div/div/div/div[8]/div/div/div/fieldset/table/tbody/tr[4]/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//tr[4]/td[2]/fieldset/div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "b5a8936b-61e6-4ff5-8487-1003968c56d5", + "comment": "", + "command": "assertChecked", + "target": "css=#root_attributeRelease_4", + "targets": [ + ["css=tr:nth-child(5) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div[2]/div/form/div/div/div/div[8]/div/div/div/fieldset/table/tbody/tr[5]/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//tr[5]/td[2]/fieldset/div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "0aa952c1-249e-4a34-91fb-786dd3328d73", + "comment": "", + "command": "assertNotChecked", + "target": "css=#root_attributeRelease_0", + "targets": [ + ["css=tr:nth-child(1) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div[2]/div/form/div/div/div/div[8]/div/div/div/fieldset/table/tbody/tr/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "0bee0fbb-3f64-4c62-a033-d3dfeaee0fb9", + "comment": "", + "command": "assertNotChecked", + "target": "css=#root_attributeRelease_1", + "targets": [ + ["css=tr:nth-child(1) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div[2]/div/form/div/div/div/div[8]/div/div/div/fieldset/table/tbody/tr/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "755f8379-7abf-4a5a-b73a-44850fab0434", + "comment": "", + "command": "assertNotChecked", + "target": "css=#root_attributeRelease_5", + "targets": [ + ["css=tr:nth-child(1) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div[2]/div/form/div/div/div/div[8]/div/div/div/fieldset/table/tbody/tr/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "5a0ddf98-cafc-447f-afd6-b34d74bf5b8c", + "comment": "", + "command": "assertNotChecked", + "target": "css=#root_attributeRelease_6", + "targets": [ + ["css=tr:nth-child(1) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div[2]/div/form/div/div/div/div[8]/div/div/div/fieldset/table/tbody/tr/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "30838479-b577-47fa-ba03-a5e200910c31", + "comment": "", + "command": "assertNotChecked", + "target": "css=#root_attributeRelease_7", + "targets": [ + ["css=tr:nth-child(1) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div[2]/div/form/div/div/div/div[8]/div/div/div/fieldset/table/tbody/tr/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "55593a0b-476b-4581-b98a-e5f971995867", + "comment": "", + "command": "assertNotChecked", + "target": "css=#root_attributeRelease_8", + "targets": [ + ["css=tr:nth-child(1) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div[2]/div/form/div/div/div/div[8]/div/div/div/fieldset/table/tbody/tr/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "09c045f6-c682-4c9e-b56a-2cd34387a1fc", + "comment": "", + "command": "assertNotChecked", + "target": "css=#root_attributeRelease_9", + "targets": [ + ["css=tr:nth-child(1) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div[2]/div/form/div/div/div/div[8]/div/div/div/fieldset/table/tbody/tr/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "84183a45-a032-4da5-a441-9992b84f30cf", + "comment": "", + "command": "assertNotChecked", + "target": "css=#root_attributeRelease_10", + "targets": [ + ["css=tr:nth-child(1) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div[2]/div/form/div/div/div/div[8]/div/div/div/fieldset/table/tbody/tr/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "a23efede-f479-4a1c-b17d-82aef5ef1c6f", + "comment": "", + "command": "assertNotChecked", + "target": "css=#root_attributeRelease_11", + "targets": [ + ["css=tr:nth-child(12) .custom-control-label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div[2]/div/form/div/div/div/div[8]/div/div/div/fieldset/table/tbody/tr[12]/td[2]/fieldset/div/div/label", "xpath:idRelative"], + ["xpath=//tr[12]/td[2]/fieldset/div/div/label", "xpath:position"] + ], + "value": "" + }, { + "id": "d07498a3-8ac8-49dd-8034-258f4f1ec2fd", + "comment": "", + "command": "click", + "target": "css=.btn-info", + "targets": [ + ["css=.btn-info", "css:finder"], + ["xpath=(//button[@type='button'])[7]", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div/div[2]/div/button", "xpath:idRelative"], + ["xpath=//div[2]/div/button", "xpath:position"], + ["xpath=//button[contains(.,' Save')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "d6a2d477-4b89-4cf5-a4a8-0f35afcdd5f8", + "comment": "", + "command": "click", + "target": "css=.mx-4", + "targets": [ + ["css=.mx-4", "css:finder"], + ["xpath=(//button[@type='button'])[13]", "xpath:attributes"], + ["xpath=//div[@id='filters']/ul/li/div/button", "xpath:idRelative"], + ["xpath=//li/div/button", "xpath:position"], + ["xpath=//button[contains(.,'Test Filter')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "75411faa-5eac-4848-beb1-74dae71fbc7f", + "comment": "", + "command": "assertText", + "target": "css=.d-flex:nth-child(3) > .py-2 > span", + "targets": [ + ["css=.d-flex:nth-child(3) > .py-2 > span", "css:finder"], + ["xpath=//div[@id='filters']/ul/li/div[2]/section[3]/div/div[2]/div[2]/div[3]/div/span", "xpath:idRelative"], + ["xpath=//section[3]/div/div[2]/div[2]/div[3]/div/span", "xpath:position"], + ["xpath=//span[contains(.,'True')]", "xpath:innerText"] + ], + "value": "True" + }, { + "id": "64723648-aef5-4c50-8605-74c5992ac628", + "comment": "", + "command": "assertText", + "target": "css=.d-flex:nth-child(4) > .py-2 > span", + "targets": [ + ["css=.d-flex:nth-child(4) > .py-2 > span", "css:finder"], + ["xpath=//div[@id='filters']/ul/li/div[2]/section[3]/div/div[2]/div[2]/div[4]/div/span", "xpath:idRelative"], + ["xpath=//section[3]/div/div[2]/div[2]/div[4]/div/span", "xpath:position"] + ], + "value": "True" + }, { + "id": "509ee76e-7d39-453e-a5cc-cf7b3975b476", + "comment": "", + "command": "assertText", + "target": "css=.d-flex:nth-child(5) > .py-2 > span", + "targets": [ + ["css=.d-flex:nth-child(5) > .py-2 > span", "css:finder"], + ["xpath=//div[@id='filters']/ul/li/div[2]/section[3]/div/div[2]/div[2]/div[5]/div/span", "xpath:idRelative"], + ["xpath=//section[3]/div/div[2]/div[2]/div[5]/div/span", "xpath:position"] + ], + "value": "True" + }] + }], + "suites": [{ + "id": "56040c8b-b45c-454e-b2ba-2a06056b397f", + "name": "Default Suite", + "persistSession": false, + "parallel": false, + "timeout": 300, + "tests": ["d785839e-2982-4464-85ed-d529b3c0657a"] + }], + "urls": ["http://localhost:10101/"], + "plugins": [] +} \ No newline at end of file diff --git a/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/service/JsonSchemaBuilderService.groovy b/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/service/JsonSchemaBuilderService.groovy index 6ebdcf7be..a45448016 100644 --- a/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/service/JsonSchemaBuilderService.groovy +++ b/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/service/JsonSchemaBuilderService.groovy @@ -1,29 +1,41 @@ package edu.internet2.tier.shibboleth.admin.ui.service import edu.internet2.tier.shibboleth.admin.ui.configuration.CustomPropertiesConfiguration +import edu.internet2.tier.shibboleth.admin.ui.domain.AttributeBundle import edu.internet2.tier.shibboleth.admin.ui.domain.IRelyingPartyOverrideProperty import edu.internet2.tier.shibboleth.admin.ui.security.model.User import edu.internet2.tier.shibboleth.admin.ui.security.service.UserService +import lombok.NoArgsConstructor import org.springframework.beans.factory.annotation.Autowired /** * @author Bill Smith (wsmith@unicon.net) */ +@NoArgsConstructor class JsonSchemaBuilderService { + @Autowired + AttributeBundleService attributeBundleService @Autowired CustomPropertiesConfiguration customPropertiesConfiguration + @Autowired UserService userService - JsonSchemaBuilderService(UserService userService) { - this.userService = userService - } - void addReleaseAttributesToJson(Object json) { - json['enum'] = customPropertiesConfiguration.getAttributes().collect { + List result = new ArrayList<>() + List resultNames = new ArrayList<>() + attributeBundleService.findAll().forEach({ bundle -> + result.add(bundle.getAttributes()) + resultNames.add(bundle.getName()) + }) + + result.addAll(customPropertiesConfiguration.getAttributes().collect { it['name'] - } + }) + + json['enum'] = result + json['enumNames'] = resultNames } void addRelyingPartyOverridesToJson(Object json) { @@ -79,4 +91,4 @@ class JsonSchemaBuilderService { serviceEnabled.remove('description') } } -} +} \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/JsonSchemaComponentsConfiguration.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/JsonSchemaComponentsConfiguration.java index 97d88f5a7..d483319f3 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/JsonSchemaComponentsConfiguration.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/JsonSchemaComponentsConfiguration.java @@ -100,6 +100,6 @@ public JsonSchemaResourceLocationRegistry jsonSchemaResourceLocationRegistry(Res @Bean public JsonSchemaBuilderService jsonSchemaBuilderService(UserService userService) { - return new JsonSchemaBuilderService(userService); + return new JsonSchemaBuilderService(); } -} +} \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/AttributeBundleController.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/AttributeBundleController.java new file mode 100644 index 000000000..1dbe5e026 --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/AttributeBundleController.java @@ -0,0 +1,66 @@ +package edu.internet2.tier.shibboleth.admin.ui.controller; + +import edu.internet2.tier.shibboleth.admin.ui.domain.AttributeBundle; +import edu.internet2.tier.shibboleth.admin.ui.exception.EntityNotFoundException; +import edu.internet2.tier.shibboleth.admin.ui.exception.ObjectIdExistsException; +import edu.internet2.tier.shibboleth.admin.ui.security.exception.GroupDeleteException; +import edu.internet2.tier.shibboleth.admin.ui.security.exception.GroupExistsConflictException; +import edu.internet2.tier.shibboleth.admin.ui.security.model.Group; +import edu.internet2.tier.shibboleth.admin.ui.service.AttributeBundleService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.annotation.Secured; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/api/custom/entity/bundles") +@Slf4j +public class AttributeBundleController { + @Autowired AttributeBundleService attributeBundleService; + + @Secured("ROLE_ADMIN") + @PostMapping + @Transactional + public ResponseEntity create(@RequestBody AttributeBundle bundle) throws ObjectIdExistsException { + AttributeBundle result = attributeBundleService.create(bundle); + return ResponseEntity.status(HttpStatus.CREATED).body(result); + } + + @Secured("ROLE_ADMIN") + @DeleteMapping("/{resourceId}") + @Transactional + public ResponseEntity delete(@PathVariable String resourceId) throws EntityNotFoundException { + attributeBundleService.deleteDefinition(resourceId); + return ResponseEntity.noContent().build(); + } + + @GetMapping + @Transactional(readOnly = true) + public ResponseEntity getAll() { + return ResponseEntity.ok(attributeBundleService.findAll()); + } + + @GetMapping("/{resourceId}") + @Transactional(readOnly = true) + public ResponseEntity getOne(@PathVariable String resourceId) throws EntityNotFoundException { + return ResponseEntity.ok(attributeBundleService.findByResourceId(resourceId)); + } + + @Secured("ROLE_ADMIN") + @PutMapping + @Transactional + public ResponseEntity update(@RequestBody AttributeBundle bundle) throws EntityNotFoundException { + AttributeBundle result = attributeBundleService.updateBundle(bundle); + return ResponseEntity.ok(result); + } +} \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/AttributeBundleExceptionHandler.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/AttributeBundleExceptionHandler.java new file mode 100644 index 000000000..9f5266c3c --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/AttributeBundleExceptionHandler.java @@ -0,0 +1,29 @@ +package edu.internet2.tier.shibboleth.admin.ui.controller; + +import edu.internet2.tier.shibboleth.admin.ui.exception.EntityNotFoundException; +import edu.internet2.tier.shibboleth.admin.ui.exception.ObjectIdExistsException; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.context.request.WebRequest; +import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; + +@ControllerAdvice(assignableTypes = {AttributeBundleController.class}) +public class AttributeBundleExceptionHandler extends ResponseEntityExceptionHandler { + @ExceptionHandler({ EntityNotFoundException.class }) + public ResponseEntity handleEntityNotFoundException(EntityNotFoundException e, WebRequest request) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ErrorResponse(HttpStatus.NOT_FOUND, e.getMessage())); + } + + @ExceptionHandler({ ObjectIdExistsException.class }) + public ResponseEntity handleObjectIdExistsException(ObjectIdExistsException e, WebRequest request) { + HttpHeaders headers = new HttpHeaders(); + headers.setLocation(EntityDescriptorController.getResourceUriFor(e.getMessage())); + return ResponseEntity.status(HttpStatus.CONFLICT).headers(headers).body(new ErrorResponse( + String.valueOf(HttpStatus.CONFLICT.value()), + String.format("The attribute bundle with resource id [%s] already exists.", e.getMessage()))); + + } +} \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/DangerController.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/DangerController.java index fd6d17c51..5500bd549 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/DangerController.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/DangerController.java @@ -1,6 +1,7 @@ package edu.internet2.tier.shibboleth.admin.ui.controller; import edu.internet2.tier.shibboleth.admin.ui.configuration.DevConfig; +import edu.internet2.tier.shibboleth.admin.ui.repository.AttributeBundleRepository; import edu.internet2.tier.shibboleth.admin.ui.repository.EntityDescriptorRepository; import edu.internet2.tier.shibboleth.admin.ui.repository.FilterRepository; import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository; @@ -25,7 +26,10 @@ @Slf4j public class DangerController { @Autowired - DevConfig devConfig; + private AttributeBundleRepository attributeBundleRepository; + + @Autowired + private DevConfig devConfig; @Autowired private EntityDescriptorService entityDescriptorService; @@ -41,7 +45,7 @@ public class DangerController { @Autowired private GroupsRepository groupRepository; - + @Autowired private MetadataResolverRepository metadataResolverRepository; @@ -53,7 +57,7 @@ public class DangerController { @Autowired UserRepository userRepository; - + @Transactional @GetMapping public ResponseEntity wipeOut() { @@ -71,6 +75,7 @@ public ResponseEntity wipeOut() { this.metadataResolverRepository.deleteAll(); this.filterRepository.deleteAll(); this.metadataResolversPositionOrderContainerRepository.deleteAll(); + this.attributeBundleRepository.deleteAll(); clearUsersAndGroups(); diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorController.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorController.java index be0d39c05..3122eb90e 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorController.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorController.java @@ -2,15 +2,14 @@ import edu.internet2.tier.shibboleth.admin.ui.domain.EntityDescriptor; import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.EntityDescriptorRepresentation; -import edu.internet2.tier.shibboleth.admin.ui.exception.EntityIdExistsException; import edu.internet2.tier.shibboleth.admin.ui.exception.EntityNotFoundException; import edu.internet2.tier.shibboleth.admin.ui.exception.ForbiddenException; import edu.internet2.tier.shibboleth.admin.ui.exception.InvalidPatternMatchException; +import edu.internet2.tier.shibboleth.admin.ui.exception.ObjectIdExistsException; import edu.internet2.tier.shibboleth.admin.ui.opensaml.OpenSamlObjects; import edu.internet2.tier.shibboleth.admin.ui.service.EntityDescriptorService; import edu.internet2.tier.shibboleth.admin.ui.service.EntityDescriptorVersionService; import lombok.extern.slf4j.Slf4j; - import org.opensaml.core.xml.io.MarshallingException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.web.client.RestTemplateBuilder; @@ -30,7 +29,6 @@ import org.springframework.web.servlet.support.ServletUriComponentsBuilder; import javax.annotation.PostConstruct; - import java.net.URI; import java.util.ConcurrentModificationException; @@ -66,7 +64,7 @@ public EntityDescriptorController(EntityDescriptorVersionService versionService) @PostMapping("/EntityDescriptor") @Transactional public ResponseEntity create(@RequestBody EntityDescriptorRepresentation edRepresentation) - throws ForbiddenException, EntityIdExistsException, InvalidPatternMatchException { + throws ForbiddenException, ObjectIdExistsException, InvalidPatternMatchException { EntityDescriptorRepresentation persistedEd = entityDescriptorService.createNew(edRepresentation); return ResponseEntity.created(getResourceUriFor(persistedEd.getId())).body(persistedEd); } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorControllerExceptionHandler.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorControllerExceptionHandler.java index 6ec47a82a..32d3cd4be 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorControllerExceptionHandler.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorControllerExceptionHandler.java @@ -1,9 +1,9 @@ package edu.internet2.tier.shibboleth.admin.ui.controller; -import edu.internet2.tier.shibboleth.admin.ui.exception.EntityIdExistsException; import edu.internet2.tier.shibboleth.admin.ui.exception.EntityNotFoundException; import edu.internet2.tier.shibboleth.admin.ui.exception.ForbiddenException; import edu.internet2.tier.shibboleth.admin.ui.exception.InvalidPatternMatchException; +import edu.internet2.tier.shibboleth.admin.ui.exception.ObjectIdExistsException; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -22,22 +22,11 @@ public ResponseEntity handleConcurrentModificationException(ConcurrentModific return ResponseEntity.status(HttpStatus.CONFLICT).body(new ErrorResponse(HttpStatus.CONFLICT, e.getMessage())); } - @ExceptionHandler({ EntityIdExistsException.class }) - public ResponseEntity handleEntityExistsException(EntityIdExistsException e, WebRequest request) { - HttpHeaders headers = new HttpHeaders(); - headers.setLocation(EntityDescriptorController.getResourceUriFor(e.getMessage())); - return ResponseEntity.status(HttpStatus.CONFLICT).headers(headers) - .body(new ErrorResponse(String.valueOf(HttpStatus.CONFLICT.value()), - String.format("The entity descriptor with entity id [%s] already exists.", - e.getMessage()))); - - } - @ExceptionHandler({ EntityNotFoundException.class }) public ResponseEntity handleEntityNotFoundException(EntityNotFoundException e, WebRequest request) { return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ErrorResponse(HttpStatus.NOT_FOUND, e.getMessage())); } - + @ExceptionHandler({ ForbiddenException.class }) public ResponseEntity handleForbiddenAccess(ForbiddenException e, WebRequest request) { return ResponseEntity.status(HttpStatus.FORBIDDEN).body(new ErrorResponse(HttpStatus.FORBIDDEN, e.getMessage())); @@ -47,4 +36,14 @@ public ResponseEntity handleForbiddenAccess(ForbiddenException e, WebRequest public ResponseEntity handleInvalidUrlMatchException(InvalidPatternMatchException e, WebRequest request) { return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ErrorResponse(HttpStatus.BAD_REQUEST, e.getMessage())); } + + @ExceptionHandler({ ObjectIdExistsException.class }) + public ResponseEntity handleObjectIdExistsException(ObjectIdExistsException e, WebRequest request) { + HttpHeaders headers = new HttpHeaders(); + headers.setLocation(EntityDescriptorController.getResourceUriFor(e.getMessage())); + return ResponseEntity.status(HttpStatus.CONFLICT).headers(headers).body(new ErrorResponse( + String.valueOf(HttpStatus.CONFLICT.value()), + String.format("The entity descriptor with entity id [%s] already exists.", e.getMessage()))); + + } } \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/AttributeBundle.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/AttributeBundle.java new file mode 100644 index 000000000..2df1132ac --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/AttributeBundle.java @@ -0,0 +1,31 @@ +package edu.internet2.tier.shibboleth.admin.ui.domain; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; +import lombok.Data; + +import javax.persistence.Column; +import javax.persistence.ElementCollection; +import javax.persistence.Entity; +import javax.persistence.Id; +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +@Entity(name = "attribute_bundle_definition") +@Data +public class AttributeBundle { + @Column(nullable = false) + @ElementCollection + Set attributes = new HashSet<>(); + + @Column(name = "name", nullable = true) + String name; + + @Id + @Column(name = "resource_id", nullable = false) + String resourceId = UUID.randomUUID().toString(); +} \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/BundleableAttributeType.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/BundleableAttributeType.java new file mode 100644 index 000000000..84a80fce4 --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/BundleableAttributeType.java @@ -0,0 +1,40 @@ +package edu.internet2.tier.shibboleth.admin.ui.domain; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import edu.internet2.tier.shibboleth.admin.util.BundleableAttributeTypeValueSerializer; + +@JsonSerialize(using = BundleableAttributeTypeValueSerializer.class) +public enum BundleableAttributeType { + EDUPERSONPRINCIPALNAME("eduPersonPrincipalName"), + UID("uid"), + MAIL("mail"), + SURNAME("surname"), + GIVENNAME("givenName"), + EDUPERSONAFFILIATE("eduPersonAffiliation"), + EDUPERSONSCOPEDAFFILIATION("eduPersonScopedAffiliation"), + EDUPERSONPRIMARYAFFILIATION("eduPersonPrimaryAffiliation"), + EDUPERSONENTITLEMENT("eduPersonEntitlement"), + EDUPERSONASSURANCE("eduPersonAssurance"), + EDUPERSONUNIQUEID("eduPersonUniqueId"), + EMPLOYEENUMBER("employeeNumber"); + + String label; + + BundleableAttributeType(String val) { + label = val; + } + + public String label() {return label;} + + @JsonCreator + public static BundleableAttributeType valueOfLabel(String label) { + for (BundleableAttributeType e : values()) { + if (e.label.equals(label)) { + return e; + } + } + return null; + } + +} \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/exception/EntityIdExistsException.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/exception/EntityIdExistsException.java deleted file mode 100644 index 990eab2c3..000000000 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/exception/EntityIdExistsException.java +++ /dev/null @@ -1,8 +0,0 @@ -package edu.internet2.tier.shibboleth.admin.ui.exception; - -public class EntityIdExistsException extends Exception { - public EntityIdExistsException(String entityId) { - super(entityId); - } - -} diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/exception/ObjectIdExistsException.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/exception/ObjectIdExistsException.java new file mode 100644 index 000000000..f2604acfe --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/exception/ObjectIdExistsException.java @@ -0,0 +1,8 @@ +package edu.internet2.tier.shibboleth.admin.ui.exception; + +public class ObjectIdExistsException extends Exception { + public ObjectIdExistsException(String entityId) { + super(entityId); + } + +} \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/repository/AttributeBundleRepository.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/repository/AttributeBundleRepository.java new file mode 100644 index 000000000..0c9bc2aed --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/repository/AttributeBundleRepository.java @@ -0,0 +1,18 @@ +package edu.internet2.tier.shibboleth.admin.ui.repository; + +import edu.internet2.tier.shibboleth.admin.ui.domain.AttributeBundle; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; +import java.util.Optional; + +/** + * Repository to manage {@link edu.internet2.tier.shibboleth.admin.ui.domain.AttributeBundle} instances. + */ +public interface AttributeBundleRepository extends JpaRepository { + List findAll(); + + Optional findByResourceId(String resourceId); + + AttributeBundle save(AttributeBundle target); +} \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/AttributeBundleService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/AttributeBundleService.java new file mode 100644 index 000000000..916ea99b2 --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/AttributeBundleService.java @@ -0,0 +1,54 @@ +package edu.internet2.tier.shibboleth.admin.ui.service; + +import edu.internet2.tier.shibboleth.admin.ui.domain.AttributeBundle; +import edu.internet2.tier.shibboleth.admin.ui.exception.EntityNotFoundException; +import edu.internet2.tier.shibboleth.admin.ui.exception.ObjectIdExistsException; +import edu.internet2.tier.shibboleth.admin.ui.repository.AttributeBundleRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Optional; + +@Service +public class AttributeBundleService { + @Autowired + AttributeBundleRepository attributeBundleRepository; + + public AttributeBundle create(AttributeBundle bundle) throws ObjectIdExistsException { + if (attributeBundleRepository.findByResourceId(bundle.getResourceId()).isPresent()) { + throw new ObjectIdExistsException(bundle.getResourceId()); + } + return attributeBundleRepository.save(bundle); + } + + public List findAll() { + return attributeBundleRepository.findAll(); + } + + public void deleteDefinition(String resourceId) throws EntityNotFoundException { + if (attributeBundleRepository.findByResourceId(resourceId).isEmpty()) { + throw new EntityNotFoundException(String.format("Unable to find attribute bundle with resource id: [%s] for deletion", resourceId)); + } + attributeBundleRepository.deleteById(resourceId); + } + + public AttributeBundle updateBundle(AttributeBundle bundle) throws EntityNotFoundException { + Optional dbBundle = attributeBundleRepository.findByResourceId(bundle.getResourceId()); + if (dbBundle.isEmpty()) { + throw new EntityNotFoundException(String.format("Unable to find attribute bundle with resource id: [%s] for update", bundle.getResourceId())); + } + AttributeBundle bundleToUpdate = dbBundle.get(); + bundleToUpdate.setName(bundle.getName()); + bundleToUpdate.setAttributes(bundle.getAttributes()); + return attributeBundleRepository.save(bundleToUpdate); + } + + public AttributeBundle findByResourceId(String resourceId) throws EntityNotFoundException { + Optional result = attributeBundleRepository.findByResourceId(resourceId); + if (result.isEmpty()) { + throw new EntityNotFoundException(String.format("Unable to find attribute bundle with resource id: [%s] for deletion", resourceId)); + } + return result.get(); + } +} \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/EntityDescriptorService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/EntityDescriptorService.java index 9928eefc4..b2bf96ac3 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/EntityDescriptorService.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/EntityDescriptorService.java @@ -3,10 +3,10 @@ import edu.internet2.tier.shibboleth.admin.ui.domain.Attribute; import edu.internet2.tier.shibboleth.admin.ui.domain.EntityDescriptor; import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.EntityDescriptorRepresentation; -import edu.internet2.tier.shibboleth.admin.ui.exception.EntityIdExistsException; import edu.internet2.tier.shibboleth.admin.ui.exception.EntityNotFoundException; import edu.internet2.tier.shibboleth.admin.ui.exception.ForbiddenException; import edu.internet2.tier.shibboleth.admin.ui.exception.InvalidPatternMatchException; +import edu.internet2.tier.shibboleth.admin.ui.exception.ObjectIdExistsException; import java.util.ConcurrentModificationException; import java.util.List; @@ -30,20 +30,20 @@ public interface EntityDescriptorService { * @param ed - JPA EntityDescriptor to base creation on * @return EntityDescriptorRepresentation of the created object * @throws ForbiddenException If user is unauthorized to perform this operation - * @throws EntityIdExistsException If any EntityDescriptor already exists with the same EntityId + * @throws ObjectIdExistsException If any EntityDescriptor already exists with the same EntityId */ EntityDescriptorRepresentation createNew(EntityDescriptor ed) - throws ForbiddenException, EntityIdExistsException, InvalidPatternMatchException; + throws ForbiddenException, ObjectIdExistsException, InvalidPatternMatchException; /** * @param edRepresentation Incoming representation to save * @return EntityDescriptorRepresentation * @throws ForbiddenException If user is unauthorized to perform this operation - * @throws EntityIdExistsException If the entity already exists + * @throws ObjectIdExistsException If the entity already exists */ EntityDescriptorRepresentation createNew(EntityDescriptorRepresentation edRepresentation) - throws ForbiddenException, EntityIdExistsException, InvalidPatternMatchException; - + throws ForbiddenException, ObjectIdExistsException, InvalidPatternMatchException; + /** * Map from opensaml implementation of entity descriptor model to front-end data representation of entity descriptor * diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/JPAEntityDescriptorServiceImpl.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/JPAEntityDescriptorServiceImpl.java index db769acc3..d1f1f0ccc 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/JPAEntityDescriptorServiceImpl.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/JPAEntityDescriptorServiceImpl.java @@ -16,10 +16,10 @@ import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.OrganizationRepresentation; import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.SecurityInfoRepresentation; import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.ServiceProviderSsoDescriptorRepresentation; -import edu.internet2.tier.shibboleth.admin.ui.exception.EntityIdExistsException; import edu.internet2.tier.shibboleth.admin.ui.exception.EntityNotFoundException; import edu.internet2.tier.shibboleth.admin.ui.exception.ForbiddenException; import edu.internet2.tier.shibboleth.admin.ui.exception.InvalidPatternMatchException; +import edu.internet2.tier.shibboleth.admin.ui.exception.ObjectIdExistsException; import edu.internet2.tier.shibboleth.admin.ui.opensaml.OpenSamlObjects; import edu.internet2.tier.shibboleth.admin.ui.repository.EntityDescriptorRepository; import edu.internet2.tier.shibboleth.admin.ui.security.model.Group; @@ -103,19 +103,19 @@ public EntityDescriptor createDescriptorFromRepresentation(final EntityDescripto @Override public EntityDescriptorRepresentation createNew(EntityDescriptor ed) - throws ForbiddenException, EntityIdExistsException, InvalidPatternMatchException { + throws ForbiddenException, ObjectIdExistsException, InvalidPatternMatchException { return createNew(createRepresentationFromDescriptor(ed)); } @Override public EntityDescriptorRepresentation createNew(EntityDescriptorRepresentation edRep) - throws ForbiddenException, EntityIdExistsException, InvalidPatternMatchException { + throws ForbiddenException, ObjectIdExistsException, InvalidPatternMatchException { if (edRep.isServiceEnabled() && !userService.currentUserIsAdmin()) { throw new ForbiddenException("You do not have the permissions necessary to enable this service."); } if (entityDescriptorRepository.findByEntityID(edRep.getEntityId()) != null) { - throw new EntityIdExistsException(edRep.getEntityId()); + throw new ObjectIdExistsException(edRep.getEntityId()); } // "Create new" will use the current user's group as the owner diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/util/BundleableAttributeTypeValueSerializer.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/util/BundleableAttributeTypeValueSerializer.java new file mode 100644 index 000000000..55aa1ab44 --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/util/BundleableAttributeTypeValueSerializer.java @@ -0,0 +1,28 @@ +package edu.internet2.tier.shibboleth.admin.util; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; +import edu.internet2.tier.shibboleth.admin.ui.domain.BundleableAttributeType; + +import java.io.IOException; + +/** + * This simplifies translation to the front end. We use the ENUM on the backend, but the BundleableAttributeType + * is tagged to serialize using this helper. + * Note: The deserialize is done by the setup of the ENUM itself + */ +public class BundleableAttributeTypeValueSerializer extends StdSerializer { + public BundleableAttributeTypeValueSerializer() { + this(null); + } + + public BundleableAttributeTypeValueSerializer(Class t) { + super(t); + } + + @Override + public void serialize(BundleableAttributeType value, JsonGenerator gen, SerializerProvider provider) throws IOException { + gen.writeString(value.label()); + } +} \ No newline at end of file diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties index 5b7b801f1..0556e5b45 100644 --- a/backend/src/main/resources/application.properties +++ b/backend/src/main/resources/application.properties @@ -24,6 +24,7 @@ spring.h2.console.settings.web-allow-others=true # spring.jackson.default-property-inclusion=non_absent spring.jackson.default-property-inclusion=NON_NULL +spring.jackson.mapper.accept-case-insensitive-enums=true # Database Configuration PostgreSQL #spring.datasource.url=jdbc:postgresql://localhost:5432/shibui diff --git a/backend/src/main/resources/bundle.schema.json b/backend/src/main/resources/bundle.schema.json new file mode 100644 index 000000000..3c5111e40 --- /dev/null +++ b/backend/src/main/resources/bundle.schema.json @@ -0,0 +1,38 @@ +{ + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string", + "title": "label.bundle-name", + "description": "tooltip.bundle-name", + "minLength": 1, + "maxLength": 255 + }, + "attributes": { + "type": "array", + "title": "label.attributes", + "description": "Attribute table - select the attributes you want to bundle (default unchecked)", + "items": { + "type": "string", + "enum": [ + "eduPersonPrincipalName", + "uid", + "mail", + "surname", + "givenName", + "eduPersonAffiliation", + "eduPersonScopedAffiliation", + "eduPersonPrimaryAffiliation", + "eduPersonEntitlement", + "eduPersonAssurance", + "eduPersonUniqueId", + "employeeNumber" + ] + }, + "uniqueItems": true + } + } +} \ No newline at end of file diff --git a/backend/src/main/resources/i18n/messages.properties b/backend/src/main/resources/i18n/messages.properties index d5ae2a10a..46bcc5304 100644 --- a/backend/src/main/resources/i18n/messages.properties +++ b/backend/src/main/resources/i18n/messages.properties @@ -11,6 +11,7 @@ action.dashboard=Dashboard action.logout=Logout +action.logged-in=Logged in as {username} action.add=Add action.add-new=Add New action.add-new-provider=Add a new metadata provider @@ -62,8 +63,8 @@ action.toggle-view=Toggle view action.advanced=Advanced action.add-new-attribute=Add new attribute action.add-new-group=Add new group -action.add-attribute=Add Attribute -action.custom-entity-attributes=Custom Entity Attributes +action.add-attribute=Add attribute +action.custom-entity-attributes=Custom entity attributes action.groups=Groups action.source-group=Group action.enable=Enable @@ -496,6 +497,15 @@ label.provider=Metadata Provider label.url-validation-regex=URL validation regular expression tooltip.url-validation-regex=URL validation regular expression +label.bundle-name=Bundle name +label.bundle-disp=Bundle - {name} +action.add-new-bundle=Add bundle +tooltip.bundle-name=A user friendly name to identify the bundle +action.attribute-bundles=Attribute bundles +label.new-attribute-bundle=New attribute bundle +label.edit-attribute-bundle=Edit attribute bundle +label.bundled-attributes=Bundled Attributes +label.attribute-bundles=Attribute Bundles message.user-role-admin-group=Cannot change group for ROLE_ADMIN users. label.roles-management=Role Management diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/AttributeBundleControllerTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/AttributeBundleControllerTests.groovy new file mode 100644 index 000000000..00e624b7e --- /dev/null +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/AttributeBundleControllerTests.groovy @@ -0,0 +1,225 @@ +package edu.internet2.tier.shibboleth.admin.ui.controller + +import com.fasterxml.jackson.databind.MapperFeature +import com.fasterxml.jackson.databind.ObjectMapper +import edu.internet2.tier.shibboleth.admin.ui.configuration.ShibUIConfiguration +import edu.internet2.tier.shibboleth.admin.ui.domain.AttributeBundle +import edu.internet2.tier.shibboleth.admin.ui.exception.EntityNotFoundException +import edu.internet2.tier.shibboleth.admin.ui.exception.ObjectIdExistsException +import edu.internet2.tier.shibboleth.admin.ui.repository.AttributeBundleRepository +import edu.internet2.tier.shibboleth.admin.ui.service.AttributeBundleService +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.autoconfigure.domain.EntityScan +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest +import org.springframework.boot.test.context.TestConfiguration +import org.springframework.context.annotation.Bean +import org.springframework.data.jpa.repository.config.EnableJpaRepositories +import org.springframework.test.context.ContextConfiguration +import org.springframework.test.web.servlet.setup.MockMvcBuilders +import org.springframework.transaction.annotation.Transactional +import org.springframework.web.util.NestedServletException +import spock.lang.Specification + +import static org.hamcrest.Matchers.containsInAnyOrder +import static org.springframework.http.MediaType.APPLICATION_JSON +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status + +@DataJpaTest(properties = ["spring.jackson.mapper.accept-case-insensitive-enums=true"]) +@EnableJpaRepositories(basePackages = ["edu.internet2.tier.shibboleth.admin.ui"]) +@EntityScan("edu.internet2.tier.shibboleth.admin.ui") +@ContextConfiguration(classes = [ShibUIConfiguration, ABCTConfig]) +class AttributeBundleControllerTests extends Specification { + @Autowired + AttributeBundleController controller + + @Autowired + AttributeBundleRepository attributeBundleRepository + + ObjectMapper objectMapper = new ObjectMapper() + + def MockMvc + + @Transactional + def setup() { + mockMvc = MockMvcBuilders.standaloneSetup(controller).build() + attributeBundleRepository.deleteAll() + } + + def "GET checks" () { + expect: + attributeBundleRepository.findAll().isEmpty() + + when: "fetch for no bundles" + def result = mockMvc.perform(get('/api/custom/entity/bundles')) + + then: + result.andExpect(status().isOk()) + .andExpect(content().contentType(APPLICATION_JSON)) + .andExpect(content().json('[]')) + + when: "add a bundle" + def json = """ + { + "name": "bundleName", + "resourceId": "randomIDVal", + "attributes": ["eduPersonPrincipalName", "surname", "givenName"] + } + """ + + AttributeBundle bundle = objectMapper.readValue(json, AttributeBundle.class) + attributeBundleRepository.saveAndFlush(bundle) + result = mockMvc.perform(get('/api/custom/entity/bundles')) + + then: + result.andExpect(status().isOk()) + .andExpect(content().contentType(APPLICATION_JSON)) + .andExpect(jsonPath("\$.[0].name").value("bundleName")) + .andExpect(jsonPath("\$.[0].resourceId").value("randomIDVal")) + .andExpect(jsonPath("\$.[0].attributes", containsInAnyOrder("eduPersonPrincipalName", "surname", "givenName"))) + } + + def "CREATE checks" () { + expect: + attributeBundleRepository.findAll().isEmpty() + + when: "add a bundle" + def json = """ + { + "name": "bundleName", + "resourceId": "randomIDVal", + "attributes": ["eduPersonPrincipalName", "surname", "givenName"] + } + """ + AttributeBundle bundle = objectMapper.readValue(json, AttributeBundle.class) + attributeBundleRepository.saveAndFlush(bundle) + + then: "bundle already exists" + try { + mockMvc.perform(post('/api/custom/entity/bundles').contentType(APPLICATION_JSON).content(json)) + false + } catch (NestedServletException expected) { + expected.getCause() instanceof ObjectIdExistsException + } + + when: "new bundle" + json = """ + { + "name": "bundle2", + "resourceId": "differentResourceId", + "attributes": ["eduPersonPrincipalName", "surname", "givenName"] + } + """ + + def result = mockMvc.perform(post('/api/custom/entity/bundles').contentType(APPLICATION_JSON).content(json)) + then: + result.andExpect(status().isCreated()) + .andExpect(content().contentType(APPLICATION_JSON)) + .andExpect(jsonPath("\$.name").value("bundle2")) + .andExpect(jsonPath("\$.resourceId").value("differentResourceId")) + .andExpect(jsonPath("\$.attributes", containsInAnyOrder("eduPersonPrincipalName", "surname", "givenName"))) + } + + def "test delete" () { + expect: + attributeBundleRepository.findAll().isEmpty() + + when: + def json = """ + { + "name": "bundleName", + "resourceId": "randomIDVal", + "attributes": ["eduPersonPrincipalName", "surname", "givenName"] + } + """ + AttributeBundle bundle = objectMapper.readValue(json, AttributeBundle.class) + attributeBundleRepository.save(bundle) + + then: + attributeBundleRepository.findAll().size() == 1 + + // Delete something doesn't exist + try { + mockMvc.perform(delete("/api/custom/entity/bundles/randomIDValdoesntexist")) + false + } catch (NestedServletException expected) { + expected instanceof EntityNotFoundException + } + + when: "Delete what does exist" + def result = mockMvc.perform(delete("/api/custom/entity/bundles/randomIDVal")) + + then: + result.andExpect(status().isNoContent()) + attributeBundleRepository.findAll().isEmpty() + } + + def "Update checks" () { + expect: + attributeBundleRepository.findAll().isEmpty() + + when: "add a bundle" + def json = """ + { + "name": "bundleName", + "resourceId": "randomIDVal", + "attributes": ["eduPersonPrincipalName", "surname", "givenName"] + } + """ + AttributeBundle bundle = objectMapper.readValue(json, AttributeBundle.class) + attributeBundleRepository.saveAndFlush(bundle) + + then: "bundle doesn't exist" + bundle.setResourceId("foo") + try { + mockMvc.perform(put('/api/custom/entity/bundles').contentType(APPLICATION_JSON).content(objectMapper.writeValueAsString(bundle))) + false + } catch (NestedServletException expected) { + expected.getCause() instanceof EntityNotFoundException + } + + when: "update bundle" + json = """ + { + "name": "bundle2", + "resourceId": "randomIDVal", + "attributes": ["eduPersonUniqueId", "employeeNumber", "givenName"] + } + """ + + def result = mockMvc.perform(put('/api/custom/entity/bundles').contentType(APPLICATION_JSON).content(json)) + + then: + result.andExpect(status().isOk()) + .andExpect(content().contentType(APPLICATION_JSON)) + .andExpect(jsonPath("\$.name").value("bundle2")) + .andExpect(jsonPath("\$.resourceId").value("randomIDVal")) + .andExpect(jsonPath("\$.attributes", containsInAnyOrder("eduPersonUniqueId", "employeeNumber", "givenName"))) + } + + // can go away with merge to develop and this extends the base test class + @TestConfiguration + private static class ABCTConfig { + @Bean + AttributeBundleController attributeBundleController(AttributeBundleService attributeBundleService) { + new AttributeBundleController().with { + it.attributeBundleService = attributeBundleService + it + } + } + + @Bean + AttributeBundleService attributeBundleService(AttributeBundleRepository repo) { + new AttributeBundleService().with { + it.attributeBundleRepository = repo + it + } + } + + } +} \ No newline at end of file diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorControllerTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorControllerTests.groovy index 2b9acadda..5f14adf1c 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorControllerTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorControllerTests.groovy @@ -5,10 +5,10 @@ import edu.internet2.tier.shibboleth.admin.ui.AbstractBaseDataJpaTest import edu.internet2.tier.shibboleth.admin.ui.domain.EntityDescriptor import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.AssertionConsumerServiceRepresentation import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.EntityDescriptorRepresentation -import edu.internet2.tier.shibboleth.admin.ui.exception.EntityIdExistsException import edu.internet2.tier.shibboleth.admin.ui.exception.EntityNotFoundException import edu.internet2.tier.shibboleth.admin.ui.exception.ForbiddenException import edu.internet2.tier.shibboleth.admin.ui.exception.InvalidPatternMatchException +import edu.internet2.tier.shibboleth.admin.ui.exception.ObjectIdExistsException import edu.internet2.tier.shibboleth.admin.ui.opensaml.OpenSamlObjects import edu.internet2.tier.shibboleth.admin.ui.repository.EntityDescriptorRepository import edu.internet2.tier.shibboleth.admin.ui.security.model.Group @@ -93,7 +93,7 @@ class EntityDescriptorControllerTests extends AbstractBaseDataJpaTest { controller.restTemplate = mockRestTemplate mockMvc = MockMvcBuilders.standaloneSetup(controller).build() - + Optional userRole = roleRepository.findByName("ROLE_USER") User user = new User(username: "someUser", roles:[userRole.get()], password: "foo") user.setGroup(gb) @@ -365,7 +365,7 @@ class EntityDescriptorControllerTests extends AbstractBaseDataJpaTest { mockMvc.perform(post('/api/EntityDescriptor').contentType(APPLICATION_JSON).content(postedJsonBody)) } catch (Exception e) { - e instanceof EntityIdExistsException + e instanceof ObjectIdExistsException } } @@ -589,7 +589,7 @@ class EntityDescriptorControllerTests extends AbstractBaseDataJpaTest { mockMvc.perform(post("/api/EntityDescriptor").contentType(APPLICATION_XML).content(postedBody).param("spName", spName)) } catch (Exception e) { - e instanceof EntityIdExistsException + e instanceof ObjectIdExistsException } } diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/AttributeBundleRepositoryTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/AttributeBundleRepositoryTests.groovy new file mode 100644 index 000000000..0db6a9555 --- /dev/null +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/AttributeBundleRepositoryTests.groovy @@ -0,0 +1,42 @@ +package edu.internet2.tier.shibboleth.admin.ui.repository + +import com.fasterxml.jackson.databind.MapperFeature +import com.fasterxml.jackson.databind.ObjectMapper +import edu.internet2.tier.shibboleth.admin.ui.configuration.ShibUIConfiguration +import edu.internet2.tier.shibboleth.admin.ui.domain.AttributeBundle +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.autoconfigure.domain.EntityScan +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest +import org.springframework.data.jpa.repository.config.EnableJpaRepositories +import org.springframework.test.context.ContextConfiguration +import spock.lang.Specification + +@DataJpaTest +@EnableJpaRepositories(basePackages = ["edu.internet2.tier.shibboleth.admin.ui"]) +@EntityScan("edu.internet2.tier.shibboleth.admin.ui") +@ContextConfiguration(classes = [ShibUIConfiguration]) +class AttributeBundleRepositoryTests extends Specification { + @Autowired + AttributeBundleRepository attributeBundleRepository + + ObjectMapper objectMapper = new ObjectMapper() + + def "test create and fetch" () { + given: + def json = """ + { + "name": "bundleName", + "resourceId": "randomIDVal", + "attributes": ["eduPersonPrincipalName", "surname", "givenName"] + } + """ + + AttributeBundle bundle = objectMapper.readValue(json, AttributeBundle.class) + + when: + def result = attributeBundleRepository.save(bundle) + + then: + result == bundle + } +} \ No newline at end of file diff --git a/ui/public/assets/schema/attribute/bundle.schema.json b/ui/public/assets/schema/attribute/bundle.schema.json new file mode 100644 index 000000000..3c5111e40 --- /dev/null +++ b/ui/public/assets/schema/attribute/bundle.schema.json @@ -0,0 +1,38 @@ +{ + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string", + "title": "label.bundle-name", + "description": "tooltip.bundle-name", + "minLength": 1, + "maxLength": 255 + }, + "attributes": { + "type": "array", + "title": "label.attributes", + "description": "Attribute table - select the attributes you want to bundle (default unchecked)", + "items": { + "type": "string", + "enum": [ + "eduPersonPrincipalName", + "uid", + "mail", + "surname", + "givenName", + "eduPersonAffiliation", + "eduPersonScopedAffiliation", + "eduPersonPrimaryAffiliation", + "eduPersonEntitlement", + "eduPersonAssurance", + "eduPersonUniqueId", + "employeeNumber" + ] + }, + "uniqueItems": true + } + } +} \ No newline at end of file diff --git a/ui/public/assets/schema/source/metadata-source.json b/ui/public/assets/schema/source/metadata-source.json index dc19fe8d4..0a2f6baba 100644 --- a/ui/public/assets/schema/source/metadata-source.json +++ b/ui/public/assets/schema/source/metadata-source.json @@ -22,8 +22,7 @@ "serviceEnabled": { "title": "label.enable-this-service", "description": "tooltip.enable-this-service-upon-saving", - "type": "boolean", - "default": false + "type": "boolean" }, "organization": { "$ref": "#/definitions/Organization" @@ -76,8 +75,7 @@ }, "properties": { "x509CertificateAvailable": { - "type": "boolean", - "default": true + "type": "boolean" }, "authenticationRequestsSigned": { "title": "label.authentication-requests-signed", @@ -161,11 +159,16 @@ "type": "boolean", "default": false }, - "dontSignResponse": { - "title": "label.dont-sign-the-response", - "description": "tooltip.dont-sign-response", - "type": "boolean", - "default": false + "nameIdFormats": { + "$ref": "#/definitions/nameIdFormats" + }, + "responderId": { + "title": "label.responder-id", + "description": "tooltip.responder-id", + "type": "string" + }, + "authenticationMethods": { + "$ref": "#/definitions/authenticationMethods" }, "turnOffEncryption": { "title": "label.turn-off-encryption-of-response", @@ -173,9 +176,15 @@ "type": "boolean", "default": false }, - "useSha": { - "title": "label.use-sha1-signing-algorithm", - "description": "tooltip.usa-sha-algorithm", + "forceAuthn": { + "title": "label.force-authn", + "description": "tooltip.force-authn", + "type": "boolean", + "default": false + }, + "dontSignResponse": { + "title": "label.dont-sign-the-response", + "description": "tooltip.dont-sign-response", "type": "boolean", "default": false }, @@ -185,27 +194,15 @@ "type": "boolean", "default": false }, - "omitNotBefore": { - "title": "label.omit-not-before-condition", - "description": "tooltip.omit-not-before-condition", + "useSha": { + "title": "label.use-sha1-signing-algorithm", + "description": "tooltip.usa-sha-algorithm", "type": "boolean", "default": false }, - "responderId": { - "title": "label.responder-id", - "description": "tooltip.responder-id", - "type": "string", - "default": "" - }, - "nameIdFormats": { - "$ref": "#/definitions/nameIdFormats" - }, - "authenticationMethods": { - "$ref": "#/definitions/authenticationMethods" - }, - "forceAuthn": { - "title": "label.force-authn", - "description": "tooltip.force-authn", + "omitNotBefore": { + "title": "label.omit-not-before-condition", + "description": "tooltip.omit-not-before-condition", "type": "boolean", "default": false } @@ -218,6 +215,18 @@ "items": { "type": "string", "enum": [ + [ + "givenName", + "eduPersonAffiliation", + "eduPersonScopedAffiliation", + "employeeNumber" + ], + [ + "uid", + "surname", + "eduPersonAffiliation", + "employeeNumber" + ], "eduPersonPrincipalName", "uid", "mail", @@ -230,6 +239,10 @@ "eduPersonAssurance", "eduPersonUniqueId", "employeeNumber" + ], + "enumNames": [ + "Bundle 1", + "Bundle 2" ] }, "uniqueItems": true diff --git a/ui/public/data/bundles.json b/ui/public/data/bundles.json new file mode 100644 index 000000000..11a20d22d --- /dev/null +++ b/ui/public/data/bundles.json @@ -0,0 +1,10 @@ +[ + { + "resourceId": "abc", + "name": "Bundle 1", + "attributes": [ + "abc123", + "xyz456" + ] + } +] \ No newline at end of file diff --git a/ui/src/app/core/components/Header.js b/ui/src/app/core/components/Header.js index 3e553c595..7bb693b1e 100644 --- a/ui/src/app/core/components/Header.js +++ b/ui/src/app/core/components/Header.js @@ -6,13 +6,14 @@ import Navbar from 'react-bootstrap/Navbar'; import Dropdown from 'react-bootstrap/Dropdown'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faTh, faSignOutAlt, faPlusCircle, faCube, faCubes, faUserTag, faUsersCog } from '@fortawesome/free-solid-svg-icons'; + +import { faTh, faSignOutAlt, faPlusCircle, faCube, faCubes, faUsersCog, faSpinner, faUserCircle, faCog, faBoxOpen, faTags, faIdBadge } from '@fortawesome/free-solid-svg-icons'; import Translate from '../../i18n/components/translate'; import { useTranslator } from '../../i18n/hooks'; import { brand } from '../../app.brand'; -import { useIsAdmin } from '../user/UserContext'; +import { useCurrentUser, useCurrentUserLoading, useIsAdmin } from '../user/UserContext'; import { BASE_PATH } from '../../App.constant'; export function Header () { @@ -21,6 +22,9 @@ export function Header () { const isAdmin = useIsAdmin(); + const { username, groupId } = useCurrentUser(); + const loading = useCurrentUserLoading(); + return ( @@ -28,58 +32,84 @@ export function Header () { + {loading ? +
+ +
+ : + <> -