Subject: Fwd: pgAdmin IV : Unittest modular patch

From: Navnath Gadakh <[email-masked]>
Date: Fri, 8 Jul 2016 19:00:33 +0530

Hi Dave,

PFA patch for modular API test cases.

Kindly, review the same and let me know for any modification.

-- 
*Thanks,*
*Navnath Gadakh*
*Software Engineer*
*Phone : + 91 9975389878*

*The Postgres Database Company*
diff --git a/web/config.py b/web/config.py
index ff7c1db..6fb01ca 100644
--- a/web/config.py
+++ b/web/config.py
@@ -28,7 +28,10 @@ APP_REVISION = 0
 
 # Application version suffix, e.g. 'beta1', 'dev'. Usually an empty string
 # for GA releases.
-APP_SUFFIX = 'beta2.1'
+APP_SUFFIX = 'beta2'
+
+# Root path for pgadmin
+APP_ROOT = os.path.dirname(os.path.abspath(__file__))
 
 # Copyright string for display in the app
 APP_COPYRIGHT = 'Copyright 2013 - 2016, The pgAdmin Development Team'
@@ -154,6 +157,10 @@ MAX_SESSION_IDLE_TIME = 60
 # User account and settings storage
 ##########################################################################
 
+# The schema version number for the configuration database
+# DO NOT CHANGE UNLESS YOU ARE A PGADMIN DEVELOPER!!
+SETTINGS_SCHEMA_VERSION = 13
+
 # The default path to the SQLite database used to store user accounts and
 # settings. This default places the file in the same directory as this
 # config file, but generates an absolute path for use througout the app.
diff --git a/web/pgadmin/browser/server_groups/servers/databases/tests/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/tests/__init__.py
new file mode 100644
index 0000000..aa01297
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/tests/__init__.py
@@ -0,0 +1,15 @@
+# ##########################################################################
+#
+# #pgAdmin 4 - PostgreSQL Tools
+#
+# #Copyright (C) 2013 - 2016, The pgAdmin Development Team
+# #This software is released under the PostgreSQL Licence
+#
+# ##########################################################################
+
+from pgadmin.utils.route import BaseTestGenerator
+
+
+class DatabaseCreateTestCase(BaseTestGenerator):
+    def runTest(self):
+        return
diff --git a/web/pgadmin/browser/server_groups/servers/databases/tests/test_db_add.py b/web/pgadmin/browser/server_groups/servers/databases/tests/test_db_add.py
new file mode 100644
index 0000000..4cb5092
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/tests/test_db_add.py
@@ -0,0 +1,93 @@
+# #################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2016, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+# ##################################################################
+
+import json
+import uuid
+
+from pgadmin.utils.route import BaseTestGenerator
+from regression import test_utils as utils
+from regression.config import advance_config_data
+
+
+class DatabaseAddTestCase(BaseTestGenerator):
+    """
+    This class will check server group node present on the object browser's
+    tree node by response code.
+    """
+
+    scenarios = [
+        # Fetching default URL for database node.
+        ('Check Databases Node URL', dict(url='/browser/database/obj/'))
+    ]
+
+    def setUp(self):
+        """
+        This function perform the two tasks
+         1. Login to test client
+         2. Add the test server
+
+        :return: None
+        """
+
+        utils.login_tester_account(self.tester)
+        # Add the server
+        utils.add_server(self.tester)
+
+    def runTest(self):
+        """ This function will add database under 1st server of tree node. """
+
+        server_connect_response, server_group, server_id = \
+            utils.connect_server(self.tester)
+
+        if server_connect_response['data']['connected']:
+            data = {
+                "datacl": advance_config_data['test_add_database_data'][0]
+                ['test_privileges_acl'],
+                "datconnlimit": advance_config_data
+                ['test_add_database_data'][0]['test_conn_limit'],
+                "datowner": advance_config_data
+                ['test_add_database_data'][0]['test_owner'],
+                "deffuncacl": advance_config_data
+                ['test_add_database_data'][0]['test_fun_acl'],
+                "defseqacl": advance_config_data
+                ['test_add_database_data'][0]['test_seq_acl'],
+                "deftblacl": advance_config_data
+                ['test_add_database_data'][0]['test_tbl_acl'],
+                "deftypeacl": advance_config_data
+                ['test_add_database_data'][0]['test_type_acl'],
+                "encoding": advance_config_data
+                ['test_add_database_data'][0]['test_encoding'],
+                "name": str(uuid.uuid4())[1:8],
+                "privileges": advance_config_data
+                ['test_add_database_data'][0]['test_privileges'],
+                "securities": advance_config_data
+                ['test_add_database_data'][0]['test_securities'],
+                "variables": advance_config_data
+                ['test_add_database_data'][0]['test_variables']
+            }
+
+            db_response = self.tester.post(self.url + str(server_group) + "/"
+                                           + server_id + "/",
+                                           data=json.dumps(data),
+                                           content_type='html/json')
+            self.assertTrue(db_response.status_code, 200)
+            response_data = json.loads(db_response.data.decode())
+            utils.write_db_parent_id(response_data)
+
+    def tearDown(self):
+        """
+        This function deletes the 'parent_id.pkl' file which is created in
+        setup() function. Also this function logout the test client
+
+        :return: None
+        """
+
+        utils.delete_parent_id_file()
+        utils.logout_tester_account(self.tester)
+
diff --git a/web/pgadmin/browser/server_groups/servers/databases/tests/test_db_delete.py b/web/pgadmin/browser/server_groups/servers/databases/tests/test_db_delete.py
new file mode 100644
index 0000000..f21905b
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/tests/test_db_delete.py
@@ -0,0 +1,70 @@
+# #################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2016, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+# ##################################################################
+
+import json
+
+from pgadmin.utils.route import BaseTestGenerator
+from regression import test_utils as utils
+from regression.config import config_data
+from regression.test_nodes import test_getnodes
+from regression.test_utils import get_ids
+
+
+class DatabaseDeleteTestCase(BaseTestGenerator):
+    """ This class will delete the database under last added server. """
+
+    scenarios = [
+        # Fetching default URL for database node.
+        ('Check Databases Node URL', dict(url='/browser/database/obj/'))
+    ]
+
+    def setUp(self):
+        """
+        This function perform the three tasks
+         1. Login to test client
+         2. Add the test server
+         3. Connect to server
+
+        :return: None
+        """
+
+        utils.login_tester_account(self.tester)
+        # Firstly, add the server
+        utils.add_server(self.tester)
+        # Secondly, connect to server/database
+        utils.connect_server(self.tester)
+
+    def runTest(self):
+        """ This function will delete the database."""
+
+        all_id = get_ids()
+        server_id = all_id["sid"][0]
+        db_id = all_id["did"][0]
+        srv_grp = config_data['test_server_group']
+        db_con = test_getnodes(node=self)
+        if len(db_con) == 0:
+            raise Exception("No database(s) to delete!!!")
+        response = self.tester.delete(self.url + str(srv_grp) + '/' +
+                                      str(server_id) + '/' + str(db_id),
+                                      follow_redirects=True)
+
+        response_data = json.loads(response.data.decode())
+        self.assertTrue(response_data['success'], 1)
+
+    def tearDown(self):
+        """
+        This function deletes the 'parent_id.pkl' file which is created in
+        setup() function. Also this function logout the test client
+
+        :return: None
+        """
+
+        utils.delete_parent_id_file()
+        utils.logout_tester_account(self.tester)
+
diff --git a/web/pgadmin/browser/server_groups/servers/databases/tests/test_db_get.py b/web/pgadmin/browser/server_groups/servers/databases/tests/test_db_get.py
new file mode 100644
index 0000000..e07fbba
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/tests/test_db_get.py
@@ -0,0 +1,67 @@
+# #################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2016, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+# ##################################################################
+
+from pgadmin.utils.route import BaseTestGenerator
+from regression import test_utils as utils
+from regression.config import config_data
+from regression.test_nodes import test_getnodes
+from regression.test_utils import get_ids
+
+
+class DatabasesGetTestCase(BaseTestGenerator):
+    """
+    This class will fetch database added under last added server.
+    """
+
+    scenarios = [
+        # Fetching default URL for database node.
+        ('Check Databases Node URL', dict(url='/browser/database/obj/'))
+    ]
+
+    def setUp(self):
+        """
+        This function perform the three tasks
+         1. Login to test client
+         2. Add the test server
+         3. Connect to server
+
+        :return: None
+        """
+
+        utils.login_tester_account(self.tester)
+        # Firstly, add the server
+        utils.add_server(self.tester)
+        # Secondly, connect to server/database
+        utils.connect_server(self.tester)
+
+    def runTest(self):
+        """ This function will fetch added database. """
+
+        all_id = get_ids()
+        server_id = all_id["sid"][0]
+        db_id = all_id["did"][0]
+        srv_grp = config_data['test_server_group']
+
+        db_con = test_getnodes(node=self)
+        if db_con["info"] == "Database connected.":
+            response = self.tester.get(self.url + str(srv_grp) + '/' +
+                                       str(server_id) + '/' + str(db_id),
+                                       follow_redirects=True)
+            self.assertEquals(response.status_code, 200)
+
+    def tearDown(self):
+        """
+        This function deletes the 'parent_id.pkl' file which is created in
+        setup() function. Also this function logout the test client
+
+        :return: None
+        """
+
+        utils.delete_parent_id_file()
+        utils.logout_tester_account(self.tester)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/tests/test_db_put.py b/web/pgadmin/browser/server_groups/servers/databases/tests/test_db_put.py
new file mode 100644
index 0000000..5d36400
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/tests/test_db_put.py
@@ -0,0 +1,76 @@
+# #################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2016, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+# ##################################################################
+
+import json
+
+from pgadmin.utils.route import BaseTestGenerator
+from regression import test_utils as utils
+from regression.config import config_data, advance_config_data
+from regression.test_nodes import test_getnodes
+from regression.test_utils import get_ids
+
+
+class DatabasesUpdateTestCase(BaseTestGenerator):
+    """
+    This class will update the database under last added server.
+    """
+
+    scenarios = [
+        # Fetching default URL for database node.
+        ('Check Databases Node', dict(url='/browser/database/obj/'))
+    ]
+
+    def setUp(self):
+        """
+        This function perform the three tasks
+         1. Login to test client
+         2. Add the test server
+         3. Connect to server
+
+        :return: None
+        """
+
+        utils.login_tester_account(self.tester)
+        # Firstly, add the server
+        utils.add_server(self.tester)
+        # Secondly, connect to server/database
+        utils.connect_server(self.tester)
+
+    def runTest(self):
+        """ This function will update the comments field of database."""
+
+        all_id = get_ids()
+        server_id = all_id["sid"][0]
+        db_id = all_id["did"][0]
+        test_getnodes(node=self)
+        srv_grp = config_data['test_server_group']
+
+        data = {
+            "comments": advance_config_data["test_db_update_data"][0]
+            ["test_comment"],
+            "id": db_id
+        }
+
+        put_response = self.tester.put(self.url + str(srv_grp) + '/' +
+                                       str(server_id) + '/' + str(db_id),
+                                       data=json.dumps(data),
+                                       follow_redirects=True)
+        self.assertEquals(put_response.status_code, 200)
+
+    def tearDown(self):
+        """
+        This function deletes the 'parent_id.pkl' file which is created in
+        setup() function. Also this function logout the test client
+
+        :return: None
+        """
+
+        utils.delete_parent_id_file()
+        utils.logout_tester_account(self.tester)
+
diff --git a/web/pgadmin/browser/server_groups/servers/tests/__init__.py b/web/pgadmin/browser/server_groups/servers/tests/__init__.py
index 28cdb94..55a3a17 100644
--- a/web/pgadmin/browser/server_groups/servers/tests/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/tests/__init__.py
@@ -12,4 +12,4 @@ from pgadmin.utils.route import BaseTestGenerator
 
 class ServerGenerateTestCase(BaseTestGenerator):
     def runTest(self):
-        print ("In ServerGenerateTestCase...")
+        return
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/tests/test_server_add.py b/web/pgadmin/browser/server_groups/servers/tests/test_server_add.py
index 0af13d3..3592cf2 100644
--- a/web/pgadmin/browser/server_groups/servers/tests/test_server_add.py
+++ b/web/pgadmin/browser/server_groups/servers/tests/test_server_add.py
@@ -9,45 +9,47 @@
 
 import json
 
-from pgadmin.browser.tests.test_login import LoginTestCase
-from regression.config import config_data
+from pgadmin.utils.route import BaseTestGenerator
+from regression import test_utils as utils

-class ServersAddTestCase(LoginTestCase):
-    """
-    This class will add the servers under default server group and verify with
-    server's name.
-    """
-
-    priority = 4
+class ServersAddTestCase(BaseTestGenerator):
+    """ This class will add the servers under default server group. """
 
     scenarios = [
         # Fetch the default url for server object
         ('Default Server Node url', dict(url='/browser/server/obj/'))
     ]
 
-    def runTest(self):
+    def setUp(self):
         """
-        This function will add the server under default server group.
-        Verify the added server with response code as well as server name.
+        This function login the test account before running the logout
+        test case
         """
 
-        srv_grp = config_data['test_server_group']
-
-        for srv in config_data['test_server_credentials']:
-            data = {"name": srv['test_name'],
-                    "comment": "",
-                    "host": srv['test_host'],
-                    "port": srv['test_db_port'],
-                    "db": srv['test_maintenance_db'],
-                    "username": srv['test_db_username'],
-                    "role": "",
-                    "sslmode": srv['test_sslmode']}
+        utils.login_tester_account(self.tester)
 
-            url = self.url + str(srv_grp) + "/"
+    def runTest(self):
+        """ This function will add the server under default server group."""
 
