diff --git a/web/pgadmin/feature_tests/query_tool_tests.py b/web/pgadmin/feature_tests/query_tool_tests.py index a0b3713..232eb1e 100644 --- a/web/pgadmin/feature_tests/query_tool_tests.py +++ b/web/pgadmin/feature_tests/query_tool_tests.py @@ -96,6 +96,11 @@ class QueryToolFeatureTest(BaseFeatureTest): print("OK.", file=sys.stderr) self._clear_query_tool() + # Notify Statements. + print("Capture Notify Statements... ", file=sys.stderr, end="") + self._query_tool_notify_statements() + self._clear_query_tool() + def after(self): self.page.remove_server(self.server) connection = test_utils.get_db_connection( @@ -615,3 +620,41 @@ SELECT 1, pg_sleep(300)""" self.server['sslmode'] ) return connection.server_version > 90100 + + def _query_tool_notify_statements(self): + print("\n\tListen on an event... ", file=sys.stderr, end="") + self.page.fill_codemirror_area_with("LISTEN foo;") + self.page.find_by_id("btn-flash").click() + self.page.wait_for_query_tool_loading_indicator_to_disappear() + self.page.click_tab('Messages') + self.page.find_by_xpath( + '//div[contains(@class, "sql-editor-message") and ' + 'contains(string(), "LISTEN")]' + ) + print("OK.", file=sys.stderr) + self._clear_query_tool() + + print("\tNotify event without data... ", file=sys.stderr, end="") + self.page.fill_codemirror_area_with("NOTIFY foo;") + self.page.find_by_id("btn-flash").click() + self.page.wait_for_query_tool_loading_indicator_to_disappear() + self.page.click_tab('Messages') + self.page.find_by_xpath( + '//div[contains(@class, "sql-editor-message") and ' + 'contains(string(), "Asynchronous notification")]' + ) + print("OK.", file=sys.stderr) + self._clear_query_tool() + + print("\tNotify event with data... ", file=sys.stderr, end="") + self.page.fill_codemirror_area_with("SELECT pg_notify('foo', " + "'This is bar')") + self.page.find_by_id("btn-flash").click() + self.page.wait_for_query_tool_loading_indicator_to_disappear() + self.page.click_tab('Messages') + self.page.find_by_xpath( + '//div[contains(@class, "sql-editor-message") and ' + 'contains(string(), "This is bar")]' + ) + print("OK.", file=sys.stderr) + self._clear_query_tool() diff --git a/web/pgadmin/utils/driver/psycopg2/connection.py b/web/pgadmin/utils/driver/psycopg2/connection.py index 315631c..fc3b260 100644 --- a/web/pgadmin/utils/driver/psycopg2/connection.py +++ b/web/pgadmin/utils/driver/psycopg2/connection.py @@ -155,6 +155,7 @@ class Connection(BaseConnection): self.execution_aborted = False self.row_count = 0 self.__notices = None + self.__notifies = None self.password = None # This flag indicates the connection status (connected/disconnected). self.wasConnected = False @@ -891,6 +892,7 @@ WHERE try: self.__notices = [] + self.__notifies = [] self.execution_aborted = False cur.execute(query, params) res = self._wait_timeout(cur.connection) @@ -1366,6 +1368,10 @@ Failed to reset the connection to the server due to following error: self.__notices.extend(self.conn.notices) self.conn.notices.clear() + if self.conn.notifies and self.__notifies is not None: + self.__notifies.extend(self.conn.notifies) + self.conn.notifies.clear() + # We also need to fetch notices before we return from function in case # of any Exception, To avoid code duplication we will return after # fetching the notices in case of any Exception @@ -1542,6 +1548,21 @@ Failed to reset the connection to the server due to following error: resp = [] while self.__notices: resp.append(self.__notices.pop(0)) + + while self.__notifies: + notify = self.__notifies.pop(0) + if notify.payload is not None and notify.payload is not '': + notify_msg = gettext( + "Asynchronous notification of {0} received from " + "backend pid {1}\n Data: {2}\n").format(notify.channel, + notify.pid, + notify.payload) + else: + notify_msg = gettext( + "Asynchronous notification of {0} received from " + "backend pid {1}\n").format(notify.channel, notify.pid) + resp.append(notify_msg) + return resp def decode_to_utf8(self, value):