From 8e896af6a998d9c00945e2d316844d74b647dc92 Mon Sep 17 00:00:00 2001 From: Dave Lasley Date: Tue, 5 Jul 2016 17:12:08 -0700 Subject: [PATCH] [IMP] base_report_to_printer: Add test coverage * Add test coverage * Minor touch ups in wizard * Prefer UserError to Warning --- .../models/printing_printer.py | 10 +- base_report_to_printer/models/res_users.py | 6 +- base_report_to_printer/tests/__init__.py | 9 ++ .../tests/test_ir_actions_report_xml.py | 53 +++++++++ .../tests/test_printing_printer.py | 107 ++++++++++++++++++ .../tests/test_printing_printer_wizard.py | 105 +++++++++++++++++ base_report_to_printer/tests/test_report.py | 44 +++++++ .../tests/test_res_users.py | 28 +++++ .../wizards/printing_printer_update_wizard.py | 5 +- 9 files changed, 359 insertions(+), 8 deletions(-) create mode 100755 base_report_to_printer/tests/__init__.py create mode 100755 base_report_to_printer/tests/test_ir_actions_report_xml.py create mode 100755 base_report_to_printer/tests/test_printing_printer.py create mode 100755 base_report_to_printer/tests/test_printing_printer_wizard.py create mode 100755 base_report_to_printer/tests/test_report.py create mode 100755 base_report_to_printer/tests/test_res_users.py diff --git a/base_report_to_printer/models/printing_printer.py b/base_report_to_printer/models/printing_printer.py index dba4382..98a44a1 100644 --- a/base_report_to_printer/models/printing_printer.py +++ b/base_report_to_printer/models/printing_printer.py @@ -12,7 +12,7 @@ import os from tempfile import mkstemp from openerp import models, fields, api, _ -from openerp.exceptions import Warning +from openerp.exceptions import UserError from openerp.tools.config import config try: @@ -54,8 +54,10 @@ class PrintingPrinter(models.Model): uri = fields.Char(string='URI', readonly=True) @api.model - def update_printers_status(self): - printer_recs = self.search([]) + def update_printers_status(self, domain=None): + if domain is None: + domain = [] + printer_recs = self.search(domain) try: connection = cups.Connection(CUPS_HOST, CUPS_PORT) printers = connection.getPrinters() @@ -131,7 +133,7 @@ class PrintingPrinter(models.Model): connection = cups.Connection(CUPS_HOST, CUPS_PORT) _logger.debug('Connection to CUPS successfull') except: - raise Warning( + raise UserError( _("Failed to connect to the CUPS server on %s:%s. " "Check that the CUPS server is running and that " "you can reach it from the Odoo server.") diff --git a/base_report_to_printer/models/res_users.py b/base_report_to_printer/models/res_users.py index e5cf607..1787e81 100644 --- a/base_report_to_printer/models/res_users.py +++ b/base_report_to_printer/models/res_users.py @@ -20,8 +20,12 @@ class ResUsers(models.Model): printing_printer_id = fields.Many2one(comodel_name='printing.printer', string='Default Printer') + @api.model + def _available_action_types(self): + return _available_action_types(self) + @api.model def _user_available_action_types(self): return [(code, string) for code, string - in _available_action_types(self) + in self._available_action_types() if code != 'user_default'] diff --git a/base_report_to_printer/tests/__init__.py b/base_report_to_printer/tests/__init__.py new file mode 100755 index 0000000..90bcf20 --- /dev/null +++ b/base_report_to_printer/tests/__init__.py @@ -0,0 +1,9 @@ +# -*- coding: utf-8 -*- +# Copyright 2016 LasLabs Inc. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from . import test_printing_printer +from . import test_report +from . import test_res_users +from . import test_ir_actions_report_xml +from . import test_printing_printer_wizard diff --git a/base_report_to_printer/tests/test_ir_actions_report_xml.py b/base_report_to_printer/tests/test_ir_actions_report_xml.py new file mode 100755 index 0000000..49fd70d --- /dev/null +++ b/base_report_to_printer/tests/test_ir_actions_report_xml.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- +# Copyright 2016 LasLabs Inc. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +import mock + +from openerp.tests.common import TransactionCase + + +class TestIrActionsReportXml(TransactionCase): + + def setUp(self): + super(TestIrActionsReportXml, self).setUp() + self.Model = self.env['ir.actions.report.xml'] + self.vals = {} + + def new_record(self): + return self.Model.create(self.vals) + + def test_print_action_for_report_name_gets_report(self): + """ It should get report by name """ + with mock.patch.object(self.Model, 'env') as mk: + expect = 'test' + self.Model.print_action_for_report_name(expect) + mk['report']._get_report_from_name.assert_called_once_with( + expect + ) + + def test_print_action_for_report_name_returns_if_no_report(self): + """ It should return empty dict when no matching report """ + with mock.patch.object(self.Model, 'env') as mk: + expect = 'test' + mk['report']._get_report_from_name.return_value = False + res = self.Model.print_action_for_report_name(expect) + self.assertDictEqual( + {}, res, + ) + + def test_print_action_for_report_name_returns_if_report(self): + """ It should return correct serializable result for behaviour """ + with mock.patch.object(self.Model, 'env') as mk: + res = self.Model.print_action_for_report_name('test') + behaviour = mk['report']._get_report_from_name().behaviour()[ + mk['report']._get_report_from_name().id + ] + expect = { + 'action': behaviour['action'], + 'printer_name': behaviour['printer'].name, + } + self.assertDictEqual( + expect, res, + 'Expect %s, Got %s' % (expect, res), + ) diff --git a/base_report_to_printer/tests/test_printing_printer.py b/base_report_to_printer/tests/test_printing_printer.py new file mode 100755 index 0000000..7801fe8 --- /dev/null +++ b/base_report_to_printer/tests/test_printing_printer.py @@ -0,0 +1,107 @@ +# -*- coding: utf-8 -*- +# Copyright 2016 LasLabs Inc. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +import mock + +from openerp.tests.common import TransactionCase + +from openerp.addons.base_report_to_printer.models.printing_printer import ( + CUPS_HOST, + CUPS_PORT, +) + + +model = 'openerp.addons.base_report_to_printer.models.printing_printer' + + +class TestPrintingPrinter(TransactionCase): + + def setUp(self): + super(TestPrintingPrinter, self).setUp() + self.Model = self.env['printing.printer'] + self.printer_vals = { + 'name': 'Printer', + 'system_name': 'Sys Name', + 'default': True, + 'status': 'unknown', + 'status_message': 'Msg', + 'model': 'res.users', + 'location': 'Location', + 'uri': 'URI', + } + + def new_record(self): + return self.Model.create(self.printer_vals) + + @mock.patch('%s.cups' % model) + def test_update_printers_status_error(self, cups): + """ It should catch any exception from CUPS and update status """ + cups.Connection.side_effect = Exception + rec_id = self.new_record() + self.Model.update_printers_status() + self.assertEqual( + 'server-error', rec_id.status, + ) + + @mock.patch('%s.cups' % model) + def test_update_printers_status_inits_cups(self, cups): + """ It should init CUPS connection """ + self.new_record() + self.Model.update_printers_status() + cups.Connection.assert_called_once_with( + CUPS_HOST, CUPS_PORT, + ) + + @mock.patch('%s.cups' % model) + def test_update_printers_status_gets_all_printers(self, cups): + """ It should get all printers from CUPS server """ + self.new_record() + self.Model.update_printers_status() + cups.Connection().getPrinters.assert_called_once_with() + + @mock.patch('%s.cups' % model) + def test_update_printers_status_gets_printer(self, cups): + """ It should get printer from CUPS by system_name """ + rec_id = self.new_record() + self.Model.update_printers_status() + cups.Connection().getPrinters().get.assert_called_once_with( + rec_id.system_name, + ) + + @mock.patch('%s.cups' % model) + def test_update_printers_status_search(self, cups): + """ It should search all when no domain """ + with mock.patch.object(self.Model, 'search') as search: + self.Model.update_printers_status() + search.assert_called_once_with([]) + + @mock.patch('%s.cups' % model) + def test_update_printers_status_search_domain(self, cups): + """ It should use specific domain for search """ + with mock.patch.object(self.Model, 'search') as search: + expect = [('id', '>', 0)] + self.Model.update_printers_status(expect) + search.assert_called_once_with(expect) + + @mock.patch('%s.cups' % model) + def test_update_printers_status_update_printer(self, cups): + """ It should update from CUPS when printer identified """ + with mock.patch.object(self.Model, 'search') as search: + printer_mk = mock.MagicMock() + search.return_value = [printer_mk] + self.Model.update_printers_status() + printer_mk.update_from_cups.assert_called_once_with( + cups.Connection(), + cups.Connection().getPrinters().get(), + ) + + @mock.patch('%s.cups' % model) + def test_update_printers_status_update_unavailable(self, cups): + """ It should update status when printer is unavailable """ + rec_id = self.new_record() + cups.Connection().getPrinters().get.return_value = False + self.Model.update_printers_status() + self.assertEqual( + 'unavailable', rec_id.status, + ) diff --git a/base_report_to_printer/tests/test_printing_printer_wizard.py b/base_report_to_printer/tests/test_printing_printer_wizard.py new file mode 100755 index 0000000..2f7358c --- /dev/null +++ b/base_report_to_printer/tests/test_printing_printer_wizard.py @@ -0,0 +1,105 @@ +# -*- coding: utf-8 -*- +# Copyright 2016 LasLabs Inc. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +import mock + +from openerp.tests.common import TransactionCase +from openerp.exceptions import UserError + +from openerp.addons.base_report_to_printer.models.printing_printer import ( + CUPS_HOST, + CUPS_PORT, +) + + +model = '%s.%s' % ('openerp.addons.base_report_to_printer.wizards', + 'printing_printer_update_wizard') + + +class StopTest(Exception): + pass + + +class TestPrintingPrinterWizard(TransactionCase): + + def setUp(self): + super(TestPrintingPrinterWizard, self).setUp() + self.Model = self.env['printing.printer.update.wizard'] + self.printer_vals = { + 'printer-info': 'Info', + 'printer-make-and-model': 'Make and Model', + 'printer-location': "location", + 'device-uri': 'URI', + } + + def _record_vals(self, sys_name='sys_name'): + return { + 'name': self.printer_vals['printer-info'], + 'system_name': sys_name, + 'model': self.printer_vals['printer-make-and-model'], + 'location': self.printer_vals['printer-location'], + 'uri': self.printer_vals['device-uri'], + } + + @mock.patch('%s.cups' % model) + def test_action_ok_inits_connection(self, cups): + """ It should initialize CUPS connection """ + try: + self.Model.action_ok() + except: + pass + cups.Connection.assert_called_once_with( + CUPS_HOST, CUPS_PORT, + ) + + @mock.patch('%s.cups' % model) + def test_action_ok_gets_printers(self, cups): + """ It should get printers from CUPS """ + cups.Connection().getPrinters.return_value = { + 'sys_name': self.printer_vals, + } + self.Model.action_ok() + cups.Connection().getPrinters.assert_called_once_with() + + @mock.patch('%s.cups' % model) + def test_action_ok_raises_warning_on_error(self, cups): + """ It should raise Warning on any error """ + cups.Connection.side_effect = StopTest + with self.assertRaises(UserError): + self.Model.action_ok() + + @mock.patch('%s.cups' % model) + def test_action_ok_creates_new_printer(self, cups): + """ It should create new printer w/ proper vals """ + cups.Connection().getPrinters.return_value = { + 'sys_name': self.printer_vals, + } + self.Model.action_ok() + rec_id = self.env['printing.printer'].search([ + ('system_name', '=', 'sys_name') + ], + limit=1, + ) + self.assertTrue(rec_id) + for key, val in self._record_vals().iteritems(): + self.assertEqual( + val, getattr(rec_id, key), + ) + + @mock.patch('%s.cups' % model) + def test_action_ok_skips_existing_printer(self, cups): + """ It should not recreate existing printers """ + cups.Connection().getPrinters.return_value = { + 'sys_name': self.printer_vals, + } + self.env['printing.printer'].create( + self._record_vals() + ) + self.Model.action_ok() + res_ids = self.env['printing.printer'].search([ + ('system_name', '=', 'sys_name') + ]) + self.assertEqual( + 1, len(res_ids), + ) diff --git a/base_report_to_printer/tests/test_report.py b/base_report_to_printer/tests/test_report.py new file mode 100755 index 0000000..2f7f272 --- /dev/null +++ b/base_report_to_printer/tests/test_report.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +# Copyright 2016 LasLabs Inc. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from openerp.tests.common import TransactionCase + + +class StopTest(Exception): + pass + + +class TestReport(TransactionCase): + + def setUp(self): + super(TestReport, self).setUp() + self.Model = self.env['report'] + self.report_vals = {} + + def new_record(self): + return self.Model.create(self.report_vals) + + def test_can_print_report_context_skip(self): + """ It should return False based on context """ + rec_id = self.new_record().with_context( + must_skip_send_to_printer=True + ) + res = rec_id._can_print_report( + {'action': 'server'}, True, True + ) + self.assertFalse(res) + + def test_can_print_report_true(self): + """ It should return True when server print allowed """ + res = self.new_record()._can_print_report( + {'action': 'server'}, True, True + ) + self.assertTrue(res) + + def test_can_print_report_false(self): + """ It should return False when server print not allowed """ + res = self.new_record()._can_print_report( + {'action': 'server'}, True, False + ) + self.assertFalse(res) diff --git a/base_report_to_printer/tests/test_res_users.py b/base_report_to_printer/tests/test_res_users.py new file mode 100755 index 0000000..3db8165 --- /dev/null +++ b/base_report_to_printer/tests/test_res_users.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +# Copyright 2016 LasLabs Inc. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from openerp.tests.common import TransactionCase + + +class TestResUsers(TransactionCase): + + def setUp(self): + super(TestResUsers, self).setUp() + self.user_vals = {'name': 'Test', + 'login': 'login', + } + + def new_record(self): + return self.env['res.users'].create(self.user_vals) + + def test_available_action_types_excludes_user_default(self): + """ It should not contain `user_default` in avail actions """ + self.user_vals['printing_action'] = 'user_default' + with self.assertRaises(ValueError): + self.new_record() + + def test_available_action_types_includes_something_else(self): + """ It should still contain other valid keys """ + self.user_vals['printing_action'] = 'server' + self.assertTrue(self.new_record()) diff --git a/base_report_to_printer/wizards/printing_printer_update_wizard.py b/base_report_to_printer/wizards/printing_printer_update_wizard.py index d4d3492..b4f81fc 100644 --- a/base_report_to_printer/wizards/printing_printer_update_wizard.py +++ b/base_report_to_printer/wizards/printing_printer_update_wizard.py @@ -26,9 +26,8 @@ class PrintingPrinterUpdateWizard(models.TransientModel): _name = 'printing.printer.update.wizard' _description = 'Printing Printer Update Wizard' - @api.multi + @api.model def action_ok(self): - self.ensure_one() # Update Printers printer_obj = self.env['printing.printer'] try: @@ -57,7 +56,7 @@ class PrintingPrinterUpdateWizard(models.TransientModel): 'location': printer.get('printer-location', False), 'uri': printer.get('device-uri', False), } - self.env['printing.printer'].create(values) + printer_obj.create(values) _logger.info( 'Created new printer %s with URI %s' % (values['name'], values['uri']))