diff --git a/functional_tests/features/sharing.feature b/functional_tests/features/sharing.feature new file mode 100644 index 000000000..44c93006f --- /dev/null +++ b/functional_tests/features/sharing.feature @@ -0,0 +1,52 @@ +# +# This file is part of FreedomBox. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# + +@apps @sharing +Feature: Sharing + Share server folders over HTTP, etc. + +Background: + Given I'm a logged in user + +Scenario: Add new share + Given share tmp is not available + When I add a share tmp from path /tmp for admin + Then the share tmp should be listed from path /tmp for admin + Then the share tmp should be accessible + +Scenario: Edit a share + Given share tmp is not available + When I remove share boot + When I add a share tmp from path /tmp for admin + When I edit share tmp to boot from path /boot for admin + Then the share tmp should not be listed + Then the share tmp should not exist + Then the share boot should be listed from path /boot for admin + Then the share boot should be accessible + +Scenario: Remove a share + When I remove share tmp + When I add a share tmp from path /tmp for admin + When I remove share tmp + Then the share tmp should not be listed + Then the share tmp should not exist + +Scenario: Share permissions + When I remove share tmp + When I add a share tmp from path /tmp for syncthing + Then the share tmp should be listed from path /tmp for syncthing + Then the share tmp should not be accessible diff --git a/functional_tests/step_definitions/application.py b/functional_tests/step_definitions/application.py index af2650622..d7ff7c7ed 100644 --- a/functional_tests/step_definitions/application.py +++ b/functional_tests/step_definitions/application.py @@ -15,6 +15,8 @@ # along with this program. If not, see . # +import pytest +import splinter from pytest_bdd import given, parsers, then, when from support import application @@ -111,3 +113,54 @@ def assert_max_file_size(browser, size): @when(parsers.parse('I modify the coquelicot upload password to {password:w}')) def modify_upload_password(browser, password): application.modify_upload_password(browser, password) + + +@given(parsers.parse('share {name:w} is not available')) +def remove_share(browser, name): + application.remove_share(browser, name) + + +@when(parsers.parse('I add a share {name:w} from path {path} for {group:w}')) +def add_share(browser, name, path, group): + application.add_share(browser, name, path, group) + + +@when( + parsers.parse( + 'I edit share {old_name:w} to {new_name:w} from path {path} for {group:w}' + )) +def edit_share(browser, old_name, new_name, path, group): + application.edit_share(browser, old_name, new_name, path, group) + + +@when(parsers.parse('I remove share {name:w}')) +def remove_share2(browser, name): + application.remove_share(browser, name) + + +@then( + parsers.parse( + 'the share {name:w} should be listed from path {path} for {group:w}')) +def verify_share(browser, name, path, group): + application.verify_share(browser, name, path, group) + + +@then(parsers.parse('the share {name:w} should not be listed')) +def verify_invalid_share(browser, name): + with pytest.raises(splinter.exceptions.ElementDoesNotExist): + application.get_share(browser, name) + + +@then(parsers.parse('the share {name:w} should be accessible')) +def access_share(browser, name): + application.access_share(browser, name) + + +@then(parsers.parse('the share {name:w} should not exist')) +def verify_nonexistant_share(browser, name): + application.verify_nonexistant_share(browser, name) + + +@then(parsers.parse('the share {name:w} should not be accessible')) +def verify_inaccessible_share(browser, name): + application.verify_inaccessible_share(browser, name) diff --git a/functional_tests/support/application.py b/functional_tests/support/application.py index 5e06385f8..a0ea35703 100644 --- a/functional_tests/support/application.py +++ b/functional_tests/support/application.py @@ -17,6 +17,7 @@ from time import sleep +import splinter from support import config, interface from support.service import eventually @@ -128,3 +129,77 @@ def modify_upload_password(browser, password): browser.find_by_value('Update setup').click() # Wait for the service to restart after updating password eventually(browser.is_text_present, args=['Upload password updated']) + + +def remove_share(browser, name): + """Remove a share in sharing app.""" + try: + share_row = get_share(browser, name) + except splinter.exceptions.ElementDoesNotExist: + pass + else: + share_row.find_by_css('.share-remove')[0].click() + + +def add_share(browser, name, path, group): + """Add a share in sharing app.""" + browser.visit('{}/plinth/apps/sharing/add/'.format(default_url)) + browser.fill('sharing-name', name) + browser.fill('sharing-path', path) + browser.find_by_css( + '#id_sharing-groups input[value="{}"]'.format(group)).check() + browser.find_by_css('input[type="submit"]').click() + eventually(browser.is_text_present, args=['Share added.']) + + +def edit_share(browser, old_name, new_name, path, group): + """Edit a share in sharing app.""" + row = get_share(browser, old_name) + row.find_by_css('.share-edit')[0].click() + eventually(browser.is_text_present, args=['Edit Share']) + browser.fill('sharing-name', new_name) + browser.fill('sharing-path', path) + browser.find_by_css('#id_sharing-groups input').uncheck() + browser.find_by_css('#id_sharing-groups input[value="{}"]'.format(group)).check() + browser.find_by_css('input[type="submit"]').click() + eventually(browser.is_text_present, args=['Share edited.']) + + +def get_share(browser, name): + """Return the row for a given share.""" + browser.visit('{}/plinth/apps/sharing/'.format(default_url)) + return browser.find_by_id('share-{}'.format(name))[0] + + +def verify_share(browser, name, path, group): + """Verfiy that a share exists in list of shares.""" + href = '{}/share/{}'.format(default_url, name) + url = '/share/{}'.format(name) + row = get_share(browser, name) + assert row.find_by_css('.share-name')[0].text == name + assert row.find_by_css('.share-path')[0].text == path + assert row.find_by_css('.share-url a')[0]['href'] == href + assert row.find_by_css('.share-url a')[0].text == url + assert row.find_by_css('.share-groups')[0].text == group + + +def access_share(browser, name): + """Visit a share and see if it is accessible.""" + row = get_share(browser, name) + url = row.find_by_css('.share-url a')[0]['href'] + browser.visit(url) + browser.is_text_present('Index of /share/{}'.format(name)) + + +def verify_nonexistant_share(browser, name): + """Verify that given URL for a given share name is a 404.""" + url = '{}/share/{}'.format(default_url, name) + browser.visit(url) + browser.is_text_present('Not Found') + + +def verify_inaccessible_share(browser, name): + """Verify that given URL for a given share name denies permission.""" + url = '{}/share/{}'.format(default_url, name) + browser.visit(url) + eventually(lambda: '/plinth' in browser.url, args=[])