-            response = self.tester.post(url, data=json.dumps(data),
+        server_group, config_data, pickle_id_dict = utils.get_config_data()
+        for server_data in config_data:
+            url = "{0}{1}/".format(self.url, server_group)
+            response = self.tester.post(url, data=json.dumps(server_data),
                                         content_type='html/json')
+
             self.assertTrue(response.status_code, 200)
-            respdata = json.loads(response.data)
-            self.assertTrue(respdata['node']['label'], srv['test_name'])
+
+            response_data = json.loads(response.data.decode())
+            utils.write_parent_id(response_data, pickle_id_dict)
+
+    def tearDown(self):
+        """
+        This function deletes the 'parent_id.pkl' file which is created in
+        setup() function. Also this function logout the test client
+
+        :return: None
+        """
+
+        utils.delete_parent_id_file()
+        utils.logout_tester_account(self.tester)
diff --git a/web/pgadmin/browser/server_groups/servers/tests/test_server_delete.py b/web/pgadmin/browser/server_groups/servers/tests/test_server_delete.py
index 329d74f..1e9a686 100644
--- a/web/pgadmin/browser/server_groups/servers/tests/test_server_delete.py
+++ b/web/pgadmin/browser/server_groups/servers/tests/test_server_delete.py
@@ -9,49 +9,56 @@
 
 import json
 
-from pgadmin.browser.tests.test_login import LoginTestCase
+from pgadmin.utils.route import BaseTestGenerator
+from regression import test_utils as utils
 from regression.config import config_data

-class ServersDeleteTestCase(LoginTestCase):
-    """
-    This class will check server node present on the object browser's tree node
-    by response code.
-    """
-    priority = 7
+class ServerDeleteTestCase(BaseTestGenerator):
+    """ This class will delete the last server present under tree node."""
 
     scenarios = [
         # Fetching the default url for server node
         ('Default Server Node url', dict(url='/browser/server/obj/'))
     ]
 
-    def runTest(self):
+    def setUp(self):
         """
-        This function will get all available servers under object browser
-        and delete the servers using server id.
+        This function perform the two tasks
+         1. Login to test client
+         2. Add the test server
+
+        :return: None
         """
 
-        srv_grp = config_data['test_server_group']
+        utils.login_tester_account(self.tester)
+        # Firstly, add the server
+        utils.add_server(self.tester)
 
-        for srv in config_data['test_server_credentials']:
+    def runTest(self):
+        """ This function will get all available servers under object browser
+        and delete the last server using server id."""
 
-            data = {"name": srv['test_name'],
-                    "host": srv['test_host'],
-                    "port": srv['test_db_port'],
-                    "db": srv['test_maintenance_db'],
-                    "username": srv['test_db_username'],
-                    "role": "",
-                    "sslmode": srv['test_sslmode']}
+        srv_grp = config_data['test_server_group']
+        url = self.url + str(srv_grp) + "/"
+        response = self.tester.get(url)
+        response_data = json.loads(response.data.decode())
+        if len(response_data) == 0:
+            raise Exception("No server(s) to delete!!!")
 
-            url = self.url + str(srv_grp) + "/"
+        # Delete last server
+        server = response_data[-1]
+        response = self.tester.delete(url + str(server['id']))
+        self.assertTrue(response.status_code, 200)
+        response_data = json.loads(response.data.decode())
+        self.assertTrue(response_data['success'], 1)
 
-            response = self.tester.get(url, data=json.dumps(data),
-                                       content_type='html/json')
-            self.assertTrue(response.status_code, 200)
-            respdata = json.loads(response.data)
+    def tearDown(self):
+        """
+        This function deletes the 'parent_id.pkl' file which is created in
+        setup() function. Also this function logout the test client
 
-            for server in respdata:
-                response = self.tester.delete(url + json.dumps(server['id']))
-                self.assertTrue(response.status_code, 200)
-                respdata = json.loads(response.data)
-                self.assertTrue(respdata['success'], 1)
+        :return: None
+        """
+        utils.delete_parent_id_file()
+        utils.logout_tester_account(self.tester)
diff --git a/web/pgadmin/browser/server_groups/servers/tests/test_server_get.py b/web/pgadmin/browser/server_groups/servers/tests/test_server_get.py
index 050843e..abf49a3 100644
--- a/web/pgadmin/browser/server_groups/servers/tests/test_server_get.py
+++ b/web/pgadmin/browser/server_groups/servers/tests/test_server_get.py
@@ -7,43 +7,53 @@
 #
 # ##########################################################################
 
-import json
-
-from pgadmin.browser.tests.test_login import LoginTestCase
+from pgadmin.utils.route import BaseTestGenerator
+from regression import test_utils as utils
 from regression.config import config_data
+from regression.test_utils import get_ids

-class ServersGetTestCase(LoginTestCase):
+class ServersGetTestCase(BaseTestGenerator):
     """
-    This class will check server node present on the object browser's tree node
+    This class will fetch added servers under default server group
     by response code.
     """
 
-    priority = 5
-
     scenarios = [
         # Fetch the default url for server node
         ('Default Server Node url', dict(url='/browser/server/obj/'))
     ]
 
-    def runTest(self):
+    def setUp(self):
         """
-        This function will get all available servers present under
-        object browser.
+        This function perform the two tasks
+         1. Login to test client
+         2. Add the test server
+
+        :return: None
         """
 
+        utils.login_tester_account(self.tester)
+        utils.add_server(self.tester)
+
+    def runTest(self):
+        """ This function will fetch the added servers to object browser. """
+
+        all_id = get_ids()
+        server_ids = all_id["sid"]
         srv_grp = config_data['test_server_group']
 
-        for srv in config_data['test_server_credentials']:
-            data = {"name": srv['test_name'],
-                    "host": srv['test_host'],
-                    "port": srv['test_db_port'],
-                    "db": srv['test_maintenance_db'],
-                    "username": srv['test_db_username'],
-                    "role": "",
-                    "sslmode": srv['test_sslmode']}
-
-            url = self.url + str(srv_grp) + "/"
-            response = self.tester.get(url, data=json.dumps(data),
-                                       content_type='html/json')
-            self.assertTrue(response.status_code, 200)
+        for server_id in server_ids:
+            url = "{0}{1}/{2}".format(self.url, srv_grp, server_id)
+            response = self.tester.get(url, content_type='html/json')
+            self.assertEquals(response.status_code, 200)
+
+    def tearDown(self):
+        """
+        This function deletes the 'parent_id.pkl' file which is created in
+        setup() function. Also this function logout the test client
+
+        :return: None
+        """
+        utils.delete_parent_id_file()
+        utils.logout_tester_account(self.tester)
diff --git a/web/pgadmin/browser/server_groups/servers/tests/test_server_put.py b/web/pgadmin/browser/server_groups/servers/tests/test_server_put.py
index 306bb03..e2cd329 100644
--- a/web/pgadmin/browser/server_groups/servers/tests/test_server_put.py
+++ b/web/pgadmin/browser/server_groups/servers/tests/test_server_put.py
@@ -9,57 +9,66 @@
 
 import json
 
-from pgadmin.browser.tests.test_login import LoginTestCase
+from pgadmin.utils.route import BaseTestGenerator
+from regression import test_utils as utils
 from regression.config import config_data

-class ServersUpdateTestCase(LoginTestCase):
-    """
-    This class will check server node present on the object browser's tree node
-    by response code.
-    """
-
-    priority = 6
+class ServerUpdateTestCase(BaseTestGenerator):
+    """ This class will update server's comment field. """
 
     scenarios = [
         # Fetching the default url for server node
         ('Default Server Node url', dict(url='/browser/server/obj/'))
     ]
 
-    def runTest(self):
-        """
-        This function will edit and update the server's comment field
-        by the server id.
+    def setUp(self):
         """
+        This function perform the four tasks
+         1. Login to test client
+         2. Add the test server
+         3. Get the server
+         4. Connect to server
 
-        srv_grp = config_data['test_server_group']
+        :return: None
+        """
 
-        for srv in config_data['test_server_credentials']:
+        utils.login_tester_account(self.tester)
+        # Firstly, add the server
+        utils.add_server(self.tester)
+        # Get the server
+        utils.get_server(self.tester)
+        # Connect to server
+        self.server_connect, self.server_group, self.server_id = \
+            utils.connect_server(self.tester)
+        if len(self.server_connect) == 0:
+            raise Exception("No Server(s) connected to update!!!")
 
-            data = {"name": srv['test_name'],
-                    "host": srv['test_host'],
-                    "port": srv['test_db_port'],
-                    "db": srv['test_maintenance_db'],
-                    "username": srv['test_db_username'],
-                    "role": "",
-                    "sslmode": srv['test_sslmode']}
+    def runTest(self):
+        """ This function will update the server's comment field. """
 
-            url = self.url + str(srv_grp) + "/"
+        data = {
+            "comment":
+                config_data['test_server_update_data']['test_comment'],
+            "id": self.server_id
+        }
 
-            response = self.tester.get(url, data=json.dumps(data),
-                                       content_type='html/json')
+        put_response = self.tester.put(
+            self.url + str(self.server_group) + '/' +
+            str(self.server_id), data=json.dumps(data),
+            content_type='html/json')
+        self.assertEquals(put_response.status_code, 200)
 
-            self.assertTrue(response.status_code, 200)
-            respdata = json.loads(response.data)
+        response_data = json.loads(put_response.data.decode())
+        self.assertTrue(response_data['success'], 1)
 
-            for server in respdata:
+    def tearDown(self):
+        """
+        This function deletes the 'parent_id.pkl' file which is created in
+        setup() function. Also this function logout the test client
 
-                url = self.url + str(srv_grp) + "/" + json.dumps(server['id'])
+        :return: None
+        """
 
-                for server in config_data['test_server_update_data']:
-                    data = {"comment": server['test_comment']}
-                    response = self.tester.put(url, data=json.dumps(data),
-                                               content_type='html/json')
-                    self.assertTrue(response.status_code, 200)
-                    respdata = json.loads(response.data)
-                    self.assertTrue(respdata['success'], 1)
+        utils.delete_parent_id_file()
+        utils.logout_tester_account(self.tester)
diff --git a/web/pgadmin/browser/server_groups/tests/__init__.py b/web/pgadmin/browser/server_groups/tests/__init__.py
index 9fabed9..7fdd5c7 100644
--- a/web/pgadmin/browser/server_groups/tests/__init__.py
+++ b/web/pgadmin/browser/server_groups/tests/__init__.py
@@ -12,4 +12,4 @@ from pgadmin.utils.route import BaseTestGenerator
 
 class SGGenerateTestCase(BaseTestGenerator):
     def runTest(self):
-        print ("In SGGenerateTestCase...")
+        return
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/tests/test_sg_add.py b/web/pgadmin/browser/server_groups/tests/test_sg_add.py
index e70bb65..07bbe96 100644
--- a/web/pgadmin/browser/server_groups/tests/test_sg_add.py
+++ b/web/pgadmin/browser/server_groups/tests/test_sg_add.py
@@ -9,28 +9,40 @@
 
 import json
 
-from pgadmin.browser.tests.test_login import LoginTestCase
+from pgadmin.utils.route import BaseTestGenerator
+from regression import test_utils as utils
 from regression.config import config_data

-class SgNodeTestCase(LoginTestCase):
+class SgNodeTestCase(BaseTestGenerator):
     """
      This class will check available server groups in pgAdmin.
     """
 
-    priority = 1
-
     scenarios = [
         # Fetching the default url for server group node
         ('Check Server Group Node', dict(url='/browser/server-group/obj/'))
     ]
 
+    def setUp(self):
+        """
+        This function login the test account before running the logout
+        test case
+        """
+
+        utils.login_tester_account(self.tester)
+
     def runTest(self):
         """This function will check available server groups."""
 
-        i = config_data['test_server_group']
-
-        response = self.tester.get(self.url + str(i), content_type='html/json')
+        server_group_id = config_data['test_server_group']
+        response = self.tester.get(self.url + str(server_group_id),
+                                   content_type='html/json')
         self.assertTrue(response.status_code, 200)
-        respdata = json.loads(response.data)
-        self.assertTrue(respdata['id'], i)
+        response_data = json.loads(response.data.decode('utf8'))
+        self.assertTrue(response_data['id'], server_group_id)
+
+    def tearDown(self):
+        """This function logout the test account """
+
+        utils.logout_tester_account(self.tester)
diff --git a/web/pgadmin/browser/tests/__init__.py b/web/pgadmin/browser/tests/__init__.py
index 2381efd..3fab6fe 100644
--- a/web/pgadmin/browser/tests/__init__.py
+++ b/web/pgadmin/browser/tests/__init__.py
@@ -12,4 +12,4 @@ from pgadmin.utils.route import BaseTestGenerator
 
 class BrowserGenerateTestCase(BaseTestGenerator):
     def runTest(self):
-        print ("In BrowserGenerateTestCase...")
+        return
\ No newline at end of file
diff --git a/web/pgadmin/browser/tests/test_change_password.py b/web/pgadmin/browser/tests/test_change_password.py
index dedb7d9..8b47e25 100644
--- a/web/pgadmin/browser/tests/test_change_password.py
+++ b/web/pgadmin/browser/tests/test_change_password.py
@@ -9,19 +9,18 @@
 
 import uuid
 
-from pgadmin.browser.tests.test_login import LoginTestCase
+from pgadmin.utils.route import BaseTestGenerator
 from regression.config import config_data
+from regression import test_utils as utils

-class ChangePasswordTestCase(LoginTestCase):
+class ChangePasswordTestCase(BaseTestGenerator):
     """
     This class validates the change password functionality
     by defining change password scenarios; where dict of
     parameters describes the scenario appended by test name.
     """
 
-    priority = 2
-
     scenarios = [
         # This testcase validates invalid confirmation password
         ('TestCase for Validating Incorrect_New_Password', dict(
@@ -48,8 +47,7 @@ class ChangePasswordTestCase(LoginTestCase):
             new_password='', new_password_confirm='',
             respdata='Password not provided')),
 
-        # This testcase validates if current entered password
-        # is incorrect
+        # This testcase validates if current entered password is incorrect
         ('TestCase for Validating Incorrect_Current_Password', dict(
             password=str(uuid.uuid4())[4:8],
             new_password=(config_data['pgAdmin4_login_credentials']
@@ -70,6 +68,7 @@ class ChangePasswordTestCase(LoginTestCase):
                 ['test_new_password']),
             respdata='You successfully changed your password.')),
         ('Reassigning_Password', dict(
+            test_case='reassigning_password',
             password=(config_data['pgAdmin4_login_credentials']
                       ['test_new_password']),
             new_password=(config_data['pgAdmin4_login_credentials']
@@ -81,14 +80,44 @@ class ChangePasswordTestCase(LoginTestCase):
 
     ]
 
+    def setUp(self):
+        """
+        This function login the test account before running the logout
+        test case
+        """
+
+        utils.login_tester_account(self.tester)
+
     def runTest(self):
         """This function will check change password functionality."""
 
+        # Check for 'test_case' exists in self For reassigning the password.
+        # Password gets change in change password test case.
+        if 'test_case' in dir(self):
+            email = \
+                config_data['pgAdmin4_login_credentials'][
+                    'test_login_username']
+            password = \
+                config_data['pgAdmin4_login_credentials'][
+                    'test_new_password']
+            response = self.tester.post('/login', data=dict(
+                email=email, password=password), follow_redirects=True)
+
         response = self.tester.get('/change', follow_redirects=True)
-        self.assertIn('pgAdmin 4 Password Change', response.data)
+        self.assertIn('pgAdmin 4 Password Change', response.data.decode())
+
         response = self.tester.post('/change', data=dict(
             password=self.password,
             new_password=self.new_password,
             new_password_confirm=self.new_password_confirm),
                                     follow_redirects=True)
-        self.assertIn(self.respdata, response.data)
+        self.assertIn(self.respdata, response.data.decode())
+
+    def tearDown(self):
+        """
+        This function logout the test client
+
+        :return: None
+        """
+
+        utils.logout_tester_account(self.tester)
diff --git a/web/pgadmin/browser/tests/test_login.py b/web/pgadmin/browser/tests/test_login.py
index 7c2b796..8856700 100644
--- a/web/pgadmin/browser/tests/test_login.py
+++ b/web/pgadmin/browser/tests/test_login.py
@@ -8,9 +8,9 @@
 ##########################################################################
 
 import uuid
-
 from pgadmin.utils.route import BaseTestGenerator
 from regression.config import config_data
+from regression import test_utils as utils

 class LoginTestCase(BaseTestGenerator):
@@ -20,8 +20,6 @@ class LoginTestCase(BaseTestGenerator):
     describe the scenario appended by test name.
     """
 
-    priority = 0
-
     scenarios = [
         # This test case validates the invalid/incorrect password
         ('TestCase for Checking Invalid_Password', dict(
@@ -67,13 +65,28 @@ class LoginTestCase(BaseTestGenerator):
                    ['test_login_username']),
             password=(config_data['pgAdmin4_login_credentials']
                       ['test_login_password']),
-            respdata='You are currently running version'))
+            respdata='Gravatar image for %s' %
+                     config_data['pgAdmin4_login_credentials']
+                     ['test_login_username']))
     ]
 
+    def setUp(self):
+        pass
+
     def runTest(self):
         """This function checks login functionality."""
 
         response = self.tester.post('/login', data=dict(
             email=self.email, password=self.password),
                                     follow_redirects=True)
-        self.assertIn(self.respdata, response.data)
+        self.assertIn(self.respdata, response.data.decode('utf8'))
+
+    def tearDown(self):
+        """
+        This function deletes the 'parent_id.pkl' file which is created in
+        setup() function. Also this function logout the test client
+
+        :return: None
+        """
+
+        utils.logout_tester_account(self.tester)
diff --git a/web/pgadmin/browser/tests/test_logout.py b/web/pgadmin/browser/tests/test_logout.py
index 8971e72..c2ccf94 100644
--- a/web/pgadmin/browser/tests/test_logout.py
+++ b/web/pgadmin/browser/tests/test_logout.py
@@ -7,38 +7,33 @@
 #
 # ##########################################################################
 
-from pgadmin.browser.tests.test_login import LoginTestCase
-from regression.config import config_data
 
+from pgadmin.utils.route import BaseTestGenerator
+from regression import test_utils as utils
 
-class LogoutTest(LoginTestCase):
+
+class LogoutTest(BaseTestGenerator):
     """
     This class verifies the logout functionality; provided the user is already
     logged-in. Dictionary parameters define the scenario appended by test
     name.
     """
 
-    priority = 3
-
     scenarios = [
         # This test case validate the logout page
         ('Logging Out', dict(respdata='Redirecting...'))
     ]
 
+    def setUp(self):
+        """
+        This function login the test account before running the logout
+        test case
+        """
+
+        utils.login_tester_account(self.tester)
+
     def runTest(self):
         """This function checks the logout functionality."""
 
         response = self.tester.get('/logout')
-        self.assertIn(self.respdata, response.data)
-
-    def tearDown(self):
-        """
-        Defining tear down class, which will run after each test method execute.
-        Re-logging in as further modules require login.
-        """
-
-        self.tester.post('/login', data=dict(
-            email=(config_data['pgAdmin4_login_credentials']
-                   ['test_login_username']),
-            password=(config_data['pgAdmin4_login_credentials']
-                      ['test_login_password'])), follow_redirects=True)
+        self.assertIn(self.respdata, response.data.decode('utf8'))
diff --git a/web/pgadmin/browser/tests/test_reset_password.py b/web/pgadmin/browser/tests/test_reset_password.py
index 030b182..26dd80c 100644
--- a/web/pgadmin/browser/tests/test_reset_password.py
+++ b/web/pgadmin/browser/tests/test_reset_password.py
@@ -11,6 +11,7 @@ import uuid
 
 from pgadmin.utils.route import BaseTestGenerator
 from regression.config import config_data
+from regression import test_utils as utils

 class ResetPasswordTestCase(BaseTestGenerator):
@@ -19,7 +20,6 @@ class ResetPasswordTestCase(BaseTestGenerator):
     scenarios; Each dict parameter describe a scenario appended by
     test name.
     """
-    priority = 1
 
     scenarios = [
         # This test case validates the empty email field
@@ -37,12 +37,29 @@ class ResetPasswordTestCase(BaseTestGenerator):
             ['test_login_username'], respdata='pgAdmin 4'))
     ]
 
+    def setUp(self):
+        """
+        This function login the test account before running the logout
+        test case
+        """
+
+        utils.login_tester_account(self.tester)
+
     def runTest(self):
         """This function checks reset password functionality."""
 
         response = self.tester.get('/reset')
-        self.assertIn('Recover pgAdmin 4 Password', response.data)
+        self.assertIn('Recover pgAdmin 4 Password', response.data.decode())
         response = self.tester.post(
             '/reset', data=dict(email=self.email),
             follow_redirects=True)
-        self.assertIn(self.respdata, response.data)
+        self.assertIn(self.respdata, response.data.decode())
+
+    def tearDown(self):
+        """
+        This function logout the test client
+
+        :return: None
+        """
+
+        utils.logout_tester_account(self.tester)
diff --git a/web/pgadmin/utils/route.py b/web/pgadmin/utils/route.py
index fb9de69..a2cd1eb 100644
--- a/web/pgadmin/utils/route.py
+++ b/web/pgadmin/utils/route.py
@@ -52,8 +52,10 @@ class TestsGeneratorRegistry(ABCMeta):
         from werkzeug.utils import find_modules
 
         for module_name in find_modules(pkg, False, True):
-            module = import_module(module_name)
-
+            try:
+                module = import_module(module_name)
+            except ImportError:
+                pass
 
 import six
 
diff --git a/web/regression/README b/web/regression/README
index e0003e4..ef9fd29 100644
--- a/web/regression/README
+++ b/web/regression/README
@@ -40,29 +40,40 @@ General Information
     3. test_server_get.py
     4. test_server_update.py
 
-2) The pgAdmin4 source tree includes a file template for the server configuration
-   named ‘test_config.json.in' in the ‘pgAdmin4/web/regression’ directory. After
-   completing the pgAdmin4 configuration, you must make a working copy of the
-   template called test_config.json before modifying the file contents.
+2) The pgAdmin4 source tree includes 2 different configuration file templates.
+   One file template for the server configuration
+   named ‘test_config.json.in' and another for test configuration named
+   'test_advance_config.json.in' in the ‘pgAdmin4/web/regression’ directory.
+   After completing the pgAdmin4 configuration, you must make a working copy of
+   the templates called test_config.json and test_advance_config.json
+   before modifying the file contents.
 
-	2a) The following command copies the test_config.json.in file, creating a
-	    configuration file named test_config.json
+    2a) The following command copies the test_config.json.in file, creating a
+        configuration file named test_config.json (same way user can copy
+        test_advance_config.json.in file into test_advance_config.json)
 
-            # cp pgadmin4/web/regression/test_config.json.in \
-              pgadmin4/web/regression/test_config.json
+             # cp pgadmin4/web/regression/test_config.json.in \
+               pgadmin4/web/regression/test_config.json
 
-	2b) After creating the server configuration file, add (or modify)
-	    parameter values as per requirements. The configuration
-	    files are owned by root/user. The pgAdmin4 regression framework expects
-	    to find the files in the  directory '/<installation dir>/web/regression/'.
-	    If you move the file to another location, you must create a symbolic link
-	    that specifies the new location.
+    2b) After creating the server and test configuration file, add (or modify)
+        parameter values as per requirements. The configuration
+        files are owned by root/user. The pgAdmin4 regression framework expects
+        to find the files in the  directory '/<installation dir>/web/regression/'.
+        If you move the file to another location, you must create a symbolic
+        link that specifies the new location.
 
-	2c) Specifying Server Configuration file:
+    2c) Specifying Server Configuration file:
+
+        server details and connection properties as per their local setup. The
+        test_config file is in json format and property values are
+        case-sensitive.
+
+    2d) Specifying the Test Configuration file:
+
+        The user can add/change test data as per their need. The
+        test_advance_config file is in json format and property values are
+        case-sensitive.
 
-	    The user can use the parameters in the configuration file to specify the
-	    server details and connection properties as per their local setup. The
-	    test_config file is in json format and property values are case-sensitive.
 
 Test Data Details
 -----------------
@@ -92,5 +103,18 @@ Execution:
   and registered automatically by its module name in
   'pgadmin4/web/pgadmin/utils/test.py' file.
 
-- Execute test framework run 'regression/testsuite.py' file.
+- As the test framework is modular and dynamically locates the tests
+  package, We can now executes test framework node wise
+
+- Execute test framework for all nodes
+     run 'regression/testsuite.py --pkg all'
+
+- Execute test framework for single node at a time
+
+     Example 1) Run test framework for 'browser' node
+     run 'regression/testsuite.py --pkg browser'
+
+     Example 2) Run test framework for 'database' node
+     run 'regression/testsuite.py --pkg browser.server_groups.servers.databases'
+
 
diff --git a/web/regression/config.py b/web/regression/config.py
index bef65fb..f48eade 100644
--- a/web/regression/config.py
+++ b/web/regression/config.py
@@ -14,3 +14,8 @@ root = os.path.dirname(os.path.realpath(__file__))
 
 with open(root + '/test_config.json') as data_file:
     config_data = json.load(data_file)
