Beispiel #1
0
    def test_enforce_quota_applies_to_app(self, mock_RQ, mock_active_app,
                                          mock_passes_quota):
        mock_RQ.objects.get.return_value = mock.MagicMock(
            codename='foo', applies_to='tethys_apps.models.TethysApp')
        mock_request = mock.MagicMock(spec=HttpRequest)
        mock_active_app.return_value = mock.MagicMock(
            TethysApp(name='Test App'))

        ret = a_controller(mock_request)

        mock_passes_quota.assert_called()
        self.assertEqual('Success', ret)
Beispiel #2
0
    def test_get_resource_available_app(self, mock_rq, mock_get_quota):
        rq = mock.MagicMock()
        rq.units = 'gb'
        mock_rq.objects.get.return_value = rq
        rqh = mock.MagicMock()
        rq.handler.return_value = rqh
        rqh.get_current_use.return_value = 1
        mock_get_quota.return_value = {'quota': 5}

        ret = utilities.get_resource_available(TethysApp(), 'codename')

        self.assertEqual(4, ret['resource_available'])
        self.assertEqual('gb', ret['units'])
Beispiel #3
0
    def test_clear_workspace_successful(self, mock_redirect, mock_message,
                                        mock_app, mock_user, mock_guw,
                                        mock_get_app_class):  # noqa: E501
        mock_request = mock.MagicMock(method='POST',
                                      POST='clear-workspace-submit')
        mock_request.user.username = '******'

        mock_user.objects.get.return_value = mock.MagicMock(
            User(username='******'))
        app = TethysApp(name='app_name')
        mock_app.objects.get.return_value = app
        mock_get_app_class.return_value = app
        app.pre_delete_user_workspace = mock.MagicMock()
        app.post_delete_user_workspace = mock.MagicMock()
        mock_guw.return_value = mock.MagicMock()

        clear_workspace(mock_request, 'ThisIsMe', 'root_url')

        mock_message.assert_called_once_with(
            mock_request, 'Your workspace has been successfully cleared.')
        mock_redirect.assert_called_once_with(
            'user:manage_storage', username=mock_request.user.username)
Beispiel #4
0
    def test_tethys_apps_context_feedback(self, mock_get_active_app):
        mock_args = mock.MagicMock()
        app = TethysApp()
        app.id = 'foo.id'
        app.name = models.CharField(max_length=200, default='')
        app.name.value = 'foo.name'
        app.icon = models.CharField(max_length=200, default='')
        app.icon.value = 'foo.icon'
        app.color = models.CharField(max_length=10, default='')
        app.color.value = '#foobar'
        app.tags = models.CharField(max_length=200, blank=True, default='')
        app.tags.value = 'tags'
        app.description = models.TextField(max_length=1000,
                                           blank=True,
                                           default='')
        app.description.value = 'foo.description'
        app.enable_feedback = models.BooleanField(default=True)
        app.enable_feedback.value = True
        app.feedback_emails = ListField(default='', blank=True)
        app.feedback_emails.append('foo.feedback')
        mock_get_active_app.return_value = app

        context = tethys_apps_context(mock_args)

        mock_get_active_app.assert_called_once()
        self.assertEqual('foo.id', context['tethys_app']['id'])
        self.assertEqual('foo.name', context['tethys_app']['name'].value)
        self.assertEqual('foo.icon', context['tethys_app']['icon'].value)
        self.assertEqual('#foobar', context['tethys_app']['color'].value)
        self.assertEqual('tags', context['tethys_app']['tags'].value)
        self.assertEqual('foo.description',
                         context['tethys_app']['description'].value)
        self.assertTrue('enable_feedback' in context['tethys_app'])
        self.assertTrue('feedback_emails' in context['tethys_app'])
        self.assertEqual(True, context['tethys_app']['enable_feedback'].value)
        self.assertEqual(['foo.feedback'],
                         context['tethys_app']['feedback_emails'])
Beispiel #5
0
    def test_manage_storage_successful(self, mock_render, mock_harvester, mock_user, mock_convert_storage, _, __):
        mock_request = mock.MagicMock()
        mock_request.user.username = '******'
        app = TethysApp(name="app_name")
        mock_harvester().apps = [app]
        mock_user.objects.get.return_value = mock.MagicMock()
        mock_convert_storage.return_value = '0 bytes'

        expected_context = {'apps': mock_harvester().apps,
                            'context_user': mock_request.user,
                            'current_use': '0 bytes',
                            'quota': None,
                            }

        manage_storage(mock_request, 'ThisIsMe')

        mock_render.assert_called_once_with(mock_request, 'tethys_portal/user/manage_storage.html', expected_context)
Beispiel #6
0
    def test_clear_workspace_display(self, mock_render, mock_app,
                                     mock_get_app_class, _):
        mock_request = mock.MagicMock()
        app = TethysApp(name='app_name')
        mock_get_app_class.return_value = app
        mock_app.objects.get.return_value = app

        expected_context = {
            'app_name': mock_app.objects.get().name,
            'change_url': '/admin/tethys_apps/tethysapp/app_name/change/'
        }

        clear_workspace(mock_request, 'app_name')

        mock_render.assert_called_once_with(
            mock_request,
            'tethys_portal/admin/tethys_app/clear_workspace.html',
            expected_context)
