summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAmjith Ramanujam <amjith.r@gmail.com>2015-07-04 10:23:29 -0700
committerAmjith Ramanujam <amjith.r@gmail.com>2015-07-04 10:23:29 -0700
commita37713ff0754bafffb6ca7098b99d4fbb4968e8d (patch)
tree230bb43c8b51265e5053bd5526f206085a4011b6
parentcb9905a44e78b2fa257fc5308341a2d010a306c7 (diff)
parent09cae83eb8c4acf3a787b26f354d627440fc3a40 (diff)
Merge pull request #269 from dbcli/j-bennet/itegration-tests
Started working on integration tests.
-rw-r--r--DEVELOP.rst30
-rw-r--r--behave.ini5
-rw-r--r--features/db_utils.py81
-rw-r--r--features/environment.py77
-rw-r--r--features/fixture_data/help.txt24
-rw-r--r--features/fixture_data/help_commands.txt21
-rw-r--r--features/fixture_utils.py34
-rw-r--r--features/simple_cli_commands.feature22
-rw-r--r--features/steps/step_definitions.py76
-rw-r--r--requirements-dev.txt5
10 files changed, 375 insertions, 0 deletions
diff --git a/DEVELOP.rst b/DEVELOP.rst
index 2daf4cb5..39e932f0 100644
--- a/DEVELOP.rst
+++ b/DEVELOP.rst
@@ -122,3 +122,33 @@ The rpm package can be installed as follows:
::
$ sudo yum install pgcli*.rpm
+
+Running the integration tests
+-----------------------------
+
+Integration tests use `behave package http://pythonhosted.org/behave/`_.
+Configuration settings for this package are provided via ``behave.ini`` file
+in root directory.
+
+The database user (``pg_test_user = postgres`` in .ini file) has to have
+permissions to create and drop test database. Dafault user is ``postgres``
+at ``localhost``, without the password (authentication mode trust).
+
+First, install the requirements for testing:
+
+::
+
+ $ pip install -r requirements-dev.txt
+
+After that, tests can be run with:
+
+::
+
+ $ behave
+
+To see stdout/stderr, use the following command:
+
+::
+
+ $ behave --no-capture
+
diff --git a/behave.ini b/behave.ini
new file mode 100644
index 00000000..c555d3c0
--- /dev/null
+++ b/behave.ini
@@ -0,0 +1,5 @@
+[behave.userdata]
+pg_test_user = postgres
+pg_test_pass =
+pg_test_host = localhost
+pg_test_db = pgcli_behave_tests
diff --git a/features/db_utils.py b/features/db_utils.py
new file mode 100644
index 00000000..e059c762
--- /dev/null
+++ b/features/db_utils.py
@@ -0,0 +1,81 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+from __future__ import print_function
+
+from psycopg2 import connect
+from psycopg2.extensions import AsIs
+
+
+def create_db(hostname='localhost', username=None, password=None,
+ dbname=None):
+ """
+ Create test database.
+ :param hostname: string
+ :param username: string
+ :param password: string
+ :param dbname: string
+ :return:
+ """
+ cn = create_cn(hostname, password, username, 'postgres')
+
+ # ISOLATION_LEVEL_AUTOCOMMIT = 0
+ # Needed for DB creation.
+ cn.set_isolation_level(0)
+
+ with cn.cursor() as cr:
+ cr.execute('create database %s', (AsIs(dbname),))
+
+ cn.close()
+
+ cn = create_cn(hostname, password, username, dbname)
+ return cn
+
+
+def create_cn(hostname, password, username, dbname):
+ """
+ Open connection to database.
+ :param hostname:
+ :param password:
+ :param username:
+ :param dbname: string
+ :return: psycopg2.connection
+ """
+ if password:
+ cn = connect(host=hostname, user=username, database=dbname,
+ password=password)
+ else:
+ cn = connect(host=hostname, user=username, database=dbname)
+
+ print('Created connection: {0}.'.format(cn.dsn))
+ return cn
+
+
+def drop_db(hostname='localhost', username=None, password=None,
+ dbname=None):
+ """
+ Drop database.
+ :param hostname: string
+ :param username: string
+ :param password: string
+ :param dbname: string
+ """
+ cn = create_cn(hostname, password, username, 'postgres')
+
+ # ISOLATION_LEVEL_AUTOCOMMIT = 0
+ # Needed for DB drop.
+ cn.set_isolation_level(0)
+
+ with cn.cursor() as cr:
+ cr.execute('drop database %s', (AsIs(dbname),))
+
+ close_cn(cn)
+
+
+def close_cn(cn=None):
+ """
+ Close connection.
+ :param connection: psycopg2.connection
+ """
+ if cn:
+ cn.close()
+ print('Closed connection: {0}.'.format(cn.dsn))
diff --git a/features/environment.py b/features/environment.py
new file mode 100644
index 00000000..64ca66de
--- /dev/null
+++ b/features/environment.py
@@ -0,0 +1,77 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+from __future__ import print_function
+
+import os
+import pexpect
+import db_utils as dbutils
+import fixture_utils as fixutils
+
+
+def before_all(context):
+ """
+ Set env parameters.
+ """
+ os.environ['LINES'] = "100"
+ os.environ['COLUMNS'] = "100"
+ os.environ['PAGER'] = 'cat'
+
+ context.exit_sent = False
+
+ # Store get params from config.
+ context.conf = {
+ 'host': context.config.userdata.get('pg_test_host', 'localhost'),
+ 'user': context.config.userdata.get('pg_test_user', 'root'),
+ 'pass': context.config.userdata.get('pg_test_pass', None),
+ 'dbname': context.config.userdata.get('pg_test_db', None),
+ }
+
+ # Store old env vars.
+ context.pgenv = {
+ 'PGDATABASE': os.environ.get('PGDATABASE', None),
+ 'PGUSER': os.environ.get('PGUSER', None),
+ 'PGHOST': os.environ.get('PGHOST', None),
+ 'PGPASS': os.environ.get('PGPASS', None),
+ }
+
+ # Set new env vars.
+ os.environ['PGDATABASE'] = context.conf['dbname']
+ os.environ['PGUSER'] = context.conf['user']
+ os.environ['PGHOST'] = context.conf['host']
+ if context.conf['pass']:
+ os.environ['PGPASS'] = context.conf['pass']
+ elif 'PGPASS' in os.environ:
+ del os.environ['PGPASS']
+
+ context.cn = dbutils.create_db(context.conf['host'], context.conf['user'],
+ context.conf['pass'],
+ context.conf['dbname'])
+
+ context.fixture_data = fixutils.read_fixture_files()
+
+
+def after_all(context):
+ """
+ Unset env parameters.
+ """
+ dbutils.close_cn(context.cn)
+ dbutils.drop_db(context.conf['host'], context.conf['user'],
+ context.conf['pass'], context.conf['dbname'])
+
+ # Restore env vars.
+ for k, v in context.pgenv.items():
+ if k in os.environ and v is None:
+ del os.environ[k]
+ elif v:
+ os.environ[k] = v
+
+
+def after_scenario(context, _):
+ """
+ Cleans up after each test complete.
+ """
+
+ if hasattr(context, 'cli') and not context.exit_sent:
+ # Send Ctrl + D into cli
+ context.cli.sendcontrol('d')
+ context.cli.expect(pexpect.EOF)
diff --git a/features/fixture_data/help.txt b/features/fixture_data/help.txt
new file mode 100644
index 00000000..8a495041
--- /dev/null
+++ b/features/fixture_data/help.txt
@@ -0,0 +1,24 @@
++--------------------------+-----------------------------------------------+
+| Command | Description |
+|--------------------------+-----------------------------------------------|
+| \# | Refresh auto-completions. |
+| \? | Show Help. |
+| \c[onnect] database_name | Change to a new database. |
+| \d [pattern] | List or describe tables, views and sequences. |
+| \dT[S+] [pattern] | List data types |
+| \df[+] [pattern] | List functions. |
+| \di[+] [pattern] | List indexes. |
+| \dn[+] [pattern] | List schemas. |
+| \ds[+] [pattern] | List sequences. |
+| \dt[+] [pattern] | List tables. |
+| \du[+] [pattern] | List roles. |
+| \dv[+] [pattern] | List views. |
+| \e [file] | Edit the query with external editor. |
+| \l | List databases. |
+| \n[+] [name] | List or execute named queries. |
+| \nd [name [query]] | Delete a named query. |
+| \ns [name [query]] | Save a named query. |
+| \refresh | Refresh auto-completions. |
+| \timing | Toggle timing of commands. |
+| \x | Toggle expanded output. |
++--------------------------+-----------------------------------------------+
diff --git a/features/fixture_data/help_commands.txt b/features/fixture_data/help_commands.txt
new file mode 100644
index 00000000..fcee0775
--- /dev/null
+++ b/features/fixture_data/help_commands.txt
@@ -0,0 +1,21 @@
+Command
+\#
+\?
+\c[onnect] database_name
+\d [pattern]
+\dT[S+] [pattern]
+\df[+] [pattern]
+\di[+] [pattern]
+\dn[+] [pattern]
+\ds[+] [pattern]
+\dt[+] [pattern]
+\du[+] [pattern]
+\dv[+] [pattern]
+\e [file]
+\l
+\n[+] [name]
+\nd [name [query]]
+\ns [name [query]]
+\refresh
+\timing
+\x \ No newline at end of file
diff --git a/features/fixture_utils.py b/features/fixture_utils.py
new file mode 100644
index 00000000..af768977
--- /dev/null
+++ b/features/fixture_utils.py
@@ -0,0 +1,34 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+from __future__ import print_function
+
+import os
+import codecs
+
+
+def read_fixture_lines(filename):
+ """
+ Read lines of text from file.
+ :param filename: string name
+ :return: list of strings
+ """
+ lines = []
+ for line in codecs.open(filename, 'r', encoding='utf-8'):
+ lines.append(line.strip())
+ return lines
+
+
+def read_fixture_files():
+ """
+ Read all files inside fixture_data directory.
+ """
+ fixture_dict = {}
+
+ current_dir = os.path.dirname(__file__)
+ fixture_dir = os.path.join(current_dir, 'fixture_data/')
+ for filename in os.listdir(fixture_dir):
+ if filename not in ['.', '..']:
+ fullname = os.path.join(fixture_dir, filename)
+ fixture_dict[filename] = read_fixture_lines(fullname)
+
+ return fixture_dict
diff --git a/features/simple_cli_commands.feature b/features/simple_cli_commands.feature
new file mode 100644
index 00000000..1121651c
--- /dev/null
+++ b/features/simple_cli_commands.feature
@@ -0,0 +1,22 @@
+Feature: run the cli,
+ call the help command,
+ exit the cli
+
+ Scenario: run the cli
+ Given we have pgcli installed
+ when we run pgcli
+ then we see pgcli prompt
+
+ Scenario: run "\?" command
+ Given we have pgcli installed
+ when we run pgcli
+ and we wait for prompt
+ and we send "\?" command
+ then we see help output
+
+ Scenario: run the cli and exit
+ Given we have pgcli installed
+ when we run pgcli
+ and we wait for prompt
+ and we send "ctrl + d"
+ then pgcli exits
diff --git a/features/steps/step_definitions.py b/features/steps/step_definitions.py
new file mode 100644
index 00000000..454d8cc3
--- /dev/null
+++ b/features/steps/step_definitions.py
@@ -0,0 +1,76 @@
+# -*- coding: utf-8 -*-
+"""
+Steps for behavioral style tests are defined in this module.
+Each step is defined by the string decorating it.
+This string is used to call the step in "*.feature" file.
+"""
+from __future__ import unicode_literals
+
+import pip
+import pexpect
+
+from behave import given, when, then
+
+
+@given('we have pgcli installed')
+def step_install_cli(_):
+ """
+ Check that pgcli is in installed modules.
+ """
+ dists = set([di.key for di in pip.get_installed_distributions()])
+ assert 'pgcli' in dists
+
+
+@when('we run pgcli')
+def step_run_cli(context):
+ """
+ Run the process using pexpect.
+ """
+ context.cli = pexpect.spawnu('pgcli')
+
+
+@when('we wait for prompt')
+def step_wait_prompt(context):
+ """
+ Make sure prompt is displayed.
+ """
+ context.cli.expect('{0}> '.format(context.conf['dbname']))
+
+
+@when('we send "ctrl + d"')
+def step_ctrl_d(context):
+ """
+ Send Ctrl + D to hopefully exit.
+ """
+ context.cli.sendcontrol('d')
+ context.exit_sent = True
+
+
+@when('we send "\?" command')
+def step_send_help(context):
+ """
+ Send \? to see help.
+ """
+ context.cli.sendline('\?')
+
+
+@then('pgcli exits')
+def step_wait_exit(context):
+ """
+ Make sure the cli exits.
+ """
+ context.cli.expect(pexpect.EOF)
+
+
+@then('we see pgcli prompt')
+def step_see_prompt(context):
+ """
+ Wait to see the prompt.
+ """
+ context.cli.expect('{0}> '.format(context.conf['dbname']))
+
+
+@then('we see help output')
+def step_see_help(context):
+ for expected_line in context.fixture_data['help_commands.txt']:
+ context.cli.expect_exact(expected_line)
diff --git a/requirements-dev.txt b/requirements-dev.txt
new file mode 100644
index 00000000..d6e3e92e
--- /dev/null
+++ b/requirements-dev.txt
@@ -0,0 +1,5 @@
+pytest>=2.7.0
+mock>=1.0.1
+tox>=1.9.2
+behave>=1.2.4
+pexpect>=3.3