diff options
author | Amjith Ramanujam <amjith.r@gmail.com> | 2015-07-04 10:23:29 -0700 |
---|---|---|
committer | Amjith Ramanujam <amjith.r@gmail.com> | 2015-07-04 10:23:29 -0700 |
commit | a37713ff0754bafffb6ca7098b99d4fbb4968e8d (patch) | |
tree | 230bb43c8b51265e5053bd5526f206085a4011b6 | |
parent | cb9905a44e78b2fa257fc5308341a2d010a306c7 (diff) | |
parent | 09cae83eb8c4acf3a787b26f354d627440fc3a40 (diff) |
Merge pull request #269 from dbcli/j-bennet/itegration-tests
Started working on integration tests.
-rw-r--r-- | DEVELOP.rst | 30 | ||||
-rw-r--r-- | behave.ini | 5 | ||||
-rw-r--r-- | features/db_utils.py | 81 | ||||
-rw-r--r-- | features/environment.py | 77 | ||||
-rw-r--r-- | features/fixture_data/help.txt | 24 | ||||
-rw-r--r-- | features/fixture_data/help_commands.txt | 21 | ||||
-rw-r--r-- | features/fixture_utils.py | 34 | ||||
-rw-r--r-- | features/simple_cli_commands.feature | 22 | ||||
-rw-r--r-- | features/steps/step_definitions.py | 76 | ||||
-rw-r--r-- | requirements-dev.txt | 5 |
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 |