class TestInstallCommands(TestCase):
    def setUp(self):
        from tethys_apps.models import TethysApp
        self.src_dir = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
        self.root_app_path = os.path.join(self.src_dir, 'apps', 'tethysapp-test_app')
        self.app_model = TethysApp(
            name='test_app',
            package='test_app'
        )
        self.app_model.save()

    def tearDown(self):
        self.app_model.delete()

    @mock.patch('tethys_cli.cli_colors.pretty_output')
    @mock.patch('builtins.input', side_effect=['x', 'n'])
    @mock.patch('tethys_cli.install_commands.exit')
    @mock.patch('tethys_cli.install_commands.call')
    def test_install_file_not_generate(self, mock_call, mock_exit, _, __):
        args = mock.MagicMock(file=None, quiet=False, only_dependencies=False, without_dependencies=False)

        mock_exit.side_effect = SystemExit

        self.assertRaises(SystemExit, install_commands.install_command, args)
        self.assertEqual(3, len(mock_call.call_args_list))

        mock_exit.assert_called_with(0)

    @mock.patch('tethys_cli.cli_colors.pretty_output')
    @mock.patch('builtins.input', side_effect=['y'])
    @mock.patch('tethys_cli.install_commands.call')
    @mock.patch('tethys_cli.install_commands.exit')
    def test_install_file_generate(self, mock_exit, mock_call, _, __):
        args = mock.MagicMock(file=None, quiet=False, only_dependencies=False, without_dependencies=False)
        check_call = ['tethys', 'gen', 'install']

        mock_exit.side_effect = SystemExit

        self.assertRaises(SystemExit, install_commands.install_command, args)
        mock_call.assert_called_with(check_call)
        mock_exit.assert_called_with(0)

    @mock.patch('tethys_cli.install_commands.run_services')
    @mock.patch('tethys_cli.install_commands.call')
    @mock.patch('tethys_cli.install_commands.exit')
    @mock.patch('tethys_cli.cli_colors.pretty_output')
    def test_no_conda_input_file(self, mock_pretty_output, mock_exit, _, __):
        file_path = os.path.join(self.root_app_path, 'install-no-dep.yml')
        args = mock.MagicMock(file=file_path, verbose=False, only_dependencies=False, without_dependencies=False)
        mock_exit.side_effect = SystemExit

        self.assertRaises(SystemExit, install_commands.install_command, args)

        po_call_args = mock_pretty_output().__enter__().write.call_args_list
        self.assertIn("Running application install....", po_call_args[0][0][0])
        self.assertIn("Quiet mode: No additional service setting validation will be performed.", po_call_args[1][0][0])
        self.assertIn("Services Configuration Completed.", po_call_args[2][0][0])
        self.assertIn("Skipping syncstores.", po_call_args[3][0][0])
        mock_exit.assert_called_with(0)

    @mock.patch('tethys_cli.install_commands.run_services')
    @mock.patch('tethys_cli.install_commands.call')
    @mock.patch('tethys_cli.install_commands.exit')
    @mock.patch('tethys_cli.cli_colors.pretty_output')
    def test_input_file_with_post(self, mock_pretty_output, mock_exit, _, __):
        file_path = os.path.join(self.root_app_path, 'install-with-post.yml')
        args = mock.MagicMock(file=file_path, verbose=False, only_dependencies=False, without_dependencies=False)
        mock_exit.side_effect = SystemExit

        self.assertRaises(SystemExit, install_commands.install_command, args)

        po_call_args = mock_pretty_output().__enter__().write.call_args_list
        self.assertIn("Running application install....", po_call_args[1][0][0])
        self.assertIn("Quiet mode: No additional service setting validation will be performed.", po_call_args[2][0][0])
        self.assertIn("Services Configuration Completed.", po_call_args[3][0][0])
        self.assertIn("Skipping syncstores.", po_call_args[4][0][0])
        self.assertIn("Running post installation tasks...", po_call_args[5][0][0])
        self.assertIn("Post Script Result: b'test\\n'", po_call_args[6][0][0])
        mock_exit.assert_called_with(0)

    @mock.patch('tethys_cli.install_commands.run_services')
    @mock.patch('tethys_cli.install_commands.run_sync_stores')
    @mock.patch('tethys_cli.install_commands.run_interactive_services')
    @mock.patch('tethys_cli.install_commands.call')
    @mock.patch('tethys_cli.install_commands.run_portal_install', return_value=False)
    @mock.patch('tethys_cli.install_commands.run_services')
    @mock.patch('tethys_cli.install_commands.exit')
    @mock.patch('tethys_cli.cli_colors.pretty_output')
    def test_skip_input_file(self, mock_pretty_output, mock_exit, _, __, ___, ____, _____, ______):
        file_path = os.path.join(self.root_app_path, 'install-skip-setup.yml')
        mock_exit.side_effect = SystemExit

        args = mock.MagicMock(file=file_path, verbose=False, only_dependencies=False, without_dependencies=False)
        self.assertRaises(SystemExit, install_commands.install_command, args)

        args = mock.MagicMock(file=file_path, develop=False, only_dependencies=False, without_dependencies=False)
        self.assertRaises(SystemExit, install_commands.install_command, args)

        args = mock.MagicMock(file=file_path, verbose=False, develop=False, force_services=False, quiet=False,
                              no_sync=False, only_dependencies=False, without_dependencies=False)
        self.assertRaises(SystemExit, install_commands.install_command, args)

        po_call_args = mock_pretty_output().__enter__().write.call_args_list
        self.assertEqual("Skipping package installation, Skip option found.", po_call_args[0][0][0])
        mock_exit.assert_called_with(0)

    @mock.patch('tethys_cli.install_commands.run_services')
    @mock.patch('tethys_cli.install_commands.call')
    @mock.patch('tethys_cli.install_commands.conda_run', return_value=['', '', 1])
    @mock.patch('tethys_cli.install_commands.exit')
    @mock.patch('tethys_cli.cli_colors.pretty_output')
    def test_conda_and_pip_package_install(self, mock_pretty_output, mock_exit, mock_conda_run, mock_call, _):
        file_path = os.path.join(self.root_app_path, 'install-dep.yml')
        args = mock.MagicMock(file=file_path, develop=False, verbose=False, services_file=None, update_installed=False,
                              only_dependencies=False, without_dependencies=False)
        mock_exit.side_effect = SystemExit
        self.assertRaises(SystemExit, install_commands.install_command, args)

        mock_conda_run.assert_called_with(Commands.INSTALL, '-c', 'tacaswell', '--freeze-installed', 'geojson',
                                          use_exception_handler=False, stdout=None, stderr=None)

        po_call_args = mock_pretty_output().__enter__().write.call_args_list
        self.assertEqual("Running conda installation tasks...", po_call_args[0][0][0])
        self.assertIn("Warning: Packages installation ran into an error.", po_call_args[1][0][0])
        self.assertEqual("Running pip installation tasks...", po_call_args[2][0][0])
        self.assertEqual("Running application install....", po_call_args[3][0][0])
        self.assertEqual("Quiet mode: No additional service setting validation will be performed.",
                         po_call_args[4][0][0])
        self.assertEqual("Services Configuration Completed.", po_call_args[5][0][0])

        self.assertEqual(['pip', 'install', 'see'], mock_call.mock_calls[0][1][0])
        self.assertEqual(['python', 'setup.py', 'clean', '--all'], mock_call.mock_calls[1][1][0])
        self.assertEqual(['python', 'setup.py', 'install'], mock_call.mock_calls[2][1][0])
        self.assertEqual(['tethys', 'db', 'sync'], mock_call.mock_calls[3][1][0])

        mock_exit.assert_called_with(0)

    @mock.patch('tethys_cli.install_commands.run_services')
    @mock.patch('tethys_cli.install_commands.call')
    @mock.patch('tethys_cli.install_commands.conda_run', return_value=['', '', 1])
    @mock.patch('tethys_cli.install_commands.exit')
    @mock.patch('tethys_cli.cli_colors.pretty_output')
    def test_without_dependencies(self, mock_pretty_output, mock_exit, mock_conda_run, mock_call, _):
        file_path = os.path.join(self.root_app_path, 'install-dep.yml')
        args = mock.MagicMock(file=file_path, develop=False, verbose=False, services_file=None, update_installed=False,
                              only_dependencies=False, without_dependencies=True)
        mock_exit.side_effect = SystemExit
        self.assertRaises(SystemExit, install_commands.install_command, args)

        # Ensure conda command wasn't called to install dependencies
        mock_conda_run.assert_not_called()

        # Make sure 'pip install' isn't in any of the calls
        self.assertFalse(any(['pip install' in ' '.join(mc[1][0]) for mc in mock_call.mock_calls]))

        # Validate output displayed to the user
        po_call_args = mock_pretty_output().__enter__().write.call_args_list
        self.assertEqual("Skipping package installation.", po_call_args[0][0][0])
        self.assertEqual("Running application install....", po_call_args[1][0][0])
        self.assertEqual("Quiet mode: No additional service setting validation will be performed.",
                         po_call_args[2][0][0])
        self.assertEqual("Services Configuration Completed.", po_call_args[3][0][0])

        # Verify that the application install still happens
        self.assertEqual(['python', 'setup.py', 'clean', '--all'], mock_call.mock_calls[0][1][0])
        self.assertEqual(['python', 'setup.py', 'install'], mock_call.mock_calls[1][1][0])
        self.assertEqual(['tethys', 'db', 'sync'], mock_call.mock_calls[2][1][0])

        mock_exit.assert_called_with(0)

    @mock.patch('tethys_cli.install_commands.run_services')
    @mock.patch('tethys_cli.install_commands.call')
    @mock.patch('tethys_cli.install_commands.conda_run', return_value=['', '', 1])
    @mock.patch('tethys_cli.install_commands.exit')
    @mock.patch('tethys_cli.cli_colors.pretty_output')
    def test_conda_and_pip_package_install_only_dependencies(self, mock_pretty_output, mock_exit, mock_conda_run,
                                                             mock_call, _):
        file_path = os.path.join(self.root_app_path, 'install-dep.yml')
        args = mock.MagicMock(file=file_path, develop=False, verbose=False, services_file=None, update_installed=False,
                              only_dependencies=True, without_dependencies=False)
        mock_exit.side_effect = SystemExit
        self.assertRaises(SystemExit, install_commands.install_command, args)

        mock_conda_run.assert_called_with(Commands.INSTALL, '-c', 'tacaswell', '--freeze-installed', 'geojson',
                                          use_exception_handler=False, stdout=None, stderr=None)

        po_call_args = mock_pretty_output().__enter__().write.call_args_list
        self.assertEqual("Running conda installation tasks...", po_call_args[0][0][0])
        self.assertIn("Warning: Packages installation ran into an error.", po_call_args[1][0][0])
        self.assertEqual("Running pip installation tasks...", po_call_args[2][0][0])
        self.assertEqual("Installed dependencies only. Skipping remaining installation.", po_call_args[3][0][0])

        self.assertEqual(1, len(mock_call.mock_calls))
        self.assertEqual(['pip', 'install', 'see'], mock_call.mock_calls[0][1][0])

        mock_exit.assert_called_with(0)

    @mock.patch('tethys_cli.install_commands.run_services')
    @mock.patch('tethys_cli.install_commands.call')
    @mock.patch('tethys_cli.install_commands.conda_run', return_value=['', '', 1])
    @mock.patch('tethys_cli.install_commands.exit')
    @mock.patch('tethys_cli.cli_colors.pretty_output')
    def test_conda_and_pip_package_install_update_installed(self, mock_pretty_output, mock_exit, mock_conda_run,
                                                            mock_call, _):
        file_path = os.path.join(self.root_app_path, 'install-dep.yml')
        args = mock.MagicMock(file=file_path, develop=False, verbose=False, services_file=None, update_installed=True,
                              only_dependencies=False, without_dependencies=False)
        mock_exit.side_effect = SystemExit
        self.assertRaises(SystemExit, install_commands.install_command, args)

        mock_conda_run.assert_called_with(Commands.INSTALL, '-c', 'tacaswell', 'geojson', use_exception_handler=False,
                                          stdout=None, stderr=None)

        po_call_args = mock_pretty_output().__enter__().write.call_args_list
        self.assertEqual("Warning: Updating previously installed packages. This could break your Tethys environment.",
                         po_call_args[0][0][0])
        self.assertEqual("Running conda installation tasks...", po_call_args[1][0][0])
        self.assertIn("Warning: Packages installation ran into an error.", po_call_args[2][0][0])
        self.assertEqual("Running pip installation tasks...", po_call_args[3][0][0])
        self.assertEqual("Running application install....", po_call_args[4][0][0])
        self.assertEqual("Quiet mode: No additional service setting validation will be performed.",
                         po_call_args[5][0][0])
        self.assertEqual("Services Configuration Completed.", po_call_args[6][0][0])

        self.assertEqual(['pip', 'install', 'see'], mock_call.mock_calls[0][1][0])
        self.assertEqual(['python', 'setup.py', 'clean', '--all'], mock_call.mock_calls[1][1][0])
        self.assertEqual(['python', 'setup.py', 'install'], mock_call.mock_calls[2][1][0])
        self.assertEqual(['tethys', 'db', 'sync'], mock_call.mock_calls[3][1][0])

        mock_exit.assert_called_with(0)

    @mock.patch('builtins.input', side_effect=['x', 5])
    @mock.patch('tethys_cli.install_commands.get_app_settings')
    @mock.patch('tethys_cli.cli_colors.pretty_output')
    def test_interactive_custom_setting_set(self, mock_pretty_output, mock_gas, _):
        mock_cs = mock.MagicMock()
        mock_cs.name = 'mock_cs'
        mock_cs.save.side_effect = [ValidationError('error'), mock.DEFAULT]
        mock_gas.return_value = {'unlinked_settings': [mock_cs]}

        install_commands.run_interactive_services('foo')

        po_call_args = mock_pretty_output().__enter__().write.call_args_list
        self.assertIn("Configuring mock_cs", po_call_args[2][0][0])
        self.assertIn("Type", po_call_args[3][0][0])
        self.assertIn("Enter the desired value", po_call_args[4][0][0])
        self.assertIn("Incorrect value type", po_call_args[5][0][0])
        self.assertIn("Enter the desired value", po_call_args[6][0][0])
        self.assertEqual(mock_cs.name + " successfully set with value: 5.", po_call_args[7][0][0])

    @mock.patch('builtins.input', side_effect=[''])
    @mock.patch('tethys_cli.install_commands.get_app_settings')
    @mock.patch('tethys_cli.cli_colors.pretty_output')
    def test_interactive_custom_setting_skip(self, mock_pretty_output, mock_gas, _):
        mock_cs = mock.MagicMock()
        mock_cs.name = 'mock_cs'
        mock_gas.return_value = {'unlinked_settings': [mock_cs]}

        install_commands.run_interactive_services('foo')

        po_call_args = mock_pretty_output().__enter__().write.call_args_list
        self.assertIn("Configuring mock_cs", po_call_args[2][0][0])
        self.assertIn("Type", po_call_args[3][0][0])
        self.assertIn("Enter the desired value", po_call_args[4][0][0])
        self.assertEqual(f"Skipping setup of {mock_cs.name}", po_call_args[5][0][0])

    @mock.patch('builtins.input', side_effect=KeyboardInterrupt)
    @mock.patch('tethys_cli.install_commands.exit')
    @mock.patch('tethys_cli.install_commands.get_app_settings')
    @mock.patch('tethys_cli.cli_colors.pretty_output')
    def test_interactive_custom_setting_interrupt(self, mock_pretty_output, mock_gas, mock_exit, _):
        mock_cs = mock.MagicMock()
        mock_cs.name = 'mock_cs'
        mock_gas.return_value = {'unlinked_settings': [mock_cs]}

        mock_exit.side_effect = SystemExit

        self.assertRaises(SystemExit, install_commands.run_interactive_services, 'foo')

        po_call_args = mock_pretty_output().__enter__().write.call_args_list
        self.assertIn("Configuring mock_cs", po_call_args[2][0][0])
        self.assertIn("Type", po_call_args[3][0][0])
        self.assertIn("Enter the desired value", po_call_args[4][0][0])
        self.assertEqual("\nInstall Command cancelled.", po_call_args[5][0][0])

        mock_exit.assert_called_with(0)

    @mock.patch('builtins.input', side_effect=['1', '1', '', '1', '1', KeyboardInterrupt])
    @mock.patch('tethys_cli.install_commands.validate_service_id', side_effect=[False, True])
    @mock.patch('tethys_cli.install_commands.get_setting_type', return_value='persistent')
    @mock.patch('tethys_cli.install_commands.get_setting_type_from_setting',
                side_effect=['ps_database', 'ps_database', 'ps_database', RuntimeError('setting_type_not_found')])
    @mock.patch('tethys_cli.install_commands.get_service_type_from_setting',
                side_effect=['persistent', 'persistent', RuntimeError('service_type_not_found'), 'persistent'])
    @mock.patch('tethys_cli.install_commands.exit')
    @mock.patch('tethys_cli.install_commands.services_list_command')
    @mock.patch('tethys_cli.install_commands.get_app_settings')
    @mock.patch('tethys_cli.install_commands.link_service_to_app_setting')
    @mock.patch('tethys_cli.cli_colors.pretty_output')
    def test_interactive_service_setting_all(self, mock_pretty_output, mock_lstas, mock_gas, mock_slc,
                                             mock_exit, _, __, ___, ____, _____):
        mock_ss = mock.MagicMock()
        del mock_ss.value
        mock_ss.name = 'mock_ss'
        mock_ss.description = 'This is a fake setting for testing.'
        mock_ss.required = True
        mock_ss.save.side_effect = [ValidationError('error'), mock.DEFAULT]
        mock_gas.return_value = {'unlinked_settings': [mock_ss, mock_ss, mock_ss, mock_ss, mock_ss, mock_ss]}

        mock_s = mock.MagicMock()
        mock_slc.side_effect = [[[]], [[mock_s]], [[mock_s]], [[mock_s]], [[mock_s]], [[mock_s]]]

        mock_exit.side_effect = SystemExit

        self.assertRaises(SystemExit, install_commands.run_interactive_services, 'foo')

        po_call_args = mock_pretty_output().__enter__().write.call_args_list
        self.assertEqual('Running Interactive Service Mode. Any configuration options in services.yml or '
                         'portal_config.yml will be ignored...', po_call_args[0][0][0])
        self.assertIn("Hit return at any time to skip a step.", po_call_args[1][0][0])
        self.assertIn("Configuring mock_ss", po_call_args[2][0][0])
        self.assertIn("Type: MagicMock", po_call_args[3][0][0])
        self.assertIn(f"Description: {mock_ss.description}", po_call_args[3][0][0])
        self.assertIn(f"Required: {mock_ss.required}", po_call_args[3][0][0])
        self.assertIn("No compatible services found.", po_call_args[4][0][0])
        self.assertIn("tethys services create persistent -h", po_call_args[4][0][0])
        self.assertIn("Enter the service ID/Name", po_call_args[7][0][0])
        self.assertIn("Incorrect service ID/Name. Please try again.", po_call_args[8][0][0])
        self.assertIn("Enter the service ID/Name", po_call_args[9][0][0])
        self.assertIn(f"Skipping setup of {mock_ss.name}", po_call_args[13][0][0])
        self.assertEqual("service_type_not_found Skipping...", po_call_args[17][0][0])
        self.assertEqual("setting_type_not_found Skipping...", po_call_args[21][0][0])
        self.assertEqual("\nInstall Command cancelled.", po_call_args[25][0][0])

        mock_lstas.assert_called_with('persistent', '1', 'foo', 'ps_database', 'mock_ss')
        mock_exit.assert_called_with(0)

    @mock.patch('builtins.input', side_effect=['x', 5])
    @mock.patch('tethys_cli.install_commands.get_app_settings')
    @mock.patch('tethys_cli.cli_colors.pretty_output')
    def test_interactive_no_settings(self, mock_pretty_output, mock_gas, _):
        mock_cs = mock.MagicMock()
        mock_cs.name = 'mock_cs'
        mock_cs.save.side_effect = [ValidationError('error'), mock.DEFAULT]
        mock_gas.return_value = None

        install_commands.run_interactive_services('foo')

        po_call_args = mock_pretty_output().__enter__().write.call_args_list
        self.assertIn('No settings found for app "foo". Skipping interactive configuration...', po_call_args[2][0][0])