+
+with open(root + '/test_advance_config.json') as data_file:
+    advance_config_data = json.load(data_file)
+
+pickle_path = os.path.join(root, 'parent_id.pkl')
diff --git a/web/regression/test_advance_config.json.in b/web/regression/test_advance_config.json.in
new file mode 100644
index 0000000..bcb867c
--- /dev/null
+++ b/web/regression/test_advance_config.json.in
@@ -0,0 +1,105 @@
+{
+  "test_add_database_data": [
+   {
+    "test_privileges_acl": [
+      {
+        "grantee": "postgres",
+        "grantor": "postgres",
+        "privileges": [
+          {
+            "privilege_type": "C",
+            "privilege": true,
+            "with_grant": true
+          },
+          {
+            "privilege_type": "T",
+            "privilege": true,
+            "with_grant": false
+          }
+        ]
+      }
+    ],
+    "test_conn_limit": -1,
+    "test_owner": "postgres",
+    "test_fun_acl": [
+      {
+        "grantee": "postgres",
+        "grantor": "postgres",
+        "privileges": [
+          {
+            "privilege_type": "X",
+            "privilege": true,
+            "with_grant": false
+          }
+        ]
+      }
+    ],
+    "test_seq_acl": [
+      {
+        "grantee": "postgres",
+        "grantor": "postgres",
+        "privileges": [
+          {
+            "privilege_type": "r",
+            "privilege": true,
+            "with_grant": false
+          },
+          {
+            "privilege_type": "w",
+            "privilege": true,
+            "with_grant": false
+          },
+          {
+            "privilege_type": "U",
+            "privilege": true,
+            "with_grant": false
+          }
+        ]
+      }
+    ],
+    "test_tbl_acl": [
+      {
+        "grantee": "postgres",
+        "grantor": "postgres",
+        "privileges": [
+          {
+            "privilege_type": "a",
+            "privilege": true,
+            "with_grant": true
+          },
+          {
+            "privilege_type": "r",
+            "privilege": true,
+            "with_grant": false
+          }
+        ]
+      }
+    ],
+    "test_type_acl": [
+      {
+        "grantee": "postgres",
+        "grantor": "postgres",
+        "privileges": [
+          {
+            "privilege_type": "U",
+            "privilege": true,
+            "with_grant": false
+          }
+        ]
+      }
+    ],
+    "test_encoding": "UTF8",
+    "test_name": "test_db_automation",
+    "test_privileges": [],
+    "test_securities": [],
+    "test_variables": []
+  }
+ ],
+
+  "test_db_update_data": [
+  {
+      "test_comment": "This is db update comment"
+  }
+ ]
+
+}
\ No newline at end of file
diff --git a/web/regression/test_nodes.py b/web/regression/test_nodes.py
new file mode 100644
index 0000000..0fa4695
--- /dev/null
+++ b/web/regression/test_nodes.py
@@ -0,0 +1,40 @@
+# ##################################################################
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2016, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+# ##################################################################
+
+import json
+
+from regression.config import config_data
+from regression.test_utils import get_ids
+
+
+def test_getnodes(node=None):
+    # Connect to server and database.
+
+    if not node:
+        return None
+
+    all_id = get_ids()
+
+    server_id = all_id["sid"][0]
+    db_id = all_id["did"][0]
+    srv_grp = config_data['test_server_group']
+
+    # Connect to server
+    response = node.tester.post('browser/server/connect/{0}/{1}'.format(
+        srv_grp, server_id), data = dict(
+        password=config_data['test_server_credentials'][0]['test_db_password']),
+        follow_redirects = True)
+
+    # Connect to database
+    con_response = node.tester.post(
+        'browser/database/connect/{0}/{1}/{2}'.format(
+            srv_grp, server_id, db_id), follow_redirects = True)
+
+    db_con = json.loads(con_response.data.decode())
+
+    return db_con
\ No newline at end of file
diff --git a/web/regression/test_utils.py b/web/regression/test_utils.py
new file mode 100644
index 0000000..f21de54
--- /dev/null
+++ b/web/regression/test_utils.py
@@ -0,0 +1,289 @@
+# #################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2016, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+# ##################################################################
+
+import os
+import pickle
+import json
+import uuid
+
+import config
+from regression.config import config_data
+
+SERVER_URL = '/browser/server/obj/'
+SERVER_CONNECT_URL = 'browser/server/connect/'
+DATABASE_CONNECT_URL = '/browser/database/obj/'
+
+
+def get_ids(url=config.APP_ROOT + '/regression/parent_id.pkl'):
+    """
+    This function read the parent node's id and return it
+
+    :param url: file path from which it will red the ids
+    :type url: str
+    :return: node ids
+    :rtype: dict
+    """
+
+    output = open(url, 'rb')
+    ids = pickle.load(output)
+    output.close()
+
+    return ids
+
+
+def login_tester_account(tester):
+    """
+    This function login the test account using credentials mentioned in
+    config file
+
+    :param tester: test client
+    :type tester: flask test client object
+    :return: None
+    """
+
+    email = \
+        config_data['pgAdmin4_login_credentials']['test_login_username']
+    password = \
+        config_data['pgAdmin4_login_credentials']['test_login_password']
+    response = tester.post('/login', data=dict(
+        email=email, password=password), follow_redirects=True)
+
+
+def logout_tester_account(tester):
+    """
+    This function logout the test account
+
+    :param tester: test client
+    :type tester: flask test client object
+    :return: None
+    """
+
+    response = tester.get('/logout')
+
+
+def get_config_data():
+    """
+    This function get the data related to server group and database
+    like db name, host, port and username etc.
+
+    :return: server_group, db_data, pickle_id_dict
+    :rtype: server_group:dict, db_data:list, pickle_id_dict:dict
+    """
+
+    db_data = []
+
+    pickle_id_dict = {
+        "sid": [],  # server
+        "did": [],  # database
+        "lrid": [],  # login role
+        "tsid": [],  # tablspace
+        "cid": [],  # cast
+        "eid": [],  # extention
+        "lid": [12397],  # language
+        "scid": [],  # schema
+        "tfnid": [],  # trigger function
+        "etid": [],  # event trigger
+        "coid": [],  # collation
+        "fid": [],  # FDW
+        "doid": [],  # Domain
+        "seid": [],  # Sequence
+        "tid": [],  # table
+        "vid": [],  # view
+        "mvid": [],  # mview
+        "fsid": [],  # foreign server
+        "umid": [],  # User mapping
+        "foid": []  # foreign table
+    }
+
+    server_group = config_data['test_server_group']
+
+    for srv in config_data['test_server_credentials']:
+        data = {"name": srv['test_name'],
+                "comment": "",
+                "host": srv['test_host'],
+                "port": srv['test_db_port'],
+                "db": srv['test_maintenance_db'],
+                "username": srv['test_db_username'],
+                "role": "",
+                "sslmode": srv['test_sslmode']}
+        db_data.append(data)
+    return server_group, db_data, pickle_id_dict
+
+
+def write_parent_id(response_data, pickle_id_dict):
+    """
+    This function writes the server's details to file parent_id.pkl
+
+    :param response_data: server's data
+    :type response_data: list of dictionary
+    :param pickle_id_dict: contains ids of server,database,tables etc.
+    :type pickle_id_dict: dict
+    :return: None
+    """
+
+    server_id = response_data['node']['_id']
+    if os.path.isfile(config.APP_ROOT + '/regression/parent_id.pkl'):
+        existed_server_id = open(
+            config.APP_ROOT + '/regression/parent_id.pkl', 'rb')
+        pickle_id_dict = pickle.load(existed_server_id)
+
+    pickle_id_dict["sid"].append(server_id)
+    output = open(config.APP_ROOT + '/regression/parent_id.pkl', 'wb')
+    pickle.dump(pickle_id_dict, output)
+    output.close()
+
+
+def write_db_parent_id(response_data):
+    """
+    This function writes the server and database related data like server
+    name, server id , database name, database id etc.
+
+    :param response_data: server and databases details
+    :type response_data: dict
+    :return: None
+    """
+
+    db_id = response_data['node']['_id']
+    if os.path.isfile(config.APP_ROOT + '/regression/parent_id.pkl'):
+        existing_server_id = open(
+            config.APP_ROOT + '/regression/parent_id.pkl', 'rb')
+        tol_server_id = pickle.load(existing_server_id)
+        pickle_id_dict = tol_server_id
+
+        pickle_id_dict["did"].append(db_id)
+
+        db_output = open(
+            config.APP_ROOT + '/regression/parent_id.pkl', 'wb')
+        pickle.dump(pickle_id_dict, db_output)
+        db_output.close()
+
+
+def delete_parent_id_file():
+    """
+    This function deletes the file parent_id.pkl which contains server and
+    database details
+
+    :return: None
+    """
+
+    if os.path.isfile(config.APP_ROOT + '/regression/parent_id.pkl'):
+        os.remove(config.APP_ROOT + '/regression/parent_id.pkl')
+
+
+def add_server(tester):
+    """
+    This function add the server in the existing server group
+
+    :param tester: test object
+    :type tester: flask test object
+    :return:None
+    """
+
+    server_group, db_data, pickle_id_dict = get_config_data()
+    url = "{0}{1}/".format(SERVER_URL, server_group)
+    response = tester.post(url, data=json.dumps(db_data[0]),
+                           content_type='html/json')
+    response_data = json.loads(response.data.decode())
+    write_parent_id(response_data, pickle_id_dict)
+
+
+def get_server(tester):
+    """
+    This function gets the added serer details
+
+    :param tester: test client object
+    :type tester: flask test object
+    :return: response_data
+    :rtype: list
+    """
+
+    all_id = get_ids()
+    server_id = all_id["sid"][0]
+    server_group = config_data['test_server_group']
+
+    response = tester.get(SERVER_URL + str(server_group) + '/' +
+                          str(server_id),
+                          follow_redirects=True)
+    response_data = json.loads(response.data.decode())
+    return response_data
+
+
+def connect_server(tester):
+    """
+    This function used to connect added server
+
+    :param tester:test client object
+    :type tester: flask test object
+    :return: server_connect, server_group, server_id
+    :rtype: server_connect:dict, server_group:dict, server_id:str
+    """
+
+    srv_id = get_ids()
+    server_id = srv_id["sid"][0]
+    server_group = config_data['test_server_group']
+    response = tester.post(SERVER_CONNECT_URL + str(server_group) +
+                           '/' + server_id,
+                           data=dict(
+                               password=config_data
+                               ['test_server_credentials'][0]
+                               ['test_db_password']),
+                           follow_redirects=True)
+    server_connect = json.loads(response.data.decode())
+    connect_database(tester, server_connect, server_id, server_group)
+    return server_connect, server_group, server_id
+
+
+def connect_database(tester, server_connect, server_id, server_group):
+    """
+    This function is used to connect database and writes it's details to
+    file 'parent_id.pkl'
+
+    :param tester: test client object
+    :type tester: flask test client object
+    :param server_connect: server's data
+    :type server_connect: dict
+    :param server_id: server id
+    :type server_id: str
+    :param server_group: server group name
+    :type server_group: str
+    :return: None
+    """
+
+    if server_connect['data']['connected']:
+        data = {
+            "datacl": config_data['test_add_database_data']
+            ['test_privileges_acl'],
+            "datconnlimit": config_data['test_add_database_data']
+            ['test_conn_limit'],
+            "datowner": config_data['test_add_database_data']
+            ['test_owner'],
+            "deffuncacl": config_data['test_add_database_data']
+            ['test_fun_acl'],
+            "defseqacl": config_data['test_add_database_data']
+            ['test_seq_acl'],
+            "deftblacl": config_data['test_add_database_data']
+            ['test_tbl_acl'],
+            "deftypeacl": config_data['test_add_database_data']
+            ['test_type_acl'],
+            "encoding": config_data['test_add_database_data']
+            ['test_encoding'],
+            "name": str(uuid.uuid4())[1:8],
+            "privileges": config_data['test_add_database_data']
+            ['test_privileges'],
+            "securities": config_data['test_add_database_data']
+            ['test_securities'],
+            "variables": config_data['test_add_database_data']
+            ['test_variables']
+        }
+        db_response = tester.post(
+            DATABASE_CONNECT_URL + str(server_group) + "/" + server_id + "/",
+            data=json.dumps(data),
+            content_type='html/json')
+        response_data = json.loads(db_response.data.decode())
+        write_db_parent_id(response_data)
diff --git a/web/regression/testsuite.py b/web/regression/testsuite.py
index 75d437b..c342805 100644
--- a/web/regression/testsuite.py
+++ b/web/regression/testsuite.py
@@ -10,70 +10,140 @@
 """ This file collect all modules/files present in tests directory and add
 them to TestSuite. """
 
+import argparse
 import os
 import sys
 import unittest
+import logging
 
 from testscenarios.scenarios import generate_scenarios
 
-# We need to include the root directory in sys.path to ensure that we can
-# find everything we need when running in the standalone runtime.
-current_path = os.path.dirname(os.path.realpath(__file__))
-root = os.path.dirname(current_path)
+CURRENT_PATH = os.path.dirname(os.path.realpath(__file__))
 
-if sys.path[0] != root:
-    sys.path.insert(0, root)
 
-from pgadmin import create_app
-import config
+def create_pgadmin_app():
+    """
+    This function creates the pgadmin app for testing
 
-# Get the config database schema version. We store this in pgadmin.model
-# as it turns out that putting it in the config files isn't a great idea
-from pgadmin.model import SCHEMA_VERSION
-config.SETTINGS_SCHEMA_VERSION = SCHEMA_VERSION
+    :return: test client
+    :rtype: test app object
+    """
 
-# Create the app!
-app = create_app()
+    # Set sys path to current directory so that we can import pgadmin package
+    root = os.path.dirname(CURRENT_PATH)
+    if sys.path[0] != root:
+        sys.path.insert(0, root)
 
-# Disabling Cross-site request forgery(CSRF token) for testing purpose.
-# CSRF prevent session against malicious Web site, or end users who wants to
-# execute unwanted actions.
-app.config['WTF_CSRF_ENABLED'] = False
+    from pgadmin import create_app
 
-from pgadmin.utils.route import TestsGeneratorRegistry
+    # Create the app
+    app = create_app()
+    app.config['WTF_CSRF_ENABLED'] = False
+    test_app_client = app.test_client()
 
-# Registry will load all the testcases/modules from pgadmin path those are
-# register as BaseTestGenerator.
-TestsGeneratorRegistry.load_generators('pgadmin')
+    return test_app_client
 
-# Create test client
-# werkzeug provides a test client which gives a simple interface to the
-# application. We can trigger test request to the application.
-test_client = app.test_client()
 
+def get_suite(arguments, test_app_client):
+    """
+     This function loads the all modules in the tests directory into testing
+     environment.
 
-def suite():
-    """ Defining test suite which will execute all the testcases present in
-    tests directory according to set priority."""
+    :param arguments: this is command line arguments for module name to
+    which test suite will run
+    :type arguments: str
+    :param test_app_client: test client
+    :type test_app_client: pgadmin app object
+    :return pgadmin_suite: test suite with test cases
+    :rtype: TestSuite
+    """
 
-    pgadmin_suite = unittest.TestSuite()
+    from pgadmin.utils.route import TestsGeneratorRegistry
 
     modules = []
+    pgadmin_suite = unittest.TestSuite()
 
+    # Load the test modules which are in given package(i.e. arguments.pkg)
+    if arguments.pkg == "all":
+        TestsGeneratorRegistry.load_generators('pgadmin')
+    else:
+        TestsGeneratorRegistry.load_generators('pgadmin.{}.tests'.format(
+            arguments.pkg))
+
+    # Get the each test module and add into list
     for key, klass in TestsGeneratorRegistry.registry.items():
         gen = klass
+        modules.append(gen)
 
-        modules.insert(gen.priority, gen)
-
-    for m in modules:
-        obj = m()
-        obj.setTestClient(test_client)
+    # Set the test client to each module & generate the scenarios
+    for module in modules:
+        obj = module()
+        obj.setTestClient(test_app_client)
         scenario = generate_scenarios(obj)
         pgadmin_suite.addTests(scenario)
 
     return pgadmin_suite

+def add_arguments():
+    """
+    This function parse the command line arguments(project's package name
+    e.g. browser) & add into parser
+
+    :return args: command line argument for pgadmin's package name
+    :rtype: argparse namespace
+    """
+
+    parser = argparse.ArgumentParser(description='Test suite for pgAdmin4')
+    parser.add_argument('--pkg', help='Executes the test cases of particular'
+                                      ' package')
+    arg = parser.parse_args()
+
+    return arg
+
+
+class StreamToLogger(object):
+    def __init__(self, logger, log_level=logging.INFO):
+        self.terminal = sys.stderr
+        self.logger = logger
+        self.log_level = log_level
+        self.linebuf = ''
+
+    def write(self, buf):
+        """
+        This function writes the log in the logger file as well as on console
+
+        :param buf: log message
+        :type buf: str
+        :return: None
+        """
+
+        self.terminal.write(buf)
+        for line in buf.rstrip().splitlines():
+            self.logger.log(self.log_level, line.rstrip())
+
+    def flush(self):
+        pass
+
+
 if __name__ == '__main__':
-    suite = suite()
-    tests = unittest.TextTestRunner(descriptions=True, verbosity=2).run(suite)
+    # Set basic logging configuration for log file
+    logging.basicConfig(level=logging.DEBUG,
+                        format='%(asctime)s:%(levelname)s:%(name)s:%(message)s',
+                        filename="logger.log",
+                        filemode='w'
+                        )
+
+    # Create logger to write log in the logger file with on console
+    stderr_logger = logging.getLogger('STDERR')
+    sys.stderr = StreamToLogger(stderr_logger, logging.ERROR)
+
+    # Create the pgadmin app
+    test_client = create_pgadmin_app()
+    args = add_arguments()
+    suite = get_suite(args, test_client)
+    tests = unittest.TextTestRunner(stream=sys.stderr, descriptions=True,
+                                    verbosity=2).run(suite)
+
+    print("\n\n Please check output in file: logger.log placed at ",
+          CURRENT_PATH)

-- 
Sent via pgadmin-hackers mailing list ([email-masked])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgadmin-hackers

---

From: Dave Page <[email-masked]>
Date: Mon, 11 Jul 2016 12:41:23 +0100

> Kindly, review the same and let me know for any modification.

Please re-create the patch so that it doesn't revert various changes made
to config.py etc. over the last couple of weeks.

What is the patch for? Is it fixing issues in Priyanka's last patch, or
something else?

-- 
Dave Page
VP, Chief Architect, Tools & Installers
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

Blog: http://pgsnake.blogspot.com
Twitter: @pgsnake

---

From: Navnath Gadakh <[email-masked]>
Date: Mon, 11 Jul 2016 18:46:04 +0530

Hi Dave,
PFA updated patch for modular API test cases.

> to config.py etc. over the last couple of weeks.

  config.py file was not updated at my end, I have updated it in the
current patch.  I have also added code related to advance test data
configuration which was created by Priyanka (Seprated the test data
configuration files).

