Make the query tool datatype test easily configurable and extendable and add support for multi-dimensional arrays and enums.

This commit is contained in:
Harshal Dhumal
2017-12-18 15:10:47 +00:00
committed by Dave Page
parent 6577723a2a
commit 88bcd3b512
4 changed files with 361 additions and 51 deletions

View File

@@ -0,0 +1,173 @@
[
{
"datatype": [
"smallint",
"smallint",
"integer",
"integer",
"bigint",
"bigint",
"decimal",
"decimal",
"numeric",
"numeric",
"float[]",
"float[]",
"real",
"real[]",
"bytea",
"bytea[]"
],
"input":[
"-32767",
"32767",
"-2147483647",
"2147483647",
"-9223372036854775807",
"9223372036854775807",
"922337203685.4775807",
"92203685.477",
"922337203685.922337203685",
"-92233720368547758.08",
"ARRAY[1, 2, 3]",
"ARRAY['nan', 'nan', 'nan']",
"'Infinity'",
"'{Infinity}'",
"'E\\\\xDEADBEEF'",
"ARRAY['E\\\\xDEADBEEF', 'E\\\\xDEADBEEF']"
],
"output":[
"-32767",
"32767",
"-2147483647",
"2147483647",
"-9223372036854775807",
"9223372036854775807",
"922337203685.4775807",
"92203685.477",
"922337203685.922337203685",
"-92233720368547758.08",
"{1,2,3}",
"{NaN,NaN,NaN}",
"Infinity",
"{Infinity}",
"[binary data]",
"[binary data[]]"
]
},
{
"datatype": [
"int4range",
"int8range",
"numrange",
"daterange",
"tsrange",
"tstzrange",
"int4range[]",
"int8range[]",
"numrange[]",
"daterange[]",
"tsrange[]",
"tstzrange[]",
"int8range[]",
"daterange[]",
"tstzrange[]",
"",
""
],
"input":[
"'(1,2147483647)'",
"'(2,9223372036854775807)'",
"'(3,922337203685.922337203685]'",
"'(2010-01-01, 2010-02-01]'",
"'[2010-01-01 14:00, 2010-04-01 15:00)'",
"'[2010-01-01 14:00:00{tz}, 2010-02-01 15:00:00{tz})'",
"'{\"(1,2147483647)\", \"(2,2147483647)\"}'",
"'{\"(2,9223372036854775807)\", \"(2,9223372036854775807)\"}'",
"'{\"(3,922337203685.922337203685]\", \"(5,922337203685.922337203685]\"}'",
"'{\"(2010-01-01, 2010-02-01]\", \"(2010-01-01, 2010-02-01]\"}'",
"'{\"[2010-01-01 14:00, 2010-04-01 15:00)\", \"[2010-01-01 14:00, 2010-04-01 15:00)\"}'",
"'{{\"[2010-01-01 14:00:00{tz}, 2010-02-01 15:00:00{tz})\", \"[2017-01-12 14:00:00{tz}, 2017-02-28 15:00:00{tz})\"}}'",
"'{{\"(2,9223372036854775807)\", \"(2,9223372036854775807)\"},{\"(2,9223372036854775807)\", \"(2,9223372036854775807)\"}}'",
"'{{\"(2010-01-01, 2010-02-01]\", \"(2010-01-01, 2010-02-01]\"},{\"(2010-01-01, 2010-02-01]\", \"(2010-01-01, 2010-02-01]\"}}'",
"'{{{{\"[2010-01-01 14:00:00{tz}, 2010-02-01 15:00:00{tz})\", \"[2017-01-12 14:00:00{tz}, 2017-02-28 15:00:00{tz})\"}}, {{\"[2010-01-01 14:00:00{tz}, 2010-02-01 15:00:00{tz})\", \"[2017-01-12 14:00:00{tz}, 2017-02-28 15:00:00{tz})\"}}}}'",
"enum_range(NULL::rainbow)",
"ARRAY[enum_range(NULL::rainbow), enum_range(NULL::rainbow)]"
],
"output":[
"[2,2147483647)",
"[3,9223372036854775807)",
"(3,922337203685.922337203685]",
"[2010-01-02,2010-02-02)",
"[\"2010-01-01 14:00:00\",\"2010-04-01 15:00:00\")",
"[\"2010-01-01 14:00:00{tz}\",\"2010-02-01 15:00:00{tz}\")",
"{\"[2,2147483647)\",\"[3,2147483647)\"}",
"{\"[3,9223372036854775807)\",\"[3,9223372036854775807)\"}",
"{\"(3,922337203685.922337203685]\",\"(5,922337203685.922337203685]\"}",
"{\"[2010-01-02,2010-02-02)\",\"[2010-01-02,2010-02-02)\"}",
"{\"[\\\"2010-01-01 14:00:00\\\",\\\"2010-04-01 15:00:00\\\")\",\"[\\\"2010-01-01 14:00:00\\\",\\\"2010-04-01 15:00:00\\\")\"}",
"{{\"[\\\"2010-01-01 14:00:00{tz}\\\",\\\"2010-02-01 15:00:00{tz}\\\")\",\"[\\\"2017-01-12 14:00:00{tz}\\\",\\\"2017-02-28 15:00:00{tz}\\\")\"}}",
"{{\"[3,9223372036854775807)\",\"[3,9223372036854775807)\"},{\"[3,9223372036854775807)\",\"[3,9223372036854775807)\"}}",
"{{\"[2010-01-02,2010-02-02)\",\"[2010-01-02,2010-02-02)\"},{\"[2010-01-02,2010-02-02)\",\"[2010-01-02,2010-02-02)\"}}",
"{{{{\"[\\\"2010-01-01 14:00:00{tz}\\\",\\\"2010-02-01 15:00:00{tz}\\\")\",\"[\\\"2017-01-12 14:00:00{tz}\\\",\\\"2017-02-28 15:00:00{tz}\\\")\"}},{{\"[\\\"2010-01-01 14:00:00{tz}\\\",\\\"2010-02-01 15:00:00{tz}\\\")\",\"[\\\"2017-01-12 14:00:00{tz}\\\",\\\"2017-02-28 15:00:00{tz}\\\")\"}}}}",
"{red,orange,yellow,green,blue,purple}",
"{{red,orange,yellow,green,blue,purple},{red,orange,yellow,green,blue,purple}}"
]
},
{
"datatype": [
"inet",
"inet[]",
"inet[]",
"cidr",
"cidr[]",
"cidr[]",
"uuid",
"uuid[]",
"xml",
"xml[]",
"bit",
"bit[]",
"varbit",
"varbit[]",
"macaddr",
"macaddr[]"
],
"input":[
"'::2'",
"'{\"::2\",\"192.168.1.1/16\",\"FFF0:0:007a::\"}'",
"'{{\"::2\",\"192.168.1.1/16\",\"FFF0:0:007a::\"},{\"::2\",\"192.168.1.1/16\",\"FFF0:0:007a::\"}}'",
"'::1'",
"'{\"::1\", \"192.168.100.128/25\", \"FFF0:0:007a::\"}'",
"'{{\"::1\", \"192.168.100.128/25\", \"FFF0:0:007a::\"},{\"::1\", \"192.168.100.128/25\", \"FFF0:0:007a::\"}}'",
"'e1ab7b6d-a62d-4bee-b0ce-b8488f83d89c'",
"'{55f8e502-e0b4-11e7-80c1-9a214cf093ae, e1ab7b6d-a62d-4bee-b0ce-b8488f83d89c}'",
"'<?xml version=\"1.0\" encoding=\"UTF-8\"?><name>pgAdmin 4</name>'",
"'{\"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?><name>pgAdmin 4</name>\", \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?><name>pgAdmin 4</name>\"}'",
"'1'",
"'{0,1}'",
"'1001'",
"'{10010,1011}'",
"'08:00:2b:01:02:03'",
"'{08:00:2b:01:02:03, 08-00-2b-01-02-03, 08002b:010203, 08002b-010203, 0800.2b01.0203, 0800-2b01-0203, 08002b010203}'"
],
"output":[
"::2",
"{::2,192.168.1.1/16,fff0:0:7a::}",
"{{::2,192.168.1.1/16,fff0:0:7a::},{::2,192.168.1.1/16,fff0:0:7a::}}",
"::1/128",
"{::1/128,192.168.100.128/25,fff0:0:7a::/128}",
"{{::1/128,192.168.100.128/25,fff0:0:7a::/128},{::1/128,192.168.100.128/25,fff0:0:7a::/128}}",
"e1ab7b6d-a62d-4bee-b0ce-b8488f83d89c",
"{55f8e502-e0b4-11e7-80c1-9a214cf093ae,e1ab7b6d-a62d-4bee-b0ce-b8488f83d89c}",
"<name>pgAdmin 4</name>",
"{\"<name>pgAdmin 4</name>\",\"<name>pgAdmin 4</name>\"}",
"1",
"{0,1}",
"1001",
"{10010,1011}",
"08:00:2b:01:02:03",
"{08:00:2b:01:02:03,08:00:2b:01:02:03,08:00:2b:01:02:03,08:00:2b:01:02:03,08:00:2b:01:02:03,08:00:2b:01:02:03,08:00:2b:01:02:03}"
]
}
]