Beispiel #8
0
class ResourceQuotaHandlerTest(TestCase):
    def setUp(self):
        user = User.objects.create_user(username="******",
                                        email="*****@*****.**",
                                        password="******")

        self.resource_quota_handler = WorkspaceQuotaHandler(user)
        self.resource_quota_user = ResourceQuota(
            codename='test_user_codename',
            name='test_name',
            description='test_description',
            default=1.21,
            units='gb',
            applies_to='django.contrib.auth.models.User',
            impose_default=False,
            help='Exceeded quota',
            _handler='tethys_quotas.handlers.workspace.WorkspaceQuotaHandler')
        self.resource_quota_user.save()
        self.entity_quota_user = UserQuota(
            resource_quota=self.resource_quota_user,
            entity=user,
            value=100,
        )
        self.entity_quota_user.save()

        self.resource_quota_app = ResourceQuota(
            codename='test_app_codename',
            name='test_name',
            description='test_description',
            default=1.21,
            units='gb',
            applies_to='tethys_apps.models.TethysApp',
            impose_default=True,
            help='Exceeded quota',
            _handler='tethys_quotas.handlers.workspace.WorkspaceQuotaHandler')
        self.resource_quota_app.save()

        self.app_model = TethysApp(name='Test App')
        self.app_model.save()
        self.entity_quota_app = TethysAppQuota(
            resource_quota=self.resource_quota_app,
            entity=self.app_model,
            value=200,
        )
        self.entity_quota_app.save()

    def tearDown(self):
        self.resource_quota_user.delete()
        self.entity_quota_user.delete()
        self.resource_quota_app.delete()
        self.entity_quota_app.delete()
        self.app_model.delete()

    @mock.patch('tethys_quotas.utilities.log')
    def test_rqh_check_rq_dne(self, _):
        bad_rqh = WorkspaceQuotaHandler("not.a.user")
        self.assertTrue(bad_rqh.check())

    @mock.patch('tethys_quotas.utilities.log')
    def test_rqh_check_eq_dne(self, _):
        with transaction.atomic():
            user = User.objects.create_user(username="******",
                                            email="*****@*****.**",
                                            password="******")
            resource_quota_handler = WorkspaceQuotaHandler(user)
            self.assertEquals("workspace_quota",
                              resource_quota_handler.codename)
            self.assertTrue(resource_quota_handler.check())

    @mock.patch('tethys_quotas.utilities.log')
    def test_rqh_check_eq_passes(self, _):
        self.assertTrue(self.resource_quota_handler.check())

    @mock.patch('tethys_quotas.utilities.log')
    def test_rqh_check_eq_app_passes(self, _):
        resource_quota_handler = WorkspaceQuotaHandler(self.app_model)

        self.assertTrue(resource_quota_handler.check())