> This patch is for -
> 1. Now we can run testsuite node/module wise(like for browser only, for
> databases only)  OR for all nodes/modules
> 2. I have modified the existing functionality for testsuite and all test
> case classes (Made all test cases independently runnable, removed
> the priority logic).
>

    For more details please refer the file 'regression/README'.

 
 
 import json

 
     scenarios = [
 
-    def runTest(self):
+    def setUp(self):
         """

 
 
 import json

 
     scenarios = [
 
-    def runTest(self):
+    def setUp(self):
         """

 

 
 
-import json
-

-    priority = 5
-
     scenarios = [
 
-    def runTest(self):
+    def setUp(self):
         """

 
 import json

 
     scenarios = [
 
-    def runTest(self):
-        """

 

 

 
 
 class SGGenerateTestCase(BaseTestGenerator):
     def runTest(self):
-        print ("In SGGenerateTestCase...")
+        return
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/tests/test_sg_add.py b/web/pgadmin/browser/server_groups/tests/test_sg_add.py
deleted file mode 100644
index e70bb65..0000000
--- a/web/pgadmin/browser/server_groups/tests/test_sg_add.py
+++ /dev/null
@@ -1,36 +0,0 @@
-###########################################################################
-#
-# pgAdmin 4 - PostgreSQL Tools
-#
-# Copyright (C) 2013 - 2016, The pgAdmin Development Team
-# This software is released under the PostgreSQL Licence
-#
-###########################################################################
-
-import json
-
-from pgadmin.browser.tests.test_login import LoginTestCase
-from regression.config import config_data
-
-
-class SgNodeTestCase(LoginTestCase):
-    """
-     This class will check available server groups in pgAdmin.
-    """
-
-    priority = 1
-
-    scenarios = [
-        # Fetching the default url for server group node
-        ('Check Server Group Node', dict(url='/browser/server-group/obj/'))
-    ]
-
-    def runTest(self):
-        """This function will check available server groups."""
-
-        i = config_data['test_server_group']
-
-        response = self.tester.get(self.url + str(i), content_type='html/json')
-        self.assertTrue(response.status_code, 200)
-        respdata = json.loads(response.data)
-        self.assertTrue(respdata['id'], i)
diff --git a/web/pgadmin/browser/server_groups/tests/test_sg_get.py b/web/pgadmin/browser/server_groups/tests/test_sg_get.py
new file mode 100644
index 0000000..07bbe96
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/tests/test_sg_get.py
@@ -0,0 +1,48 @@
+###########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2016, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+###########################################################################
+
+import json
+
+from pgadmin.utils.route import BaseTestGenerator
+from regression import test_utils as utils
+from regression.config import config_data
+
+
+class SgNodeTestCase(BaseTestGenerator):
+    """
+     This class will check available server groups in pgAdmin.
+    """
+
+    scenarios = [
+        # Fetching the default url for server group node
+        ('Check Server Group Node', dict(url='/browser/server-group/obj/'))
+    ]
+
+    def setUp(self):
+        """
+        This function login the test account before running the logout
+        test case
+        """
+
+        utils.login_tester_account(self.tester)
+
+    def runTest(self):
+        """This function will check available server groups."""
+
+        server_group_id = config_data['test_server_group']
+        response = self.tester.get(self.url + str(server_group_id),
+                                   content_type='html/json')
+        self.assertTrue(response.status_code, 200)
+        response_data = json.loads(response.data.decode('utf8'))
+        self.assertTrue(response_data['id'], server_group_id)
+
+    def tearDown(self):
+        """This function logout the test account """
+
+        utils.logout_tester_account(self.tester)
diff --git a/web/pgadmin/browser/tests/__init__.py b/web/pgadmin/browser/tests/__init__.py
index 2381efd..3fab6fe 100644
--- a/web/pgadmin/browser/tests/__init__.py
+++ b/web/pgadmin/browser/tests/__init__.py
@@ -12,4 +12,4 @@ from pgadmin.utils.route import BaseTestGenerator

 import uuid

 
-    priority = 2
-
     scenarios = [

     ]
 
+    def setUp(self):
+        """

 import uuid
-

-    priority = 0
-
     scenarios = [
 
+    def setUp(self):
+        pass
+
     def runTest(self):

 

-    priority = 3
-
     scenarios = [
 
+    def setUp(self):
+        """

 
     scenarios = [
 
+    def setUp(self):
+        """

 
 import six

 

 

 Test Data Details
 -----------------

 
index 0000000..900f405
@@ -0,0 +1,290 @@
index 75d437b..cf824b9 100644
@@ -10,70 +10,147 @@
 
+import argparse
 import os
 import sys
 import unittest
+import logging

 
-if sys.path[0] != root:

 
-# Create the app!
-app = create_app()
 
+    import config
 
-from pgadmin.utils.route import TestsGeneratorRegistry
+    # Get the config database schema version. We store this in pgadmin.model
+    # as it turns out that putting it in the config files isn't a great idea
+    from pgadmin.model import SCHEMA_VERSION
 
-# Registry will load all the testcases/modules from pgadmin path those are
-# register as BaseTestGenerator.
-TestsGeneratorRegistry.load_generators('pgadmin')
+    config.SETTINGS_SCHEMA_VERSION = SCHEMA_VERSION
 
-# Create test client
 
+    return test_app_client
 
-def suite():

     modules = []

 
     return pgadmin_suite

+def add_arguments():
+    """

---

From: Dave Page <[email-masked]>
Date: Fri, 15 Jul 2016 13:53:53 +0100

Hi

When running all tests, I get:

...
...
 <Rule '//static/<filename>' (HEAD, OPTIONS, GET) -> redirects.static>,
 <Rule '/backup/<filename>' (HEAD, OPTIONS, GET) -> backup.static>,
 <Rule '/reset/<token>' (HEAD, POST, OPTIONS, GET) ->
security.reset_password>,
 <Rule '/about/<filename>' (HEAD, OPTIONS, GET) -> about.static>])
Traceback (most recent call last):
  File "regression/testsuite.py", line 151, in <module>
    suite = get_suite(args, test_client)
  File "regression/testsuite.py", line 75, in get_suite
    TestsGeneratorRegistry.load_generators('pgadmin')
  File "/Users/dpage/git/pgadmin4/web/pgadmin/utils/route.py", line 56, in
load_generators
    module = import_module(module_name)
  File
"/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/importlib/__init__.py",
line 37, in import_module
    __import__(name)
  File
"/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/databases/tests/test_db_add.py",
line 14, in <module>
    from regression import test_utils as utils
  File "/Users/dpage/git/pgadmin4/web/regression/test_utils.py", line 23,
in <module>
    def get_ids(url=config.APP_ROOT + '/regression/parent_id.pkl'):
AttributeError: 'module' object has no attribute 'APP_ROOT'

That's not overly surprising, as we don't have an APP_ROOT setting in the
config (nor should we - it should be calculated dynamically). Please fix,
and remember to test your patches against a clean copy of the git tree in
the future!

Thanks!

---

From: Navnath Gadakh <[email-masked]>
Date: Mon, 18 Jul 2016 18:15:17 +0530

Hi Dave,

  Please find the revised patch for unit tests of pgAdmin4 APIs.

This patch includes-

   1.

   test_advance_config.json(for user it’s test_advance_config.json.in) for
   advance test configuration for database/server(Priyanka was working on this)
   2.

   test_config.json(for user it’s test_config_json.in) for basic
   credentials data for database/server
   3.

   From now onward we can execute test cases node wise/package wise. I have
   slightly modified the way of running the testsuite. We used the command
   line arguments(pkg) which denotes for which package testsuite going to
   run.

          Run the testsuite for all packages by following command

               Python regression/testsuite.py --pkg all

      Here, ‘all’ means for all python
packages(i.e.browser,server_groups,server,

                            databases etc. which are same names in project
directory structure)

               This will find the ‘tests’ directory in each package &
execute the test cases.

          Run the testsuite for single package by following command

      Python regression/testsuite.py --pkg browser (this execute the tests
in ‘browser’ package only)

       Python regression/testsuite.py --pkg
browser.server_groups.servers.databases (this execute the tests in
‘databases’ package only)

  4.  Logger file. Which include the detailed output of the testsuite.
Testsuite also prints the test summary on the console.

    5.  Previously, we set the priority to each test case. In this patch
priority logic is removed as there is no need to set priority.

    6. Resolution of AttributeError for attribute 'APP_ROOT'(Which is
mentioned by you in a previous email)

Note: You might get ‘AttributeError’ while running this patch on Python 3.4
(I have raised this bug in RM(#1464)), But still you can run the testsuite.
It will run on Python 2.7 without error.

On Fri, Jul 15, 2016 at 6:23 PM, Dave Page <[email-masked]>
wrote:

>>> Please re-create the patch so that it doesn't revert various changes
>>> made to config.py etc. over the last couple of weeks.
>>>
>>

-- 
Thanks,
Navnath Gadakh
Software Engineer
EnterpriseDB Corporation
Mobile: +91 9975389878
index 0000000..14b9749
@@ -0,0 +1,74 @@
+        server_connect_response, server_group, server_ids = \
+        # Store db id. Which is use to delete in tearDown()
+        self.db_id = ''
+        for server_connect, server_id in zip(server_connect_response,
+                                             server_ids):
+                data = utils.get_db_data(server_connect)
+                db_response = self.tester.post(self.url + str(server_group) +
+                                               "/" + server_id + "/",
+                response_data = json.loads(db_response.data.decode('utf-8'))
+                self.db_id = response_data['node']['_id']
+        utils.delete_database(self.tester, self.db_id)
+        utils.delete_server(self.tester)
index 0000000..46c59e4
@@ -0,0 +1,73 @@
+from regression.test_utils import get_ids, test_getnodes
+        # TODO: Need to modify the code , to delete the databases for all
+        # TODO: servers. Currently it delete only one database.
+        db_con = test_getnodes(self.tester)
+            response_data = json.loads(response.data.decode('utf-8'))
+        utils.delete_server(self.tester)
index 0000000..3edd6b8
@@ -0,0 +1,72 @@
+from regression.test_utils import get_ids, test_getnodes
+        # TODO: Code is remaining to get all databases of all servers
+        self.db_id = all_id["did"][0]
+            db_con = test_getnodes(self.tester)
+                                           str(server_id) + '/' + str(
+                    self.db_id),
+        utils.delete_database(self.tester, self.db_id)
+        utils.delete_server(self.tester)
index 0000000..347e684
@@ -0,0 +1,79 @@
+from regression.test_utils import get_ids, test_getnodes
+        # TODO: Need to modify the code , to delete the databases for all
+        # TODO: servers. Currently it delete only one database.
+        test_getnodes(self.tester)
+        utils.delete_server(self.tester)
 
index 0af13d3..847b1b6 100644
@@ -9,45 +9,50 @@
 
 import json

 
     scenarios = [
 
-    def runTest(self):
+    def setUp(self):
         """

 
+        utils.delete_server(self.tester)
index 329d74f..4f312cf 100644
@@ -9,49 +9,59 @@
 
 import json

 
     scenarios = [
 
-    def runTest(self):
+    def setUp(self):
         """

 
 
-            url = self.url + str(srv_grp) + "/"
+        url = self.url + str(srv_grp) + "/"
+        if len(server_ids) == 0:
+            raise Exception("No server(s) to delete!!!")
 
+        # Call api to delete the servers
+            response = self.tester.delete(url + str(server_id))
 
index 050843e..6356a6b 100644
@@ -7,43 +7,55 @@
 
-import json
-

-    priority = 5
-
     scenarios = [
 
-    def runTest(self):
+    def setUp(self):
         """

+        utils.delete_server(self.tester)
index 306bb03..31d3eb2 100644
@@ -9,57 +9,67 @@
 
 import json

 
     scenarios = [
 
-    def runTest(self):
-        """

+        self.server_connect, self.server_group, self.server_ids = \
 
-            for server in respdata:
+    def runTest(self):
+        """ This function will update the server's comment field. """
+
+        for server_id in self.server_ids:
+            data = {
+                "comment":
+                    config_data['test_server_update_data'][0]['test_comment'],
+                "id": server_id
+            }
+            put_response = self.tester.put(
+                self.url + str(self.server_group) + '/' +
+                str(server_id), data=json.dumps(data),
+                content_type='html/json')
+            self.assertEquals(put_response.status_code, 200)
+
+            response_data = json.loads(put_response.data.decode())
+            self.assertTrue(response_data['success'], 1)
+
+    def tearDown(self):
+        """
+        This function deletes the 'parent_id.pkl' file which is created in
+        setup() function. Also this function logout the test client

+        utils.delete_server(self.tester)

index dedb7d9..605aa0f 100644
 
 import uuid

 
-    priority = 2
-
     scenarios = [

     ]
 
+    def setUp(self):
+        """
 
+        self.assertIn(self.respdata, response.data.decode('utf-8'))
 
 import uuid
-

-    priority = 0
-
     scenarios = [
 
+    def setUp(self):
+        pass
+
     def runTest(self):

 

-    priority = 3
-
     scenarios = [
 
+    def setUp(self):
+        """
 
index 030b182..96404df 100644

 
     scenarios = [
 
+    def setUp(self):
+        """
 
+        self.assertIn(self.respdata, response.data.decode('utf-8'))

 import six
 
index e0003e4..6a91911 100644

 

 
 
 Test Data Details
 -----------------
@@ -92,5 +103,16 @@ Execution:
   and registered automatically by its module name in
   'pgadmin4/web/pgadmin/utils/test.py' file.

index bef65fb..564d1c2 100644
@@ -10,7 +10,12 @@
 import json
 import os
 
-root = os.path.dirname(os.path.realpath(__file__))
+from regression.testsuite import CURRENT_PATH
 
-with open(root + '/test_config.json') as data_file:
+with open(CURRENT_PATH + '/test_config.json') as data_file:
     config_data = json.load(data_file)
+
+with open(CURRENT_PATH + '/test_advance_config.json') as data_file:
+    advance_config_data = json.load(data_file)
+
+pickle_path = os.path.join(CURRENT_PATH, 'parent_id.pkl')
diff --git a/web/regression/test_advance_config.json.in b/web/regression/test_advance_config.json.in
new file mode 100644
index 0000000..bcb867c
--- /dev/null
+++ b/web/regression/test_advance_config.json.in
@@ -0,0 +1,105 @@
+{
+  "test_add_database_data": [
+   {
+    "test_privileges_acl": [
+      {
+        "grantee": "postgres",
+        "grantor": "postgres",
+        "privileges": [
+          {
+            "privilege_type": "C",
+            "privilege": true,
+            "with_grant": true
+          },
+          {
+            "privilege_type": "T",
+            "privilege": true,
+            "with_grant": false
+          }
+        ]
+      }
+    ],
+    "test_conn_limit": -1,
+    "test_owner": "postgres",
+    "test_fun_acl": [
+      {
+        "grantee": "postgres",
+        "grantor": "postgres",
+        "privileges": [
+          {
+            "privilege_type": "X",
+            "privilege": true,
+            "with_grant": false
+          }
+        ]
+      }
+    ],
+    "test_seq_acl": [
+      {
+        "grantee": "postgres",
+        "grantor": "postgres",
+        "privileges": [
+          {
+            "privilege_type": "r",
+            "privilege": true,
+            "with_grant": false
+          },
+          {
+            "privilege_type": "w",
+            "privilege": true,
+            "with_grant": false
+          },
+          {
+            "privilege_type": "U",
+            "privilege": true,
+            "with_grant": false
+          }
+        ]
+      }
+    ],
+    "test_tbl_acl": [
+      {
+        "grantee": "postgres",
+        "grantor": "postgres",
+        "privileges": [
+          {
+            "privilege_type": "a",
+            "privilege": true,
+            "with_grant": true
+          },
+          {
+            "privilege_type": "r",
+            "privilege": true,
+            "with_grant": false
+          }
+        ]
+      }
+    ],
+    "test_type_acl": [
+      {
+        "grantee": "postgres",
+        "grantor": "postgres",
+        "privileges": [
+          {
+            "privilege_type": "U",
+            "privilege": true,
+            "with_grant": false
+          }
+        ]
+      }
+    ],
+    "test_encoding": "UTF8",
+    "test_name": "test_db_automation",
+    "test_privileges": [],
+    "test_securities": [],
+    "test_variables": []
+  }
+ ],
+
+  "test_db_update_data": [
+  {
+      "test_comment": "This is db update comment"
+  }
+ ]
+
+}
\ No newline at end of file
diff --git a/web/regression/test_utils.py b/web/regression/test_utils.py
new file mode 100644
index 0000000..14d186c
--- /dev/null
+++ b/web/regression/test_utils.py
@@ -0,0 +1,371 @@
+# #################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2016, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+# ##################################################################
+
+import os
+import pickle
+import json
+import uuid
+
+from regression.config import config_data, advance_config_data, pickle_path
+
+SERVER_URL = '/browser/server/obj/'
+SERVER_CONNECT_URL = 'browser/server/connect/'
+DATABASE_CONNECT_URL = '/browser/database/obj/'
+
+
+def get_ids(url=pickle_path):
+    """
+    This function read the parent node's id and return it
+
+    :param url: file path from which it will red the ids
+    :type url: str
+    :return: node ids
+    :rtype: dict
+    """
+
+    output = open(url, 'rb')
+    ids = pickle.load(output)
+    output.close()
+
+    return ids
+
+
+def test_getnodes(tester=None):
+    # Connect to server and database.
+
+    if not tester:
+        return None
+
+    all_id = get_ids()
+
+    server_ids = all_id["sid"]
+    db_id = all_id["did"][0]
+    srv_grp = config_data['test_server_group']
+
+    # TODO: need to add code to handle multiple databases with servers
+    for server_id in server_ids:
+        # Connect to server
+        response = tester.post('browser/server/connect/{0}/{1}'.format(
+            srv_grp, server_id), data=dict(
+            password=config_data['test_server_credentials'][0][
+                'test_db_password']),
+            follow_redirects=True)
+
+        # Connect to database
+        con_response = tester.post(
+            'browser/database/connect/{0}/{1}/{2}'.format(
+                srv_grp, server_id, db_id), follow_redirects=True)
+        db_con = json.loads(con_response.data.decode('utf-8'))
+
+    return db_con
+
+
+def get_db_data(server_connect_data):
+    """
+    This function is used to get advance config test data for appropriate
+    server
+
+    :param server_connect_data: list of server details
+    :return data: database details
+    :rtype: dict
+    """
+
+    db_user = server_connect_data['data']['user']['name']
+
+    if db_user == "postgres":
+        # Get the advance test data of 'postgres' user
+        adv_config_data = advance_config_data[
+            'test_add_database_data'][0]
+    else:
+        # Get the advance test data of 'enterprisedb' user
+        adv_config_data = advance_config_data[
+            'test_add_database_data'][1]
+
+    data = {
+        "datacl": adv_config_data['test_privileges_acl'],
+        "datconnlimit": adv_config_data['test_conn_limit'],
+        "datowner": adv_config_data['test_owner'],
+        "deffuncacl": adv_config_data['test_fun_acl'],
+        "defseqacl": adv_config_data['test_seq_acl'],
+        "deftblacl": adv_config_data['test_tbl_acl'],
+        "deftypeacl": adv_config_data['test_type_acl'],
+        "encoding": adv_config_data['test_encoding'],
+        "name": str(uuid.uuid4())[1:8],
+        "privileges": adv_config_data['test_privileges'],
+        "securities": adv_config_data['test_securities'],
+        "variables": adv_config_data['test_variables']
+    }
+
+    return data
+
+
+def login_tester_account(tester):
+    """
+    This function login the test account using credentials mentioned in
+    config file
+
+    :param tester: test client
+    :type tester: flask test client object
+    :return: None
+    """
+
+    email = \
+        config_data['pgAdmin4_login_credentials']['test_login_username']
+    password = \
+        config_data['pgAdmin4_login_credentials']['test_login_password']
+    response = tester.post('/login', data=dict(
+        email=email, password=password), follow_redirects=True)
+
+
+def logout_tester_account(tester):
+    """
+    This function logout the test account
+
+    :param tester: test client
+    :type tester: flask test client object
+    :return: None
+    """
+
+    response = tester.get('/logout')
+
+
+def get_config_data():
+    """
+    This function get the data related to server group and database
+    like db name, host, port and username etc.
+
+    :return: server_group, db_data, pickle_id_dict
+    :rtype: server_group:dict, db_data:list, pickle_id_dict:dict
+    """
+
+    db_data = []
+
+    pickle_id_dict = {
+        "sid": [],  # server
+        "did": []  # database
+    }
+
+    server_group = config_data['test_server_group']
+
+    for srv in config_data['test_server_credentials']:
+        data = {"name": srv['test_name'],
+                "comment": "",
+                "host": srv['test_host'],
+                "port": srv['test_db_port'],
+                "db": srv['test_maintenance_db'],
+                "username": srv['test_db_username'],
+                "role": "",
+                "sslmode": srv['test_sslmode']}
+        db_data.append(data)
+    return server_group, db_data, pickle_id_dict
+
+
+def write_parent_id(response_data, pickle_id_dict):
+    """
+    This function writes the server's details to file parent_id.pkl
+
+    :param response_data: server's data
+    :type response_data: list of dictionary
+    :param pickle_id_dict: contains ids of server,database,tables etc.
+    :type pickle_id_dict: dict
+    :return: None
+    """
+
+    server_id = response_data['node']['_id']
+    if os.path.isfile(pickle_path):
+        existed_server_id = open(pickle_path, 'rb')
+        pickle_id_dict = pickle.load(existed_server_id)
+
+    pickle_id_dict["sid"].append(server_id)
+    output = open(pickle_path, 'wb')
+    pickle.dump(pickle_id_dict, output)
+    output.close()
+
+
+def write_db_parent_id(response_data):
+    """
+    This function writes the server and database related data like server
+    name, server id , database name, database id etc.
+
+    :param response_data: server and databases details
+    :type response_data: dict
+    :return: None
+    """
+
+    db_id = response_data['node']['_id']
+    if os.path.isfile(pickle_path):
+        existing_server_id = open(pickle_path, 'rb')
+        tol_server_id = pickle.load(existing_server_id)
+        pickle_id_dict = tol_server_id
+
+        pickle_id_dict["did"].append(db_id)
+
+        db_output = open(pickle_path, 'wb')
+        pickle.dump(pickle_id_dict, db_output)
+        db_output.close()
+
+
+def delete_parent_id_file():
+    """
+    This function deletes the file parent_id.pkl which contains server and
+    database details
+
+    :return: None
+    """
+
+    if os.path.isfile(pickle_path):
+        os.remove(pickle_path)
+
+
+def add_server(tester):
+    """
+    This function add the server in the existing server group
+
+    :param tester: test object
+    :type tester: flask test object
+    :return:None
+    """
+
+    server_group, db_data, pickle_id_dict = get_config_data()
+    url = "{0}{1}/".format(SERVER_URL, server_group)
+    for db_detail in db_data:
+        response = tester.post(url, data=json.dumps(db_detail),
+                               content_type='html/json')
+        response_data = json.loads(response.data.decode())
+        write_parent_id(response_data, pickle_id_dict)
+
+
+def get_server(tester):
+    """
+    This function gets the added serer details
+
+    :param tester: test client object
+    :type tester: flask test object
+    :return: response_data
+    :rtype: list
+    """
+
+    all_id = get_ids()
+    server_ids = all_id["sid"]
+    server_group = config_data['test_server_group']
+    for server_id in server_ids:
+        response = tester.get(SERVER_URL + str(server_group) + '/' +
+                              str(server_id),
+                              follow_redirects=True)
+        response_data = json.loads(response.data.decode())
+
+
+def connect_server(tester):
+    """
+    This function used to connect added server
+
+    :param tester:test client object
+    :type tester: flask test object
+    :return: server_connect, server_group, server_id
+    :rtype: server_connect:dict, server_group:dict, server_id:str
+    """
+
+    server_connect = []
+    servers = []
+
+    srv_id = get_ids()
+    server_ids = srv_id["sid"]
+    server_group = config_data['test_server_group']
+
+    # Connect to all servers
+    for server_id in server_ids:
+        response = tester.post(SERVER_CONNECT_URL + str(server_group) +
+                               '/' + server_id,
+                               data=dict(
+                                   password=config_data
+                                   ['test_server_credentials'][0]
+                                   ['test_db_password']),
+                               follow_redirects=True)
+        server_connect_detail = json.loads(response.data.decode())
+        connect_database(tester, server_connect_detail, server_id, server_group)
+        server_connect.append(server_connect_detail)
+        servers.append(server_id)
+    return server_connect, server_group, servers
+
+
+def connect_database(tester, server_connect, server_id, server_group):
+    """
+    This function is used to connect database and writes it's details to
+    file 'parent_id.pkl'
+
+    :param tester: test client object
+    :type tester: flask test client object
+    :param server_connect: server's data
+    :type server_connect: dict
+    :param server_id: server id
+    :type server_id: str
+    :param server_group: server group name
+    :type server_group: str
+    :return: None
+    """
+
+    if server_connect['data']['connected']:
+        db_data = get_db_data(server_connect)
+        db_response = tester.post(
+            DATABASE_CONNECT_URL + str(server_group) + "/" + server_id + "/",
+            data=json.dumps(db_data),
+            content_type='html/json')
+        response_data = json.loads(db_response.data.decode())
+        write_db_parent_id(response_data)
+
+
+def delete_server(tester):
+    """
+    This function used to delete the added servers
+
+    :param tester: test client object
+    :return: None
+    """
+
+    srv_grp = config_data['test_server_group']
+    all_id = get_ids()
+    server_ids = all_id["sid"]
+    url = SERVER_URL + str(srv_grp) + "/"
+
+    # Call api to delete the servers
+    for server_id in server_ids:
+        response = tester.delete(url + str(server_id))
+        assert response.status_code == 200
+        response_data = json.loads(response.data.decode())
+        assert response_data['success'] == 1
+
+
+def delete_database(tester, db_id):
+    """
+    This function used to delete the added databases
+
+    :param tester: test client object
+    :param db_id: database id to be delete
+    :type db_id: int
+    :return: None
+    """
+
+    srv_grp = config_data['test_server_group']
+    all_id = get_ids()
+    server_ids = all_id["sid"]
+
+    # TODO: Need to modify the code , to delete the databases for all
+    # TODO: servers. Currently it delete only one database.
+    #db_id = all_id["did"][0]
+
+    db_con = test_getnodes(tester)
+    if len(db_con) == 0:
+        raise Exception("No database(s) to delete!!!")
+
+    for server_id in server_ids:
+        response = tester.delete(DATABASE_CONNECT_URL + str(srv_grp) + '/' + str(
+            server_id) + '/' + str(db_id), follow_redirects=True)
+        assert response.status_code == 200
+        response_data = json.loads(response.data.decode('utf-8'))
+        assert response_data['success'] == 1
diff --git a/web/regression/testsuite.py b/web/regression/testsuite.py
index 75d437b..9c57c3e 100644
--- a/web/regression/testsuite.py
+++ b/web/regression/testsuite.py
@@ -10,16 +10,18 @@
 """ This file collect all modules/files present in tests directory and add
 them to TestSuite. """
 
+import argparse
 import os
 import sys
 import unittest
+import logging

-# We need to include the root directory in sys.path to ensure that we can
-# find everything we need when running in the standalone runtime.
-current_path = os.path.dirname(os.path.realpath(__file__))
-root = os.path.dirname(current_path)
+CURRENT_PATH = os.path.dirname(os.path.realpath(__file__))
+
+# Set sys path to current directory so that we can import pgadmin package
+root = os.path.dirname(CURRENT_PATH)
 
 if sys.path[0] != root:
     sys.path.insert(0, root)
@@ -30,50 +32,113 @@ import config
 # Get the config database schema version. We store this in pgadmin.model
 # as it turns out that putting it in the config files isn't a great idea
 from pgadmin.model import SCHEMA_VERSION
+
 config.SETTINGS_SCHEMA_VERSION = SCHEMA_VERSION
 
-# Create the app!
+# Create the app
 app = create_app()
-
-# Disabling Cross-site request forgery(CSRF token) for testing purpose.
-# CSRF prevent session against malicious Web site, or end users who wants to
-# execute unwanted actions.
 app.config['WTF_CSRF_ENABLED'] = False
+test_client = app.test_client()

-# Create test client

-def suite():
 
+    modules = []
     pgadmin_suite = unittest.TestSuite()
 
-    modules = []
+    # Load the test modules which are in given package(i.e. in arguments.pkg)
+    if arguments.pkg == "all":
+        TestsGeneratorRegistry.load_generators('pgadmin')
+    else:
+        TestsGeneratorRegistry.load_generators('pgadmin.{}.tests'.format(
+            arguments.pkg))

 
     return pgadmin_suite

+def add_arguments():
+    """
+                        filename=CURRENT_PATH + "/" + "logger.log",
+    # Create logger to write log in the logger file as well as on console
+    print("Please check output in file: logger.log placed at ",
+          CURRENT_PATH)

---

From: Dave Page <[email-masked]>
Date: Mon, 18 Jul 2016 14:55:07 +0100

Thanks - applied with some tweaks and changes, most notably:

- "--pkg all" is the default if no command line options are given.

- Output now goes in regression/regression.log

- Terminal output is limited to WARNINGS from the app server.

- The runner script is now python regression/runtests.py

On Mon, Jul 18, 2016 at 1:45 PM, Navnath Gadakh
<[email-masked]> wrote:
> test_config.json(for user it’s test_config_json.in) for basic credentials
> data for database/server
>
> slightly modified the way of running the testsuite. We used the command line
> arguments(pkg) which denotes for which package testsuite going to run.
>
>
>> On Mon, Jul 11, 2016 at 2:16 PM, Navnath Gadakh
>> <[email-masked]> wrote:
>>>
>>> Hi Dave,
>>>> On Fri, Jul 8, 2016 at 2:30 PM, Navnath Gadakh
>>>> <[email-masked]> wrote:
>>>>>
>>>>>
>>>>> Hi Dave,
>>>>>
>>>> case classes (Made all test cases independently runnable, removed the
>>>> priority logic).
>>>
>>>
>>>

---

From: Khushboo Vashi <[email-masked]>
Date: Tue, 19 Jul 2016 09:49:38 +0530

Hi Navnath,

I have just ran the automated test cases, I noticed that the login
test-case gets called (which actually post data and gets logged-in) each
time before every test case runs. I think this should not happen,  user
login should be done only once.

Thanks,
Khushboo

On Mon, Jul 18, 2016 at 7:25 PM, Dave Page <[email-masked]>
wrote:

> line
> >>> On Mon, Jul 11, 2016 at 5:11 PM, Dave Page <[email-masked]
> >
> >>> wrote:
> >>>>
> >>>>
> >>>>

---

From: Navnath Gadakh <[email-masked]>
Date: Fri, 22 Jul 2016 18:52:59 +0530

Hi Dave,

   Please find the attached patch for pgAdmin4 unittest(Support of API
testing with different servers i.e. PG and PPAS).

*This patch includes-*

   1.

   Test framework support API testing with multiple server for this we need
   to modify test_config.json(for user it’s test_config.json.in) and
   test_advanced_config.json(for user it’s test_advanced_config.json.in).
   Server details of PG and  PPAS are included in both .in files.
   2.

   Removed the logic of logging in  the test client on each test
   scenario(As per Khushboo's comment in previous email).  We need this logic
   in test cases under ‘browser/tests/’ as for test scenarios like change
   password and  invalid login test cases as test client should be logged out
   first. So, as per this the code is slightly modified in ‘browser/tests/’.
diff --git a/web/pgadmin/browser/server_groups/servers/databases/tests/test_db_add.py b/web/pgadmin/browser/server_groups/servers/databases/tests/test_db_add.py
index c0e1430..85dcc6c 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/tests/test_db_add.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/tests/test_db_add.py
@@ -8,11 +8,9 @@
 # ##################################################################
 
 import json
-import uuid
 
 from pgadmin.utils.route import BaseTestGenerator
 from regression import test_utils as utils
-from regression.test_setup import advanced_config_data

 class DatabaseAddTestCase(BaseTestGenerator):
@@ -28,14 +26,11 @@ class DatabaseAddTestCase(BaseTestGenerator):
 
     def setUp(self):
         """
-        This function perform the two tasks
-         1. Login to test client
-         2. Add the test server
+        This function used to add the sever
 
         :return: None
         """
 
-        utils.login_tester_account(self.tester)
         # Add the server
         utils.add_server(self.tester)
 
@@ -45,8 +40,6 @@ class DatabaseAddTestCase(BaseTestGenerator):
         server_connect_response, server_group, server_ids = \
             utils.connect_server(self.tester)
 
-        # Store db id. Which is use to delete in tearDown()
-        self.db_id = ''
         for server_connect, server_id in zip(server_connect_response,
                                              server_ids):
             if server_connect['data']['connected']:
@@ -58,17 +51,15 @@ class DatabaseAddTestCase(BaseTestGenerator):
                 self.assertTrue(db_response.status_code, 200)
                 response_data = json.loads(db_response.data.decode('utf-8'))
                 utils.write_db_parent_id(response_data)
-                self.db_id = response_data['node']['_id']
 
     def tearDown(self):
         """
-        This function deletes the 'parent_id.pkl' file which is created in
-        setup() function. Also this function logout the test client
+        This function deletes the added database, added server and the
+        'parent_id.pkl' file which is created in setup()
 
         :return: None
         """
 
-        utils.delete_database(self.tester, self.db_id)
+        utils.delete_database(self.tester)
         utils.delete_server(self.tester)
         utils.delete_parent_id_file()
-        utils.logout_tester_account(self.tester)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/tests/test_db_delete.py b/web/pgadmin/browser/server_groups/servers/databases/tests/test_db_delete.py
index 5f160f9..6830b5a 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/tests/test_db_delete.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/tests/test_db_delete.py
@@ -12,7 +12,7 @@ import json
 from pgadmin.utils.route import BaseTestGenerator
 from regression import test_utils as utils
 from regression.test_setup import config_data
-from regression.test_utils import get_ids, test_getnodes
+from regression.test_utils import get_ids

 class DatabaseDeleteTestCase(BaseTestGenerator):
@@ -26,14 +26,12 @@ class DatabaseDeleteTestCase(BaseTestGenerator):
     def setUp(self):
         """
         This function perform the three tasks
-         1. Login to test client
-         2. Add the test server
-         3. Connect to server
+         1. Add the test server
+         2. Connect to server
 
         :return: None
         """
 
-        utils.login_tester_account(self.tester)
         # Firstly, add the server
         utils.add_server(self.tester)
         # Secondly, connect to server/database
@@ -45,14 +43,15 @@ class DatabaseDeleteTestCase(BaseTestGenerator):
         srv_grp = config_data['test_server_group']
         all_id = get_ids()
         server_ids = all_id["sid"]
+        db_ids_dict = all_id["did"][0]
 
-        # TODO: Need to modify the code , to delete the databases for all
-        # TODO: servers. Currently it delete only one database.
-        db_id = all_id["did"][0]
-        db_con = test_getnodes(self.tester)
-        if len(db_con) == 0:
-            raise Exception("No database(s) to delete!!!")
         for server_id in server_ids:
+            db_id = db_ids_dict[int(server_id)]
+            db_con = utils.verify_database(self.tester, srv_grp, server_id,
+                                           db_id)
+            if len(db_con) == 0:
+                raise Exception("No database(s) to delete for server id %s"
+                                % server_id)
             response = self.tester.delete(self.url + str(srv_grp) + '/' +
                                           str(server_id) + '/' + str(db_id),
                                           follow_redirects=True)
@@ -62,12 +61,11 @@ class DatabaseDeleteTestCase(BaseTestGenerator):
 
     def tearDown(self):
         """
-        This function deletes the 'parent_id.pkl' file which is created in
-        setup() function. Also this function logout the test client
+        This function deletes the added server and the 'parent_id.pkl' file
+        which is created in setup() function.
 
         :return: None
         """
 
         utils.delete_server(self.tester)
         utils.delete_parent_id_file()
-        utils.logout_tester_account(self.tester)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/tests/test_db_get.py b/web/pgadmin/browser/server_groups/servers/databases/tests/test_db_get.py
index a42e0c1..7350f72 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/tests/test_db_get.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/tests/test_db_get.py
@@ -10,7 +10,7 @@
 from pgadmin.utils.route import BaseTestGenerator
 from regression import test_utils as utils
 from regression.test_setup import config_data
-from regression.test_utils import get_ids, test_getnodes
+from regression.test_utils import get_ids

 class DatabasesGetTestCase(BaseTestGenerator):
@@ -26,14 +26,12 @@ class DatabasesGetTestCase(BaseTestGenerator):
     def setUp(self):
         """
         This function perform the three tasks
-         1. Login to test client
-         2. Add the test server
-         3. Connect to server
+         1. Add the test server
+         2. Connect to server
 
         :return: None
         """
 
-        utils.login_tester_account(self.tester)
         # Firstly, add the server
         utils.add_server(self.tester)
         # Secondly, connect to server/database
@@ -45,28 +43,27 @@ class DatabasesGetTestCase(BaseTestGenerator):
         all_id = get_ids()
         server_ids = all_id["sid"]
 
-        # TODO: Code is remaining to get all databases of all servers
-        self.db_id = all_id["did"][0]
+        db_ids_dict = all_id["did"][0]
         srv_grp = config_data['test_server_group']
 
         for server_id in server_ids:
-            db_con = test_getnodes(self.tester)
+            db_id = db_ids_dict[int(server_id)]
+            db_con = utils.verify_database(self.tester, srv_grp, server_id,
+                                           db_id)
             if db_con["info"] == "Database connected.":
-                response = self.tester.get(self.url + str(srv_grp) + '/' +
-                                           str(server_id) + '/' + str(
-                    self.db_id),
-                                           follow_redirects=True)
+                response = self.tester.get(
+                    self.url + str(srv_grp) + '/' + str(server_id) + '/' +
+                    str(db_id), follow_redirects=True)
                 self.assertEquals(response.status_code, 200)
 
     def tearDown(self):
         """
-        This function deletes the 'parent_id.pkl' file which is created in
-        setup() function. Also this function logout the test client
+        This function deletes the added database, added server
+        and the 'parent_id.pkl' file which is created in setup() function.
 
         :return: None
         """
 
-        utils.delete_database(self.tester, self.db_id)
+        utils.delete_database(self.tester)
         utils.delete_server(self.tester)
         utils.delete_parent_id_file()
-        utils.logout_tester_account(self.tester)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/tests/test_db_put.py b/web/pgadmin/browser/server_groups/servers/databases/tests/test_db_put.py
index c5f92cc..4615d34 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/tests/test_db_put.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/tests/test_db_put.py
@@ -12,7 +12,7 @@ import json
 from pgadmin.utils.route import BaseTestGenerator
 from regression import test_utils as utils
 from regression.test_setup import config_data, advanced_config_data
-from regression.test_utils import get_ids, test_getnodes
+from regression.test_utils import get_ids

 class DatabasesUpdateTestCase(BaseTestGenerator):
@@ -28,14 +28,12 @@ class DatabasesUpdateTestCase(BaseTestGenerator):
     def setUp(self):
         """
         This function perform the three tasks
-         1. Login to test client
-         2. Add the test server
-         3. Connect to server
+         1. Add the test server
+         2. Connect to server
 
         :return: None
         """
 
-        utils.login_tester_account(self.tester)
         # Firstly, add the server
         utils.add_server(self.tester)
         # Secondly, connect to server/database
@@ -47,33 +45,30 @@ class DatabasesUpdateTestCase(BaseTestGenerator):
         srv_grp = config_data['test_server_group']
         all_id = get_ids()
         server_ids = all_id["sid"]
-
-        # TODO: Need to modify the code , to delete the databases for all
-        # TODO: servers. Currently it delete only one database.
-        db_id = all_id["did"][0]
-        test_getnodes(self.tester)
-
-        data = {
-            "comments": advanced_config_data["test_db_update_data"][0]
-            ["test_comment"],
-            "id": db_id
-        }
+        db_ids_dict = all_id["did"][0]
 
         for server_id in server_ids:
-            put_response = self.tester.put(self.url + str(srv_grp) + '/' +
-                                           str(server_id) + '/' + str(db_id),
-                                           data=json.dumps(data),
-                                           follow_redirects=True)
-            self.assertEquals(put_response.status_code, 200)
+            db_id = db_ids_dict[int(server_id)]
+            db_con = utils.verify_database(self.tester, srv_grp, server_id,
+                                           db_id)
+            if db_con["info"] == "Database connected.":
+                data = {
+                    "comments": advanced_config_data["test_db_update_data"][0]
+                    ["test_comment"],
+                    "id": db_id
+                }
+                put_response = self.tester.put(
+                    self.url + str(srv_grp) + '/' + str(server_id) + '/' +
+                    str(db_id), data=json.dumps(data), follow_redirects=True)
+                self.assertEquals(put_response.status_code, 200)
 
     def tearDown(self):
         """
-        This function deletes the 'parent_id.pkl' file which is created in
-        setup() function. Also this function logout the test client
+        This function deletes the added server and 'parent_id.pkl' file
+        which is created in setup() function.
 
         :return: None
         """
 
         utils.delete_server(self.tester)
         utils.delete_parent_id_file()
-        utils.logout_tester_account(self.tester)
diff --git a/web/pgadmin/browser/server_groups/servers/tests/__init__.py b/web/pgadmin/browser/server_groups/servers/tests/__init__.py
index 55a3a17..4fd2066 100644
--- a/web/pgadmin/browser/server_groups/servers/tests/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/tests/__init__.py
@@ -12,4 +12,4 @@ from pgadmin.utils.route import BaseTestGenerator
 
 class ServerGenerateTestCase(BaseTestGenerator):
     def runTest(self):
-        return
\ No newline at end of file
+        return
diff --git a/web/pgadmin/browser/server_groups/servers/tests/test_server_add.py b/web/pgadmin/browser/server_groups/servers/tests/test_server_add.py
index 0f07d21..2b1eb45 100644
--- a/web/pgadmin/browser/server_groups/servers/tests/test_server_add.py
+++ b/web/pgadmin/browser/server_groups/servers/tests/test_server_add.py
@@ -11,8 +11,6 @@ import json
 
 from pgadmin.utils.route import BaseTestGenerator
 from regression import test_utils as utils
-from regression.test_setup import config_data
-from regression.test_utils import get_ids

 class ServersAddTestCase(BaseTestGenerator):
@@ -24,12 +22,7 @@ class ServersAddTestCase(BaseTestGenerator):
     ]
 
     def setUp(self):
-        """
-        This function login the test account before running the logout
-        test case
-        """
-
-        utils.login_tester_account(self.tester)
+        pass
 
     def runTest(self):
         """ This function will add the server under default server group."""
@@ -47,12 +40,11 @@ class ServersAddTestCase(BaseTestGenerator):
 
     def tearDown(self):
         """
-        This function deletes the 'parent_id.pkl' file which is created in
-        setup() function. Also this function logout the test client
+        This function deletes the added server and the 'parent_id.pkl' file
+        which is created in setup() function.
 
         :return: None
         """
 
         utils.delete_server(self.tester)
         utils.delete_parent_id_file()
-        utils.logout_tester_account(self.tester)
diff --git a/web/pgadmin/browser/server_groups/servers/tests/test_server_delete.py b/web/pgadmin/browser/server_groups/servers/tests/test_server_delete.py
index 765a371..4fd207b 100644
--- a/web/pgadmin/browser/server_groups/servers/tests/test_server_delete.py
+++ b/web/pgadmin/browser/server_groups/servers/tests/test_server_delete.py
@@ -25,14 +25,11 @@ class ServerDeleteTestCase(BaseTestGenerator):
 
     def setUp(self):
         """
-        This function perform the two tasks
-         1. Login to test client
-         2. Add the test server
+        This function is used to add the server
 
         :return: None
         """
 
-        utils.login_tester_account(self.tester)
         # Firstly, add the server
         utils.add_server(self.tester)
 
@@ -58,10 +55,9 @@ class ServerDeleteTestCase(BaseTestGenerator):
     def tearDown(self):
         """
         This function deletes the 'parent_id.pkl' file which is created in
-        setup() function. Also this function logout the test client
+        setup() function.
 
         :return: None
         """
 
         utils.delete_parent_id_file()
-        utils.logout_tester_account(self.tester)
diff --git a/web/pgadmin/browser/server_groups/servers/tests/test_server_get.py b/web/pgadmin/browser/server_groups/servers/tests/test_server_get.py
index 6ff8e16..ea3c63f 100644
--- a/web/pgadmin/browser/server_groups/servers/tests/test_server_get.py
+++ b/web/pgadmin/browser/server_groups/servers/tests/test_server_get.py
@@ -26,14 +26,11 @@ class ServersGetTestCase(BaseTestGenerator):
 
     def setUp(self):
         """
-        This function perform the two tasks
-         1. Login to test client
-         2. Add the test server
+        This function is used to add the server
 
         :return: None
         """
 
-        utils.login_tester_account(self.tester)
         utils.add_server(self.tester)
 
     def runTest(self):
@@ -50,12 +47,11 @@ class ServersGetTestCase(BaseTestGenerator):
 
     def tearDown(self):
         """
-        This function deletes the 'parent_id.pkl' file which is created in
-        setup() function. Also this function logout the test client
+        This function deletes the added server and the 'parent_id.pkl' file
+        which is created in setup() function.
 
         :return: None
         """
 
         utils.delete_server(self.tester)
         utils.delete_parent_id_file()
-        utils.logout_tester_account(self.tester)
diff --git a/web/pgadmin/browser/server_groups/servers/tests/test_server_put.py b/web/pgadmin/browser/server_groups/servers/tests/test_server_put.py
index 659e674..5e810ba 100644
--- a/web/pgadmin/browser/server_groups/servers/tests/test_server_put.py
+++ b/web/pgadmin/browser/server_groups/servers/tests/test_server_put.py
@@ -25,15 +25,13 @@ class ServerUpdateTestCase(BaseTestGenerator):
     def setUp(self):
         """
         This function perform the four tasks
-         1. Login to test client
-         2. Add the test server
-         3. Get the server
-         4. Connect to server
+         1. Add the test server
+         2. Get the server
+         3. Connect to server
 
         :return: None
         """
 
-        utils.login_tester_account(self.tester)
         # Firstly, add the server
         utils.add_server(self.tester)
         # Get the server
@@ -64,12 +62,11 @@ class ServerUpdateTestCase(BaseTestGenerator):
 
     def tearDown(self):
         """
-        This function deletes the 'parent_id.pkl' file which is created in
-        setup() function. Also this function logout the test client
+        This function deletes the added server and the 'parent_id.pkl' file
+        which is created in setup() function.
 
         :return: None
         """
 
         utils.delete_server(self.tester)
         utils.delete_parent_id_file()
-        utils.logout_tester_account(self.tester)
diff --git a/web/pgadmin/browser/server_groups/tests/__init__.py b/web/pgadmin/browser/server_groups/tests/__init__.py
index 7fdd5c7..94218de 100644
--- a/web/pgadmin/browser/server_groups/tests/__init__.py
+++ b/web/pgadmin/browser/server_groups/tests/__init__.py
@@ -12,4 +12,4 @@ from pgadmin.utils.route import BaseTestGenerator
 
 class SGGenerateTestCase(BaseTestGenerator):
     def runTest(self):
-        return
\ No newline at end of file
+        return
diff --git a/web/pgadmin/browser/server_groups/tests/test_sg_get.py b/web/pgadmin/browser/server_groups/tests/test_sg_get.py
index adcb28a..6c164be 100644
--- a/web/pgadmin/browser/server_groups/tests/test_sg_get.py
+++ b/web/pgadmin/browser/server_groups/tests/test_sg_get.py
@@ -10,7 +10,6 @@
 import json
 
 from pgadmin.utils.route import BaseTestGenerator
-from regression import test_utils as utils
 from regression.test_setup import config_data

@@ -24,14 +23,6 @@ class SgNodeTestCase(BaseTestGenerator):
         ('Check Server Group Node', dict(url='/browser/server-group/obj/'))
     ]
 
-    def setUp(self):
-        """
-        This function login the test account before running the logout
-        test case
-        """
-
-        utils.login_tester_account(self.tester)
-
     def runTest(self):
         """This function will check available server groups."""
 
@@ -41,8 +32,3 @@ class SgNodeTestCase(BaseTestGenerator):
         self.assertTrue(response.status_code, 200)
         response_data = json.loads(response.data.decode('utf8'))
         self.assertTrue(response_data['id'], server_group_id)
-
-    def tearDown(self):
-        """This function logout the test account """
-
-        utils.logout_tester_account(self.tester)
diff --git a/web/pgadmin/browser/tests/__init__.py b/web/pgadmin/browser/tests/__init__.py
index 3fab6fe..7cce332 100644
--- a/web/pgadmin/browser/tests/__init__.py
+++ b/web/pgadmin/browser/tests/__init__.py
@@ -12,4 +12,4 @@ from pgadmin.utils.route import BaseTestGenerator
 
 class BrowserGenerateTestCase(BaseTestGenerator):
     def runTest(self):
-        return
\ No newline at end of file
+        return
diff --git a/web/pgadmin/browser/tests/test_change_password.py b/web/pgadmin/browser/tests/test_change_password.py
index 4b77a07..2f714a7 100644
--- a/web/pgadmin/browser/tests/test_change_password.py
+++ b/web/pgadmin/browser/tests/test_change_password.py
@@ -11,7 +11,6 @@ import uuid
 
 from pgadmin.utils.route import BaseTestGenerator
 from regression.test_setup import config_data
-from regression import test_utils as utils

 class ChangePasswordTestCase(BaseTestGenerator):
@@ -80,14 +79,6 @@ class ChangePasswordTestCase(BaseTestGenerator):
 
     ]
 
-    def setUp(self):
-        """
-        This function login the test account before running the logout
-        test case
-        """
-
-        utils.login_tester_account(self.tester)
-
     def runTest(self):
         """This function will check change password functionality."""
 
@@ -104,7 +95,8 @@ class ChangePasswordTestCase(BaseTestGenerator):
                 email=email, password=password), follow_redirects=True)
 
         response = self.tester.get('/change', follow_redirects=True)
-        self.assertIn('pgAdmin 4 Password Change', response.data.decode())
+        self.assertIn('pgAdmin 4 Password Change', response.data.decode(
+            'utf-8'))
 
         response = self.tester.post('/change', data=dict(
             password=self.password,
@@ -112,12 +104,3 @@ class ChangePasswordTestCase(BaseTestGenerator):
             new_password_confirm=self.new_password_confirm),
                                     follow_redirects=True)
         self.assertIn(self.respdata, response.data.decode('utf-8'))
-
-    def tearDown(self):
-        """
-        This function logout the test client
-
-        :return: None
-        """
-
-        utils.logout_tester_account(self.tester)
diff --git a/web/pgadmin/browser/tests/test_login.py b/web/pgadmin/browser/tests/test_login.py
index 0c8a16d..b0ea361 100644
--- a/web/pgadmin/browser/tests/test_login.py
+++ b/web/pgadmin/browser/tests/test_login.py
@@ -41,7 +41,7 @@ class LoginTestCase(BaseTestGenerator):
             respdata='Email not provided')),
 
         # This test case validates empty email and password
-        ('Empty_Creadentials', dict(
+        ('Empty_Credentials', dict(
             email='', password='',
             respdata='Email not provided')),
 
@@ -53,14 +53,14 @@ class LoginTestCase(BaseTestGenerator):
             respdata='Specified user does not exist')),
 
         # This test case validates invalid email and password
-        ('Invalid_Creadentials', dict(
+        ('Invalid_Credentials', dict(
             email=str(uuid.uuid4())[1:6] + [email-masked]',
             password=str(uuid.uuid4())[4:8],
             respdata='Specified user does not exist')),
 
         # This test case validates the valid/correct credentials and allow user
         # to login pgAdmin 4
-        ('Valid_Creadentials', dict(
+        ('Valid_Credentials', dict(
             email=(config_data['pgAdmin4_login_credentials']
                    ['test_login_username']),
             password=(config_data['pgAdmin4_login_credentials']
@@ -71,7 +71,12 @@ class LoginTestCase(BaseTestGenerator):
     ]
 
     def setUp(self):
-        pass
+        """
+        We need to logout the test client as we are testing scenarios of
+        logging in the client like invalid password, invalid emails,
+        empty credentials etc.
+        """
+        utils.logout_tester_account(self.tester)
 
     def runTest(self):
         """This function checks login functionality."""
@@ -83,10 +88,7 @@ class LoginTestCase(BaseTestGenerator):
 
     def tearDown(self):
         """
-        This function deletes the 'parent_id.pkl' file which is created in
-        setup() function. Also this function logout the test client
-
-        :return: None
+        We need to again login the test client as soon as test scenarios
+        finishes.
         """
-
-        utils.logout_tester_account(self.tester)
+        utils.login_tester_account(self.tester)
diff --git a/web/pgadmin/browser/tests/test_logout.py b/web/pgadmin/browser/tests/test_logout.py
index c2ccf94..729f7b1 100644
--- a/web/pgadmin/browser/tests/test_logout.py
+++ b/web/pgadmin/browser/tests/test_logout.py
@@ -25,15 +25,17 @@ class LogoutTest(BaseTestGenerator):
     ]
 
     def setUp(self):
-        """
-        This function login the test account before running the logout
-        test case
-        """
-
-        utils.login_tester_account(self.tester)
+        pass
 
     def runTest(self):
 
         response = self.tester.get('/logout')
         self.assertIn(self.respdata, response.data.decode('utf8'))
+
+    def tearDown(self):
+        """
+        We need to again login the test client as soon as test scenarios
+        finishes.
+        """
+        utils.login_tester_account(self.tester)
diff --git a/web/pgadmin/browser/tests/test_reset_password.py b/web/pgadmin/browser/tests/test_reset_password.py
index d0a6fa7..231c40e 100644
--- a/web/pgadmin/browser/tests/test_reset_password.py
+++ b/web/pgadmin/browser/tests/test_reset_password.py
@@ -11,7 +11,6 @@ import uuid
 
 from pgadmin.utils.route import BaseTestGenerator
 from regression.test_setup import config_data
-from regression import test_utils as utils

 class ResetPasswordTestCase(BaseTestGenerator):
@@ -37,29 +36,13 @@ class ResetPasswordTestCase(BaseTestGenerator):
             ['test_login_username'], respdata='pgAdmin 4'))
     ]
 
-    def setUp(self):
-        """
-        This function login the test account before running the logout
-        test case
-        """
-
-        utils.login_tester_account(self.tester)
-
     def runTest(self):
         """This function checks reset password functionality."""
 
         response = self.tester.get('/reset')
-        self.assertIn('Recover pgAdmin 4 Password', response.data.decode())
+        self.assertIn('Recover pgAdmin 4 Password', response.data.decode(
+            'utf-8'))
         response = self.tester.post(
             '/reset', data=dict(email=self.email),
             follow_redirects=True)
         self.assertIn(self.respdata, response.data.decode('utf-8'))
-
-    def tearDown(self):
-        """
-        This function logout the test client
-
-        :return: None
-        """
-
-        utils.logout_tester_account(self.tester)
diff --git a/web/regression/runtests.py b/web/regression/runtests.py
index 2e3520a..d11a794 100644
--- a/web/regression/runtests.py
+++ b/web/regression/runtests.py
@@ -32,6 +32,7 @@ import config
 # Get the config database schema version. We store this in pgadmin.model
 # as it turns out that putting it in the config files isn't a great idea
 from pgadmin.model import SCHEMA_VERSION
+from test_utils import login_tester_account, logout_tester_account

@@ -43,6 +44,8 @@ config.CONSOLE_LOG_LEVEL = WARNING
 app = create_app()
 app.config['WTF_CSRF_ENABLED'] = False
 test_client = app.test_client()
+# Login the test client
+login_tester_account(test_client)

 def get_suite(arguments, test_app_client):
@@ -65,11 +68,11 @@ def get_suite(arguments, test_app_client):
     pgadmin_suite = unittest.TestSuite()
 
     # Load the test modules which are in given package(i.e. in arguments.pkg)
-    if arguments.pkg is None or arguments.pkg == "all":
+    if arguments['pkg'] is None or arguments['pkg'] == "all":
         TestsGeneratorRegistry.load_generators('pgadmin')
     else:
         TestsGeneratorRegistry.load_generators('pgadmin.{}.tests'.format(
-            arguments.pkg))
+            arguments['pkg']))
 
     # Get the each test module and add into list
     for key, klass in TestsGeneratorRegistry.registry.items():
@@ -130,7 +133,8 @@ class StreamToLogger(object):
 if __name__ == '__main__':
     # Set basic logging configuration for log file
     logging.basicConfig(level=logging.DEBUG,
-                        format='%(asctime)s:%(levelname)s:%(name)s:%(message)s',
+                        format='%(asctime)s:%(levelname)s:%(name)s:%(message)s'
+                        ,
                         filename=CURRENT_PATH + "/" + "regression.log",
                         filemode='w'
                         )
@@ -139,9 +143,12 @@ if __name__ == '__main__':
     stderr_logger = logging.getLogger('STDERR')
     sys.stderr = StreamToLogger(stderr_logger, logging.ERROR)
 
-    args = add_arguments()
+    args = vars(add_arguments())
     suite = get_suite(args, test_client)
     tests = unittest.TextTestRunner(stream=sys.stderr, descriptions=True,
                                     verbosity=2).run(suite)
 
+    # Logout the test client
+    logout_tester_account(test_client)
+
     print("Please check output in file: %s/regression.log " % CURRENT_PATH)
diff --git a/web/regression/test_advanced_config.json.in b/web/regression/test_advanced_config.json.in
index bcb867c..c0d278b 100644
--- a/web/regression/test_advanced_config.json.in
+++ b/web/regression/test_advanced_config.json.in
@@ -93,7 +93,101 @@
     "test_privileges": [],
     "test_securities": [],
     "test_variables": []
-  }
+  },
+       {
+         "test_privileges_acl": [
+           {
+             "grantee": "enterprisedb",
+             "grantor": "enterprisedb",
+             "privileges": [
+               {
+                 "privilege_type": "C",
+                 "privilege": true,
+                 "with_grant": true
+               },
+               {
+                 "privilege_type": "T",
+                 "privilege": true,
+                 "with_grant": false
+               }
+             ]
+           }
+         ],
+         "test_conn_limit": -1,
+         "test_owner": "enterprisedb",
+         "test_fun_acl": [
+           {
+             "grantee": "enterprisedb",
+             "grantor": "enterprisedb",
+             "privileges": [
+               {
+                 "privilege_type": "X",
+                 "privilege": true,
+                 "with_grant": false
+               }
+             ]
+           }
+         ],
+         "test_seq_acl": [
+           {
+             "grantee": "enterprisedb",
+             "grantor": "enterprisedb",
+             "privileges": [
+               {
+                 "privilege_type": "r",
+                 "privilege": true,
+                 "with_grant": false
+               },
+               {
+                 "privilege_type": "w",
+                 "privilege": true,
+                 "with_grant": false
+               },
+               {
+                 "privilege_type": "U",
+                 "privilege": true,
+                 "with_grant": false
+               }
+             ]
+           }
+         ],
+         "test_tbl_acl": [
+           {
+             "grantee": "enterprisedb",
+             "grantor": "enterprisedb",
+             "privileges": [
+               {
+                 "privilege_type": "a",
+                 "privilege": true,
+                 "with_grant": true
+               },
+               {
+                 "privilege_type": "r",
+                 "privilege": true,
+                 "with_grant": false
+               }
+             ]
+           }
+         ],
+         "test_type_acl": [
+           {
+             "grantee": "enterprisedb",
+             "grantor": "enterprisedb",
+             "privileges": [
+               {
+                 "privilege_type": "U",
+                 "privilege": true,
+                 "with_grant": false
+               }
+             ]
+           }
+         ],
+         "test_encoding": "UTF8",
+         "test_name": "test_db_automation",
+         "test_privileges": [],
+         "test_securities": [],
+         "test_variables": []
+       }
  ],
 
   "test_db_update_data": [
diff --git a/web/regression/test_config.json.in b/web/regression/test_config.json.in
index d81d179..028d1e7 100644
--- a/web/regression/test_config.json.in
+++ b/web/regression/test_config.json.in
@@ -15,7 +15,17 @@
       "test_db_port": 5432,
       "test_maintenance_db": "postgres",
       "test_sslmode": "prefer"
-    }
+    },
+     {
+       "test_name": "Postgres Plus Advanced Server 9.4",
+       "test_comment": "Postgres Plus Advanced 9.4 Server (EDB Installer)",
+       "test_db_username": "enterprisedb",
+       "test_host": "localhost",
+       "test_db_password": "edb",
+       "test_db_port": 5444,
+       "test_maintenance_db": "edb",
+       "test_sslmode": "prefer"
+     }
   ],
   "test_server_update_data": [
     {
diff --git a/web/regression/test_utils.py b/web/regression/test_utils.py
index 0bcc10f..6be2bb2 100644
--- a/web/regression/test_utils.py
+++ b/web/regression/test_utils.py
@@ -12,11 +12,13 @@ import pickle
 import json
 import uuid
 
-from test_setup import config_data, advanced_config_data, pickle_path
+from test_setup import config_data, advanced_config_data, \
+    pickle_path
 
 SERVER_URL = '/browser/server/obj/'
 SERVER_CONNECT_URL = 'browser/server/connect/'
-DATABASE_CONNECT_URL = '/browser/database/obj/'
+DATABASE_URL = '/browser/database/obj/'
+DATABASE_CONNECT_URL = 'browser/database/connect/'

 def get_ids(url=pickle_path):
@@ -36,6 +38,39 @@ def get_ids(url=pickle_path):
     return ids

+def verify_database(tester, server_group, server_id, db_id):
+    """
+    This function verifies that database is exists and whether it connect
+    successfully or not
+
+    :param tester: test client
+    :type tester: flask test client object
+    :param server_group: server group id
+    :type server_group: int
+    :param server_id: server id
+    :type server_id: str
+    :param db_id: database id
+    :type db_id: str
+    :return: temp_db_con
+    :rtype: list
+    """
+
+    # Connect to server
+    response = tester.post('{0}{1}/{2}'.format(
+        SERVER_CONNECT_URL, server_group, server_id), data=dict(
+        password=config_data['test_server_credentials'][0][
+            'test_db_password']),
+        follow_redirects=True)
+
+    # Connect to database
+    con_response = tester.post('{0}{1}/{2}/{3}'.format(
+        DATABASE_CONNECT_URL, server_group, server_id, db_id),
+        follow_redirects=True)
+    temp_db_con = json.loads(con_response.data.decode('utf-8'))
+
+    return temp_db_con
+
+
 def test_getnodes(tester=None):
     # Connect to server and database.
 
@@ -45,24 +80,13 @@ def test_getnodes(tester=None):
     all_id = get_ids()
 
     server_ids = all_id["sid"]
-    db_id = all_id["did"][0]
+    db_ids_dict = all_id["did"][0]
     srv_grp = config_data['test_server_group']
 
-    # TODO: need to add code to handle multiple databases with servers
+    db_con = []
     for server_id in server_ids:
-        # Connect to server
-        response = tester.post('browser/server/connect/{0}/{1}'.format(
-            srv_grp, server_id), data=dict(
-            password=config_data['test_server_credentials'][0][
-                'test_db_password']),
-            follow_redirects=True)
-
-        # Connect to database
-        con_response = tester.post(
-            'browser/database/connect/{0}/{1}/{2}'.format(
-                srv_grp, server_id, db_id), follow_redirects=True)
-        db_con = json.loads(con_response.data.decode('utf-8'))
-
+        db_id = db_ids_dict[int(server_id)]
+        db_con.append(verify_database(tester, srv_grp, server_id, db_id))
     return db_con

@@ -76,31 +100,30 @@ def get_db_data(server_connect_data):
     :rtype: dict
     """
 
+    adv_config_data = None
+    data = None
     db_user = server_connect_data['data']['user']['name']
 
-    if db_user == "postgres":
-        # Get the advance test data of 'postgres' user
-        adv_config_data = advanced_config_data[
-            'test_add_database_data'][0]
-    else:
-        # Get the advance test data of 'enterprisedb' user
-        adv_config_data = advanced_config_data[
-            'test_add_database_data'][1]
-
-    data = {
-        "datacl": adv_config_data['test_privileges_acl'],
-        "datconnlimit": adv_config_data['test_conn_limit'],
-        "datowner": adv_config_data['test_owner'],
-        "deffuncacl": adv_config_data['test_fun_acl'],
-        "defseqacl": adv_config_data['test_seq_acl'],
-        "deftblacl": adv_config_data['test_tbl_acl'],
-        "deftypeacl": adv_config_data['test_type_acl'],
-        "encoding": adv_config_data['test_encoding'],
-        "name": str(uuid.uuid4())[1:8],
-        "privileges": adv_config_data['test_privileges'],
-        "securities": adv_config_data['test_securities'],
-        "variables": adv_config_data['test_variables']
-    }
+    # Get the config data of appropriate db user
+    for config_test_data in advanced_config_data['test_add_database_data']:
+        if db_user == config_test_data['test_owner']:
+            adv_config_data = config_test_data
+
+    if adv_config_data is not None:
+        data = {
+            "datacl": adv_config_data['test_privileges_acl'],
+            "datconnlimit": adv_config_data['test_conn_limit'],
+            "datowner": adv_config_data['test_owner'],
+            "deffuncacl": adv_config_data['test_fun_acl'],
+            "defseqacl": adv_config_data['test_seq_acl'],
+            "deftblacl": adv_config_data['test_tbl_acl'],
+            "deftypeacl": adv_config_data['test_type_acl'],
+            "encoding": adv_config_data['test_encoding'],
+            "name": str(uuid.uuid4())[1:8],
+            "privileges": adv_config_data['test_privileges'],
+            "securities": adv_config_data['test_securities'],
+            "variables": adv_config_data['test_variables']
+        }
 
     return data
 
@@ -199,13 +222,18 @@ def write_db_parent_id(response_data):
     """
 
     db_id = response_data['node']['_id']
+    server_id = response_data['node']['_pid']
     if os.path.isfile(pickle_path):
         existing_server_id = open(pickle_path, 'rb')
         tol_server_id = pickle.load(existing_server_id)
         pickle_id_dict = tol_server_id
-
-        pickle_id_dict["did"].append(db_id)
-
+        if 'did' in pickle_id_dict:
+            if pickle_id_dict['did']:
+                # Add the db_id as value in dict
+                pickle_id_dict["did"][0].update({server_id: db_id})
+            else:
+                # Create new dict with server_id and db_id
+                pickle_id_dict["did"].append({server_id: db_id})
         db_output = open(pickle_path, 'wb')
         pickle.dump(pickle_id_dict, db_output)
         db_output.close()
@@ -288,7 +316,8 @@ def connect_server(tester):
                                    ['test_db_password']),
                                follow_redirects=True)
         server_connect_detail = json.loads(response.data.decode())
-        connect_database(tester, server_connect_detail, server_id, server_group)
+        connect_database(tester, server_connect_detail, server_id,
+                         server_group)
         server_connect.append(server_connect_detail)
         servers.append(server_id)
     return server_connect, server_group, servers
@@ -313,7 +342,7 @@ def connect_database(tester, server_connect, server_id, server_group):
     if server_connect['data']['connected']:
         db_data = get_db_data(server_connect)
         db_response = tester.post(
-            DATABASE_CONNECT_URL + str(server_group) + "/" + server_id + "/",
+            DATABASE_URL + str(server_group) + "/" + server_id + "/",
             data=json.dumps(db_data),
             content_type='html/json')
         response_data = json.loads(db_response.data.decode())
@@ -341,31 +370,28 @@ def delete_server(tester):
         assert response_data['success'] == 1

-def delete_database(tester, db_id):
+def delete_database(tester):
     """
     This function used to delete the added databases
 
     :param tester: test client object
-    :param db_id: database id to be delete
-    :type db_id: int
     :return: None
     """
 
     srv_grp = config_data['test_server_group']
     all_id = get_ids()
     server_ids = all_id["sid"]
-
-    # TODO: Need to modify the code , to delete the databases for all
-    # TODO: servers. Currently it delete only one database.
-    #db_id = all_id["did"][0]
+    db_ids_dict = all_id['did'][0]
 
     db_con = test_getnodes(tester)
     if len(db_con) == 0:
         raise Exception("No database(s) to delete.")
 
     for server_id in server_ids:
-        response = tester.delete(DATABASE_CONNECT_URL + str(srv_grp) + '/' + str(
-            server_id) + '/' + str(db_id), follow_redirects=True)
+        db_id = db_ids_dict[int(server_id)]
+        response = tester.delete(DATABASE_URL + str(srv_grp) + '/' +
+                                 str(server_id) + '/' + str(db_id),
+                                 follow_redirects=True)
         assert response.status_code == 200
         response_data = json.loads(response.data.decode('utf-8'))
         assert response_data['success'] == 1

---

From: Dave Page <[email-masked]>
Date: Fri, 22 Jul 2016 17:18:09 +0100

Hi

On Fri, Jul 22, 2016 at 2:22 PM, Navnath Gadakh
<[email-masked]> wrote:
> Test framework support API testing with multiple server for this we need to
> modify test_config.json(for user it’s test_config.json.in) and
> Removed the logic of logging in  the test client on each test scenario(As
> per Khushboo's comment in previous email).  We need this logic in test cases
> under ‘browser/tests/’ as for test scenarios like change password and
> invalid login test cases as test client should be logged out first. So, as
> per this the code is slightly modified in ‘browser/tests/’.

OK in principle, but it doesn't seem to work:

This function will add the server under default server group. (Default
Server Node url) ... ok

======================================================================
FAIL: runTest (pgadmin.browser.tests.test_reset_password.ResetPasswordTestCase)
This function checks reset password functionality. (TestCase for
Validating Empty Email)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/dpage/git/pgadmin4/web/pgadmin/browser/tests/test_reset_password.py",
line 44, in runTest
    'utf-8'))
AssertionError: 'Recover pgAdmin 4 Password' not found in u'<!DOCTYPE
HTML PUBLIC "-//W3C//DTD HTML 3.2
Final//EN">\n<title>Redirecting...</title>\n<h1>Redirecting...</h1>\n<p>You
should be redirected automatically to target URL: <a href="/">/</a>.
If not click the link.'

======================================================================
FAIL: runTest (pgadmin.browser.tests.test_reset_password.ResetPasswordTestCase)
This function checks reset password functionality. (TestCase for
Validating Invalid_Email)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/dpage/git/pgadmin4/web/pgadmin/browser/tests/test_reset_password.py",
line 44, in runTest
    'utf-8'))
AssertionError: 'Recover pgAdmin 4 Password' not found in u'<!DOCTYPE
HTML PUBLIC "-//W3C//DTD HTML 3.2
Final//EN">\n<title>Redirecting...</title>\n<h1>Redirecting...</h1>\n<p>You
should be redirected automatically to target URL: <a href="/">/</a>.
If not click the link.'

======================================================================
FAIL: runTest (pgadmin.browser.tests.test_reset_password.ResetPasswordTestCase)
This function checks reset password functionality. (TestCase for
Validating Valid_Email)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/dpage/git/pgadmin4/web/pgadmin/browser/tests/test_reset_password.py",
line 44, in runTest
    'utf-8'))
AssertionError: 'Recover pgAdmin 4 Password' not found in u'<!DOCTYPE
HTML PUBLIC "-//W3C//DTD HTML 3.2
Final//EN">\n<title>Redirecting...</title>\n<h1>Redirecting...</h1>\n<p>You
should be redirected automatically to target URL: <a href="/">/</a>.
If not click the link.'

----------------------------------------------------------------------
Ran 26 tests in 30.109s

FAILED (failures=3)

It's very far from obvious what's wrong here (/reset looks just fine
to me). How can we get more useful info out of the framework?

---

From: Navnath Gadakh <[email-masked]>
Date: Mon, 25 Jul 2016 22:27:32 +0530

Hi Dave,
             I tried to reproduce this issue at my end, but didn't work.
Also tried with clean GIT tree.
Will look more into this tomorrow.
Thanks!

On Fri, Jul 22, 2016 at 9:48 PM, Dave Page <[email-masked]>
wrote:

> to
> FAIL: runTest
> (pgadmin.browser.tests.test_reset_password.ResetPasswordTestCase)
> "/Users/dpage/git/pgadmin4/web/pgadmin/browser/tests/test_reset_password.py",
> line 44, in runTest
>     'utf-8'))
> FAIL: runTest
> (pgadmin.browser.tests.test_reset_password.ResetPasswordTestCase)
> "/Users/dpage/git/pgadmin4/web/pgadmin/browser/tests/test_reset_password.py",
> line 44, in runTest
>     'utf-8'))
> FAIL: runTest
> (pgadmin.browser.tests.test_reset_password.ResetPasswordTestCase)
> "/Users/dpage/git/pgadmin4/web/pgadmin/browser/tests/test_reset_password.py",
> line 44, in runTest
>     'utf-8'))

-- 
Thanks,
Navnath Gadakh
Software Engineer
EnterpriseDB Corporation
Mobile: +91 9975389878

---

From: Navnath Gadakh <[email-masked]>
Date: Wed, 27 Jul 2016 17:49:20 +0530

Hi Dave,
      We have reproduced the issue you mentioned in the previous
email. We need to skip the login related test cases when SERVER_MODE =
False in the web/config_local.py.

Please find the revised patch for the same.

Thanks!

-- 
Thanks,
Navnath Gadakh
Software Engineer
EnterpriseDB Corporation
Mobile: +91 9975389878

---

From: Dave Page <[email-masked]>
Date: Wed, 27 Jul 2016 15:42:02 +0100

Ahh, that explains it. Nice catch! It's working in both server and
desktop modes now :-).

I've committed the patch, but can you please look at the following issues:

1) When testing SMTP, the encoded password used to connect to the
server is displayed in both the logs and stdout (the "send: 'AUTH
PLAIN ....'" lines). Can you catch that, and replace it with *'s
please? Sooner or later someone will reveal a password otherwise.

2) Is the test count in the summary correct when you have multiple
servers? I think it might be resetting between servers.

3) Please ensure that test databases that are created are also dropped
again. I'm getting tired of deleting them manually!

Thanks, Dave.

---

From: Priyanka Shendge <[email-masked]>
Date: Wed, 27 Jul 2016 20:57:33 +0530

> Ahh, that explains it. Nice catch! It's working in both server and

Great. Thanks to Khushboo for helping Navnath in this task.

Thank you.

> scenario(As

-- 
Best,
Priyanka

EnterpriseDB Corporation

---

From: Navnath Gadakh <[email-masked]>
Date: Thu, 28 Jul 2016 12:42:29 +0530

Thanks Dave!

> please? Sooner or later someone will reveal a password otherwise.
  Sure. I will implement in the next patch.
> servers? I think it might be resetting between servers.
     In the current code runTest() function calls only one time for
single/multiple server/s that's why it's showing same count for both
(single & multiple).
   Question: What exactly we are looking for, only count? Or we need
any more logs like for adding database, it should display in which
server (PG/PPAS) its adding database if this is the case we need a
feasibility check.

> again. I'm getting tired of deleting them manually!
    I already added delete databases in tearDown () function, But
yeah, I found two test cases where this code missed. I will add this
in the next patch.

-- 
Thanks,
Navnath Gadakh
Software Engineer
EnterpriseDB Corporation
Mobile: +91 9975389878

---

From: Dave Page <[email-masked]>
Date: Mon, 1 Aug 2016 10:47:42 +0100

> server (PG/PPAS) its adding database if this is the case we need a

Right now I would like to see the summary updated so it outputs useful
(and correct) information - for example, it could say something like:

=====
Testing completed:

PostgreSQL 9.4:  23 tests passed, 0 tests failed
EPAS 9.5:            25 tests passed, 2 tests failed (foo_test, bar_test)
=====

where PostgreSQL 9.4 and EPAS 9.5 are the two servers configured in
test_config.py and foo_test and bar_test are the names of the tests
that failed.

> yeah, I found two test cases where this code missed. I will add this

Thanks.

---

From: Navnath Gadakh <[email-masked]>
Date: Mon, 1 Aug 2016 15:24:25 +0530

Hi Dave,

>>> please? Sooner or later someone will reveal a password otherwise.
        Could you please send me your's regression.log file. While
testing SMTP I didn't see encoded password displayed on both logs and
stdout.
> test_config.py and foo_test and bar_test are the names of the tests
   Thanks for additional info.

-- 
Thanks,
Navnath Gadakh
Software Engineer
EnterpriseDB Corporation
Mobile: +91 9975389878

---

From: Dave Page <[email-masked]>
Date: Mon, 1 Aug 2016 11:26:01 +0100

Hi

> testing SMTP I didn't see encoded password displayed on both logs and

Here's an extract from stdout (with the encoded password replaced with
xxxxxx). I don't actually see the same in regression.log, but that may
be because of the log settings I'm using - we should filter the same
from there though to be safe:

...
This function checks reset password functionality. (TestCase for
Validating Valid_Email) ... send: 'ehlo
piranha.ox.uk.enterprisedb.com\r\n'
reply: '250-smtp.gmail.com at your service, [194.73.70.210]\r\n'
reply: '250-SIZE 35882577\r\n'
reply: '250-8BITMIME\r\n'
reply: '250-AUTH LOGIN PLAIN XOAUTH2 PLAIN-CLIENTTOKEN OAUTHBEARER XOAUTH\r\n'
reply: '250-ENHANCEDSTATUSCODES\r\n'
reply: '250-PIPELINING\r\n'
reply: '250-CHUNKING\r\n'
reply: '250 SMTPUTF8\r\n'
reply: retcode (250); Msg: smtp.gmail.com at your service, [194.73.70.210]
SIZE 35882577
8BITMIME
AUTH LOGIN PLAIN XOAUTH2 PLAIN-CLIENTTOKEN OAUTHBEARER XOAUTH
ENHANCEDSTATUSCODES
PIPELINING
CHUNKING
SMTPUTF8
send: 'AUTH PLAIN xxxxxx\r\n'
reply: '235 2.7.0 Accepted\r\n'
reply: retcode (235); Msg: 2.7.0 Accepted
send: u'mail FROM:<no-reply@localhost> size=1122\r\n'
reply: '250 2.1.0 OK v26sm44372678pfi.41 - gsmtp\r\n'
reply: retcode (250); Msg: 2.1.0 OK v26sm44372678pfi.41 - gsmtp
send: u'rcpt TO:<[email-masked]>\r\n'
reply: '250 2.1.5 OK v26sm44372678pfi.41 - gsmtp\r\n'
reply: retcode (250); Msg: 2.1.5 OK v26sm44372678pfi.41 - gsmtp
send: 'data\r\n'
reply: '354  Go ahead v26sm44372678pfi.41 - gsmtp\r\n'
reply: retcode (354); Msg: Go ahead v26sm44372678pfi.41 - gsmtp
data: (354, 'Go ahead v26sm44372678pfi.41 - gsmtp')
send: 'Content-Type: multipart/mixed;
boundary="===============5947340609837468105=="\r\nMIME-Version:
1.0\r\nSubject: Password reset instructions for pgAdmin 4\r\nFrom:
no-reply@localhost\r\nTo: [email-masked]\r\nDate: Mon, 01 Aug 2016
11:18:01 +0100\r\nMessage-ID:
<[email-masked]>\r\n\r\n--===============5947340609837468105==\r\nContent-Type:
multipart/alternative;\r\n
boundary="===============4573645557236154244=="\r\nMIME-Version:
1.0\r\n\r\n--===============4573645557236154244==\r\nContent-Type:
text/plain; charset="utf-8"\r\nMIME-Version:
1.0\r\nContent-Transfer-Encoding: 7bit\r\n\r\nClick the link below to
reset your password:\r\n\r\nhttp://localhost/reset/WyIxIiwiYTY2ODY0ZTY0NzlmMzM1NTNhYTc0NzUwYzEwNDc5ZmQiXQ.CoCzVg.FE0MhiGBwOgVWTcX8mB3Xgq54yw\r\n--===============4573645557236154244==\r\nContent-Type:
text/html; charset="utf-8"\r\nMIME-Version:
1.0\r\nContent-Transfer-Encoding: 7bit\r\n\r\n<p><a
href="http://localhost/reset/WyIxIiwiYTY2ODY0ZTY0NzlmMzM1NTNhYTc0NzUwYzEwNDc5ZmQiXQ.CoCzVg.FE0MhiGBwOgVWTcX8mB3Xgq54yw">Click
here to reset your
password</a></p>\r\n--===============4573645557236154244==--\r\n\r\n--===============5947340609837468105==--\r\n.\r\n'
reply: '250 2.0.0 OK 1470046685 v26sm44372678pfi.41 - gsmtp\r\n'
reply: retcode (250); Msg: 2.0.0 OK 1470046685 v26sm44372678pfi.41 - gsmtp
data: (250, '2.0.0 OK 1470046685 v26sm44372678pfi.41 - gsmtp')
send: 'quit\r\n'
reply: '221 2.0.0 closing connection v26sm44372678pfi.41 - gsmtp\r\n'
reply: retcode (221); Msg: 2.0.0 closing connection v26sm44372678pfi.41 - gsmtp
ok
runTest (pgadmin.browser.server_groups.servers.tests.test_server_put.ServerUpdateTestCase)
...

These are the relevant settings I'm using:

# Debug mode
DEBUG = True

# App mode
SERVER_MODE = True

# Log
CONSOLE_LOG_LEVEL = DEBUG
FILE_LOG_LEVEL = DEBUG

# Mail server settings
MAIL_SERVER = 'smtp.gmail.com'
MAIL_PORT = 465
MAIL_USE_SSL = True
MAIL_USERNAME = [email-masked]'
MAIL_PASSWORD = 'xxxxxx'

---

From: Navnath Gadakh <[email-masked]>
Date: Tue, 2 Aug 2016 20:28:02 +0530

Hi Dave,
     Please find the attached patch.
*This patch includes:*
1. API test cases for Roles & Tablespaces node(Completed nodes: server
groups, servers, databases)
    You can run test-suite using following command
     for roles node
               python regression/runtests.py --pkg
browser.server_groups.servers.roles
     for tablespaces node
               python regression/runtests.py --pkg
browser.server_groups.servers.tablespaces
     for all nodes
               python regression/runtests.py
     You can also test with multiple  servers.
2. Delete database code in some of the missed test files.
3. Added advanced configurations in test_advanced_config.json.in for roles
& tablespaces. So, accordingly you need change the file
 test_advanced_config.json
4. Added one test user credentials in test_config.json.in to test the
‘valid password’ test case which is present in
browser/tests/test_change_password.py
    Why test user credentials in test_config.json.in?
           Currently, I am getting ‘UnicodeDecodeError’ when I run
test-suite(runtests.py) with existing code. I already explained the detail
about this error in RM(#1521 <https://redmine.postgresql.org/issues/1521>).
I am creating test user to test the ‘valid password’ test case.

*Notes:*
 1. Code not added to encode the password which is displaying in log file
while testing SMTP(Will add the code in next patch)
 2. Code not added to show enhanced the test summary report(that you
mentioned in the previous email). I will look into this, need to decide
approach what are the code changes required in the current code.

Thanks!

On Mon, Aug 1, 2016 at 3:56 PM, Dave Page <[email-masked]>
wrote:

> <[email-masked]
> >\r\n\r\n--===============5947340609837468105==\r\nContent-Type:
> reset your
> password:\r\n\r\nhttp://localhost/reset/WyIxIiwiYTY2ODY0ZTY0NzlmMzM1NTNhYTc0NzUwYzEwNDc5ZmQiXQ.CoCzVg.FE0MhiGBwOgVWTcX8mB3Xgq54yw\r\n--===============4573645557236154244==\r\nContent-Type:
> href="
> http://localhost/reset/WyIxIiwiYTY2ODY0ZTY0NzlmMzM1NTNhYTc0NzUwYzEwNDc5ZmQiXQ.CoCzVg.FE0MhiGBwOgVWTcX8mB3Xgq54yw
> ">Click
> here to reset your
>
> runTest
> (pgadmin.browser.server_groups.servers.tests.test_server_put.ServerUpdateTestCase)
> ...
>

-- 
Thanks,
Navnath Gadakh
Software Engineer
EnterpriseDB Corporation
Mobile: +91 9975389878

---

From: Dave Page <[email-masked]>
Date: Wed, 3 Aug 2016 10:15:46 +0100

Hi Navnath

On Tue, Aug 2, 2016 at 3:58 PM, Navnath Gadakh
<[email-masked]> wrote:
> This patch includes:
> 3. Added advanced configurations in test_advanced_config.json.in for roles &
> tablespaces. So, accordingly you need change the file
> 4. Added one test user credentials in test_config.json.in to test the ‘valid
> password’ test case which is present in
> about this error in RM(#1521). I am creating test user to test the ‘valid
> password’ test case.

The tablespace test is one that I think is going to cause us problems
- we really can't have a hard-coded path in the config;

- It might need to be different for each server being tested

- It is very likely to be different for each user

I think what we need to do is:

- Skip the tests if the server is not connected via a Unix domain
socket (hostname starts with /), 127.0.0.1 or ::1.

- Add per-server configuration options for the tablespace path and
service account under which the database server runs. These values
should default to /tmp and postgres for a PostgreSQL server, and edb
for PPAS.

- Otherwise; assume the server is on the local machine, and:
  - Create /$tblspace_path/<random_string>/
  - chown $service_account /$tblspace_path/<random_string>/
  - Run the tests

Thoughts?

I'd also suggest another couple of changes:

- Remove the test_ prefix from the values in the config files. It
doesn't really help in the code as there you'll always have the data
in a variable anyway, e.g. adv_config_data["spc_location"] instead of
adv_config_data["test_spc_location"].

- I think we should fall back to using test_advanced_config.json.in if
the user hasn't made their own copy, e.g.

try:
    with open(CURRENT_PATH + '/test_advanced_config.json') as data_file:
        advanced_config_data = json.load(data_file)
except:
    with open(CURRENT_PATH + '/test_advanced_config.json.in') as data_file:
        advanced_config_data = json.load(data_file)

---

From: Navnath Gadakh <[email-masked]>
Date: Wed, 3 Aug 2016 18:31:19 +0530

Hi Dave,
     Thanks for clarification.

> - we really can't have a hard-coded path in the config;
      Understood.

>   Current patch supports multiple servers if you add
> tablespace configurations for multiple servers. In the current patch, it's
> only for one server.
>
      For multiple servers you need to add multiple
tablespace configuration:
          "test_tablespc_credentials":[{
    "test_tblspace_name": "test_tablespace",
    "test_spc_location": "/Library/PostgreSQL/9.6/data",
    "test_spc_opts": [],
    "test_spc_user": "XXXXX"
  },
  "test_tblspace_name": "test_tablespace1",
    "test_spc_seclable": [],
    "test_spc_location": "/Library/PostgrePlus/9.4AS/data",
    "test_spc_opts": [],
    "test_spc_user": "YYYYY"
  }]
   Anyhow, we are not going to use a hard coded path.

> socket (hostname starts with /), 127.0.0.1 or ::1.
    Understood.

> should default to /tmp and postgres for a PostgreSQL server, and edb
    Ok. For server connected via Unix domain socket. As per my
understanding modified configuration should be,
     "tablespc_credentials":[{
    "tblspace_name": "tablespace1",
    "testspc_seclable": [],
    "spc_acl": [
      {
        "grantee":"postgres",
        "grantor":"postgres",
        "privileges":[
          {
            "privilege_type":"C",
            "privilege":true,
            "with_grant":false
          }
        ]
      }
    ],
    "spc_location": "/tmp",
    "spc_opts": [],
    "spc_user": "postgres",
    "service_account": "test1_user"
  },{
    "tblspace_name": "tablespace2",
    "spc_seclable": [],
    "spc_acl": [
      {
        "grantee":"enterprisedb",
        "grantor":"enterprisedb",
        "privileges":[
          {
            "privilege_type":"C",
            "privilege":true,
            "with_grant":false
          }
        ]
      }
    ],
    "spc_location": "/tmp",
    "spc_opts": [],
    "spc_user": "enterprisedb",
    "service_account": "test2_user"
  }]
        Please correct me if I am wrong.

>   - chown $service_account /$tblspace_path/<random_string>/
      We can't set the owner for a tablespace path directory using normal
user, the user should be 'root'
      Say, I am logged in my machine as a 'abc' user  & I have installed
PostgreSQL9.5 with 'postgres' user.
      It won't run chown postgres /$tablespace_path_for_PostgreSQL9.5
/<random_string>

>         advanced_config_data = json.load(data_file)

    Understood.

-- 
Thanks,
Navnath Gadakh
Software Engineer
EnterpriseDB Corporation
Mobile: +91 9975389878

---

From: Dave Page <[email-masked]>
Date: Wed, 3 Aug 2016 16:02:33 +0100

On Wed, Aug 3, 2016 at 2:01 PM, Navnath Gadakh
<[email-masked]> wrote:
>>   Current patch supports multiple servers if you add tablespace
>> configurations for multiple servers. In the current patch, it's only for one
>> server.
>
>       For multiple servers you need to add multiple tablespace
> configuration:

Oh - does the per-server config override the main config? That's
useful. So anything that's in test_advanced_config.py can be
overridden on a per-server basis in test_config.py?

>> socket (hostname starts with /), 127.0.0.1 or ::1.

Please output a notice saying the test was skipped, and note it in the
summary as well (as we're planning to do with failed tests).

>     Ok. For server connected via Unix domain socket. As per my understanding
> modified configuration should be,

Something like that yes - though service_account seems pointless given
your comment below...

>       It won't run chown postgres
> /$tablespace_path_for_PostgreSQL9.5/<random_string>

Aww crap. Yeah :-(. OK in that case let's have the user specify (and
create) the path themselves for each server. If they don't specify a
path, then skip the test.

In fact - you might as well only skip the test in that case, and
forget about the address check above.

---

From: Navnath Gadakh <[email-masked]>
Date: Thu, 4 Aug 2016 14:57:09 +0530

Hi Dave,

> overridden on a per-server basis in test_config.py?

    No.
    per-server i.e advance config(test_advanced_config.json.in) and main
config(test_config.json) both are different files. In main config we just
  mention the server’s credentials.(We can also mention per server
credentails) and in test_advanced_config.json.in(here we say per-server
config)
we mention the advanced configurations i.e. test data for each node.

>     So, let's summarize the discussion:
    - Let user specify the tablespace path in test_advanced_config.json.in
    - If path not specified in the test_advanced_config.json.in skip the
test cases for tablespace.
    - Output a notice saying the test was skipped, and note it in the
summary.
    - No need to check the address.(Unix domain socket). It seems correct
way.

   Please tell me if I missed anything.

   Thanks!

--

-- 
Thanks,
Navnath Gadakh
Software Engineer
EnterpriseDB Corporation
Mobile: +91 9975389878

---

From: Dave Page <[email-masked]>
Date: Thu, 4 Aug 2016 11:34:10 +0100

Hi

> we mention the advanced configurations i.e. test data for each node.

OK.

>     - Let user specify the tablespace path in test_advanced_config.json.in

No - test_config.py. It should be per-server.

> test cases for tablespace.

Yes (but, test_config.py), for that server only.

>     - Output a notice saying the test was skipped, and note it in the

Yes.

>     - No need to check the address.(Unix domain socket). It seems correct

Right.

Thanks!

---

From: Navnath Gadakh <[email-masked]>
Date: Thu, 4 Aug 2016 17:32:47 +0530

Hi Dave,

> No - test_config.py. It should be per-server.
     We don't have a file named 'test_config.py' but we have a server's
credential file named 'test_config.json'.
     So, you are saying the tablespace path to be added in
'test_config.json'.
     Am I correct?

-- 
Thanks,
Navnath Gadakh
Software Engineer
EnterpriseDB Corporation
Mobile: +91 9975389878

---

From: Dave Page <[email-masked]>
Date: Thu, 4 Aug 2016 13:25:57 +0100

>      So, you are saying the tablespace path to be added in

Yeah, sorry. It should be a property of the server configuration.

---

From: Navnath Gadakh <[email-masked]>
Date: Mon, 8 Aug 2016 19:37:32 +0530

Hi Dave,
    Please find the updated patch for API unit test cases for *Roles and
Tablespaces *nodes
As we finalized
Now,
   1. The user will specify the tablespace path in test_config.json.in
   2.  If tablespace path not found, skip the test cases for that
server(Only tablespace test cases)
   3.  Add the skipped test summary in the test result. (Now it's
showing on console + in log file, but need to update in a final enhanced
test summary report. Which is research point we will work on that after
finishing all nodes API test cases)
   4.  Removed the test_ prefix from the values in the config files.

Thanks!

-- 
Thanks,
Navnath Gadakh
Software Engineer
EnterpriseDB Corporation
Mobile: +91 9975389878

---

From: Dave Page <[email-masked]>
Date: Mon, 8 Aug 2016 16:45:51 +0100

Hi

I guess you need to test if tablespace_path is omitted, not just empty?

This function test the add tablespace scenario (Check Tablespace Node) ... ERROR

======================================================================
ERROR: setUpClass
(pgadmin.browser.server_groups.servers.tablespaces.tests.test_tbspc_put.TableSpaceUpdateTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/tablespaces/tests/test_tbspc_put.py",
line 48, in setUpClass
    cls.server_group, cls.server_ids)
  File "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/tablespaces/tests/utils.py",
line 122, in add_table_space
    data = get_tablespace_data(server_connect)
  File "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/tablespaces/tests/utils.py",
line 41, in get_tablespace_data
    config_test_data['spc_location'] = server_config['tablespace_path']
KeyError: 'tablespace_path'

======================================================================
ERROR: setUpClass
(pgadmin.browser.server_groups.servers.tablespaces.tests.test_tbspc_delete.TableSpaceDeleteTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/tablespaces/tests/test_tbspc_delete.py",
line 46, in setUpClass
    cls.server_group, cls.server_ids)
  File "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/tablespaces/tests/utils.py",
line 122, in add_table_space
    data = get_tablespace_data(server_connect)
  File "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/tablespaces/tests/utils.py",
line 41, in get_tablespace_data
    config_test_data['spc_location'] = server_config['tablespace_path']
KeyError: 'tablespace_path'

======================================================================
ERROR: setUpClass
(pgadmin.browser.server_groups.servers.tablespaces.tests.test_tbspc_get.TablespaceGetTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/tablespaces/tests/test_tbspc_get.py",
line 45, in setUpClass
    cls.server_group, cls.server_ids)
  File "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/tablespaces/tests/utils.py",
line 122, in add_table_space
    data = get_tablespace_data(server_connect)
  File "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/tablespaces/tests/utils.py",
line 41, in get_tablespace_data
    config_test_data['spc_location'] = server_config['tablespace_path']
KeyError: 'tablespace_path'

======================================================================
ERROR: runTest (pgadmin.browser.server_groups.servers.tablespaces.tests.test_tbspc_add.TableSpaceAddTestCase)
This function test the add tablespace scenario (Check Tablespace Node)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/tablespaces/tests/test_tbspc_add.py",
line 47, in runTest
    self.server_ids)
  File "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/tablespaces/tests/utils.py",
line 122, in add_table_space
    data = get_tablespace_data(server_connect)
  File "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/tablespaces/tests/utils.py",
line 41, in get_tablespace_data
    config_test_data['spc_location'] = server_config['tablespace_path']
KeyError: 'tablespace_path'

Ran 14 tests in 9.326s

FAILED (errors=4)

On Mon, Aug 8, 2016 at 3:07 PM, Navnath Gadakh
<[email-masked]> wrote:
> Hi Dave,
>     Please find the updated patch for API unit test cases for Roles and
> Tablespaces nodes
> As we finalized
> Now,
>    3.  Add the skipped test summary in the test result. (Now it's showing on
> console + in log file, but need to update in a final enhanced test summary
> report. Which is research point we will work on that after finishing all
> nodes API test cases)

---

From: Navnath Gadakh <[email-masked]>
Date: Tue, 9 Aug 2016 14:49:56 +0530

Hi Dave,

> I guess you need to test if tablespace_path is omitted, not just empty?
    Yes, thats right.. Please find the updated patch.

>   File "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups
> /servers/tablespaces/tests/test_tbspc_put.py",
> line 48, in setUpClass
> (pgadmin.browser.server_groups.servers.tablespaces.tests.
> test_tbspc_delete.TableSpaceDeleteTestCase)
>   File "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups
> /servers/tablespaces/tests/test_tbspc_delete.py",
> line 46, in setUpClass
>   File "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups
> /servers/tablespaces/tests/test_tbspc_get.py",
> line 45, in setUpClass
>   File "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups
> /servers/tablespaces/tests/test_tbspc_add.py",
> line 47, in runTest
>     self.server_ids)
> showing on
> >> > On Thu, Aug 4, 2016 at 4:04 PM, Dave Page <[email-masked]
> >
> >> > wrote:
> >> >>
> >> >> Hi
> >> >>
> >> >> >     per-server i.e advance config(test_advanced_config.json.in)
> and
> >> >> > main
> >> >> > config(test_config.json) both are different files. In main config
> we
> >> >> > just

-- 
Thanks,
Navnath Gadakh
Software Engineer
EnterpriseDB Corporation
Mobile: +91 9975389878

---

From: Dave Page <[email-masked]>
Date: Tue, 9 Aug 2016 16:06:04 +0100

Thanks - applied with some minor wording and README tweaks.

On Tue, Aug 9, 2016 at 10:19 AM, Navnath Gadakh
<[email-masked]> wrote:
>> "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/tablespaces/tests/test_tbspc_put.py",
>> line 48, in setUpClass
>> "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/tablespaces/tests/utils.py",
>> "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/tablespaces/tests/utils.py",
>> "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/tablespaces/tests/test_tbspc_delete.py",
>> line 46, in setUpClass
>> "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/tablespaces/tests/utils.py",
>> "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/tablespaces/tests/utils.py",
>> "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/tablespaces/tests/test_tbspc_get.py",
>> line 45, in setUpClass
>> "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/tablespaces/tests/utils.py",
>> "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/tablespaces/tests/utils.py",
>> ERROR: runTest
>> (pgadmin.browser.server_groups.servers.tablespaces.tests.test_tbspc_add.TableSpaceAddTestCase)
>> "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/tablespaces/tests/test_tbspc_add.py",
>> line 47, in runTest
>>     self.server_ids)
>>   File
>> "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/tablespaces/tests/utils.py",
>> "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/tablespaces/tests/utils.py",