Skip to content

Commit

Permalink
Angular2 webdriver test updates (vitessio#2038)
Browse files Browse the repository at this point in the history
Angular2 webdriver test updates
thompsonja authored Sep 14, 2016
1 parent d550824 commit 30b6d1a
Showing 23 changed files with 649 additions and 290 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@ MAKEFLAGS = -s

.PHONY: all build build_web test clean unit_test unit_test_cover unit_test_race integration_test proto proto_banner site_test site_integration_test docker_bootstrap docker_test docker_unit_test java_test php_test reshard_tests

all: build build_web test
all: build test

# Set a custom value for -p, the number of packages to be built/tested in parallel.
# This is currently only used by our Travis CI test configuration.
9 changes: 7 additions & 2 deletions py/vttest/local_database.py
Original file line number Diff line number Diff line change
@@ -20,7 +20,8 @@ def __init__(self,
init_data_options,
web_dir=None,
default_schema_dir=None,
extra_my_cnf=None):
extra_my_cnf=None,
web_dir2=None):
"""Initializes an object of this class.
Args:
@@ -38,6 +39,8 @@ def __init__(self,
default_schema_dir: a directory to use if no keyspace is found in the
schema_dir directory.
extra_my_cnf: additional cnf file to use for the EXTRA_MY_CNF var.
web_dir2: see the documentation for the corresponding command line
flag in run_local_database.py
"""

self.topology = topology
@@ -47,6 +50,7 @@ def __init__(self,
self.web_dir = web_dir
self.default_schema_dir = default_schema_dir
self.extra_my_cnf = extra_my_cnf
self.web_dir2 = web_dir2

def setup(self):
"""Create a MySQL instance and all Vitess processes."""
@@ -66,7 +70,8 @@ def setup(self):

vt_processes.start_vt_processes(self.directory, self.topology,
self.mysql_db, self.schema_dir,
web_dir=self.web_dir)
web_dir=self.web_dir,
web_dir2=self.web_dir2)

