ah That diff was generated before the python 3 patch was applied. This should work against master
Cheers, George On Tue, Jan 24, 2017 at 4:43 AM, Dave Page <dp...@pgadmin.org> wrote: > On Fri, Jan 20, 2017 at 5:33 PM, George Gelashvili > <ggelashv...@pivotal.io> wrote: > > Thanks for bringing that to our attention! Here's the latest patch > > piranha:pgadmin4 dpage$ git apply > ~/Downloads/acceptance-tests-with-server-start-and-polling.diff > error: patch failed: web/regression/test_utils.py:69 > error: web/regression/test_utils.py: patch does not apply > > :-( > > > On Fri, Jan 20, 2017 at 10:38 AM, Dave Page <dp...@pgadmin.org> wrote: > >> > >> On Thu, Jan 19, 2017 at 10:07 PM, George Gelashvili > >> <ggelashv...@pivotal.io> wrote: > >> > > >> > Here is an updated patch which starts the server up when the test > starts > >> > and > >> > uses the values from config.py for server name etc. It still requires > >> > installing chromedriver before running. Should we add something to the > >> > readme about that? > >> > >> Yes, we definitely should (including download site URL) > >> > >> > On Tue, Jan 17, 2017 at 11:09 AM, Atira Odhner <aodh...@pivotal.io> > >> > wrote: > >> >> > >> >> Thanks for your feedback, Dave! > >> >> > >> >> We can put the tests under the regression directory. I think that > makes > >> >> sense. > >> >> I'm not picturing these tests being module specific, but we may want > to > >> >> enable running it as a separate suite of tests. > >> >> > >> >> Thanks for the callout about the port and title. We'll make sure > those > >> >> are > >> >> pulled from config or that the pgAdmin server is spun up by the test > >> >> with > >> >> specific values. > >> >> > >> >> I have a couple ideas about why the test might not have been running > >> >> for > >> >> you. I think the patch we attached didn't spin up its own pgAdmin yet > >> >> and it > >> >> definitely doesn't fill in username/password if your app is running > >> >> that > >> >> way. That's part of the WIP-ness :-P > >> >> > >> >> -Tira > >> >> > >> >> Hi > >> >> > >> >> On Thu, Jan 12, 2017 at 10:41 PM, George Gelashvili > >> >> <ggelashvili(at)pivotal(dot)io> wrote: > >> >> > here's the patch we forgot to attach. Also, you can see work on our > >> >> > branch > >> >> > at: > >> >> > > >> >> > > >> >> > https://github.com/pivotalsoftware/pgadmin4/tree/ > pivotal/acceptance-tests > >> >> > > >> >> > On Thu, Jan 12, 2017 at 5:26 PM, George Gelashvili > >> >> > <ggelashvili(at)pivotal(dot)io> > >> >> > wrote: > >> >> >> > >> >> >> Hi there, > >> >> >> > >> >> >> We are working on browser-automation-based acceptance tests that > >> >> >> exercise > >> >> >> pgAdmin4 the way a user might. > >> >> > >> >> Nice! > >> >> > >> >> >> The first "connect to database" test works, but at the moment > >> >> >> depends > >> >> >> on > >> >> >> Chrome and chromedriver. We would appreciate feedback on any > >> >> >> possible > >> >> >> license or code style issues at this point, as well as any > thoughts > >> >> >> on > >> >> >> adding this sort of test to the codebase. > >> >> > >> >> A few thoughts: > >> >> > >> >> - If these tests are to run as part of the regression suite, the > >> >> framework for them should live under that directory. > >> >> > >> >> - Are any of the tests likely to be module-specific? If so, they > >> >> should really be part of the relevant module as the regression tests > >> >> are. If they're more general/less tightly coupled, then I don't see a > >> >> problem with them residing where they are. > >> >> > >> >> - Please take care not to include changes to .gitgnore files that > >> >> aren't relevant to the rest of us. > >> >> > >> >> - The port number is hard-coded in the test. > >> >> > >> >> - You've hard-coded the string "pgAdmin 4". We've tried to keep that > >> >> title as a config option in config.py, so you should pull the string > >> >> from there rather than hard-coding it. > >> >> > >> >> - The connect test fails for me (Mac, Python 2.7). I have a suspicion > >> >> that this may be because when the test starts chromedriver, OS X > >> >> prompts the user about whether a listening port should be opened, but > >> >> the tests don't wait (though, I tested with 3 servers configured and > >> >> it failed with the same error on the second and third as well, long > >> >> after I clicked OK on the prompt): > >> >> > >> >> Traceback (most recent call last): > >> >> File > >> >> > >> >> "/Users/dpage/git/pgadmin4/web/acceptance/test_connects_ > to_database.py", > >> >> line 32, in runTest > >> >> self.assertEqual("pgAdmin 4", self.driver.title) > >> >> AssertionError: 'pgAdmin 4' != u'localhost' > >> >> > >> >> - Please keep tests in the pgadmin. namespace > (pgadmin.acceptance.??). > >> >> > >> >> - It looks like running a single test won't work yet (because of > >> >> TestsGeneratorRegistry.load_generators('pgadmin.%s.tests' % > >> >> arguments['pkg'])) > >> >> > >> >> Thanks! > >> >> > >> >> -- > >> >> Dave Page > >> >> Blog: http://pgsnake.blogspot.com > >> >> Twitter: @pgsnake > >> >> > >> >> EnterpriseDB UK: http://www.enterprisedb.com > >> >> The Enterprise PostgreSQL Company > >> >> > >> >> > >> > > >> > > >> > > >> > -- > >> > Sent via pgadmin-hackers mailing list (pgadmin-hackers@postgresql.org > ) > >> > To make changes to your subscription: > >> > http://www.postgresql.org/mailpref/pgadmin-hackers > >> > > >> > >> > >> > >> -- > >> Dave Page > >> Blog: http://pgsnake.blogspot.com > >> Twitter: @pgsnake > >> > >> EnterpriseDB UK: http://www.enterprisedb.com > >> The Enterprise PostgreSQL Company > > > > > > > > -- > Dave Page > Blog: http://pgsnake.blogspot.com > Twitter: @pgsnake > > EnterpriseDB UK: http://www.enterprisedb.com > The Enterprise PostgreSQL Company >
diff --git a/requirements_py2.txt b/requirements_py2.txt index 51170a45..de167121 100644 --- a/requirements_py2.txt +++ b/requirements_py2.txt @@ -36,6 +36,7 @@ testscenarios==0.5.0 testtools==2.0.0 traceback2==1.4.0 unittest2==1.1.0 +selenium==3.0.2 Werkzeug==0.9.6 WTForms==2.0.2 sqlparse==0.1.19 diff --git a/requirements_py3.txt b/requirements_py3.txt index f68db7a8..9565a6e4 100644 --- a/requirements_py3.txt +++ b/requirements_py3.txt @@ -35,6 +35,7 @@ testscenarios==0.5.0 testtools==2.0.0 traceback2==1.4.0 unittest2==1.1.0 +selenium==3.0.2 Werkzeug==0.9.6 WTForms==2.0.2 sqlparse==0.1.19 diff --git a/web/pgadmin/acceptance/__init__.py b/web/pgadmin/acceptance/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/web/pgadmin/acceptance/tests/__init__.py b/web/pgadmin/acceptance/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/web/pgadmin/acceptance/tests/test_connects_to_database.py b/web/pgadmin/acceptance/tests/test_connects_to_database.py new file mode 100644 index 00000000..c35cd0fd --- /dev/null +++ b/web/pgadmin/acceptance/tests/test_connects_to_database.py @@ -0,0 +1,127 @@ +############################################################# +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2017, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +############################################################## + +import time + +from selenium import webdriver +from selenium.common.exceptions import NoSuchElementException +from selenium.webdriver import ActionChains + +from pgadmin.utils.route import BaseTestGenerator + +import subprocess +import os +import signal +import config + + +class ConnectsToDatabase(BaseTestGenerator): + """ + Tests that a database connection can be created from the UI + """ + + def setUp(self): + if config.SERVER_MODE: + self.skipTest("Currently, config is set to start pgadmin in server mode. " + "This test doesn't know username and password so doesn't work in server mode") + + self.pgadmin_process = subprocess.Popen(["python", "pgAdmin4.py"], shell=False, preexec_fn=os.setsid, + stderr=open(os.devnull, 'w')) + + self.driver = webdriver.Chrome() + self.server_config = self.server + + print("opening browser") + self.driver.get("http://" + config.DEFAULT_SERVER + ":" + str(config.DEFAULT_SERVER_PORT)) + self._wait_for_app() + + def runTest(self): + self.assertEqual(config.APP_NAME, self.driver.title) + self._wait_for_spinner_to_disappear() + + self._find_by_xpath("//*[@class='aciTreeText' and .='Servers']").click() + self.driver.find_element_by_link_text("Object").click() + ActionChains(self.driver) \ + .move_to_element(self.driver.find_element_by_link_text("Create")) \ + .perform() + self._find_by_partial_link_text("Server...").click() + + self._fill_input_by_xpath("name", self.server_config['name']) + self._find_by_partial_link_text("Connection").click() + self._fill_input_by_xpath("host", self.server_config['host']) + self._fill_input_by_xpath("port", self.server_config['port']) + self._fill_input_by_xpath("username", self.server_config['username']) + self._fill_input_by_xpath("password", self.server_config['db_password']) + self._find_by_xpath("//button[contains(.,'Save')]").click() + + self._find_by_xpath("//*[@id='tree']//*[.='" + self.server_config['name'] + "']") + + def tearDown(self): + self.driver.close() + os.killpg(os.getpgid(self.pgadmin_process.pid), signal.SIGTERM) + + def failureException(self, *args, **kwargs): + self.driver.save_screenshot('/tmp/pgadmin_test_screenshot.png') + return AssertionError(*args, **kwargs) + + def _find_by_xpath(self, xpath): + return self._wait_for_element(lambda: self.driver.find_element_by_xpath(xpath)) + + def _find_by_partial_link_text(self, link_text): + return self._wait_for_element(lambda: self.driver.find_element_by_partial_link_text(link_text)) + + def _fill_input_by_xpath(self, field_name, field_content): + self._find_by_xpath("//input[@name='" + field_name + "']").clear() + self._find_by_xpath("//input[@name='" + field_name + "']").send_keys( + field_content) + + def _wait_for_element(self, find_method_with_args): + def element_if_it_exists(): + try: + element = find_method_with_args() + if element.is_displayed() & element.is_enabled(): + return element + except NoSuchElementException: + return False + + return self.__wait_for("element to exist", element_if_it_exists) + + def _wait_for_spinner_to_disappear(self): + def spinner_has_disappeared(): + try: + self.driver.find_element_by_id("pg-spinner") + return False + except NoSuchElementException: + return True + + self.__wait_for("spinner to disappear", spinner_has_disappeared) + + def _wait_for_app(self): + def page_shows_app(): + if self.driver.title == config.APP_NAME: + return True + else: + self.driver.refresh() + return False + + self.__wait_for("app to start", page_shows_app) + + def __wait_for(self, waiting_for_message, condition_met_function): + timeout = 5 + time_waited = 0 + sleep_time = 0.01 + + while time_waited < timeout: + result = condition_met_function() + if result: + return result + time_waited += sleep_time + time.sleep(sleep_time) + + self.fail("Timed out waiting for " + waiting_for_message) diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/__init__.py index f501d3d0..99fa00c7 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/__init__.py @@ -1673,8 +1673,8 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings): return make_json_response( success=1, - info=gettext("Trigger(s) have been enabled") if is_enable - else gettext("Trigger(s) have been disabled"), + info=gettext("Trigger(s) has been enabled") if is_enable + else gettext("Trigger(s) has been disabled"), data={ 'id': tid, 'scid': scid @@ -1706,7 +1706,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings): return make_json_response( success=1, - info=gettext("Table statistics have been reset"), + info=gettext("Table statistics has been reset"), data={ 'id': tid, 'scid': scid diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/exclusion_constraint/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/exclusion_constraint/__init__.py index fe7d9349..6b7f52b0 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/exclusion_constraint/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/exclusion_constraint/__init__.py @@ -816,7 +816,7 @@ class ExclusionConstraintView(PGChildNodeView): sql = render_template("/".join([self.template_path, 'create.sql']), data=data, conn=self.conn) - return sql, data['name'] + return sql, data['name'] if 'name' in data else old_data['name'] @check_precondition def sql(self, gid, sid, did, scid, tid, exid=None): diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/exclusion_constraint/templates/exclusion_constraint/js/exclusion_constraint.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/exclusion_constraint/templates/exclusion_constraint/js/exclusion_constraint.js index e7bd905c..cfe15195 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/exclusion_constraint/templates/exclusion_constraint/js/exclusion_constraint.js +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/exclusion_constraint/templates/exclusion_constraint/js/exclusion_constraint.js @@ -7,11 +7,10 @@ function($, _, S, pgAdmin, pgBrowser, Alertify) { defaults: { column: undefined, oper_class: undefined, - order: false, - nulls_order: false, + order: undefined, + nulls_order: undefined, operator:undefined, - col_type:undefined, - is_sort_nulls_applicable: true + col_type:undefined }, toJSON: function () { var d = pgBrowser.Node.Model.prototype.toJSON.apply(this, arguments); @@ -24,9 +23,26 @@ function($, _, S, pgAdmin, pgBrowser, Alertify) { },{ id: 'oper_class', label:'{{ _('Operator class') }}', type:'text', node: 'table', url: 'get_oper_class', first_empty: true, - editable: true, + editable: function(m) { + if (m instanceof Backbone.Collection) { + return true; + } + if ((_.has(m.collection, 'handler') && + !_.isUndefined(m.collection.handler) && + !_.isUndefined(m.collection.handler.get('oid')))) { + return false; + } + + if (m.collection) { + var indexType = m.collection.handler.get('amname') + return (indexType == 'btree' || _.isUndefined(indexType) || + _.isNull(indexType) || indexType == ''); + } else { + return true; + } + }, select2: { - allowClear: true, width: 'style', tags: true, + allowClear: true, width: 'style', placeholder: '{{ _("Select the operator class") }}' }, cell: Backgrid.Extension.Select2Cell.extend({ initialize: function () { @@ -39,12 +55,6 @@ function($, _, S, pgAdmin, pgBrowser, Alertify) { if (url && (indextype == 'btree' || _.isUndefined(indextype) || _.isNull(indextype) || indextype == '')) { - // Set sort_order and nulls to true if access method is btree - setTimeout(function() { - m.set('order', true); - m.set('nulls_order', true); - }, 10); - var node = this.column.get('schema_node'), eventHandler = m.top || m, node_info = this.column.get('node_info'), @@ -98,14 +108,6 @@ function($, _, S, pgAdmin, pgBrowser, Alertify) { if (m instanceof Backbone.Collection) { return true; } - else { - if (m.top.get('amname') === 'btree') { - m.set('is_sort_nulls_applicable', true); - return true; - } - m.set('is_sort_nulls_applicable', false); - return false; - } if ((_.has(m.collection, 'handler') && !_.isUndefined(m.collection.handler) && !_.isUndefined(m.collection.handler.get('oid')))) { @@ -122,15 +124,6 @@ function($, _, S, pgAdmin, pgBrowser, Alertify) { if (m instanceof Backbone.Collection) { return true; } - else { - if (m.top.get('amname') === 'btree') { - m.set('is_sort_nulls_applicable', true); - return true; - } - m.set('is_sort_nulls_applicable', false); - return false; - } - if ((_.has(m.collection, 'handler') && !_.isUndefined(m.collection.handler) && !_.isUndefined(m.collection.handler.get('oid')))) { @@ -905,15 +898,8 @@ function($, _, S, pgAdmin, pgBrowser, Alertify) { }], validate: function() { this.errorModel.clear(); - var columns = this.get('columns'), - name = this.get('name'); - - if ((_.isUndefined(name) || _.isNull(name) || name.length < 1)) { - var msg = '{{ _('Please specify name for exclusion constraint.') }}'; - this.errorModel.set('name', msg); - return msg; - } - else if ((_.isUndefined(columns) || _.isNull(columns) || columns.length < 1)) { + var columns = this.get('columns'); + if ((_.isUndefined(columns) || _.isNull(columns) || columns.length < 1)) { var msg = '{{ _('Please specify columns for exclusion constraint.') }}'; this.errorModel.set('columns', msg); return msg; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/templates/index/js/index.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/templates/index/js/index.js index 6f462652..6531ba5e 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/templates/index/js/index.js +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/templates/index/js/index.js @@ -51,8 +51,7 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) { collspcname: undefined, op_class: undefined, sort_order: false, - nulls: false, - is_sort_nulls_applicable: true + nulls: false }, schema: [ { @@ -78,7 +77,7 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) { control: 'node-ajax-options', url: 'get_collations', node: 'index' },{ id: 'op_class', label:'{{ _('Operator class') }}', - cell: NodeAjaxOptionsDepsCell, tags: true, + cell: NodeAjaxOptionsDepsCell, type: 'text', disabled: 'checkAccessMethod', editable: function(m) { // Header cell then skip @@ -109,19 +108,13 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) { },{ id: 'sort_order', label:'{{ _('Sort order') }}', cell: Backgrid.Extension.TableChildSwitchCell, type: 'switch', + disabled: 'checkAccessMethod', editable: function(m) { - // Header cell then skip - if (m instanceof Backbone.Collection) { - return false; - } - else { - if (m.top.get('amname') === 'btree') { - m.set('is_sort_nulls_applicable', true); - return true; + // Header cell then skip + if (m instanceof Backbone.Collection) { + return false; } - m.set('is_sort_nulls_applicable', false); - return false; - } + return !(m.checkAccessMethod.apply(this, arguments)); }, deps: ['amname'], options: { @@ -132,18 +125,13 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) { },{ id: 'nulls', label:'{{ _('NULLs') }}', cell: Backgrid.Extension.TableChildSwitchCell, type: 'switch', + disabled: 'checkAccessMethod', editable: function(m) { - // Header cell then skip - if (m instanceof Backbone.Collection) { - return true; - } else { - if (m.top.get('amname') === 'btree') { - m.set('is_sort_nulls_applicable', true); + // Header cell then skip + if (m instanceof Backbone.Collection) { return true; - } - m.set('is_sort_nulls_applicable', false); - return false; - } + } + return !(m.checkAccessMethod.apply(this, arguments)); }, deps: ['amname', 'sort_order'], options: { @@ -196,11 +184,9 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) { if(m.get('sort_order') == true && m.previous('sort_order') == false) { setTimeout(function() { m.set('nulls', true) }, 10); } + return false; } - else { - m.set('is_sort_nulls_applicable', false); - } - return false; + return true; }, }); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/create.sql index 6d0bd1be..db29048b 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/create.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/create.sql @@ -1,7 +1,7 @@ ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }} ADD{% if data.name %} CONSTRAINT {{ conn|qtIdent(data.name) }}{% endif%} EXCLUDE {% if data.amname and data.amname != '' %}USING {{data.amname}}{% endif %} ( {% for col in data.columns %}{% if loop.index != 1 %}, - {% endif %}{{ conn|qtIdent(col.column)}}{% if col.oper_class and col.oper_class != '' %} {{col.oper_class}}{% endif%}{% if col.order is defined and col.is_sort_nulls_applicable %}{% if col.order %} ASC{% else %} DESC{% endif %} NULLS{% endif %} {% if col.nulls_order is defined and col.is_sort_nulls_applicable %}{% if col.nulls_order %}FIRST {% else %}LAST {% endif %}{% endif %}WITH {{col.operator}}{% endfor %}){% if data.fillfactor %} + {% endif %}{{ conn|qtIdent(col.column)}} {% if col.oper_class and col.oper_class != '' %}{{col.oper_class}} {% endif%}{% if col.order %}ASC{% else %}DESC{% endif %} NULLS {% if col.nulls_order %}FIRST{% else %}LAST{% endif %} WITH {{col.operator}}{% endfor %}){% if data.fillfactor %} WITH (FILLFACTOR={{data.fillfactor}}){% endif %}{% if data.spcname and data.spcname != "pg_default" %} USING INDEX TABLESPACE {{ conn|qtIdent(data.spcname) }}{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/create.sql index 6d0bd1be..db29048b 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/create.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/create.sql @@ -1,7 +1,7 @@ ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }} ADD{% if data.name %} CONSTRAINT {{ conn|qtIdent(data.name) }}{% endif%} EXCLUDE {% if data.amname and data.amname != '' %}USING {{data.amname}}{% endif %} ( {% for col in data.columns %}{% if loop.index != 1 %}, - {% endif %}{{ conn|qtIdent(col.column)}}{% if col.oper_class and col.oper_class != '' %} {{col.oper_class}}{% endif%}{% if col.order is defined and col.is_sort_nulls_applicable %}{% if col.order %} ASC{% else %} DESC{% endif %} NULLS{% endif %} {% if col.nulls_order is defined and col.is_sort_nulls_applicable %}{% if col.nulls_order %}FIRST {% else %}LAST {% endif %}{% endif %}WITH {{col.operator}}{% endfor %}){% if data.fillfactor %} + {% endif %}{{ conn|qtIdent(col.column)}} {% if col.oper_class and col.oper_class != '' %}{{col.oper_class}} {% endif%}{% if col.order %}ASC{% else %}DESC{% endif %} NULLS {% if col.nulls_order %}FIRST{% else %}LAST{% endif %} WITH {{col.operator}}{% endfor %}){% if data.fillfactor %} WITH (FILLFACTOR={{data.fillfactor}}){% endif %}{% if data.spcname and data.spcname != "pg_default" %} USING INDEX TABLESPACE {{ conn|qtIdent(data.spcname) }}{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.6_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.6_plus/create.sql index 6d0bd1be..db29048b 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.6_plus/create.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.6_plus/create.sql @@ -1,7 +1,7 @@ ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }} ADD{% if data.name %} CONSTRAINT {{ conn|qtIdent(data.name) }}{% endif%} EXCLUDE {% if data.amname and data.amname != '' %}USING {{data.amname}}{% endif %} ( {% for col in data.columns %}{% if loop.index != 1 %}, - {% endif %}{{ conn|qtIdent(col.column)}}{% if col.oper_class and col.oper_class != '' %} {{col.oper_class}}{% endif%}{% if col.order is defined and col.is_sort_nulls_applicable %}{% if col.order %} ASC{% else %} DESC{% endif %} NULLS{% endif %} {% if col.nulls_order is defined and col.is_sort_nulls_applicable %}{% if col.nulls_order %}FIRST {% else %}LAST {% endif %}{% endif %}WITH {{col.operator}}{% endfor %}){% if data.fillfactor %} + {% endif %}{{ conn|qtIdent(col.column)}} {% if col.oper_class and col.oper_class != '' %}{{col.oper_class}} {% endif%}{% if col.order %}ASC{% else %}DESC{% endif %} NULLS {% if col.nulls_order %}FIRST{% else %}LAST{% endif %} WITH {{col.operator}}{% endfor %}){% if data.fillfactor %} WITH (FILLFACTOR={{data.fillfactor}}){% endif %}{% if data.spcname and data.spcname != "pg_default" %} USING INDEX TABLESPACE {{ conn|qtIdent(data.spcname) }}{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/create.sql index b7bfa527..33af1973 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/create.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/create.sql @@ -3,7 +3,7 @@ CREATE {% if data.indisunique %}UNIQUE {% endif %}INDEX {% if data.isconcurrent {% if mode == 'create' %} ({% for c in data.columns %}{% if loop.index != 1 %}, {% endif %}{{conn|qtIdent(c.colname)}}{% if c.collspcname %} COLLATE {{c.collspcname}}{% endif %}{% if c.op_class %} - {{c.op_class}}{% endif %}{% if data.amname is defined %}{% if c.sort_order is defined and c.is_sort_nulls_applicable %}{% if c.sort_order %} DESC{% else %} ASC{% endif %}{% endif %}{% if c.nulls is defined and c.is_sort_nulls_applicable %} NULLS {% if c.nulls %} + {{c.op_class}}{% endif %}{% if data.amname is defined and data.amname not in ['gist', 'gin'] %}{% if c.sort_order is defined %}{% if c.sort_order %} DESC{% else %} ASC{% endif %}{% endif %}{% if c.nulls is defined %} NULLS {% if c.nulls %} FIRST{% else %}LAST{% endif %}{% endif %}{% endif %}{% endfor %}) {% else %} {## We will get indented data from postgres for column ##} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/js/table.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/js/table.js index c87a2930..2d006090 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/js/table.js +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/js/table.js @@ -198,54 +198,51 @@ function($, _, S, pgAdmin, pgBrowser, alertify) { }); }, reset_table_stats: function(args) { - var input = args || {}, - obj = this, - t = pgBrowser.tree, - i = input.item || t.selected(), - d = i && i.length == 1 ? t.itemData(i) : undefined; + var input = args || {}; + obj = this, + t = pgBrowser.tree, + i = input.item || t.selected(), + d = i && i.length == 1 ? t.itemData(i) : undefined; if (!d) return false; alertify.confirm( - '{{ _('Reset statistics') }}', - S('{{ _('Are you sure you want to reset the statistics for table %%s?') }}').sprintf(d._label).value(), + S('{{ _('Are you sure you want to reset table statistics for %s?') }}').sprintf(d.label).value(), function (e) { - if (e) { - var data = d; - $.ajax({ - url: obj.generate_url(i, 'reset' , d, true), - type:'DELETE', - success: function(res) { - if (res.success == 1) { - alertify.success("{{ _('" + res.info + "') }}"); - t.removeIcon(i); - data.icon = 'icon-table'; - t.addIcon(i, {icon: data.icon}); - t.unload(i); - t.setInode(i); - t.deselect(i); - // Fetch updated data from server - setTimeout(function() { - t.select(i); - }, 10); - } - }, - error: function(xhr, status, error) { - try { - var err = $.parseJSON(xhr.responseText); - if (err.success == 0) { - msg = S('{{ _(' + err.errormsg + ')}}').value(); - alertify.error("{{ _('" + err.errormsg + "') }}"); - } - } catch (e) {} + if (e) { + var data = d; + $.ajax({ + url: obj.generate_url(i, 'reset' , d, true), + type:'DELETE', + success: function(res) { + if (res.success == 1) { + alertify.success("{{ _('" + res.info + "') }}"); + t.removeIcon(i); + data.icon = 'icon-table'; + t.addIcon(i, {icon: data.icon}); t.unload(i); + t.setInode(i); + t.deselect(i); + // Fetch updated data from server + setTimeout(function() { + t.select(i); + }, 10); } - }); - } - }, - function() {} - ); + }, + error: function(xhr, status, error) { + try { + var err = $.parseJSON(xhr.responseText); + if (err.success == 0) { + msg = S('{{ _(' + err.errormsg + ')}}').value(); + alertify.error("{{ _('" + err.errormsg + "') }}"); + } + } catch (e) {} + t.unload(i); + } + }); + } + }); } }, model: pgBrowser.Node.Model.extend({ diff --git a/web/pgadmin/utils/route.py b/web/pgadmin/utils/route.py index f18d2c18..fed26a0f 100644 --- a/web/pgadmin/utils/route.py +++ b/web/pgadmin/utils/route.py @@ -54,20 +54,25 @@ class TestsGeneratorRegistry(ABCMeta): ABCMeta.__init__(cls, name, bases, d) @classmethod - def load_generators(cls, pkg): + def load_generators(cls, *pkgs): cls.registry = dict() + all_modules = [] + + for pkg in pkgs: + all_modules += find_modules(pkg, False, True) + + # Check for SERVER mode - if config.SERVER_MODE: - for module_name in find_modules(pkg, False, True): + for module_name in all_modules: + if config.SERVER_MODE: try: if "tests." in str(module_name): import_module(module_name) except ImportError: traceback.print_exc(file=sys.stderr) - else: - for module_name in find_modules(pkg, False, True): + else: try: # Exclude the test cases in browser node if SERVER_MODE # is False diff --git a/web/regression/.gitignore b/web/regression/.gitignore index 0581810b..723fce7e 100644 --- a/web/regression/.gitignore +++ b/web/regression/.gitignore @@ -1,4 +1,5 @@ parent_id.pkl regression.log +test_greenplum_config.json test_advanced_config.json test_config.json diff --git a/web/regression/README b/web/regression/README index 8cc29987..ae5d268d 100644 --- a/web/regression/README +++ b/web/regression/README @@ -103,6 +103,10 @@ Test Data Details Execution: ----------- +- For acceptance tests to run as part of the entire test suite, Chrome and chromedriver need to be installed: + get chromedriver from https://sites.google.com/a/chromium.org/chromedriver/downloads or a package manager + and make sure it is on the PATH + - The test framework is modular and pluggable and dynamically locates tests for modules which are discovered at runtime. All test cases are found and registered automatically by its module name in
-- Sent via pgadmin-hackers mailing list (pgadmin-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgadmin-hackers