Beispiel #9
0
class TestInstallCommands(TestCase):
    def setUp(self):
        from tethys_apps.models import TethysApp
        self.src_dir = os.path.dirname(
            os.path.dirname(os.path.dirname(__file__)))
        self.root_app_path = os.path.join(self.src_dir, 'apps',
                                          'tethysapp-test_app')
        self.app_model = TethysApp(name='test_app', package='test_app')
        self.app_model.save()
        pass

    def tearDown(self):
        self.app_model.delete()
        pass

    @mock.patch('tethys_cli.cli_colors.pretty_output')
    @mock.patch('builtins.input', side_effect=['x', 'n'])
    @mock.patch('tethys_cli.install_commands.exit')
    @mock.patch('tethys_cli.install_commands.call')
    def test_install_file_not_generate(self, mock_call, mock_exit, _, __):
        args = mock.MagicMock(file=None, quiet=False)

        mock_exit.side_effect = SystemExit

        self.assertRaises(SystemExit, install_commands.install_command, args)
        self.assertEqual(3, len(mock_call.call_args_list))

        mock_exit.assert_called_with(0)

    @mock.patch('tethys_cli.cli_colors.pretty_output')
    @mock.patch('builtins.input', side_effect=['y'])
    @mock.patch('tethys_cli.install_commands.call')
    @mock.patch('tethys_cli.install_commands.exit')
    def test_install_file_generate(self, mock_exit, mock_call, _, __):
        args = mock.MagicMock(file=None, quiet=False)
        check_call = ['tethys', 'gen', 'install']

        mock_exit.side_effect = SystemExit

        self.assertRaises(SystemExit, install_commands.install_command, args)
        mock_call.assert_called_with(check_call)
        mock_exit.assert_called_with(0)

    @mock.patch('tethys_cli.install_commands.run_services')
    @mock.patch('tethys_cli.install_commands.call')
    @mock.patch('tethys_cli.install_commands.exit')
    @mock.patch('tethys_cli.cli_colors.pretty_output')
    def test_no_conda_input_file(self, mock_pretty_output, mock_exit, _, __):
        file_path = os.path.join(self.root_app_path, 'install-no-dep.yml')
        args = mock.MagicMock(file=file_path, verbose=False)
        mock_exit.side_effect = SystemExit

        self.assertRaises(SystemExit, install_commands.install_command, args)

        po_call_args = mock_pretty_output().__enter__().write.call_args_list
        self.assertIn("Running application install....", po_call_args[0][0][0])
        self.assertIn(
            "Quiet mode: No additional service setting validation will be performed.",
            po_call_args[1][0][0])
        self.assertIn("Services Configuration Completed.",
                      po_call_args[2][0][0])
        self.assertIn("Skipping syncstores.", po_call_args[3][0][0])
        mock_exit.assert_called_with(0)

    @mock.patch('tethys_cli.install_commands.run_services')
    @mock.patch('tethys_cli.install_commands.call')
    @mock.patch('tethys_cli.install_commands.exit')
    @mock.patch('tethys_cli.cli_colors.pretty_output')
    def test_input_file_with_post(self, mock_pretty_output, mock_exit, _, __):
        file_path = os.path.join(self.root_app_path, 'install-with-post.yml')
        args = mock.MagicMock(file=file_path, verbose=False)
        mock_exit.side_effect = SystemExit

        self.assertRaises(SystemExit, install_commands.install_command, args)

        po_call_args = mock_pretty_output().__enter__().write.call_args_list
        self.assertIn("Running application install....", po_call_args[1][0][0])
        self.assertIn(
            "Quiet mode: No additional service setting validation will be performed.",
            po_call_args[2][0][0])
        self.assertIn("Services Configuration Completed.",
                      po_call_args[3][0][0])
        self.assertIn("Skipping syncstores.", po_call_args[4][0][0])
        self.assertIn("Running post installation tasks...",
                      po_call_args[5][0][0])
        self.assertIn("Post Script Result: b'test\\n'", po_call_args[6][0][0])
        mock_exit.assert_called_with(0)

    @mock.patch('tethys_cli.install_commands.run_services')
    @mock.patch('tethys_cli.install_commands.run_sync_stores')
    @mock.patch('tethys_cli.install_commands.run_interactive_services')
    @mock.patch('tethys_cli.install_commands.call')
    @mock.patch('tethys_cli.install_commands.run_portal_install',
                return_value=False)
    @mock.patch('tethys_cli.install_commands.run_services')
    @mock.patch('tethys_cli.install_commands.exit')
    @mock.patch('tethys_cli.cli_colors.pretty_output')
    def test_skip_input_file(self, mock_pretty_output, mock_exit, _, __, ___,
                             ____, _____, ______):
        file_path = os.path.join(self.root_app_path, 'install-skip-setup.yml')
        mock_exit.side_effect = SystemExit

        args = mock.MagicMock(file=file_path, verbose=False)
        self.assertRaises(SystemExit, install_commands.install_command, args)

        args = mock.MagicMock(file=file_path, develop=False)
        self.assertRaises(SystemExit, install_commands.install_command, args)

        args = mock.MagicMock(file=file_path,
                              verbose=False,
                              develop=False,
                              force_services=False,
                              quiet=False,
                              no_sync=False)
        self.assertRaises(SystemExit, install_commands.install_command, args)

        po_call_args = mock_pretty_output().__enter__().write.call_args_list
        self.assertEqual("Skipping package installation, Skip option found.",
                         po_call_args[0][0][0])
        mock_exit.assert_called_with(0)

    @mock.patch('tethys_cli.install_commands.run_services')
    @mock.patch('tethys_cli.install_commands.call')
    @mock.patch('tethys_cli.install_commands.conda_run',
                return_value=['', '', 1])
    @mock.patch('tethys_cli.install_commands.exit')
    @mock.patch('tethys_cli.cli_colors.pretty_output')
    def test_conda_and_pip_package_install(self, mock_pretty_output, mock_exit,
                                           mock_conda_run, mock_call, _):
        file_path = os.path.join(self.root_app_path, 'install-dep.yml')
        args = mock.MagicMock(file=file_path,
                              develop=False,
                              verbose=False,
                              services_file=None)
        mock_exit.side_effect = SystemExit
        self.assertRaises(SystemExit, install_commands.install_command, args)

        mock_conda_run.assert_called_with(Commands.INSTALL,
                                          '-c',
                                          'tacaswell',
                                          'geojson',
                                          use_exception_handler=False,
                                          stdout=None,
                                          stderr=None)

        po_call_args = mock_pretty_output().__enter__().write.call_args_list
        self.assertEqual("Running conda installation tasks...",
                         po_call_args[0][0][0])
        self.assertIn("Warning: Packages installation ran into an error.",
                      po_call_args[1][0][0])
        self.assertEqual("Running pip installation tasks...",
                         po_call_args[2][0][0])
        self.assertEqual("Running application install....",
                         po_call_args[3][0][0])
        self.assertEqual(
            "Quiet mode: No additional service setting validation will be performed.",
            po_call_args[4][0][0])
        self.assertEqual("Services Configuration Completed.",
                         po_call_args[5][0][0])

        self.assertEqual(['pip', 'install', 'see'],
                         mock_call.mock_calls[0][1][0])
        self.assertEqual(['python', 'setup.py', 'clean', '--all'],
                         mock_call.mock_calls[1][1][0])
        self.assertEqual(['python', 'setup.py', 'install'],
                         mock_call.mock_calls[2][1][0])
        self.assertEqual(['tethys', 'db', 'sync'],
                         mock_call.mock_calls[3][1][0])

        mock_exit.assert_called_with(0)

    @mock.patch('builtins.input', side_effect=['x', 5])
    @mock.patch('tethys_cli.install_commands.get_app_settings')
    @mock.patch('tethys_cli.cli_colors.pretty_output')
    def test_interactive_custom_setting_set(self, mock_pretty_output,
                                            mock_get_settings, _):
        mock_cs = mock.MagicMock()
        mock_cs.name = 'mock_cs'
        mock_cs.save.side_effect = [ValidationError('error'), mock.DEFAULT]
        mock_get_settings.return_value = {'unlinked_settings': [mock_cs]}

        install_commands.run_interactive_services('foo')

        po_call_args = mock_pretty_output().__enter__().write.call_args_list
        self.assertIn("Configuring mock_cs", po_call_args[2][0][0])
        self.assertIn("Type", po_call_args[3][0][0])
        self.assertIn("Enter the desired value", po_call_args[4][0][0])
        self.assertIn("Incorrect value type", po_call_args[5][0][0])
        self.assertIn("Enter the desired value", po_call_args[6][0][0])
        self.assertEqual(mock_cs.name + " successfully set with value: 5.",
                         po_call_args[7][0][0])

    @mock.patch('builtins.input', side_effect=[''])
    @mock.patch('tethys_cli.install_commands.get_app_settings')
    @mock.patch('tethys_cli.cli_colors.pretty_output')
    def test_interactive_custom_setting_skip(self, mock_pretty_output,
                                             mock_get_settings, _):
        mock_cs = mock.MagicMock()
        mock_cs.name = 'mock_cs'
        mock_get_settings.return_value = {'unlinked_settings': [mock_cs]}

        install_commands.run_interactive_services('foo')

        po_call_args = mock_pretty_output().__enter__().write.call_args_list
        self.assertIn("Configuring mock_cs", po_call_args[2][0][0])
        self.assertIn("Type", po_call_args[3][0][0])
        self.assertIn("Enter the desired value", po_call_args[4][0][0])
        self.assertEqual(f"Skipping setup of {mock_cs.name}",
                         po_call_args[5][0][0])

    @mock.patch('builtins.input', side_effect=KeyboardInterrupt)
    @mock.patch('tethys_cli.install_commands.exit')
    @mock.patch('tethys_cli.install_commands.get_app_settings')
    @mock.patch('tethys_cli.cli_colors.pretty_output')
    def test_interactive_custom_setting_interrupt(self, mock_pretty_output,
                                                  mock_get_settings, mock_exit,
                                                  _):
        mock_cs = mock.MagicMock()
        mock_cs.name = 'mock_cs'
        mock_get_settings.return_value = {'unlinked_settings': [mock_cs]}

        mock_exit.side_effect = SystemExit

        self.assertRaises(SystemExit,
                          install_commands.run_interactive_services, 'foo')

        po_call_args = mock_pretty_output().__enter__().write.call_args_list
        self.assertIn("Configuring mock_cs", po_call_args[2][0][0])
        self.assertIn("Type", po_call_args[3][0][0])
        self.assertIn("Enter the desired value", po_call_args[4][0][0])
        self.assertEqual("\nInstall Command cancelled.", po_call_args[5][0][0])

        mock_exit.assert_called_with(0)

    @mock.patch('builtins.input',
                side_effect=['1', '1', '', KeyboardInterrupt])
    @mock.patch('tethys_cli.install_commands.get_setting_type',
                return_value='persistent')
    @mock.patch('tethys_cli.install_commands.get_service_from_id',
                side_effect=ValueError)
    @mock.patch('tethys_cli.install_commands.get_service_from_name',
                side_effect=[False, {
                    'service_type': 'st',
                    'linkParam': 'lp'
                }])
    @mock.patch('tethys_cli.install_commands.exit')
    @mock.patch('tethys_cli.install_commands.services_list_command')
    @mock.patch('tethys_cli.install_commands.get_app_settings')
    @mock.patch('tethys_cli.install_commands.link_service_to_app_setting')
    @mock.patch('tethys_cli.cli_colors.pretty_output')
    def test_interactive_service_setting_all(self, mock_pretty_output,
                                             mock_lstas, mock_get_settings,
                                             mock_slc, mock_exit, ____, ___,
                                             __, _):
        mock_ss = mock.MagicMock()
        del mock_ss.value
        mock_ss.name = 'mock_ss'
        mock_ss.save.side_effect = [ValidationError('error'), mock.DEFAULT]
        mock_get_settings.return_value = {
            'unlinked_settings': [mock_ss, mock_ss, mock_ss, mock_ss]
        }

        mock_s = mock.MagicMock()
        mock_slc.side_effect = [[[]], [[mock_s]], [[mock_s]], [[mock_s]]]

        mock_exit.side_effect = SystemExit

        self.assertRaises(SystemExit,
                          install_commands.run_interactive_services, 'foo')

        po_call_args = mock_pretty_output().__enter__().write.call_args_list
        self.assertIn("Configuring mock_ss", po_call_args[2][0][0])
        self.assertIn("Type", po_call_args[3][0][0])
        self.assertIn("No compatible services found.", po_call_args[4][0][0])
        self.assertIn("Enter the service ID/Name", po_call_args[7][0][0])
        self.assertIn("Incorrect service ID/Name.", po_call_args[8][0][0])
        self.assertIn("Enter the service ID/Name", po_call_args[9][0][0])
        self.assertIn(f"Skipping setup of {mock_ss.name}",
                      po_call_args[13][0][0])
        self.assertEqual("\nInstall Command cancelled.",
                         po_call_args[17][0][0])

        mock_lstas.assert_called_with('st', '1', 'foo', 'lp', 'mock_ss')
        mock_exit.assert_called_with(0)

    def test_get_setting_type(self):
        from tethys_apps.models import PersistentStoreDatabaseSetting

        self.assertEqual(
            'persistent',
            install_commands.get_setting_type(
                PersistentStoreDatabaseSetting()))