def teardown(self):
"""Kill all Vitess processes and wait for them to end.
4 changes: 4 additions & 0 deletions py/vttest/run_local_database.py
Original file line number Diff line number Diff line change
@@ -88,6 +88,7 @@ def main(cmdline_options):
cmdline_options.mysql_only,
init_data_opts,
web_dir=cmdline_options.web_dir,
web_dir2=cmdline_options.web_dir2,
default_schema_dir=cmdline_options.default_schema_dir,
extra_my_cnf=os.path.join(
os.environ['VTTOP'], 'config/mycnf/vtcombo.cnf')) as local_db:
@@ -161,6 +162,9 @@ def main(cmdline_options):
parser.add_option(
'-w', '--web_dir',
help='location of the vtctld web server files.')
parser.add_option(
'--web_dir2',
help='location of the vtctld2 web server files.')
parser.add_option(
'-v', '--verbose', action='store_true',
help='Display extra error messages.')
9 changes: 6 additions & 3 deletions py/vttest/vt_processes.py
Original file line number Diff line number Diff line change
@@ -125,7 +125,7 @@ class VtcomboProcess(VtProcess):
]

def __init__(self, directory, topology, mysql_db, schema_dir, charset,
web_dir=None):
web_dir=None, web_dir2=None):
VtProcess.__init__(self, 'vtcombo-%s' % os.environ['USER'], directory,
environment.vtcombo_binary, port_name='vtcombo')
self.extraparams = [
@@ -143,6 +143,8 @@ def __init__(self, directory, topology, mysql_db, schema_dir, charset,
self.extraparams.extend(['-schema_dir', schema_dir])
if web_dir:
self.extraparams.extend(['-web_dir', web_dir])
if web_dir2:
self.extraparams.extend(['-web_dir2', web_dir2])
if mysql_db.unix_socket():
self.extraparams.extend(
['-db-config-app-unixsocket', mysql_db.unix_socket(),
@@ -159,7 +161,7 @@ def __init__(self, directory, topology, mysql_db, schema_dir, charset,


def start_vt_processes(directory, topology, mysql_db, schema_dir,
charset='utf8', web_dir=None):
charset='utf8', web_dir=None, web_dir2=None):
"""Start the vt processes.
Args:
@@ -169,13 +171,14 @@ def start_vt_processes(directory, topology, mysql_db, schema_dir,
schema_dir: the directory that contains the schema / vschema.
charset: the character set for the database connections.
web_dir: contains the web app for vtctld side of vtcombo.
web_dir2: contains the web app for vtctld side of vtcombo.
"""
global vtcombo_process

logging.info('start_vt_processes(directory=%s,vtcombo_binary=%s)',
directory, environment.vtcombo_binary)
vtcombo_process = VtcomboProcess(directory, topology, mysql_db, schema_dir,
charset, web_dir=web_dir)
charset, web_dir=web_dir, web_dir2=web_dir2)
vtcombo_process.wait_start()


17 changes: 3 additions & 14 deletions test/config.json
Original file line number Diff line number Diff line change
@@ -350,7 +350,7 @@
"Args": [],
"Command": [],
"Manual": false,
"Shard": 4,
"Shard": 0,
"RetryMax": 0,
"Tags": [
"webdriver"
@@ -360,19 +360,8 @@
"File": "vtctld2_web_test.py",
"Args": [],
"Command": [],
"Manual": true,
"Shard": 4,
"RetryMax": 0,
"Tags": [
"webdriver"
]
},
"vtctld2_web_status": {
"File": "vtctld2_web_status_test.py",
"Args": [],
"Command": [],
"Manual": true,
"Shard": 4,
"Manual": false,
"Shard": 0,
"RetryMax": 0,
"Tags": [
"webdriver"
238 changes: 0 additions & 238 deletions test/vtctld2_web_status_test.py

This file was deleted.

151 changes: 143 additions & 8 deletions test/vtctld2_web_test.py
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.wait import WebDriverWait
from selenium.common.exceptions import NoSuchElementException
import unittest

from vtproto import vttest_pb2
@@ -43,7 +44,7 @@ def tearDownModule():
utils.kill_sub_processes()


class TestVtctld2Web(unittest.TestCase):
class TestVtctld2WebStatus(unittest.TestCase):

@classmethod
def setUpClass(cls):
@@ -68,6 +69,7 @@ def setUpClass(cls):

topology = vttest_pb2.VTTestTopology()
topology.cells.append('test')
topology.cells.append('test2')
keyspace = topology.keyspaces.add(name='test_keyspace')
keyspace.replica_count = 2
keyspace.rdonly_count = 2
@@ -83,9 +85,13 @@ def setUpClass(cls):
mysql_flavor.set_mysql_flavor(None)

cls.db = local_database.LocalDatabase(
topology, '', False, None,
os.path.join(os.environ['VTTOP'], 'web/vtctld2/dist'),
os.path.join(os.environ['VTTOP'], 'test/vttest_schema/default'))
topology,
os.path.join(os.environ['VTTOP'], 'test/vttest_schema'),
False, None,
web_dir=os.path.join(os.environ['VTTOP'], 'web/vtctld'),
default_schema_dir=os.path.join(
os.environ['VTTOP'], 'test/vttest_schema/default'),
web_dir2=os.path.join(os.environ['VTTOP'], 'web/vtctld2/app'))
cls.db.setup()
cls.vtctld_addr = 'http://localhost:%d' % cls.db.config()['port']
utils.pause('Paused test after vtcombo was started.\n'
@@ -102,19 +108,148 @@ def _get_keyspaces(self):
wait.until(expected_conditions.visibility_of_element_located(
(By.TAG_NAME, 'vt-dashboard')))
dashboard_content = self.driver.find_element_by_tag_name('vt-dashboard')
return [ks.text for ks in
dashboard_content.find_elements_by_tag_name('md-card-title')]
toolbars = dashboard_content.find_elements_by_class_name('vt-card-toolbar')
return [t.find_element_by_class_name('vt-title').text for t in toolbars]

def _get_dropdown_options(self, group):
status_content = self.driver.find_element_by_tag_name('vt-status')
dropdown = status_content.find_element_by_id(group)
return [op.text for op in
dropdown.find_elements_by_tag_name('option')]

def _get_dropdown_selection(self, group):
status_content = self.driver.find_element_by_tag_name('vt-status')
dropdown = status_content.find_element_by_id(group)
return dropdown.find_element_by_tag_name('label').text

def _change_dropdown_option(self, dropdown_id, dropdown_value):
status_content = self.driver.find_element_by_tag_name('vt-status')
dropdown = status_content.find_element_by_id(dropdown_id)
dropdown.click()
options = dropdown.find_elements_by_tag_name('li')
for op in options:
if op.text == dropdown_value:
logging.info('dropdown %s: option %s clicked', dropdown_id, op.text)
op.click()
break

def _check_dropdowns(self, keyspaces, selected_keyspace, cells, selected_cell,
types, selected_type, metrics, selected_metric):
"""Checking that all dropdowns have the correct options and selection."""
keyspace_options = self._get_dropdown_options('keyspace')
keyspace_selected = self._get_dropdown_selection('keyspace')
logging.info('Keyspace options: %s Keyspace selected: %s',
', '.join(keyspace_options), keyspace_selected)
self.assertListEqual(keyspaces, keyspace_options)
self.assertEqual(selected_keyspace, keyspace_selected)

cell_options = self._get_dropdown_options('cell')
cell_selected = self._get_dropdown_selection('cell')
logging.info('Cell options: %s Cell Selected: %s',
', '.join(cell_options), cell_selected)
self.assertListEqual(cells, cell_options)
self.assertEqual(selected_cell, cell_selected)

type_options = self._get_dropdown_options('type')
type_selected = self._get_dropdown_selection('type')
logging.info('Type options: %s Type Selected: %s',
', '.join(cell_options), cell_selected)
self.assertListEqual(types, type_options)
self.assertEqual(selected_type, type_selected)

metric_options = self._get_dropdown_options('metric')
metric_selected = self._get_dropdown_selection('metric')
logging.info('metric options: %s metric Selected: %s',
', '.join(metric_options), metric_selected)
self.assertListEqual(metrics, metric_options)
self.assertEqual(selected_metric, metric_selected)

def _check_heatmaps(self, selected_keyspace):
"""Checking that the view has the correct number of heatmaps drawn."""
status_content = self.driver.find_element_by_tag_name('vt-status')
keyspaces = status_content.find_elements_by_tag_name('vt-heatmap')
logging.info('Number of keyspaces found: %d', len(keyspaces))
if selected_keyspace == 'all':
available_keyspaces = self._get_dropdown_options('keyspace')
self.assertEqual(len(keyspaces), len(available_keyspaces)-1)
for ks in keyspaces:
heading = ks.find_element_by_id('keyspaceName')
logging.info('Keyspace name: %s', heading.text)
try:
ks.find_element_by_id(heading.text)
except NoSuchElementException:
self.fail('Cannot get keyspace')
self.assertIn(heading.text, available_keyspaces)
else:
self.assertEquals(len(keyspaces), 1)
heading = keyspaces[0].find_element_by_id('keyspaceName')
logging.info('Keyspace name: %s', heading.text)
try:
keyspaces[0].find_element_by_id(heading.text)
except NoSuchElementException:
self.fail('Cannot get keyspace')
self.assertEquals(heading.text, selected_keyspace)

def _check_new_view(
self, keyspaces, selected_keyspace, cells, selected_cell, types,
selected_type, metrics, selected_metric):
"""Checking the dropdowns and heatmaps for each newly routed view."""
logging.info('Testing realtime stats view')
self._check_dropdowns(keyspaces, selected_keyspace, cells, selected_cell,
types, selected_type, metrics, selected_metric)
self._check_heatmaps(selected_keyspace)

def test_dashboard(self):
logging.info('Testing dashboard view')

logging.info('Fetching main vtctld page: %s', self.vtctld_addr)
self.driver.get(self.vtctld_addr)
logging.info('Fetching main vtctld page: %s/app2', self.vtctld_addr)
self.driver.get('%s/app2' % self.vtctld_addr)

keyspace_names = self._get_keyspaces()
logging.info('Keyspaces: %s', ', '.join(keyspace_names))
self.assertListEqual(['test_keyspace', 'test_keyspace2'], keyspace_names)

def test_realtime_stats(self):
logging.info('Testing realtime stats view')

# Navigate to the status page from initial app.
# TODO(thompsonja): Fix this once direct navigation works (going to status
# page directly should display correctly)
self.driver.get('%s/app2' % self.vtctld_addr)
status_button = self.driver.find_element_by_partial_link_text('Status')
status_button.click()
wait = WebDriverWait(self.driver, 10)
wait.until(expected_conditions.visibility_of_element_located(
(By.TAG_NAME, 'vt-status')))

test_cases = [
(None, None, 'all', 'all', 'all'),
('type', 'REPLICA', 'all', 'all', 'REPLICA'),
('cell', 'test2', 'all', 'test2', 'REPLICA'),
('keyspace', 'test_keyspace', 'test_keyspace', 'test2', 'REPLICA'),
('cell', 'all', 'test_keyspace', 'all', 'REPLICA'),
('type', 'all', 'test_keyspace', 'all', 'all'),
('cell', 'test2', 'test_keyspace', 'test2', 'all'),
('keyspace', 'all', 'all', 'test2', 'all'),
]

for (dropdown_id, dropdown_val, keyspace, cell, tablet_type) in test_cases:
logging.info('Routing to new %s-%s-%s view', keyspace, cell, tablet_type)
if dropdown_id and dropdown_val:
self._change_dropdown_option(dropdown_id, dropdown_val)
tablet_type_options = ['all', 'MASTER', 'REPLICA', 'RDONLY']
if cell == 'test2':
tablet_type_options = ['all', 'REPLICA', 'RDONLY']
self._check_new_view(keyspaces=['all', 'test_keyspace', 'test_keyspace2'],
selected_keyspace=keyspace,
cells=['all', 'test', 'test2'],
selected_cell=cell,
types=tablet_type_options,
selected_type=tablet_type,
metrics=['lag', 'qps', 'health'],
selected_metric='health'
)


def add_test_options(parser):
parser.add_option(
12 changes: 7 additions & 5 deletions tools/bootstrap_web.sh
100644 → 100755
Original file line number Diff line number Diff line change
@@ -30,11 +30,13 @@ fi
echo "Installing dependencies for building web UI"
angular_cli_dir=$VTROOT/dist/angular-cli
web_dir2=$VTTOP/web/vtctld2
rm -rf $angular_cli_dir
cd $VTROOT/dist && git clone https://github.com/angular/angular-cli.git --quiet
cd $angular_cli_dir && git checkout 3dcd49bc625db36dd9f539cf9ce2492107e0258c --quiet
angular_cli_commit=cacaa4eff10e135016ef81076fab1086a3bce92f
if [[ -d $angular_cli_dir && `cd $angular_cli_dir && git rev-parse HEAD` == "$angular_cli_commit" ]]; then
echo "skipping angular cli download. remove $angular_cli_dir to force download."
else
cd $VTROOT/dist && git clone https://github.com/angular/angular-cli.git --quiet
cd $angular_cli_dir && git checkout $angular_cli_commit --quiet
fi
cd $angular_cli_dir && $node_dist/bin/npm link --silent
$node_dist/bin/npm install -g bower --silent
cd $web_dir2 && $node_dist/bin/npm install --silent
cd $web_dir2 && $node_dist/bin/npm link angular-cli --silent
cd $web_dir2 && $node_dist/bin/bower install --silent
18 changes: 18 additions & 0 deletions tools/generate_web_artifacts.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/bin/bash

# Copyright 2016, Google Inc. All rights reserved.
# Use of this source code is governed by a BSD-style license that can
# be found in the LICENSE file.

# This script is used to build and copy the Angular 2 based vtctld UI
# into the release folder (app) for checkin. Prior to running this script,
# bootstrap.sh and bootstrap_web.sh should already have been run.

set -e

vtctld2_dir=$VTTOP/web/vtctld2
if [[ -d $vtctld2_dir/app ]]; then
rm -rf $vtctld2_dir/app
fi
cd $vtctld2_dir && ng build -prod --output-path app/
rm -rf $vtctld2_dir/app/assets
11 changes: 7 additions & 4 deletions web/vtctld2/angular-cli.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"project": {
"version": "1.0.0-beta.11-webpack.2",
"version": "1.0.0-beta.11-webpack.8",
"name": "vtctld2"
},
"apps": [
@@ -14,7 +14,10 @@
"tsconfig": "tsconfig.json",
"prefix": "vt",
"mobile": false,
"styles": "styles.css",
"styles": [
"styles.css"
],
"scripts": [],
"environments": {
"source": "environments/environment.ts",
"prod": "environments/environment.prod.ts",
@@ -26,12 +29,12 @@
"packages": [],
"e2e": {
"protractor": {
"config": "config/protractor.conf.js"
"config": "./protractor.conf.js"
}
},
"test": {
"karma": {
"config": "config/karma.conf.js"
"config": "./karma.conf.js"
}
},
"defaults": {
Binary file not shown.
Binary file not shown.
308 changes: 308 additions & 0 deletions web/vtctld2/app/3d3a53586bd78d1069ae4b89a3b9aa98.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file not shown.
32 changes: 32 additions & 0 deletions web/vtctld2/app/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Vitess</title>
<base href=".">

<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:400,500,700,400italic">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">

<!-- Styles for Polymer Elements-->
<style is="custom-style">
body {
@apply(--layout-fullbleed);
@apply(--paper-font-body1);
background: var(--primary-background-color);
color: var(--primary-text-color);
}
</style>

<!-- PrimeNG -->
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css"/>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/primeui/4.1.14/primeui-ng-all.min.css"/>

<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
</head>
<body class="flex-column">
<vt-app-root class="flex-column flex-grow">Loading...</vt-app-root>
<script type="text/javascript" src="inline.js"></script><script type="text/javascript" src="styles.07f8743f5392cfdfbcb5.bundle.js"></script><script type="text/javascript" src="main.bc4acc7f8258a037cbf9.bundle.js"></script></body>
</html>
1 change: 1 addition & 0 deletions web/vtctld2/app/inline.js
96 changes: 96 additions & 0 deletions web/vtctld2/app/main.bc4acc7f8258a037cbf9.bundle.js

Large diffs are not rendered by default.

Binary file not shown.
2 changes: 2 additions & 0 deletions web/vtctld2/app/styles.07f8743f5392cfdfbcb5.bundle.js

Large diffs are not rendered by default.

Binary file not shown.
2 changes: 2 additions & 0 deletions web/vtctld2/e2e/app.po.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { browser, element, by } from 'protractor/globals';

export class Vtctld2Page {
navigateTo() {
return browser.get('/');
27 changes: 12 additions & 15 deletions web/vtctld2/package.json
Original file line number Diff line number Diff line change
@@ -20,17 +20,17 @@
"@angular/platform-browser": "2.0.0-rc.5",
"@angular/platform-browser-dynamic": "2.0.0-rc.5",
"@angular/router": "3.0.0-rc.1",
"@angular2-material/button": "^2.0.0-alpha.7-2",
"@angular2-material/card": "^2.0.0-alpha.7-2",
"@angular2-material/checkbox": "^2.0.0-alpha.7-2",
"@angular2-material/core": "^2.0.0-alpha.7-2",
"@angular2-material/icon": "^2.0.0-alpha.7-2",
"@angular2-material/input": "^2.0.0-alpha.7-2",
"@angular2-material/list": "^2.0.0-alpha.7-2",
"@angular2-material/progress-bar": "^2.0.0-alpha.7-2",
"@angular2-material/sidenav": "^2.0.0-alpha.7-2",
"@angular2-material/tabs": "^2.0.0-alpha.7-2",
"@angular2-material/toolbar": "^2.0.0-alpha.7-2",
"@angular2-material/button": "2.0.0-alpha.7-2",
"@angular2-material/card": "2.0.0-alpha.7-2",
"@angular2-material/checkbox": "2.0.0-alpha.7-2",
"@angular2-material/core": "2.0.0-alpha.7-2",
"@angular2-material/icon": "2.0.0-alpha.7-2",
"@angular2-material/input": "2.0.0-alpha.7-2",
"@angular2-material/list": "2.0.0-alpha.7-2",
"@angular2-material/progress-bar": "2.0.0-alpha.7-2",
"@angular2-material/sidenav": "2.0.0-alpha.7-2",
"@angular2-material/tabs": "2.0.0-alpha.7-2",
"@angular2-material/toolbar": "2.0.0-alpha.7-2",
"@vaadin/angular2-polymer": "^1.0.0-beta2",
"core-js": "^2.4.0",
"primeng": "1.0.0-beta.13",
@@ -42,16 +42,13 @@
"zone.js": "0.6.12"
},
"devDependencies": {
"@types/jasmine": "^2.2.30",
"@types/protractor": "^1.5.16",
"angular-cli": "1.0.0-beta.11-webpack.2",
"angular-cli": "1.0.0-beta.11-webpack.8",
"codelyzer": "~0.0.26",
"jasmine-core": "2.4.1",
"jasmine-spec-reporter": "2.5.0",
"karma": "0.13.22",
"karma-chrome-launcher": "0.2.3",
"karma-jasmine": "0.3.8",
"karma-remap-istanbul": "^0.2.1",
"protractor": "3.3.0",
"ts-node": "1.2.1",
"tslint": "3.13.0",

0 comments on commit 30b6d1a

Please sign in to comment.