Adding upstream version 3.1.0.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
f2184ff4ed
commit
ec5391b244
104 changed files with 15144 additions and 0 deletions
0
tests/features/__init__.py
Normal file
0
tests/features/__init__.py
Normal file
12
tests/features/auto_vertical.feature
Normal file
12
tests/features/auto_vertical.feature
Normal file
|
@ -0,0 +1,12 @@
|
|||
Feature: auto_vertical mode:
|
||||
on, off
|
||||
|
||||
Scenario: auto_vertical on with small query
|
||||
When we run dbcli with --auto-vertical-output
|
||||
and we execute a small query
|
||||
then we see small results in horizontal format
|
||||
|
||||
Scenario: auto_vertical on with large query
|
||||
When we run dbcli with --auto-vertical-output
|
||||
and we execute a large query
|
||||
then we see large results in vertical format
|
58
tests/features/basic_commands.feature
Normal file
58
tests/features/basic_commands.feature
Normal file
|
@ -0,0 +1,58 @@
|
|||
Feature: run the cli,
|
||||
call the help command,
|
||||
exit the cli
|
||||
|
||||
Scenario: run "\?" command
|
||||
When we send "\?" command
|
||||
then we see help output
|
||||
|
||||
Scenario: run source command
|
||||
When we send source command
|
||||
then we see help output
|
||||
|
||||
Scenario: run partial select command
|
||||
When we send partial select command
|
||||
then we see error message
|
||||
then we see dbcli prompt
|
||||
|
||||
Scenario: check our application_name
|
||||
When we run query to check application_name
|
||||
then we see found
|
||||
|
||||
Scenario: run the cli and exit
|
||||
When we send "ctrl + d"
|
||||
then dbcli exits
|
||||
|
||||
Scenario: list databases
|
||||
When we list databases
|
||||
then we see list of databases
|
||||
|
||||
Scenario: run the cli with --username
|
||||
When we launch dbcli using --username
|
||||
and we send "\?" command
|
||||
then we see help output
|
||||
|
||||
Scenario: run the cli with --user
|
||||
When we launch dbcli using --user
|
||||
and we send "\?" command
|
||||
then we see help output
|
||||
|
||||
Scenario: run the cli with --port
|
||||
When we launch dbcli using --port
|
||||
and we send "\?" command
|
||||
then we see help output
|
||||
|
||||
Scenario: run the cli with --password
|
||||
When we launch dbcli using --password
|
||||
then we send password
|
||||
and we see dbcli prompt
|
||||
when we send "\?" command
|
||||
then we see help output
|
||||
|
||||
@wip
|
||||
Scenario: run the cli with dsn and password
|
||||
When we launch dbcli using dsn_password
|
||||
then we send password
|
||||
and we see dbcli prompt
|
||||
when we send "\?" command
|
||||
then we see help output
|
17
tests/features/crud_database.feature
Normal file
17
tests/features/crud_database.feature
Normal file
|
@ -0,0 +1,17 @@
|
|||
Feature: manipulate databases:
|
||||
create, drop, connect, disconnect
|
||||
|
||||
Scenario: create and drop temporary database
|
||||
When we create database
|
||||
then we see database created
|
||||
when we drop database
|
||||
then we confirm the destructive warning
|
||||
then we see database dropped
|
||||
when we connect to dbserver
|
||||
then we see database connected
|
||||
|
||||
Scenario: connect and disconnect from test database
|
||||
When we connect to test database
|
||||
then we see database connected
|
||||
when we connect to dbserver
|
||||
then we see database connected
|
22
tests/features/crud_table.feature
Normal file
22
tests/features/crud_table.feature
Normal file
|
@ -0,0 +1,22 @@
|
|||
Feature: manipulate tables:
|
||||
create, insert, update, select, delete from, drop
|
||||
|
||||
Scenario: create, insert, select from, update, drop table
|
||||
When we connect to test database
|
||||
then we see database connected
|
||||
when we create table
|
||||
then we see table created
|
||||
when we insert into table
|
||||
then we see record inserted
|
||||
when we update table
|
||||
then we see record updated
|
||||
when we select from table
|
||||
then we see data selected
|
||||
when we delete from table
|
||||
then we confirm the destructive warning
|
||||
then we see record deleted
|
||||
when we drop table
|
||||
then we confirm the destructive warning
|
||||
then we see table dropped
|
||||
when we connect to dbserver
|
||||
then we see database connected
|
78
tests/features/db_utils.py
Normal file
78
tests/features/db_utils.py
Normal file
|
@ -0,0 +1,78 @@
|
|||
from psycopg2 import connect
|
||||
from psycopg2.extensions import AsIs
|
||||
|
||||
|
||||
def create_db(
|
||||
hostname="localhost", username=None, password=None, dbname=None, port=None
|
||||
):
|
||||
"""Create test database.
|
||||
|
||||
:param hostname: string
|
||||
:param username: string
|
||||
:param password: string
|
||||
:param dbname: string
|
||||
:param port: int
|
||||
:return:
|
||||
|
||||
"""
|
||||
cn = create_cn(hostname, password, username, "postgres", port)
|
||||
|
||||
# ISOLATION_LEVEL_AUTOCOMMIT = 0
|
||||
# Needed for DB creation.
|
||||
cn.set_isolation_level(0)
|
||||
|
||||
with cn.cursor() as cr:
|
||||
cr.execute("drop database if exists %s", (AsIs(dbname),))
|
||||
cr.execute("create database %s", (AsIs(dbname),))
|
||||
|
||||
cn.close()
|
||||
|
||||
cn = create_cn(hostname, password, username, dbname, port)
|
||||
return cn
|
||||
|
||||
|
||||
def create_cn(hostname, password, username, dbname, port):
|
||||
"""
|
||||
Open connection to database.
|
||||
:param hostname:
|
||||
:param password:
|
||||
:param username:
|
||||
:param dbname: string
|
||||
:return: psycopg2.connection
|
||||
"""
|
||||
cn = connect(
|
||||
host=hostname, user=username, database=dbname, password=password, port=port
|
||||
)
|
||||
|
||||
print("Created connection: {0}.".format(cn.dsn))
|
||||
return cn
|
||||
|
||||
|
||||
def drop_db(hostname="localhost", username=None, password=None, dbname=None, port=None):
|
||||
"""
|
||||
Drop database.
|
||||
:param hostname: string
|
||||
:param username: string
|
||||
:param password: string
|
||||
:param dbname: string
|
||||
"""
|
||||
cn = create_cn(hostname, password, username, "postgres", port)
|
||||
|
||||
# ISOLATION_LEVEL_AUTOCOMMIT = 0
|
||||
# Needed for DB drop.
|
||||
cn.set_isolation_level(0)
|
||||
|
||||
with cn.cursor() as cr:
|
||||
cr.execute("drop database if exists %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))
|
192
tests/features/environment.py
Normal file
192
tests/features/environment.py
Normal file
|
@ -0,0 +1,192 @@
|
|||
import copy
|
||||
import os
|
||||
import sys
|
||||
import db_utils as dbutils
|
||||
import fixture_utils as fixutils
|
||||
import pexpect
|
||||
import tempfile
|
||||
import shutil
|
||||
import signal
|
||||
|
||||
|
||||
from steps import wrappers
|
||||
|
||||
|
||||
def before_all(context):
|
||||
"""Set env parameters."""
|
||||
env_old = copy.deepcopy(dict(os.environ))
|
||||
os.environ["LINES"] = "100"
|
||||
os.environ["COLUMNS"] = "100"
|
||||
os.environ["PAGER"] = "cat"
|
||||
os.environ["EDITOR"] = "ex"
|
||||
os.environ["VISUAL"] = "ex"
|
||||
os.environ["PROMPT_TOOLKIT_NO_CPR"] = "1"
|
||||
|
||||
context.package_root = os.path.abspath(
|
||||
os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
|
||||
)
|
||||
fixture_dir = os.path.join(context.package_root, "tests/features/fixture_data")
|
||||
|
||||
print("package root:", context.package_root)
|
||||
print("fixture dir:", fixture_dir)
|
||||
|
||||
os.environ["COVERAGE_PROCESS_START"] = os.path.join(
|
||||
context.package_root, ".coveragerc"
|
||||
)
|
||||
|
||||
context.exit_sent = False
|
||||
|
||||
vi = "_".join([str(x) for x in sys.version_info[:3]])
|
||||
db_name = context.config.userdata.get("pg_test_db", "pgcli_behave_tests")
|
||||
db_name_full = "{0}_{1}".format(db_name, vi)
|
||||
|
||||
# Store get params from config.
|
||||
context.conf = {
|
||||
"host": context.config.userdata.get(
|
||||
"pg_test_host", os.getenv("PGHOST", "localhost")
|
||||
),
|
||||
"user": context.config.userdata.get(
|
||||
"pg_test_user", os.getenv("PGUSER", "postgres")
|
||||
),
|
||||
"pass": context.config.userdata.get(
|
||||
"pg_test_pass", os.getenv("PGPASSWORD", None)
|
||||
),
|
||||
"port": context.config.userdata.get(
|
||||
"pg_test_port", os.getenv("PGPORT", "5432")
|
||||
),
|
||||
"cli_command": (
|
||||
context.config.userdata.get("pg_cli_command", None)
|
||||
or '{python} -c "{startup}"'.format(
|
||||
python=sys.executable,
|
||||
startup="; ".join(
|
||||
[
|
||||
"import coverage",
|
||||
"coverage.process_startup()",
|
||||
"import pgcli.main",
|
||||
"pgcli.main.cli()",
|
||||
]
|
||||
),
|
||||
)
|
||||
),
|
||||
"dbname": db_name_full,
|
||||
"dbname_tmp": db_name_full + "_tmp",
|
||||
"vi": vi,
|
||||
"pager_boundary": "---boundary---",
|
||||
}
|
||||
os.environ["PAGER"] = "{0} {1} {2}".format(
|
||||
sys.executable,
|
||||
os.path.join(context.package_root, "tests/features/wrappager.py"),
|
||||
context.conf["pager_boundary"],
|
||||
)
|
||||
|
||||
# Store old env vars.
|
||||
context.pgenv = {
|
||||
"PGDATABASE": os.environ.get("PGDATABASE", None),
|
||||
"PGUSER": os.environ.get("PGUSER", None),
|
||||
"PGHOST": os.environ.get("PGHOST", None),
|
||||
"PGPASSWORD": os.environ.get("PGPASSWORD", None),
|
||||
"PGPORT": os.environ.get("PGPORT", None),
|
||||
"XDG_CONFIG_HOME": os.environ.get("XDG_CONFIG_HOME", None),
|
||||
"PGSERVICEFILE": os.environ.get("PGSERVICEFILE", None),
|
||||
}
|
||||
|
||||
# Set new env vars.
|
||||
os.environ["PGDATABASE"] = context.conf["dbname"]
|
||||
os.environ["PGUSER"] = context.conf["user"]
|
||||
os.environ["PGHOST"] = context.conf["host"]
|
||||
os.environ["PGPORT"] = context.conf["port"]
|
||||
os.environ["PGSERVICEFILE"] = os.path.join(fixture_dir, "mock_pg_service.conf")
|
||||
|
||||
if context.conf["pass"]:
|
||||
os.environ["PGPASSWORD"] = context.conf["pass"]
|
||||
else:
|
||||
if "PGPASSWORD" in os.environ:
|
||||
del os.environ["PGPASSWORD"]
|
||||
|
||||
context.cn = dbutils.create_db(
|
||||
context.conf["host"],
|
||||
context.conf["user"],
|
||||
context.conf["pass"],
|
||||
context.conf["dbname"],
|
||||
context.conf["port"],
|
||||
)
|
||||
|
||||
context.fixture_data = fixutils.read_fixture_files()
|
||||
|
||||
# use temporary directory as config home
|
||||
context.env_config_home = tempfile.mkdtemp(prefix="pgcli_home_")
|
||||
os.environ["XDG_CONFIG_HOME"] = context.env_config_home
|
||||
show_env_changes(env_old, dict(os.environ))
|
||||
|
||||
|
||||
def show_env_changes(env_old, env_new):
|
||||
"""Print out all test-specific env values."""
|
||||
print("--- os.environ changed values: ---")
|
||||
all_keys = set(list(env_old.keys()) + list(env_new.keys()))
|
||||
for k in sorted(all_keys):
|
||||
old_value = env_old.get(k, "")
|
||||
new_value = env_new.get(k, "")
|
||||
if new_value and old_value != new_value:
|
||||
print('{}="{}"'.format(k, new_value))
|
||||
print("-" * 20)
|
||||
|
||||
|
||||
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"],
|
||||
context.conf["port"],
|
||||
)
|
||||
|
||||
# Remove temp config direcotry
|
||||
shutil.rmtree(context.env_config_home)
|
||||
|
||||
# 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 before_step(context, _):
|
||||
context.atprompt = False
|
||||
|
||||
|
||||
def before_scenario(context, scenario):
|
||||
if scenario.name == "list databases":
|
||||
# not using the cli for that
|
||||
return
|
||||
wrappers.run_cli(context)
|
||||
wrappers.wait_prompt(context)
|
||||
|
||||
|
||||
def after_scenario(context, scenario):
|
||||
"""Cleans up after each scenario completes."""
|
||||
if hasattr(context, "cli") and context.cli and not context.exit_sent:
|
||||
# Quit nicely.
|
||||
if not context.atprompt:
|
||||
dbname = context.currentdb
|
||||
context.cli.expect_exact("{0}> ".format(dbname), timeout=15)
|
||||
context.cli.sendcontrol("c")
|
||||
context.cli.sendcontrol("d")
|
||||
try:
|
||||
context.cli.expect_exact(pexpect.EOF, timeout=15)
|
||||
except pexpect.TIMEOUT:
|
||||
print("--- after_scenario {}: kill cli".format(scenario.name))
|
||||
context.cli.kill(signal.SIGKILL)
|
||||
if hasattr(context, "tmpfile_sql_help") and context.tmpfile_sql_help:
|
||||
context.tmpfile_sql_help.close()
|
||||
context.tmpfile_sql_help = None
|
||||
|
||||
|
||||
# # TODO: uncomment to debug a failure
|
||||
# def after_step(context, step):
|
||||
# if step.status == "failed":
|
||||
# import pdb; pdb.set_trace()
|
29
tests/features/expanded.feature
Normal file
29
tests/features/expanded.feature
Normal file
|
@ -0,0 +1,29 @@
|
|||
Feature: expanded mode:
|
||||
on, off, auto
|
||||
|
||||
Scenario: expanded on
|
||||
When we prepare the test data
|
||||
and we set expanded on
|
||||
and we select from table
|
||||
then we see expanded data selected
|
||||
when we drop table
|
||||
then we confirm the destructive warning
|
||||
then we see table dropped
|
||||
|
||||
Scenario: expanded off
|
||||
When we prepare the test data
|
||||
and we set expanded off
|
||||
and we select from table
|
||||
then we see nonexpanded data selected
|
||||
when we drop table
|
||||
then we confirm the destructive warning
|
||||
then we see table dropped
|
||||
|
||||
Scenario: expanded auto
|
||||
When we prepare the test data
|
||||
and we set expanded auto
|
||||
and we select from table
|
||||
then we see auto data selected
|
||||
when we drop table
|
||||
then we confirm the destructive warning
|
||||
then we see table dropped
|
25
tests/features/fixture_data/help.txt
Normal file
25
tests/features/fixture_data/help.txt
Normal file
|
@ -0,0 +1,25 @@
|
|||
+--------------------------+------------------------------------------------+
|
||||
| Command | Description |
|
||||
|--------------------------+------------------------------------------------|
|
||||
| \# | Refresh auto-completions. |
|
||||
| \? | Show Help. |
|
||||
| \T [format] | Change the table format used to output results |
|
||||
| \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. |
|
||||
+--------------------------+------------------------------------------------+
|
64
tests/features/fixture_data/help_commands.txt
Normal file
64
tests/features/fixture_data/help_commands.txt
Normal file
|
@ -0,0 +1,64 @@
|
|||
Command
|
||||
Description
|
||||
\#
|
||||
Refresh auto-completions.
|
||||
\?
|
||||
Show Commands.
|
||||
\T [format]
|
||||
Change the table format used to output results
|
||||
\c[onnect] database_name
|
||||
Change to a new database.
|
||||
\copy [tablename] to/from [filename]
|
||||
Copy data between a file and a table.
|
||||
\d[+] [pattern]
|
||||
List or describe tables, views and sequences.
|
||||
\dT[S+] [pattern]
|
||||
List data types
|
||||
\db[+] [pattern]
|
||||
List tablespaces.
|
||||
\df[+] [pattern]
|
||||
List functions.
|
||||
\di[+] [pattern]
|
||||
List indexes.
|
||||
\dm[+] [pattern]
|
||||
List materialized views.
|
||||
\dn[+] [pattern]
|
||||
List schemas.
|
||||
\ds[+] [pattern]
|
||||
List sequences.
|
||||
\dt[+] [pattern]
|
||||
List tables.
|
||||
\du[+] [pattern]
|
||||
List roles.
|
||||
\dv[+] [pattern]
|
||||
List views.
|
||||
\dx[+] [pattern]
|
||||
List extensions.
|
||||
\e [file]
|
||||
Edit the query with external editor.
|
||||
\h
|
||||
Show SQL syntax and help.
|
||||
\i filename
|
||||
Execute commands from file.
|
||||
\l
|
||||
List databases.
|
||||
\n[+] [name] [param1 param2 ...]
|
||||
List or execute named queries.
|
||||
\nd [name]
|
||||
Delete a named query.
|
||||
\ns name query
|
||||
Save a named query.
|
||||
\o [filename]
|
||||
Send all query results to file.
|
||||
\pager [command]
|
||||
Set PAGER. Print the query results via PAGER.
|
||||
\pset [key] [value]
|
||||
A limited version of traditional \pset
|
||||
\refresh
|
||||
Refresh auto-completions.
|
||||
\sf[+] FUNCNAME
|
||||
Show a function's definition.
|
||||
\timing
|
||||
Toggle timing of commands.
|
||||
\x
|
||||
Toggle expanded output.
|
4
tests/features/fixture_data/mock_pg_service.conf
Normal file
4
tests/features/fixture_data/mock_pg_service.conf
Normal file
|
@ -0,0 +1,4 @@
|
|||
[mock_postgres]
|
||||
dbname=postgres
|
||||
host=localhost
|
||||
user=postgres
|
28
tests/features/fixture_utils.py
Normal file
28
tests/features/fixture_utils.py
Normal file
|
@ -0,0 +1,28 @@
|
|||
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, "rb", encoding="utf-8"):
|
||||
lines.append(line.strip())
|
||||
return lines
|
||||
|
||||
|
||||
def read_fixture_files():
|
||||
"""Read all files inside fixture_data directory."""
|
||||
current_dir = os.path.dirname(__file__)
|
||||
fixture_dir = os.path.join(current_dir, "fixture_data/")
|
||||
print("reading fixture data: {}".format(fixture_dir))
|
||||
fixture_dict = {}
|
||||
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
|
17
tests/features/iocommands.feature
Normal file
17
tests/features/iocommands.feature
Normal file
|
@ -0,0 +1,17 @@
|
|||
Feature: I/O commands
|
||||
|
||||
Scenario: edit sql in file with external editor
|
||||
When we start external editor providing a file name
|
||||
and we type sql in the editor
|
||||
and we exit the editor
|
||||
then we see dbcli prompt
|
||||
and we see the sql in prompt
|
||||
|
||||
Scenario: tee output from query
|
||||
When we tee output
|
||||
and we wait for prompt
|
||||
and we query "select 123456"
|
||||
and we wait for prompt
|
||||
and we stop teeing output
|
||||
and we wait for prompt
|
||||
then we see 123456 in tee output
|
10
tests/features/named_queries.feature
Normal file
10
tests/features/named_queries.feature
Normal file
|
@ -0,0 +1,10 @@
|
|||
Feature: named queries:
|
||||
save, use and delete named queries
|
||||
|
||||
Scenario: save, use and delete named queries
|
||||
When we connect to test database
|
||||
then we see database connected
|
||||
when we save a named query
|
||||
then we see the named query saved
|
||||
when we delete a named query
|
||||
then we see the named query deleted
|
6
tests/features/specials.feature
Normal file
6
tests/features/specials.feature
Normal file
|
@ -0,0 +1,6 @@
|
|||
Feature: Special commands
|
||||
|
||||
Scenario: run refresh command
|
||||
When we refresh completions
|
||||
and we wait for prompt
|
||||
then we see completions refresh started
|
0
tests/features/steps/__init__.py
Normal file
0
tests/features/steps/__init__.py
Normal file
99
tests/features/steps/auto_vertical.py
Normal file
99
tests/features/steps/auto_vertical.py
Normal file
|
@ -0,0 +1,99 @@
|
|||
from textwrap import dedent
|
||||
from behave import then, when
|
||||
import wrappers
|
||||
|
||||
|
||||
@when("we run dbcli with {arg}")
|
||||
def step_run_cli_with_arg(context, arg):
|
||||
wrappers.run_cli(context, run_args=arg.split("="))
|
||||
|
||||
|
||||
@when("we execute a small query")
|
||||
def step_execute_small_query(context):
|
||||
context.cli.sendline("select 1")
|
||||
|
||||
|
||||
@when("we execute a large query")
|
||||
def step_execute_large_query(context):
|
||||
context.cli.sendline("select {}".format(",".join([str(n) for n in range(1, 50)])))
|
||||
|
||||
|
||||
@then("we see small results in horizontal format")
|
||||
def step_see_small_results(context):
|
||||
wrappers.expect_pager(
|
||||
context,
|
||||
dedent(
|
||||
"""\
|
||||
+------------+\r
|
||||
| ?column? |\r
|
||||
|------------|\r
|
||||
| 1 |\r
|
||||
+------------+\r
|
||||
SELECT 1\r
|
||||
"""
|
||||
),
|
||||
timeout=5,
|
||||
)
|
||||
|
||||
|
||||
@then("we see large results in vertical format")
|
||||
def step_see_large_results(context):
|
||||
wrappers.expect_pager(
|
||||
context,
|
||||
dedent(
|
||||
"""\
|
||||
-[ RECORD 1 ]-------------------------\r
|
||||
?column? | 1\r
|
||||
?column? | 2\r
|
||||
?column? | 3\r
|
||||
?column? | 4\r
|
||||
?column? | 5\r
|
||||
?column? | 6\r
|
||||
?column? | 7\r
|
||||
?column? | 8\r
|
||||
?column? | 9\r
|
||||
?column? | 10\r
|
||||
?column? | 11\r
|
||||
?column? | 12\r
|
||||
?column? | 13\r
|
||||
?column? | 14\r
|
||||
?column? | 15\r
|
||||
?column? | 16\r
|
||||
?column? | 17\r
|
||||
?column? | 18\r
|
||||
?column? | 19\r
|
||||
?column? | 20\r
|
||||
?column? | 21\r
|
||||
?column? | 22\r
|
||||
?column? | 23\r
|
||||
?column? | 24\r
|
||||
?column? | 25\r
|
||||
?column? | 26\r
|
||||
?column? | 27\r
|
||||
?column? | 28\r
|
||||
?column? | 29\r
|
||||
?column? | 30\r
|
||||
?column? | 31\r
|
||||
?column? | 32\r
|
||||
?column? | 33\r
|
||||
?column? | 34\r
|
||||
?column? | 35\r
|
||||
?column? | 36\r
|
||||
?column? | 37\r
|
||||
?column? | 38\r
|
||||
?column? | 39\r
|
||||
?column? | 40\r
|
||||
?column? | 41\r
|
||||
?column? | 42\r
|
||||
?column? | 43\r
|
||||
?column? | 44\r
|
||||
?column? | 45\r
|
||||
?column? | 46\r
|
||||
?column? | 47\r
|
||||
?column? | 48\r
|
||||
?column? | 49\r
|
||||
SELECT 1\r
|
||||
"""
|
||||
),
|
||||
timeout=5,
|
||||
)
|
147
tests/features/steps/basic_commands.py
Normal file
147
tests/features/steps/basic_commands.py
Normal file
|
@ -0,0 +1,147 @@
|
|||
"""
|
||||
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.
|
||||
"""
|
||||
|
||||
import pexpect
|
||||
import subprocess
|
||||
import tempfile
|
||||
|
||||
from behave import when, then
|
||||
from textwrap import dedent
|
||||
import wrappers
|
||||
|
||||
|
||||
@when("we list databases")
|
||||
def step_list_databases(context):
|
||||
cmd = ["pgcli", "--list"]
|
||||
context.cmd_output = subprocess.check_output(cmd, cwd=context.package_root)
|
||||
|
||||
|
||||
@then("we see list of databases")
|
||||
def step_see_list_databases(context):
|
||||
assert b"List of databases" in context.cmd_output
|
||||
assert b"postgres" in context.cmd_output
|
||||
context.cmd_output = None
|
||||
|
||||
|
||||
@when("we run dbcli")
|
||||
def step_run_cli(context):
|
||||
wrappers.run_cli(context)
|
||||
|
||||
|
||||
@when("we launch dbcli using {arg}")
|
||||
def step_run_cli_using_arg(context, arg):
|
||||
prompt_check = False
|
||||
currentdb = None
|
||||
if arg == "--username":
|
||||
arg = "--username={}".format(context.conf["user"])
|
||||
if arg == "--user":
|
||||
arg = "--user={}".format(context.conf["user"])
|
||||
if arg == "--port":
|
||||
arg = "--port={}".format(context.conf["port"])
|
||||
if arg == "--password":
|
||||
arg = "--password"
|
||||
prompt_check = False
|
||||
# This uses the mock_pg_service.conf file in fixtures folder.
|
||||
if arg == "dsn_password":
|
||||
arg = "service=mock_postgres --password"
|
||||
prompt_check = False
|
||||
currentdb = "postgres"
|
||||
wrappers.run_cli(
|
||||
context, run_args=[arg], prompt_check=prompt_check, currentdb=currentdb
|
||||
)
|
||||
|
||||
|
||||
@when("we wait for prompt")
|
||||
def step_wait_prompt(context):
|
||||
wrappers.wait_prompt(context)
|
||||
|
||||
|
||||
@when('we send "ctrl + d"')
|
||||
def step_ctrl_d(context):
|
||||
"""
|
||||
Send Ctrl + D to hopefully exit.
|
||||
"""
|
||||
# turn off pager before exiting
|
||||
context.cli.sendline("\pset pager off")
|
||||
wrappers.wait_prompt(context)
|
||||
context.cli.sendcontrol("d")
|
||||
context.cli.expect(pexpect.EOF, timeout=15)
|
||||
context.exit_sent = True
|
||||
|
||||
|
||||
@when('we send "\?" command')
|
||||
def step_send_help(context):
|
||||
"""
|
||||
Send \? to see help.
|
||||
"""
|
||||
context.cli.sendline("\?")
|
||||
|
||||
|
||||
@when("we send partial select command")
|
||||
def step_send_partial_select_command(context):
|
||||
"""
|
||||
Send `SELECT a` to see completion.
|
||||
"""
|
||||
context.cli.sendline("SELECT a")
|
||||
|
||||
|
||||
@then("we see error message")
|
||||
def step_see_error_message(context):
|
||||
wrappers.expect_exact(context, 'column "a" does not exist', timeout=2)
|
||||
|
||||
|
||||
@when("we send source command")
|
||||
def step_send_source_command(context):
|
||||
context.tmpfile_sql_help = tempfile.NamedTemporaryFile(prefix="pgcli_")
|
||||
context.tmpfile_sql_help.write(b"\?")
|
||||
context.tmpfile_sql_help.flush()
|
||||
context.cli.sendline("\i {0}".format(context.tmpfile_sql_help.name))
|
||||
wrappers.expect_exact(context, context.conf["pager_boundary"] + "\r\n", timeout=5)
|
||||
|
||||
|
||||
@when("we run query to check application_name")
|
||||
def step_check_application_name(context):
|
||||
context.cli.sendline(
|
||||
"SELECT 'found' FROM pg_stat_activity WHERE application_name = 'pgcli' HAVING COUNT(*) > 0;"
|
||||
)
|
||||
|
||||
|
||||
@then("we see found")
|
||||
def step_see_found(context):
|
||||
wrappers.expect_exact(
|
||||
context,
|
||||
context.conf["pager_boundary"]
|
||||
+ "\r"
|
||||
+ dedent(
|
||||
"""
|
||||
+------------+\r
|
||||
| ?column? |\r
|
||||
|------------|\r
|
||||
| found |\r
|
||||
+------------+\r
|
||||
SELECT 1\r
|
||||
"""
|
||||
)
|
||||
+ context.conf["pager_boundary"],
|
||||
timeout=5,
|
||||
)
|
||||
|
||||
|
||||
@then("we confirm the destructive warning")
|
||||
def step_confirm_destructive_command(context):
|
||||
"""Confirm destructive command."""
|
||||
wrappers.expect_exact(
|
||||
context,
|
||||
"You're about to run a destructive command.\r\nDo you want to proceed? (y/n):",
|
||||
timeout=2,
|
||||
)
|
||||
context.cli.sendline("y")
|
||||
|
||||
|
||||
@then("we send password")
|
||||
def step_send_password(context):
|
||||
wrappers.expect_exact(context, "Password for", timeout=5)
|
||||
context.cli.sendline(context.conf["pass"] or "DOES NOT MATTER")
|
93
tests/features/steps/crud_database.py
Normal file
93
tests/features/steps/crud_database.py
Normal file
|
@ -0,0 +1,93 @@
|
|||
"""
|
||||
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.
|
||||
"""
|
||||
import pexpect
|
||||
|
||||
from behave import when, then
|
||||
import wrappers
|
||||
|
||||
|
||||
@when("we create database")
|
||||
def step_db_create(context):
|
||||
"""
|
||||
Send create database.
|
||||
"""
|
||||
context.cli.sendline("create database {0};".format(context.conf["dbname_tmp"]))
|
||||
|
||||
context.response = {"database_name": context.conf["dbname_tmp"]}
|
||||
|
||||
|
||||
@when("we drop database")
|
||||
def step_db_drop(context):
|
||||
"""
|
||||
Send drop database.
|
||||
"""
|
||||
context.cli.sendline("drop database {0};".format(context.conf["dbname_tmp"]))
|
||||
|
||||
|
||||
@when("we connect to test database")
|
||||
def step_db_connect_test(context):
|
||||
"""
|
||||
Send connect to database.
|
||||
"""
|
||||
db_name = context.conf["dbname"]
|
||||
context.cli.sendline("\\connect {0}".format(db_name))
|
||||
|
||||
|
||||
@when("we connect to dbserver")
|
||||
def step_db_connect_dbserver(context):
|
||||
"""
|
||||
Send connect to database.
|
||||
"""
|
||||
context.cli.sendline("\\connect postgres")
|
||||
context.currentdb = "postgres"
|
||||
|
||||
|
||||
@then("dbcli exits")
|
||||
def step_wait_exit(context):
|
||||
"""
|
||||
Make sure the cli exits.
|
||||
"""
|
||||
wrappers.expect_exact(context, pexpect.EOF, timeout=5)
|
||||
|
||||
|
||||
@then("we see dbcli prompt")
|
||||
def step_see_prompt(context):
|
||||
"""
|
||||
Wait to see the prompt.
|
||||
"""
|
||||
db_name = getattr(context, "currentdb", context.conf["dbname"])
|
||||
wrappers.expect_exact(context, "{0}> ".format(db_name), timeout=5)
|
||||
context.atprompt = True
|
||||
|
||||
|
||||
@then("we see help output")
|
||||
def step_see_help(context):
|
||||
for expected_line in context.fixture_data["help_commands.txt"]:
|
||||
wrappers.expect_exact(context, expected_line, timeout=2)
|
||||
|
||||
|
||||
@then("we see database created")
|
||||
def step_see_db_created(context):
|
||||
"""
|
||||
Wait to see create database output.
|
||||
"""
|
||||
wrappers.expect_pager(context, "CREATE DATABASE\r\n", timeout=5)
|
||||
|
||||
|
||||
@then("we see database dropped")
|
||||
def step_see_db_dropped(context):
|
||||
"""
|
||||
Wait to see drop database output.
|
||||
"""
|
||||
wrappers.expect_pager(context, "DROP DATABASE\r\n", timeout=2)
|
||||
|
||||
|
||||
@then("we see database connected")
|
||||
def step_see_db_connected(context):
|
||||
"""
|
||||
Wait to see drop database output.
|
||||
"""
|
||||
wrappers.expect_exact(context, "You are now connected to database", timeout=2)
|
118
tests/features/steps/crud_table.py
Normal file
118
tests/features/steps/crud_table.py
Normal file
|
@ -0,0 +1,118 @@
|
|||
"""
|
||||
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 behave import when, then
|
||||
from textwrap import dedent
|
||||
import wrappers
|
||||
|
||||
|
||||
@when("we create table")
|
||||
def step_create_table(context):
|
||||
"""
|
||||
Send create table.
|
||||
"""
|
||||
context.cli.sendline("create table a(x text);")
|
||||
|
||||
|
||||
@when("we insert into table")
|
||||
def step_insert_into_table(context):
|
||||
"""
|
||||
Send insert into table.
|
||||
"""
|
||||
context.cli.sendline("""insert into a(x) values('xxx');""")
|
||||
|
||||
|
||||
@when("we update table")
|
||||
def step_update_table(context):
|
||||
"""
|
||||
Send insert into table.
|
||||
"""
|
||||
context.cli.sendline("""update a set x = 'yyy' where x = 'xxx';""")
|
||||
|
||||
|
||||
@when("we select from table")
|
||||
def step_select_from_table(context):
|
||||
"""
|
||||
Send select from table.
|
||||
"""
|
||||
context.cli.sendline("select * from a;")
|
||||
|
||||
|
||||
@when("we delete from table")
|
||||
def step_delete_from_table(context):
|
||||
"""
|
||||
Send deete from table.
|
||||
"""
|
||||
context.cli.sendline("""delete from a where x = 'yyy';""")
|
||||
|
||||
|
||||
@when("we drop table")
|
||||
def step_drop_table(context):
|
||||
"""
|
||||
Send drop table.
|
||||
"""
|
||||
context.cli.sendline("drop table a;")
|
||||
|
||||
|
||||
@then("we see table created")
|
||||
def step_see_table_created(context):
|
||||
"""
|
||||
Wait to see create table output.
|
||||
"""
|
||||
wrappers.expect_pager(context, "CREATE TABLE\r\n", timeout=2)
|
||||
|
||||
|
||||
@then("we see record inserted")
|
||||
def step_see_record_inserted(context):
|
||||
"""
|
||||
Wait to see insert output.
|
||||
"""
|
||||
wrappers.expect_pager(context, "INSERT 0 1\r\n", timeout=2)
|
||||
|
||||
|
||||
@then("we see record updated")
|
||||
def step_see_record_updated(context):
|
||||
"""
|
||||
Wait to see update output.
|
||||
"""
|
||||
wrappers.expect_pager(context, "UPDATE 1\r\n", timeout=2)
|
||||
|
||||
|
||||
@then("we see data selected")
|
||||
def step_see_data_selected(context):
|
||||
"""
|
||||
Wait to see select output.
|
||||
"""
|
||||
wrappers.expect_pager(
|
||||
context,
|
||||
dedent(
|
||||
"""\
|
||||
+-----+\r
|
||||
| x |\r
|
||||
|-----|\r
|
||||
| yyy |\r
|
||||
+-----+\r
|
||||
SELECT 1\r
|
||||
"""
|
||||
),
|
||||
timeout=1,
|
||||
)
|
||||
|
||||
|
||||
@then("we see record deleted")
|
||||
def step_see_data_deleted(context):
|
||||
"""
|
||||
Wait to see delete output.
|
||||
"""
|
||||
wrappers.expect_pager(context, "DELETE 1\r\n", timeout=2)
|
||||
|
||||
|
||||
@then("we see table dropped")
|
||||
def step_see_table_dropped(context):
|
||||
"""
|
||||
Wait to see drop output.
|
||||
"""
|
||||
wrappers.expect_pager(context, "DROP TABLE\r\n", timeout=2)
|
70
tests/features/steps/expanded.py
Normal file
70
tests/features/steps/expanded.py
Normal file
|
@ -0,0 +1,70 @@
|
|||
"""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 behave import when, then
|
||||
from textwrap import dedent
|
||||
import wrappers
|
||||
|
||||
|
||||
@when("we prepare the test data")
|
||||
def step_prepare_data(context):
|
||||
"""Create table, insert a record."""
|
||||
context.cli.sendline("drop table if exists a;")
|
||||
wrappers.expect_exact(
|
||||
context,
|
||||
"You're about to run a destructive command.\r\nDo you want to proceed? (y/n):",
|
||||
timeout=2,
|
||||
)
|
||||
context.cli.sendline("y")
|
||||
|
||||
wrappers.wait_prompt(context)
|
||||
context.cli.sendline("create table a(x integer, y real, z numeric(10, 4));")
|
||||
wrappers.expect_pager(context, "CREATE TABLE\r\n", timeout=2)
|
||||
context.cli.sendline("""insert into a(x, y, z) values(1, 1.0, 1.0);""")
|
||||
wrappers.expect_pager(context, "INSERT 0 1\r\n", timeout=2)
|
||||
|
||||
|
||||
@when("we set expanded {mode}")
|
||||
def step_set_expanded(context, mode):
|
||||
"""Set expanded to mode."""
|
||||
context.cli.sendline("\\" + "x {}".format(mode))
|
||||
wrappers.expect_exact(context, "Expanded display is", timeout=2)
|
||||
wrappers.wait_prompt(context)
|
||||
|
||||
|
||||
@then("we see {which} data selected")
|
||||
def step_see_data(context, which):
|
||||
"""Select data from expanded test table."""
|
||||
if which == "expanded":
|
||||
wrappers.expect_pager(
|
||||
context,
|
||||
dedent(
|
||||
"""\
|
||||
-[ RECORD 1 ]-------------------------\r
|
||||
x | 1\r
|
||||
y | 1.0\r
|
||||
z | 1.0000\r
|
||||
SELECT 1\r
|
||||
"""
|
||||
),
|
||||
timeout=1,
|
||||
)
|
||||
else:
|
||||
wrappers.expect_pager(
|
||||
context,
|
||||
dedent(
|
||||
"""\
|
||||
+-----+-----+--------+\r
|
||||
| x | y | z |\r
|
||||
|-----+-----+--------|\r
|
||||
| 1 | 1.0 | 1.0000 |\r
|
||||
+-----+-----+--------+\r
|
||||
SELECT 1\r
|
||||
"""
|
||||
),
|
||||
timeout=1,
|
||||
)
|
80
tests/features/steps/iocommands.py
Normal file
80
tests/features/steps/iocommands.py
Normal file
|
@ -0,0 +1,80 @@
|
|||
import os
|
||||
import os.path
|
||||
|
||||
from behave import when, then
|
||||
import wrappers
|
||||
|
||||
|
||||
@when("we start external editor providing a file name")
|
||||
def step_edit_file(context):
|
||||
"""Edit file with external editor."""
|
||||
context.editor_file_name = os.path.join(
|
||||
context.package_root, "test_file_{0}.sql".format(context.conf["vi"])
|
||||
)
|
||||
if os.path.exists(context.editor_file_name):
|
||||
os.remove(context.editor_file_name)
|
||||
context.cli.sendline("\e {0}".format(os.path.basename(context.editor_file_name)))
|
||||
wrappers.expect_exact(
|
||||
context, 'Entering Ex mode. Type "visual" to go to Normal mode.', timeout=2
|
||||
)
|
||||
wrappers.expect_exact(context, ":", timeout=2)
|
||||
|
||||
|
||||
@when("we type sql in the editor")
|
||||
def step_edit_type_sql(context):
|
||||
context.cli.sendline("i")
|
||||
context.cli.sendline("select * from abc")
|
||||
context.cli.sendline(".")
|
||||
wrappers.expect_exact(context, ":", timeout=2)
|
||||
|
||||
|
||||
@when("we exit the editor")
|
||||
def step_edit_quit(context):
|
||||
context.cli.sendline("x")
|
||||
wrappers.expect_exact(context, "written", timeout=2)
|
||||
|
||||
|
||||
@then("we see the sql in prompt")
|
||||
def step_edit_done_sql(context):
|
||||
for match in "select * from abc".split(" "):
|
||||
wrappers.expect_exact(context, match, timeout=1)
|
||||
# Cleanup the command line.
|
||||
context.cli.sendcontrol("c")
|
||||
# Cleanup the edited file.
|
||||
if context.editor_file_name and os.path.exists(context.editor_file_name):
|
||||
os.remove(context.editor_file_name)
|
||||
context.atprompt = True
|
||||
|
||||
|
||||
@when("we tee output")
|
||||
def step_tee_ouptut(context):
|
||||
context.tee_file_name = os.path.join(
|
||||
context.package_root, "tee_file_{0}.sql".format(context.conf["vi"])
|
||||
)
|
||||
if os.path.exists(context.tee_file_name):
|
||||
os.remove(context.tee_file_name)
|
||||
context.cli.sendline("\o {0}".format(os.path.basename(context.tee_file_name)))
|
||||
wrappers.expect_exact(context, context.conf["pager_boundary"] + "\r\n", timeout=5)
|
||||
wrappers.expect_exact(context, "Writing to file", timeout=5)
|
||||
wrappers.expect_exact(context, context.conf["pager_boundary"] + "\r\n", timeout=5)
|
||||
wrappers.expect_exact(context, "Time", timeout=5)
|
||||
|
||||
|
||||
@when('we query "select 123456"')
|
||||
def step_query_select_123456(context):
|
||||
context.cli.sendline("select 123456")
|
||||
|
||||
|
||||
@when("we stop teeing output")
|
||||
def step_notee_output(context):
|
||||
context.cli.sendline("\o")
|
||||
wrappers.expect_exact(context, "Time", timeout=5)
|
||||
|
||||
|
||||
@then("we see 123456 in tee output")
|
||||
def step_see_123456_in_ouput(context):
|
||||
with open(context.tee_file_name) as f:
|
||||
assert "123456" in f.read()
|
||||
if os.path.exists(context.tee_file_name):
|
||||
os.remove(context.tee_file_name)
|
||||
context.atprompt = True
|
57
tests/features/steps/named_queries.py
Normal file
57
tests/features/steps/named_queries.py
Normal file
|
@ -0,0 +1,57 @@
|
|||
"""
|
||||
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 behave import when, then
|
||||
import wrappers
|
||||
|
||||
|
||||
@when("we save a named query")
|
||||
def step_save_named_query(context):
|
||||
"""
|
||||
Send \ns command
|
||||
"""
|
||||
context.cli.sendline("\\ns foo SELECT 12345")
|
||||
|
||||
|
||||
@when("we use a named query")
|
||||
def step_use_named_query(context):
|
||||
"""
|
||||
Send \n command
|
||||
"""
|
||||
context.cli.sendline("\\n foo")
|
||||
|
||||
|
||||
@when("we delete a named query")
|
||||
def step_delete_named_query(context):
|
||||
"""
|
||||
Send \nd command
|
||||
"""
|
||||
context.cli.sendline("\\nd foo")
|
||||
|
||||
|
||||
@then("we see the named query saved")
|
||||
def step_see_named_query_saved(context):
|
||||
"""
|
||||
Wait to see query saved.
|
||||
"""
|
||||
wrappers.expect_exact(context, "Saved.", timeout=2)
|
||||
|
||||
|
||||
@then("we see the named query executed")
|
||||
def step_see_named_query_executed(context):
|
||||
"""
|
||||
Wait to see select output.
|
||||
"""
|
||||
wrappers.expect_exact(context, "12345", timeout=1)
|
||||
wrappers.expect_exact(context, "SELECT 1", timeout=1)
|
||||
|
||||
|
||||
@then("we see the named query deleted")
|
||||
def step_see_named_query_deleted(context):
|
||||
"""
|
||||
Wait to see query deleted.
|
||||
"""
|
||||
wrappers.expect_pager(context, "foo: Deleted\r\n", timeout=1)
|
26
tests/features/steps/specials.py
Normal file
26
tests/features/steps/specials.py
Normal file
|
@ -0,0 +1,26 @@
|
|||
"""
|
||||
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 behave import when, then
|
||||
import wrappers
|
||||
|
||||
|
||||
@when("we refresh completions")
|
||||
def step_refresh_completions(context):
|
||||
"""
|
||||
Send refresh command.
|
||||
"""
|
||||
context.cli.sendline("\\refresh")
|
||||
|
||||
|
||||
@then("we see completions refresh started")
|
||||
def step_see_refresh_started(context):
|
||||
"""
|
||||
Wait to see refresh output.
|
||||
"""
|
||||
wrappers.expect_pager(
|
||||
context, "Auto-completion refresh started in the background.\r\n", timeout=2
|
||||
)
|
67
tests/features/steps/wrappers.py
Normal file
67
tests/features/steps/wrappers.py
Normal file
|
@ -0,0 +1,67 @@
|
|||
import re
|
||||
import pexpect
|
||||
from pgcli.main import COLOR_CODE_REGEX
|
||||
import textwrap
|
||||
|
||||
try:
|
||||
from StringIO import StringIO
|
||||
except ImportError:
|
||||
from io import StringIO
|
||||
|
||||
|
||||
def expect_exact(context, expected, timeout):
|
||||
timedout = False
|
||||
try:
|
||||
context.cli.expect_exact(expected, timeout=timeout)
|
||||
except pexpect.TIMEOUT:
|
||||
timedout = True
|
||||
if timedout:
|
||||
# Strip color codes out of the output.
|
||||
actual = re.sub(r"\x1b\[([0-9A-Za-z;?])+[m|K]?", "", context.cli.before)
|
||||
raise Exception(
|
||||
textwrap.dedent(
|
||||
"""\
|
||||
Expected:
|
||||
---
|
||||
{0!r}
|
||||
---
|
||||
Actual:
|
||||
---
|
||||
{1!r}
|
||||
---
|
||||
Full log:
|
||||
---
|
||||
{2!r}
|
||||
---
|
||||
"""
|
||||
).format(expected, actual, context.logfile.getvalue())
|
||||
)
|
||||
|
||||
|
||||
def expect_pager(context, expected, timeout):
|
||||
expect_exact(
|
||||
context,
|
||||
"{0}\r\n{1}{0}\r\n".format(context.conf["pager_boundary"], expected),
|
||||
timeout=timeout,
|
||||
)
|
||||
|
||||
|
||||
def run_cli(context, run_args=None, prompt_check=True, currentdb=None):
|
||||
"""Run the process using pexpect."""
|
||||
run_args = run_args or []
|
||||
cli_cmd = context.conf.get("cli_command")
|
||||
cmd_parts = [cli_cmd] + run_args
|
||||
cmd = " ".join(cmd_parts)
|
||||
context.cli = pexpect.spawnu(cmd, cwd=context.package_root)
|
||||
context.logfile = StringIO()
|
||||
context.cli.logfile = context.logfile
|
||||
context.exit_sent = False
|
||||
context.currentdb = currentdb or context.conf["dbname"]
|
||||
context.cli.sendline("\pset pager always")
|
||||
if prompt_check:
|
||||
wait_prompt(context)
|
||||
|
||||
|
||||
def wait_prompt(context):
|
||||
"""Make sure prompt is displayed."""
|
||||
expect_exact(context, "{0}> ".format(context.conf["dbname"]), timeout=5)
|
16
tests/features/wrappager.py
Executable file
16
tests/features/wrappager.py
Executable file
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env python
|
||||
import sys
|
||||
|
||||
|
||||
def wrappager(boundary):
|
||||
print(boundary)
|
||||
while 1:
|
||||
buf = sys.stdin.read(2048)
|
||||
if not buf:
|
||||
break
|
||||
sys.stdout.write(buf)
|
||||
print(boundary)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
wrappager(sys.argv[1])
|
Loading…
Add table
Add a link
Reference in a new issue