Beispiel #10
0
class TestTethysAppAdmin(unittest.TestCase):
    def setUp(self):
        from tethys_apps.models import TethysApp
        self.src_dir = os.path.dirname(
            os.path.dirname(os.path.dirname(__file__)))
        self.root_app_path = os.path.join(self.src_dir, 'apps',
                                          'tethysapp-test_app')
        self.app_model = TethysApp(name='test_app', package='test_app')
        self.app_model.save()

        from django.contrib.auth.models import ContentType, Group, Permission

        app_content_type_id = ContentType.objects.get(app_label='tethys_apps',
                                                      model='tethysapp').pk
        self.perm_model = Permission(name='Test Perm | Test',
                                     content_type_id=app_content_type_id,
                                     codename='test_perm:test')
        self.perm_model.save()

        self.group_model = Group(name='test_group')
        self.group_model.save()

    def tearDown(self):
        self.app_model.delete()
        self.perm_model.delete()
        self.group_model.delete()

    def test_TethysAppSettingInline(self):
        expected_template = 'tethys_portal/admin/edit_inline/tabular.html'
        TethysAppSettingInline.model = mock.MagicMock()
        ret = TethysAppSettingInline(mock.MagicMock(), mock.MagicMock())
        self.assertEqual(expected_template, ret.template)

    def test_has_delete_permission(self):
        TethysAppSettingInline.model = mock.MagicMock()
        ret = TethysAppSettingInline(mock.MagicMock(), mock.MagicMock())
        self.assertFalse(ret.has_delete_permission(mock.MagicMock()))

    def test_has_add_permission(self):
        TethysAppSettingInline.model = mock.MagicMock()
        ret = TethysAppSettingInline(mock.MagicMock(), mock.MagicMock())
        self.assertFalse(ret.has_add_permission(mock.MagicMock()))

    def test_CustomSettingInline(self):
        expected_readonly_fields = ('name', 'description', 'type', 'required')
        expected_fields = ('name', 'description', 'type', 'value', 'required')
        expected_model = CustomSetting

        ret = CustomSettingInline(mock.MagicMock(), mock.MagicMock())

        self.assertEqual(expected_readonly_fields, ret.readonly_fields)
        self.assertEqual(expected_fields, ret.fields)
        self.assertEqual(expected_model, ret.model)

    def test_DatasetServiceSettingInline(self):
        expected_readonly_fields = ('name', 'description', 'required',
                                    'engine')
        expected_fields = ('name', 'description', 'dataset_service', 'engine',
                           'required')
        expected_model = DatasetServiceSetting

        ret = DatasetServiceSettingInline(mock.MagicMock(), mock.MagicMock())

        self.assertEqual(expected_readonly_fields, ret.readonly_fields)
        self.assertEqual(expected_fields, ret.fields)
        self.assertEqual(expected_model, ret.model)

    def test_SpatialDatasetServiceSettingInline(self):
        expected_readonly_fields = ('name', 'description', 'required',
                                    'engine')
        expected_fields = ('name', 'description', 'spatial_dataset_service',
                           'engine', 'required')
        expected_model = SpatialDatasetServiceSetting

        ret = SpatialDatasetServiceSettingInline(mock.MagicMock(),
                                                 mock.MagicMock())

        self.assertEqual(expected_readonly_fields, ret.readonly_fields)
        self.assertEqual(expected_fields, ret.fields)
        self.assertEqual(expected_model, ret.model)

    def test_WebProcessingServiceSettingInline(self):
        expected_readonly_fields = ('name', 'description', 'required')
        expected_fields = ('name', 'description', 'web_processing_service',
                           'required')
        expected_model = WebProcessingServiceSetting

        ret = WebProcessingServiceSettingInline(mock.MagicMock(),
                                                mock.MagicMock())

        self.assertEqual(expected_readonly_fields, ret.readonly_fields)
        self.assertEqual(expected_fields, ret.fields)
        self.assertEqual(expected_model, ret.model)

    def test_PersistentStoreConnectionSettingInline(self):
        expected_readonly_fields = ('name', 'description', 'required')
        expected_fields = ('name', 'description', 'persistent_store_service',
                           'required')
        expected_model = PersistentStoreConnectionSetting

        ret = PersistentStoreConnectionSettingInline(mock.MagicMock(),
                                                     mock.MagicMock())

        self.assertEqual(expected_readonly_fields, ret.readonly_fields)
        self.assertEqual(expected_fields, ret.fields)
        self.assertEqual(expected_model, ret.model)

    def test_PersistentStoreDatabaseSettingInline(self):
        expected_readonly_fields = ('name', 'description', 'required',
                                    'spatial', 'initialized')
        expected_fields = ('name', 'description', 'spatial', 'initialized',
                           'persistent_store_service', 'required')
        expected_model = PersistentStoreDatabaseSetting

        ret = PersistentStoreDatabaseSettingInline(mock.MagicMock(),
                                                   mock.MagicMock())

        self.assertEqual(expected_readonly_fields, ret.readonly_fields)
        self.assertEqual(expected_fields, ret.fields)
        self.assertEqual(expected_model, ret.model)

    # Need to check
    def test_PersistentStoreDatabaseSettingInline_get_queryset(self):
        obj = PersistentStoreDatabaseSettingInline(mock.MagicMock(),
                                                   mock.MagicMock())
        mock_request = mock.MagicMock()
        obj.get_queryset(mock_request)

    def test_TethysAppQuotasSettingInline(self):
        expected_readonly_fields = ('name', 'description', 'default', 'units')
        expected_fields = ('name', 'description', 'value', 'default', 'units')
        expected_model = TethysAppQuota

        ret = TethysAppQuotasSettingInline(mock.MagicMock(), mock.MagicMock())

        self.assertEquals(expected_readonly_fields, ret.readonly_fields)
        self.assertEquals(expected_fields, ret.fields)
        self.assertEquals(expected_model, ret.model)

    # Need to check
    # def test_TethysAppQuotasSettingInline_get_queryset(self):
    #     obj = TethysAppQuotasSettingInline(mock.MagicMock(), mock.MagicMock())
    #     mock_request = mock.MagicMock()
    #     obj.get_queryset(mock_request)

    def test_TethysAppAdmin(self):
        expected_readonly_fields = (
            'package',
            'manage_app_storage',
        )
        expected_fields = (
            'package',
            'name',
            'description',
            'icon',
            'tags',
            'enabled',
            'show_in_apps_library',
            'enable_feedback',
            'manage_app_storage',
        )
        expected_inlines = [
            CustomSettingInline, PersistentStoreConnectionSettingInline,
            PersistentStoreDatabaseSettingInline, DatasetServiceSettingInline,
            SpatialDatasetServiceSettingInline,
            WebProcessingServiceSettingInline, TethysAppQuotasSettingInline
        ]

        ret = TethysAppAdmin(mock.MagicMock(), mock.MagicMock())

        self.assertEqual(expected_readonly_fields, ret.readonly_fields)
        self.assertEqual(expected_fields, ret.fields)
        self.assertEqual(expected_inlines, ret.inlines)

    def test_TethysAppAdmin_has_delete_permission(self):
        ret = TethysAppAdmin(mock.MagicMock(), mock.MagicMock())
        self.assertFalse(ret.has_delete_permission(mock.MagicMock()))

    def test_TethysAppAdmin_has_add_permission(self):
        ret = TethysAppAdmin(mock.MagicMock(), mock.MagicMock())
        self.assertFalse(ret.has_add_permission(mock.MagicMock()))

    @mock.patch('tethys_apps.admin.get_quota')
    @mock.patch('tethys_apps.admin._convert_storage_units')
    def test_TethysAppAdmin_manage_app_storage(self, mock_convert,
                                               mock_get_quota):
        ret = TethysAppAdmin(mock.MagicMock(), mock.MagicMock())
        app = mock.MagicMock()
        app.id = 1
        mock_convert.return_value = '0 bytes'
        mock_get_quota.return_value = {'quota': None}
        url = reverse('admin:clear_workspace', kwargs={'app_id': app.id})

        expected_html = format_html("""
                <span>{} of {}</span>
                <a id="clear-workspace" class="btn btn-danger btn-sm"
                href="{url}">
                Clear Workspace</a>
                """.format('0 bytes', "&#8734;", url=url))
        actual_html = ret.manage_app_storage(app)

        self.assertEquals(expected_html.replace(" ", ""),
                          actual_html.replace(" ", ""))

        mock_convert.return_value = '0 bytes'
        mock_get_quota.return_value = {'quota': 5, 'units': 'gb'}
        url = reverse('admin:clear_workspace', kwargs={'app_id': app.id})

        expected_html = format_html("""
                        <span>{} of {}</span>
                        <a id="clear-workspace" class="btn btn-danger btn-sm"
                        href="{url}">
                        Clear Workspace</a>
                        """.format('0 bytes', "0 bytes", url=url))
        actual_html = ret.manage_app_storage(app)

        self.assertEquals(expected_html.replace(" ", ""),
                          actual_html.replace(" ", ""))

    def test_TethysExtensionAdmin(self):
        expected_readonly_fields = ('package', 'name', 'description')
        expected_fields = ('package', 'name', 'description', 'enabled')

        ret = TethysExtensionAdmin(mock.MagicMock(), mock.MagicMock())

        self.assertEqual(expected_readonly_fields, ret.readonly_fields)
        self.assertEqual(expected_fields, ret.fields)

    def test_TethysExtensionAdmin_has_delete_permission(self):
        ret = TethysExtensionAdmin(mock.MagicMock(), mock.MagicMock())
        self.assertFalse(ret.has_delete_permission(mock.MagicMock()))

    def test_TethysExtensionAdmin_has_add_permission(self):
        ret = TethysExtensionAdmin(mock.MagicMock(), mock.MagicMock())
        self.assertFalse(ret.has_add_permission(mock.MagicMock()))

    @mock.patch('django.contrib.auth.admin.UserAdmin.change_view')
    @mock.patch('django.contrib.auth.admin.UserAdmin.add_view')
    def test_admin_site_register_custom_user(self, mock_ua_add_view,
                                             mock_ua_change_view):
        from django.contrib import admin
        ret = CustomUser(mock.MagicMock(), mock.MagicMock())

        # Add custom inline when change_view is called
        ret.change_view(mock.MagicMock())
        mock_ua_change_view.assert_called()
        self.assertIn(UserQuotasSettingInline, ret.inlines)

        # Remove custom inline when change_view is called
        ret.add_view(mock.MagicMock())
        mock_ua_add_view.assert_called()
        self.assertNotIn(UserQuotasSettingInline, ret.inlines)

        # Repeat to complete full cycle (change -> add -> change -> add)
        # Add custom inline when change_view is called
        ret.change_view(mock.MagicMock())
        mock_ua_change_view.assert_called()
        self.assertIn(UserQuotasSettingInline, ret.inlines)

        # Remove custom inline when change_view is called
        ret.add_view(mock.MagicMock())
        mock_ua_add_view.assert_called()
        self.assertNotIn(UserQuotasSettingInline, ret.inlines)

        # Check registration
        registry = admin.site._registry
        self.assertIn(User, registry)
        self.assertIsInstance(registry[User], CustomUser)

    def test_admin_site_register_tethys_app_admin(self):
        from django.contrib import admin
        registry = admin.site._registry
        self.assertIn(TethysApp, registry)
        self.assertIsInstance(registry[TethysApp], TethysAppAdmin)

    def test_admin_site_register_tethys_app_extension(self):
        from django.contrib import admin
        registry = admin.site._registry
        self.assertIn(TethysExtension, registry)
        self.assertIsInstance(registry[TethysExtension], TethysExtensionAdmin)

    def test_admin_site_register_proxy_app(self):
        from django.contrib import admin
        registry = admin.site._registry
        self.assertIn(ProxyApp, registry)

    @mock.patch('tethys_apps.admin.GroupObjectPermission.objects')
    @mock.patch('tethys_apps.admin.TethysApp.objects.all')
    def test_make_gop_app_access_form(self, mock_all_apps, mock_gop):
        mock_all_apps.return_value = [self.app_model]
        mock_gop.filter().values().distinct.return_value = [{'group_id': 9999}]

        ret = make_gop_app_access_form()

        self.assertIn('test_app_permissions', ret.base_fields)
        self.assertIn('test_app_groups', ret.base_fields)

    @mock.patch('tethys_apps.admin.Group.objects')
    @mock.patch('tethys_apps.admin.Permission.objects')
    @mock.patch('tethys_apps.admin.GroupObjectPermission.objects')
    @mock.patch('tethys_apps.admin.TethysApp.objects.all')
    def test_gop_form_init(self, mock_all_apps, mock_gop, mock_perms,
                           mock_groups):
        mock_all_apps.return_value = [self.app_model]
        mock_obj = mock.MagicMock(pk=True)
        mock_gop.values().distinct().filter.return_value = [{
            'object_pk':
            self.app_model.pk
        }]
        mock_gop.values_list().filter().distinct.side_effect = [
            [9999], [9999],
            mock.MagicMock(exclude=mock.MagicMock(
                return_value=[self.app_model.pk, 9999])), [self.app_model.pk]
        ]

        mock_perms.filter().exclude.side_effect = [
            mock_perms.none(), '_permissions_test'
        ]
        mock_groups.filter().exclude.return_value = '_groups_test'

        gop_app_access_form_dynamic = make_gop_app_access_form()
        ret = gop_app_access_form_dynamic(instance=mock_obj)

        self.assertIn(self.app_model, ret.fields['apps'].initial)
        self.assertEqual(ret.fields['test_app_permissions'].initial,
                         '_permissions_test')
        self.assertEqual(ret.fields['test_app_groups'].initial, '_groups_test')

    @mock.patch('tethys_apps.admin.TethysApp.objects.all')
    def test_gop_form_clean(self, mock_all_apps):
        mock_all_apps.return_value = [self.app_model]
        mock_obj = mock.MagicMock(pk=True)
        mock_data = mock.MagicMock(getlist=mock.MagicMock(return_value=[9999]))

        gop_app_access_form_dynamic = make_gop_app_access_form()
        ret = gop_app_access_form_dynamic(instance=mock_obj)

        ret.data = mock_data
        ret.cleaned_data = {}
        ret.clean()

        self.assertIn('test_app_permissions', ret.cleaned_data)
        self.assertIn('test_app_groups', ret.cleaned_data)

    @mock.patch('tethys_apps.admin.remove_perm')
    @mock.patch('tethys_apps.admin.assign_perm')
    @mock.patch('tethys_apps.admin.TethysApp.objects.all')
    def test_gop_form_save_new(self, mock_all_apps, _, __):
        mock_all_apps.return_value = [self.app_model]
        mock_obj = mock.MagicMock(pk=False)
        mock_data = mock.MagicMock(getlist=mock.MagicMock(return_value=[9999]))

        gop_app_access_form_dynamic = make_gop_app_access_form()
        ret = gop_app_access_form_dynamic(instance=mock_obj)

        ret.data = mock_data
        ret.cleaned_data = {'apps': [self.app_model]}
        ret.fields = {'apps': ret.fields['apps']}

        ret.save()

        self.assertEqual(mock_obj.save.call_count, 1)

    @mock.patch('tethys_apps.admin.assign_perm')
    @mock.patch('tethys_apps.admin.remove_perm')
    @mock.patch('tethys_apps.admin.TethysApp.objects')
    def test_gop_form_save_edit_apps(self, mock_apps, mock_remove_perm,
                                     mock_assign_perm):
        mock_apps.all.return_value = [self.app_model]
        mock_diff = mock.MagicMock(return_value=[self.app_model])
        mock_apps.filter.return_value = mock.MagicMock(difference=mock_diff,
                                                       return_value=True)
        mock_obj = mock.MagicMock(pk=True)
        mock_data = mock.MagicMock(getlist=mock.MagicMock(return_value=[9999]))

        gop_app_access_form_dynamic = make_gop_app_access_form()
        ret = gop_app_access_form_dynamic(instance=mock_obj)

        ret.data = mock_data
        ret.cleaned_data = {'apps': [self.app_model]}
        ret.fields = {'apps': ret.fields['apps']}

        ret.save()

        mock_remove_perm.assert_called_with('test_app:access_app', mock_obj,
                                            self.app_model)
        mock_assign_perm.assert_called_with('test_app:access_app', mock_obj,
                                            self.app_model)

    @mock.patch('tethys_apps.admin.assign_perm')
    @mock.patch('tethys_apps.admin.remove_perm')
    @mock.patch('tethys_apps.admin.TethysApp.objects')
    def test_gop_form_save_edit_permissions(self, mock_apps, mock_remove_perm,
                                            mock_assign_perm):
        mock_apps.all.return_value = [self.app_model]
        mock_diff = mock.MagicMock(
            side_effect=[[self.app_model], [self.perm_model]])
        mock_apps.filter.return_value = mock.MagicMock(difference=mock_diff,
                                                       return_value=True)
        mock_obj = mock.MagicMock(pk=True)
        mock_data = mock.MagicMock(getlist=mock.MagicMock(return_value=[9999]))

        gop_app_access_form_dynamic = make_gop_app_access_form()
        ret = gop_app_access_form_dynamic(instance=mock_obj)

        ret.data = mock_data
        ret.cleaned_data = {
            'apps': [self.app_model],
            'test_app_permissions': [self.perm_model]
        }
        ret.fields = {
            'apps': ret.fields['apps'],
            'test_app_permissions': ret.fields['apps']
        }

        ret.save()

        mock_remove_perm.assert_called_with('test_perm:test', mock_obj,
                                            mock_apps.filter())
        mock_assign_perm.assert_called_with('test_perm:test', mock_obj,
                                            mock_apps.filter())

    @mock.patch('tethys_apps.admin.assign_perm')
    @mock.patch('tethys_apps.admin.remove_perm')
    @mock.patch('tethys_apps.admin.GroupObjectPermission.objects')
    @mock.patch('tethys_apps.admin.TethysApp.objects')
    def test_gop_form_save_edit_groups(self, mock_apps, mock_gop,
                                       mock_remove_perm, mock_assign_perm):
        mock_apps.all.return_value = [self.app_model]
        mock_diff = mock.MagicMock(
            side_effect=[[self.app_model],
                         mock.MagicMock(values_list=mock.MagicMock(
                             distinct=[self.group_model.pk]))])
        mock_apps.filter.return_value = mock.MagicMock(difference=mock_diff,
                                                       return_value=True)
        mock_obj = mock.MagicMock(pk=True)
        mock_data = mock.MagicMock(getlist=mock.MagicMock(return_value=[9999]))
        mock_gop.filter().values_list().distinct.return_value = [
            self.perm_model.pk
        ]

        gop_app_access_form_dynamic = make_gop_app_access_form()
        ret = gop_app_access_form_dynamic(instance=mock_obj)

        ret.data = mock_data
        ret.cleaned_data = {
            'apps': [self.app_model],
            'test_app_groups': mock.MagicMock()
        }
        ret.cleaned_data['test_app_groups'].values_list(
        ).distinct.return_value = [self.group_model.pk]
        ret.fields = {
            'apps': ret.fields['apps'],
            'test_app_groups': ret.fields['apps']
        }

        ret.save()

        mock_remove_perm.assert_called_with('test_perm:test', mock_obj,
                                            mock_apps.filter())
        mock_assign_perm.assert_called_with('test_perm:test', mock_obj,
                                            mock_apps.filter())

    @mock.patch('tethys_apps.admin.tethys_log.warning')
    @mock.patch('tethys_apps.admin.make_gop_app_access_form')
    def test_admin_programming_error(self, mock_gop_form, mock_logwarning):
        mock_gop_form.side_effect = ProgrammingError

        register_custom_group()

        mock_gop_form.assert_called()
        mock_logwarning.assert_called_with('Unable to register CustomGroup.')

    @mock.patch('tethys_apps.admin.tethys_log.warning')
    @mock.patch('tethys_apps.admin.admin.site.register')
    def test_admin_user_keys_programming_error(self, mock_register,
                                               mock_logwarning):
        mock_register.side_effect = ProgrammingError

        register_user_keys_admin()

        mock_register.assert_called()
        mock_logwarning.assert_called_with('Unable to register UserKeys.')
