From ef598f95eb62f7e6718d14dae8855146b46e8297 Mon Sep 17 00:00:00 2001 From: Gervais Naoussi Date: Thu, 8 Sep 2016 09:24:27 -0400 Subject: [PATCH] [MIG] base external dbsource * Migration of base_external_dbsource to odoo 9.0 * Fixing test error * Moving test from yaml to python * Fixing pylint error in test class * Placeholder added to connection string text zone * improving test coverage --- base_external_dbsource/README.rst | 82 ++++++++++++++++ base_external_dbsource/__init__.py | 4 +- base_external_dbsource/__openerp__.py | 53 ++--------- .../base_external_dbsource_demo.xml | 15 --- .../demo/base_external_dbsource.xml | 9 ++ base_external_dbsource/models/__init__.py | 22 +++++ .../{ => models}/base_external_dbsource.py | 95 ++++++++++--------- .../test/dbsource_connect.yml | 9 -- base_external_dbsource/tests/__init__.py | 3 + .../tests/test_create_dbsource.py | 58 +++++++++++ .../base_external_dbsource.xml} | 49 ++++------ 11 files changed, 252 insertions(+), 147 deletions(-) create mode 100644 base_external_dbsource/README.rst delete mode 100644 base_external_dbsource/base_external_dbsource_demo.xml create mode 100644 base_external_dbsource/demo/base_external_dbsource.xml create mode 100644 base_external_dbsource/models/__init__.py rename base_external_dbsource/{ => models}/base_external_dbsource.py (69%) delete mode 100644 base_external_dbsource/test/dbsource_connect.yml create mode 100644 base_external_dbsource/tests/__init__.py create mode 100644 base_external_dbsource/tests/test_create_dbsource.py rename base_external_dbsource/{base_external_dbsource_view.xml => views/base_external_dbsource.xml} (56%) diff --git a/base_external_dbsource/README.rst b/base_external_dbsource/README.rst new file mode 100644 index 000000000..79760c960 --- /dev/null +++ b/base_external_dbsource/README.rst @@ -0,0 +1,82 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + +========================= +External Database Sources +========================= + +This module allows you to define connections to foreign databases using ODBC, +Oracle Client or SQLAlchemy. + +Installation +============ + +No installation required. + +Configuration +============= + +Database sources can be configured in Settings > Configuration -> Data sources. + +Depending on the database, you need: + +* to install unixodbc and python-pyodbc packages to use ODBC connections. +* to install FreeTDS driver (tdsodbc package) and configure it through ODBC toconnect to Microsoft SQL Server. +* to install and configure Oracle Instant Client and cx_Oracle python library to connect to Oracle. + + +Usage +===== + +To use this module: + +* Go to Settings > Database Structure > Database Sources +* Click on Create to enter the following information: + +* Datasource nameĀ  +* Pasword +* Connector: Choose the database to which you want to connect +* Connection stringĀ : Specify how to connect to database + +.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas + :alt: Try me on Runbot + :target: https://runbot.odoo-community.org/runbot/149/9.0 for server-tools + +Known issues / Roadmap +====================== + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed feedback `here `_. + +Credits +======= + +Contributors +------------ + +* Daniel Reis +* Maxime Chambreuil +* Gervais Naoussi + +Maintainer +---------- + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +This module is maintained by the OCA. + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +To contribute to this module, please visit http://odoo-community.org. diff --git a/base_external_dbsource/__init__.py b/base_external_dbsource/__init__.py index 3f4df04a8..ea2f55388 100644 --- a/base_external_dbsource/__init__.py +++ b/base_external_dbsource/__init__.py @@ -19,6 +19,4 @@ # ############################################################################## -from . import base_external_dbsource - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: +from . import models diff --git a/base_external_dbsource/__openerp__.py b/base_external_dbsource/__openerp__.py index 6084cf331..58d3dddde 100644 --- a/base_external_dbsource/__openerp__.py +++ b/base_external_dbsource/__openerp__.py @@ -1,48 +1,12 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# Daniel Reis, 2011 -# Additional contributions by Maxime Chambreuil, Savoir-faire Linux -# -# 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 . -# -############################################################################## - +# Copyright <2011> +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). { 'name': 'External Database Sources', - 'version': '8.0.1.3.0', + 'version': '9.0.1.0.0', 'category': 'Tools', - 'description': """ -This module allows you to define connections to foreign databases using ODBC, -Oracle Client or SQLAlchemy. - -Database sources can be configured in Settings > Configuration -> Data sources. - -Depending on the database, you need: - * to install unixodbc and python-pyodbc packages to use ODBC connections. - * to install FreeTDS driver (tdsodbc package) and configure it through ODBC to - connect to Microsoft SQL Server. - * to install and configure Oracle Instant Client and cx_Oracle python library - to connect to Oracle. - -Contributors -============ - -* Maxime Chambreuil - """, 'author': "Daniel Reis,Odoo Community Association (OCA)", - 'website': 'http://launchpad.net/addons-tko', + 'website': 'https://github.com/OCA/server-tools', 'license': 'AGPL-3', 'images': [ 'images/screenshot01.png', @@ -51,14 +15,11 @@ Contributors 'base', ], 'data': [ - 'base_external_dbsource_view.xml', + 'views/base_external_dbsource.xml', 'security/ir.model.access.csv', ], 'demo': [ - 'base_external_dbsource_demo.xml', + 'demo/base_external_dbsource.xml', ], - 'test': [ - 'test/dbsource_connect.yml', - ], - 'installable': False, + 'installable': True, } diff --git a/base_external_dbsource/base_external_dbsource_demo.xml b/base_external_dbsource/base_external_dbsource_demo.xml deleted file mode 100644 index 29e4e2eb8..000000000 --- a/base_external_dbsource/base_external_dbsource_demo.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - PostgreSQL local - dbname='postgres' password=%s - postgresql - postgresql - - - - - - diff --git a/base_external_dbsource/demo/base_external_dbsource.xml b/base_external_dbsource/demo/base_external_dbsource.xml new file mode 100644 index 000000000..82abd66cd --- /dev/null +++ b/base_external_dbsource/demo/base_external_dbsource.xml @@ -0,0 +1,9 @@ + + + + PostgreSQL local + dbname='postgres' password=%s + postgresql + postgresql + + diff --git a/base_external_dbsource/models/__init__.py b/base_external_dbsource/models/__init__.py new file mode 100644 index 000000000..76ae45df6 --- /dev/null +++ b/base_external_dbsource/models/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Daniel Reis +# 2011 +# +# 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 . +# +############################################################################## + +from . import base_external_dbsource diff --git a/base_external_dbsource/base_external_dbsource.py b/base_external_dbsource/models/base_external_dbsource.py similarity index 69% rename from base_external_dbsource/base_external_dbsource.py rename to base_external_dbsource/models/base_external_dbsource.py index 9beb69e9e..3bea4672e 100644 --- a/base_external_dbsource/base_external_dbsource.py +++ b/base_external_dbsource/models/base_external_dbsource.py @@ -21,8 +21,9 @@ import os import logging -from openerp.osv import orm, fields -from openerp.tools.translate import _ +import psycopg2 +from openerp import models, fields, api, _ +from openerp.exceptions import Warning as UserError import openerp.tools as tools _logger = logging.getLogger(__name__) @@ -62,58 +63,60 @@ except: _logger.info('Oracle libraries not available. Please install "cx_Oracle"\ python package.') -import psycopg2 CONNECTORS.append(('postgresql', 'PostgreSQL')) -class base_external_dbsource(orm.Model): +class BaseExternalDbsource(models.Model): _name = "base.external.dbsource" _description = 'External Database Sources' - _columns = { - 'name': fields.char('Datasource name', required=True, size=64), - 'conn_string': fields.text('Connection string', help=""" -Sample connection strings: -- Microsoft SQL Server: - mssql+pymssql://username:%s@server:port/dbname?charset=utf8 -- MySQL: mysql://user:%s@server:port/dbname -- ODBC: DRIVER={FreeTDS};SERVER=server.address;Database=mydb;UID=sa -- ORACLE: username/%s@//server.address:port/instance -- PostgreSQL: - dbname='template1' user='dbuser' host='localhost' port='5432' password=%s -- SQLite: sqlite:///test.db -"""), - 'password': fields.char('Password', size=40), - 'connector': fields.selection(CONNECTORS, 'Connector', - required=True, - help="If a connector is missing from the\ + name = fields.Char('Datasource name', required=True, size=64) + conn_string = fields.Text('Connection string', help=""" + Sample connection strings: + - Microsoft SQL Server: + mssql+pymssql://username:%s@server:port/dbname?charset=utf8 + - MySQL: mysql://user:%s@server:port/dbname + - ODBC: DRIVER={FreeTDS};SERVER=server.address;Database=mydb;UID=sa + - ORACLE: username/%s@//server.address:port/instance + - PostgreSQL: + dbname='template1' user='dbuser' host='localhost' port='5432' \ + password=%s + - SQLite: sqlite:///test.db + """) + password = fields.Char('Password', size=40) + connector = fields.Selection(CONNECTORS, 'Connector', required=True, + help="If a connector is missing from the\ list, check the server log to confirm\ that the required components were\ - detected."), - } + detected.") - def conn_open(self, cr, uid, id1): + @api.multi + def conn_open(self): + """The connection is open here.""" + + self.ensure_one() # Get dbsource record - data = self.browse(cr, uid, id1) + # data = self.browse(cr, uid, id1) # Build the full connection string - connStr = data.conn_string - if data.password: - if '%s' not in data.conn_string: + connStr = self.conn_string + if self.password: + if '%s' not in self.conn_string: connStr += ';PWD=%s' - connStr = connStr % data.password + connStr = connStr % self.password # Try to connect - if data.connector == 'cx_Oracle': + if self.connector == 'cx_Oracle': os.environ['NLS_LANG'] = 'AMERICAN_AMERICA.UTF8' conn = cx_Oracle.connect(connStr) - elif data.connector == 'pyodbc': + elif self.connector == 'pyodbc': conn = pyodbc.connect(connStr) - elif data.connector in ('sqlite', 'mysql', 'mssql'): + elif self.connector in ('sqlite', 'mysql', 'mssql'): conn = sqlalchemy.create_engine(connStr).connect() - elif data.connector == 'postgresql': + elif self.connector == 'postgresql': conn = psycopg2.connect(connStr) return conn - def execute(self, cr, uid, ids, sqlquery, sqlparams=None, metadata=False, + @api.multi + def execute(self, sqlquery, sqlparams=None, metadata=False, context=None): """Executes SQL and returns a list of rows. @@ -131,10 +134,10 @@ Sample connection strings: { 'cols': [ 'col_a', 'col_b', ...] , 'rows': [ (a0, b0, ...), (a1, b1, ...), ...] } """ - data = self.browse(cr, uid, ids) + # data = self.browse(cr, uid, ids) rows, cols = list(), list() - for obj in data: - conn = self.conn_open(cr, uid, obj.id) + for obj in self: + conn = obj.conn_open() if obj.connector in ["sqlite", "mysql", "mssql"]: # using sqlalchemy cur = conn.execute(sqlquery, sqlparams) @@ -154,15 +157,17 @@ Sample connection strings: else: return rows - def connection_test(self, cr, uid, ids, context=None): - for obj in self.browse(cr, uid, ids, context): + @api.multi + def connection_test(self): + """Test of connection.""" + + for obj in self: conn = False try: - conn = self.conn_open(cr, uid, obj.id) + conn = self.conn_open() except Exception as e: - raise orm.except_orm(_("Connection test failed!"), - _("Here is what we got instead:\n %s") - % tools.ustr(e)) + raise UserError(_("Connection test failed: \ + Here is what we got instead:\n %s") % tools.ustr(e)) finally: try: if conn: @@ -171,5 +176,5 @@ Sample connection strings: # ignored, just a consequence of the previous exception pass # TODO: if OK a (wizard) message box should be displayed - raise orm.except_orm(_("Connection test succeeded!"), - _("Everything seems properly set up!")) + raise UserError(_("Connection test succeeded: \ + Everything seems properly set up!")) diff --git a/base_external_dbsource/test/dbsource_connect.yml b/base_external_dbsource/test/dbsource_connect.yml deleted file mode 100644 index f1105697d..000000000 --- a/base_external_dbsource/test/dbsource_connect.yml +++ /dev/null @@ -1,9 +0,0 @@ -- - Connect to local Postgres. -- - !python {model: base.external.dbsource}: | - from openerp.osv.orm import except_orm - try: - self.connection_test(cr, uid, [ref("demo_postgre")]) - except except_orm as e: - assert e.value == u'Everything seems properly set up!' diff --git a/base_external_dbsource/tests/__init__.py b/base_external_dbsource/tests/__init__.py new file mode 100644 index 000000000..4c52d80b3 --- /dev/null +++ b/base_external_dbsource/tests/__init__.py @@ -0,0 +1,3 @@ +# -*- encoding: utf-8 -*- + +from . import test_create_dbsource diff --git a/base_external_dbsource/tests/test_create_dbsource.py b/base_external_dbsource/tests/test_create_dbsource.py new file mode 100644 index 000000000..f255fb62c --- /dev/null +++ b/base_external_dbsource/tests/test_create_dbsource.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- + +from openerp.exceptions import Warning as UserError +from openerp.tests import common +import logging + + +class TestCreateDbsource(common.TransactionCase): + """Test class for base_external_dbsource.""" + + def test_create_dbsource(self): + """source creation should succeed.""" + dbsource = self.env.ref('base_external_dbsource.demo_postgre') + try: + dbsource.connection_test() + except UserError as e: + logging.warning("Log = " + str(e)) + self.assertTrue(u'Everything seems properly set up!' in str(e)) + + def test_create_dbsource_failed(self): + """source creation without connection string should failed.""" + dbsource = self.env.ref('base_external_dbsource.demo_postgre') + + # Connection without connection_string + dbsource.conn_string = "" + try: + dbsource.connection_test() + except UserError as e: + logging.warning("Log = " + str(e)) + self.assertTrue(u'Here is what we got instead:' in str(e)) + + def test_create_dbsource_without_connector_failed(self): + """source creation with other connector should failed.""" + dbsource = self.env.ref('base_external_dbsource.demo_postgre') + + # Connection to mysql + try: + dbsource.connector = "mysql" + dbsource.connection_test() + except ValueError as e: + logging.warning("Log = " + str(e)) + self.assertTrue(u'Wrong value for' in str(e)) + + # Connection to mysql + try: + dbsource.connector = "pyodbc" + dbsource.connection_test() + except ValueError as e: + logging.warning("Log = " + str(e)) + self.assertTrue(u'Wrong value for' in str(e)) + + # Connection to oracle + try: + dbsource.connector = "cx_Oracle" + dbsource.connection_test() + except ValueError as e: + logging.warning("Log = " + str(e)) + self.assertTrue(u'Wrong value for' in str(e)) diff --git a/base_external_dbsource/base_external_dbsource_view.xml b/base_external_dbsource/views/base_external_dbsource.xml similarity index 56% rename from base_external_dbsource/base_external_dbsource_view.xml rename to base_external_dbsource/views/base_external_dbsource.xml index ad694555e..4ea5f2ade 100644 --- a/base_external_dbsource/base_external_dbsource_view.xml +++ b/base_external_dbsource/views/base_external_dbsource.xml @@ -1,8 +1,6 @@ - - - - + + base.external.dbsource.tree @@ -11,32 +9,32 @@ - - + + - + base.external.dbsource.form base.external.dbsource -
- - + + - + + + + + + - - + + + +