View File

@@ -7,14 +7,27 @@
#
##########################################################################
import os
import json
import time
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver import ActionChains
from regression.python_test_utils import test_utils
from regression.feature_utils.base_feature_test import BaseFeatureTest
CURRENT_PATH = os.path.dirname(os.path.realpath(__file__))
try:
with open(CURRENT_PATH + '/datatype_test.json') as data_file:
config_data = json.load(data_file)
except Exception as e:
print(str(e))
class PGDataypeFeatureTest(BaseFeatureTest):
"""
This feature test will test the different Postgres
@@ -32,9 +45,74 @@ class PGDataypeFeatureTest(BaseFeatureTest):
self.server['host'],
self.server['port'],
self.server['sslmode'])
self.timezone = int(test_utils.get_timezone_without_dst(connection))
if abs(self.timezone) % 3600 > 0:
hh_mm = '%H:%M'
else:
hh_mm = '%H'
self.timezone_hh_mm = time.strftime(
hh_mm, time.gmtime(abs(self.timezone)))
if self.timezone < 0:
self.timezone_hh_mm = '-{}'.format(self.timezone_hh_mm)
else:
self.timezone_hh_mm = '+{}'.format(self.timezone_hh_mm)
test_utils.drop_database(connection, "acceptance_test_db")
test_utils.create_database(self.server, "acceptance_test_db")
# For this test case we need to set "Insert bracket pairs?"
# SQL Editor preference to 'false' to avoid codemirror
# to add matching closing bracket by it self.
self._update_preferences()
def _update_preferences(self):
self.page.find_by_id("mnu_file").click()
self.page.find_by_id("mnu_preferences").click()
wait = WebDriverWait(self.page.driver, 10)
wait.until(EC.presence_of_element_located(
(By.XPATH, "//*[contains(string(), 'Show system objects?')]"))
)
self.page.find_by_css_selector(".ajs-maximize").click()
sql_editor = self.page.find_by_xpath(
"//*[contains(@class,'aciTreeLi') and contains(.,'SQL Editor')]")
sql_editor.find_element_by_xpath(
"//*[contains(@class,'aciTreeText') and contains(.,'Options')]")\
.click()
insert_bracket_pairs_control= self.page.find_by_xpath(
"//div[contains(@class,'pgadmin-control-group') and contains(.,'Insert bracket pairs?')]")
switch_btn = insert_bracket_pairs_control.\
find_element_by_class_name('bootstrap-switch')
# check if switch is on then only toggle.
if 'bootstrap-switch-on' in switch_btn.get_attribute('class'):
switch_btn.click()
# save and close the preference dialog.
self.page.find_by_xpath(
"//*[contains(@class,'btn-primary') and contains(.,'OK')]").click()
self.page.wait_for_element_to_disappear(
lambda driver: driver.find_element_by_css_selector(".ajs-modal")
)
def _create_enum_type(self):
query = """CREATE TYPE public.rainbow AS ENUM ('red', 'orange',
'yellow','green','blue','purple');
"""
self.page.fill_codemirror_area_with(query)
self.page.find_by_id("btn-flash").click()
self._clear_query_tool()
def runTest(self):
self.page.wait_for_spinner_to_disappear()
self.page.add_server(self.server)
@@ -60,59 +138,87 @@ class PGDataypeFeatureTest(BaseFeatureTest):
self.page.toggle_open_tree_item('acceptance_test_db')
def _check_datatype(self):
query = r"SELECT -32767::smallint, 32767::smallint," \
r"-2147483647::integer, 2147483647::integer," \
r"9223372036854775807::bigint, 9223372036854775807::bigint," \
r"922337203685.4775807::decimal, 92203685.477::decimal," \
r"922337203685.922337203685::numeric, " \
r"-92233720368547758.08::numeric," \
r"ARRAY[1, 2, 3]::float[], ARRAY['nan', 'nan', 'nan']::float[]," \
r"'Infinity'::real, '{Infinity}'::real[]," \
r"E'\\xDEADBEEF'::bytea, ARRAY[E'\\xDEADBEEF', E'\\xDEADBEEF']::bytea[];"
expected_output = [
'-32767', '32767', '-2147483647', '2147483647',
'9223372036854775807', '9223372036854775807',
'922337203685.4775807', '92203685.477',
'922337203685.922337203685', '-92233720368547758.08',
'{1,2,3}', '{NaN,NaN,NaN}',
'Infinity', '{Infinity}',
'binary data', 'binary data[]'
]
# Slick grid does not render all the column if viewport is not enough
# wide. So execute test as batch of queries.
self.page.open_query_tool()
self.page.fill_codemirror_area_with(query)
self.page.find_by_id("btn-flash").click()
wait = WebDriverWait(self.page.driver, 5)
self._create_enum_type()
for batch in config_data:
query = self.construct_select_query(batch)
self.page.fill_codemirror_area_with(query)
self.page.find_by_id("btn-flash").click()
wait = WebDriverWait(self.page.driver, 5)
canvas = wait.until(EC.presence_of_element_located(
(By.CSS_SELECTOR, "#datagrid .slick-viewport .grid-canvas"))
)
# For every sample data-type value, check the expected output.
cnt = 2
cells = canvas.find_elements_by_css_selector('.slick-cell')
# remove first element as it is row number.
cells.pop(0)
for val, cell in zip(expected_output, cells):
try:
source_code = cell.text
PGDataypeFeatureTest.check_result(
source_code,
expected_output[cnt - 2]
)
cnt += 1
except TimeoutException:
assert False, "{0} does not match with {1}".format(
val, expected_output[cnt]
)
@staticmethod
def check_result(source_code, string_to_find):
assert source_code.find(string_to_find) != -1,\
"{0} does not match with {1}".format(
source_code, string_to_find
wait.until(EC.presence_of_element_located(
(By.XPATH,
"//*[contains(@class,'column-type') and contains(.,'{}')]".format(batch['datatype'][0])
))
)
canvas = wait.until(EC.presence_of_element_located(
(By.CSS_SELECTOR, "#datagrid .slick-viewport .grid-canvas"))
)
# For every sample data-type value, check the expected output.
cnt = 2
cells = canvas.find_elements_by_css_selector('.slick-cell')
# remove first element as it is row number.
cells.pop(0)
for val, cell, datatype in zip(batch['output'], cells, batch['datatype']):
expected_output = batch['output'][cnt - 2]
if datatype in ('tstzrange', 'tstzrange[]'):
expected_output = expected_output.format(
**dict([('tz', self.timezone_hh_mm)]))
try:
source_code = cell.text
PGDataypeFeatureTest.check_result(
datatype,
source_code,
expected_output
)
cnt += 1
except TimeoutException:
assert False,\
"for datatype {0}\n{1} does not match with {2}".format(
datatype, val, expected_output
)
self._clear_query_tool()
def construct_select_query(self, batch):
query = 'SELECT '
first = True
for datatype, inputdata in zip(batch['datatype'], batch['input']):
if datatype != '':
dataformatter = '{}::{}'
else:
dataformatter = '{}'
if datatype in ('tstzrange', 'tstzrange[]'):
inputdata = inputdata.format(
**dict([('tz', self.timezone_hh_mm)]))
if first:
query += dataformatter.format(inputdata, datatype)
else:
query += ','+dataformatter.format(inputdata, datatype)
first = False
return query + ';'
@staticmethod
def check_result(datatype, source_code, string_to_find):
assert source_code == string_to_find,\
"for datatype {0}\n{1} does not match with {2}".format(
datatype, source_code, string_to_find
)
def _clear_query_tool(self):
self.page.click_element(
self.page.find_by_xpath("//*[@id='btn-clear-dropdown']")
)
ActionChains(self.driver)\
.move_to_element(self.page.find_by_xpath("//*[@id='btn-clear']"))\
.perform()
self.page.click_element(
self.page.find_by_xpath("//*[@id='btn-clear']")
)
self.page.click_modal('Yes')