Beispiel #11
0
    def sync_with_tethys_db(self):
        """
        Sync installed apps with database.
        """
        from django.conf import settings
        from tethys_apps.models import TethysApp

        try:
            # Make pass to add apps to db that are newly installed
            # Query to see if installed app is in the database
            db_apps = TethysApp.objects.\
                filter(package__exact=self.package).all()

            # If the app is not in the database, then add it
            if len(db_apps) == 0:
                db_app = TethysApp(
                    name=self.name,
                    package=self.package,
                    description=self.description,
                    enable_feedback=self.enable_feedback,
                    feedback_emails=self.feedback_emails,
                    index=self.index,
                    icon=self.icon,
                    root_url=self.root_url,
                    color=self.color,
                    tags=self.tags
                )
                db_app.save()

                # custom settings
                db_app.add_settings(self.custom_settings())
                # dataset services settings
                db_app.add_settings(self.dataset_service_settings())
                # spatial dataset services settings
                db_app.add_settings(self.spatial_dataset_service_settings())
                # wps settings
                db_app.add_settings(self.web_processing_service_settings())
                # persistent store settings
                db_app.add_settings(self.persistent_store_settings())

                db_app.save()

            # If the app is in the database, update developer-first attributes
            elif len(db_apps) == 1:
                db_app = db_apps[0]
                db_app.index = self.index
                db_app.icon = self.icon
                db_app.root_url = self.root_url
                db_app.color = self.color
                db_app.save()

                if hasattr(settings, 'DEBUG') and settings.DEBUG:
                    db_app.name = self.name
                    db_app.description = self.description
                    db_app.tags = self.tags
                    db_app.enable_feedback = self.enable_feedback
                    db_app.feedback_emails = self.feedback_emails
                    db_app.save()

                    # custom settings
                    db_app.add_settings(self.custom_settings())
                    # dataset services settings
                    db_app.add_settings(self.dataset_service_settings())
                    # spatial dataset services settings
                    db_app.add_settings(self.spatial_dataset_service_settings())
                    # wps settings
                    db_app.add_settings(self.web_processing_service_settings())
                    # persistent store settings
                    db_app.add_settings(self.persistent_store_settings())
                    db_app.save()

            # More than one instance of the app in db... (what to do here?)
            elif len(db_apps) >= 2:
                pass
        except Exception as e:
            tethys_log.error(e)