Merge lp:~canonical-platform-qa/snappy-ecosystem-tests/adding-pylint-checker into lp:snappy-ecosystem-tests

Proposed by Heber Parrucci
Status: Merged
Merged at revision: 12
Proposed branch: lp:~canonical-platform-qa/snappy-ecosystem-tests/adding-pylint-checker
Merge into: lp:snappy-ecosystem-tests
Diff against target: 1071 lines (+721/-208)
15 files modified
README (+9/-2)
pylint.cfg (+407/-0)
requirements.txt (+2/-2)
run_pylint (+22/-0)
snappy_ecosystem_tests/data/__init__.py (+19/-0)
snappy_ecosystem_tests/helpers/__init__.py (+0/-121)
snappy_ecosystem_tests/helpers/ubuntu_store_tests_base.py (+19/-0)
snappy_ecosystem_tests/helpers/ubuntu_store_web_test_base.py (+145/-0)
snappy_ecosystem_tests/pageobjects/__init__.py (+19/-0)
snappy_ecosystem_tests/storeconfig.py (+2/-0)
snappy_ecosystem_tests/test_store_login.py (+47/-0)
snappy_ecosystem_tests/tests/__init__.py (+19/-0)
snappy_ecosystem_tests/utils/snapcraft.py (+11/-6)
tests/helpers/ubuntu-store-tests-base.py (+0/-19)
tests/test-store-login.py (+0/-58)
To merge this branch: bzr merge lp:~canonical-platform-qa/snappy-ecosystem-tests/adding-pylint-checker
Reviewer Review Type Date Requested Status
platform-qa-bot continuous-integration Needs Fixing
Omer Akram (community) Approve
Santiago Baldassin (community) Approve
I Ahmad (community) Approve
Review via email: mp+316604@code.launchpad.net

Commit message

Adding pylint as code checker

Description of the change

This change include pylint a a code checker.

Includes:
A script run_pylint that run the checking in a virtual env
A config file in which the rules are stored

To run it locally just call the script ./run_pylint and check the results in pylint-results.txt

Another changes were made to got a positive result from pylint

I removed nose and the xml runner dependencies: do not worry, I am working on a new tests runner that uses nose2 and will be able to generate xml format results.

To post a comment you must log in.
Revision history for this message
platform-qa-bot (platform-qa-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
platform-qa-bot (platform-qa-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
platform-qa-bot (platform-qa-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
platform-qa-bot (platform-qa-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
I Ahmad (iahmad) wrote :

could you please add instructions for running pylint to the README file, otherwise looks good to me

review: Approve
Revision history for this message
Heber Parrucci (heber013) wrote :

> could you please add instructions for running pylint to the README file,
> otherwise looks good to me

Sure. I will add instructions to README file. Thanks!

Revision history for this message
platform-qa-bot (platform-qa-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
platform-qa-bot (platform-qa-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Santiago Baldassin (sbaldassin) wrote :

Code looks good to me

review: Approve
Revision history for this message
Omer Akram (om26er) wrote :

Code looks good to me. We could use bzr mv instead of deleting and creating new files like tests/test-store-login.py could have been renamed to snappy_ecosystem_tests/test_store_login.py, this reduces diff size. Likewise snappy_ecosystem_tests/helpers/__init__.py could have been renamed as well.

But I won't block on that as I know revert can be quite a challenge but something we should ensure in future. Lets ship it.

review: Approve
Revision history for this message
platform-qa-bot (platform-qa-bot) wrote :

FAILED: Autolanding.
More details in the following jenkins job:
https://platform-qa-jenkins.ubuntu.com/job/snappy-ecosystem-tests-autoland/2/
Executed test runs:
    None: https://platform-qa-jenkins.ubuntu.com/job/generic-land-mp/2660/console

review: Needs Fixing (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'README'
2--- README 2017-02-03 07:25:11 +0000
3+++ README 2017-02-08 14:28:57 +0000
4@@ -1,5 +1,5 @@
5 How to setup and execute snappy ecosystem tests
6-
7+===============================================
8 Please make sure you have following dependencies installed
9 1. Python version >= 3.5
10 2. nosetests >= 1.3.7
11@@ -9,8 +9,9 @@
12
13 Make sure webdrivers are added to $PATH
14
15+
16 To run the tests checkout the branch follow the below steps
17-
18+===========================================================
19 $ bzr branch lp:snappy-ecosystem-tests
20 $ cd snappy-ecosystem-tests/
21 $ export UBUNTU_STORE_LOGIN_EMAIL=<store account email>
22@@ -19,4 +20,10 @@
23 $ nosetests --with-xunit
24
25
26+Running code analysis with pylint
27+=================================
28+To run static code analysis you can execute from root directory:
29+$ ./run_pylint
30+It will store the results in pylint-results.txt
31+The config file with all the rules is pylint.cfg
32
33
34=== added file 'pylint.cfg'
35--- pylint.cfg 1970-01-01 00:00:00 +0000
36+++ pylint.cfg 2017-02-08 14:28:57 +0000
37@@ -0,0 +1,407 @@
38+[MASTER]
39+
40+# Specify a configuration file.
41+#rcfile=
42+
43+# Python code to execute, usually for sys.path manipulation such as
44+# pygtk.require().
45+#init-hook=
46+
47+# Add files or directories to the blacklist. They should be base names, not
48+# paths.
49+ignore=CVS
50+
51+# Add files or directories matching the regex patterns to the blacklist. The
52+# regex matches against base names, not paths.
53+ignore-patterns=
54+
55+# Pickle collected data for later comparisons.
56+persistent=yes
57+
58+# List of plugins (as comma separated values of python modules names) to load,
59+# usually to register additional checkers.
60+load-plugins=
61+
62+# Use multiple processes to speed up Pylint.
63+jobs=1
64+
65+# Allow loading of arbitrary C extensions. Extensions are imported into the
66+# active Python interpreter and may run arbitrary code.
67+unsafe-load-any-extension=no
68+
69+# A comma-separated list of package or module names from where C extensions may
70+# be loaded. Extensions are loading into the active Python interpreter and may
71+# run arbitrary code
72+extension-pkg-whitelist=
73+
74+# Allow optimization of some AST trees. This will activate a peephole AST
75+# optimizer, which will apply various small optimizations. For instance, it can
76+# be used to obtain the result of joining multiple strings with the addition
77+# operator. Joining a lot of strings can lead to a maximum recursion error in
78+# Pylint and this flag can prevent that. It has one side effect, the resulting
79+# AST will be different than the one from reality. This option is deprecated
80+# and it will be removed in Pylint 2.0.
81+optimize-ast=no
82+
83+
84+[MESSAGES CONTROL]
85+
86+# Only show warnings with the listed confidence levels. Leave empty to show
87+# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED
88+confidence=
89+
90+# Enable the message, report, category or checker with the given id(s). You can
91+# either give multiple identifier separated by comma (,) or put this option
92+# multiple time (only on the command line, not in the configuration file where
93+# it should appear only once). See also the "--disable" option for examples.
94+#enable=
95+
96+# Disable the message, report, category or checker with the given id(s). You
97+# can either give multiple identifiers separated by comma (,) or put this
98+# option multiple times (only on the command line, not in the configuration
99+# file where it should appear only once).You can also use "--disable=all" to
100+# disable everything first and then reenable specific checks. For example, if
101+# you want to run only the similarities checker, you can use "--disable=all
102+# --enable=similarities". If you want to run only the classes checker, but have
103+# no Warning level messages displayed, use"--disable=all --enable=classes
104+# --disable=W"
105+disable=coerce-method,filter-builtin-not-iterating,nonzero-method,unicode-builtin,parameter-unpacking,old-raise-syntax,long-suffix,useless-suppression,unpacking-in-except,round-builtin,cmp-builtin,basestring-builtin,indexing-exception,backtick,unichr-builtin,coerce-builtin,dict-view-method,raw_input-builtin,delslice-method,no-absolute-import,print-statement,import-star-module-level,reduce-builtin,next-method-called,file-builtin,old-ne-operator,map-builtin-not-iterating,raising-string,xrange-builtin,suppressed-message,input-builtin,reload-builtin,using-cmp-argument,zip-builtin-not-iterating,standarderror-builtin,hex-method,oct-method,old-division,range-builtin-not-iterating,apply-builtin,dict-iter-method,long-builtin,buffer-builtin,metaclass-assignment,intern-builtin,execfile-builtin,cmp-method,old-octal-literal,setslice-method,getslice-method
106+
107+
108+[REPORTS]
109+
110+# Set the output format. Available formats are text, parseable, colorized, msvs
111+# (visual studio) and html. You can also give a reporter class, eg
112+# mypackage.mymodule.MyReporterClass.
113+output-format=text
114+
115+# Put messages in a separate file for each module / package specified on the
116+# command line instead of printing them on stdout. Reports (if any) will be
117+# written in a file name "pylint_global.[txt|html]". This option is deprecated
118+# and it will be removed in Pylint 2.0.
119+files-output=no
120+
121+# Tells whether to display a full report or only the messages
122+reports=yes
123+
124+# Python expression which should return a note less than 10 (10 is the highest
125+# note). You have access to the variables errors warning, statement which
126+# respectively contain the number of errors / warnings messages and the total
127+# number of statements analyzed. This is used by the global evaluation report
128+# (RP0004).
129+evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
130+
131+# Template used to display messages. This is a python new-style format string
132+# used to format the message information. See doc for all details
133+#msg-template=
134+
135+
136+[VARIABLES]
137+
138+# Tells whether we should check for unused import in __init__ files.
139+init-import=no
140+
141+# A regular expression matching the name of dummy variables (i.e. expectedly
142+# not used).
143+dummy-variables-rgx=(_+[a-zA-Z0-9]*?$)|dummy
144+
145+# List of additional names supposed to be defined in builtins. Remember that
146+# you should avoid to define new builtins when possible.
147+additional-builtins=
148+
149+# List of strings which can identify a callback function by name. A callback
150+# name must start or end with one of those strings.
151+callbacks=cb_,_cb
152+
153+# List of qualified module names which can have objects that can redefine
154+# builtins.
155+redefining-builtins-modules=six.moves,future.builtins
156+
157+
158+[LOGGING]
159+
160+# Logging modules to check that the string format arguments are in logging
161+# function parameter format
162+logging-modules=logging
163+
164+
165+[BASIC]
166+
167+# Good variable names which should always be accepted, separated by a comma
168+good-names=i,j,k,ex,Run,_
169+
170+# Bad variable names which should always be refused, separated by a comma
171+bad-names=foo,bar,baz,toto,tutu,tata
172+
173+# Colon-delimited sets of names that determine each other's naming style when
174+# the name regexes allow several styles.
175+name-group=
176+
177+# Include a hint for the correct naming format with invalid-name
178+include-naming-hint=no
179+
180+# List of decorators that produce properties, such as abc.abstractproperty. Add
181+# to this list to register other decorators that produce valid properties.
182+property-classes=abc.abstractproperty
183+
184+# Regular expression matching correct constant names
185+const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
186+
187+# Naming hint for constant names
188+const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$
189+
190+# Regular expression matching correct module names
191+module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
192+
193+# Naming hint for module names
194+module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
195+
196+# Regular expression matching correct class names
197+class-rgx=[A-Z_][a-zA-Z0-9]+$
198+
199+# Naming hint for class names
200+class-name-hint=[A-Z_][a-zA-Z0-9]+$
201+
202+# Regular expression matching correct inline iteration names
203+inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
204+
205+# Naming hint for inline iteration names
206+inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$
207+
208+# Regular expression matching correct function names
209+function-rgx=[a-z_][a-z0-9_]{2,30}$
210+
211+# Naming hint for function names
212+function-name-hint=[a-z_][a-z0-9_]{2,30}$
213+
214+# Regular expression matching correct attribute names
215+attr-rgx=[a-z_][a-z0-9_]{2,30}$
216+
217+# Naming hint for attribute names
218+attr-name-hint=[a-z_][a-z0-9_]{2,30}$
219+
220+# Regular expression matching correct method names
221+method-rgx=[a-z_][a-z0-9_]{2,30}$|setUp|tearDown
222+
223+# Naming hint for method names
224+method-name-hint=[a-z_][a-z0-9_]{2,30}$|setUp|tearDown
225+
226+# Regular expression matching correct class attribute names
227+class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
228+
229+# Naming hint for class attribute names
230+class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
231+
232+# Regular expression matching correct argument names
233+argument-rgx=[a-z_][a-z0-9_]{1,30}$
234+
235+# Naming hint for argument names
236+argument-name-hint=[a-z_][a-z0-9_]{1,30}$
237+
238+# Regular expression matching correct variable names
239+variable-rgx=[a-z_][a-z0-9_]{1,30}$
240+
241+# Naming hint for variable names
242+variable-name-hint=[a-z_][a-z0-9_]{1,30}$
243+
244+# Regular expression which should only match function or class names that do
245+# not require a docstring.
246+no-docstring-rgx=.*TestCase$|setUp|tearDown
247+
248+# Minimum line length for functions/classes that require docstrings, shorter
249+# ones are exempt.
250+docstring-min-length=-1
251+
252+
253+[ELIF]
254+
255+# Maximum number of nested blocks for function / method body
256+max-nested-blocks=5
257+
258+
259+[FORMAT]
260+
261+# Maximum number of characters on a single line.
262+max-line-length=100
263+
264+# Regexp for a line that is allowed to be longer than the limit.
265+ignore-long-lines=^\s*(# )?<?https?://\S+>?$
266+
267+# Allow the body of an if to be on the same line as the test if there is no
268+# else.
269+single-line-if-stmt=no
270+
271+# List of optional constructs for which whitespace checking is disabled. `dict-
272+# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
273+# `trailing-comma` allows a space between comma and closing bracket: (a, ).
274+# `empty-line` allows space-only lines.
275+no-space-check=trailing-comma,dict-separator
276+
277+# Maximum number of lines in a module
278+max-module-lines=1000
279+
280+# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
281+# tab).
282+indent-string=' '
283+
284+# Number of spaces of indent required inside a hanging or continued line.
285+indent-after-paren=4
286+
287+# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
288+expected-line-ending-format=
289+
290+
291+[SPELLING]
292+
293+# Spelling dictionary name. Available dictionaries: none. To make it working
294+# install python-enchant package.
295+spelling-dict=
296+
297+# List of comma separated words that should not be checked.
298+spelling-ignore-words=
299+
300+# A path to a file that contains private dictionary; one word per line.
301+spelling-private-dict-file=
302+
303+# Tells whether to store unknown words to indicated private dictionary in
304+# --spelling-private-dict-file option instead of raising a message.
305+spelling-store-unknown-words=no
306+
307+
308+[SIMILARITIES]
309+
310+# Minimum lines number of a similarity.
311+min-similarity-lines=4
312+
313+# Ignore comments when computing similarities.
314+ignore-comments=yes
315+
316+# Ignore docstrings when computing similarities.
317+ignore-docstrings=yes
318+
319+# Ignore imports when computing similarities.
320+ignore-imports=no
321+
322+
323+[MISCELLANEOUS]
324+
325+# List of note tags to take in consideration, separated by a comma.
326+notes=FIXME,XXX,TODO
327+
328+
329+[TYPECHECK]
330+
331+# Tells whether missing members accessed in mixin class should be ignored. A
332+# mixin class is detected if its name ends with "mixin" (case insensitive).
333+ignore-mixin-members=yes
334+
335+# List of module names for which member attributes should not be checked
336+# (useful for modules/projects where namespaces are manipulated during runtime
337+# and thus existing member attributes cannot be deduced by static analysis. It
338+# supports qualified module names, as well as Unix pattern matching.
339+ignored-modules=
340+
341+# List of class names for which member attributes should not be checked (useful
342+# for classes with dynamically set attributes). This supports the use of
343+# qualified names.
344+ignored-classes=optparse.Values,thread._local,_thread._local
345+
346+# List of members which are set dynamically and missed by pylint inference
347+# system, and so shouldn't trigger E1101 when accessed. Python regular
348+# expressions are accepted.
349+generated-members=
350+
351+# List of decorators that produce context managers, such as
352+# contextlib.contextmanager. Add to this list to register other decorators that
353+# produce valid context managers.
354+contextmanager-decorators=contextlib.contextmanager
355+
356+
357+[CLASSES]
358+
359+# List of method names used to declare (i.e. assign) instance attributes.
360+defining-attr-methods=__init__,__new__,setUp
361+
362+# List of valid names for the first argument in a class method.
363+valid-classmethod-first-arg=cls
364+
365+# List of valid names for the first argument in a metaclass class method.
366+valid-metaclass-classmethod-first-arg=mcs
367+
368+# List of member names, which should be excluded from the protected access
369+# warning.
370+exclude-protected=_asdict,_fields,_replace,_source,_make
371+
372+
373+[DESIGN]
374+
375+# Maximum number of arguments for function / method
376+max-args=5
377+
378+# Argument names that match this expression will be ignored. Default to name
379+# with leading underscore
380+ignored-argument-names=_.*
381+
382+# Maximum number of locals for function / method body
383+max-locals=15
384+
385+# Maximum number of return / yield for function / method body
386+max-returns=6
387+
388+# Maximum number of branch for function / method body
389+max-branches=12
390+
391+# Maximum number of statements in function / method body
392+max-statements=50
393+
394+# Maximum number of parents for a class (see R0901).
395+max-parents=7
396+
397+# Maximum number of attributes for a class (see R0902).
398+max-attributes=7
399+
400+# Minimum number of public methods for a class (see R0903).
401+min-public-methods=2
402+
403+# Maximum number of public methods for a class (see R0904).
404+max-public-methods=20
405+
406+# Maximum number of boolean expressions in a if statement
407+max-bool-expr=5
408+
409+
410+[IMPORTS]
411+
412+# Deprecated modules which should not be used, separated by a comma
413+deprecated-modules=optparse
414+
415+# Create a graph of every (i.e. internal and external) dependencies in the
416+# given file (report RP0402 must not be disabled)
417+import-graph=
418+
419+# Create a graph of external dependencies in the given file (report RP0402 must
420+# not be disabled)
421+ext-import-graph=
422+
423+# Create a graph of internal dependencies in the given file (report RP0402 must
424+# not be disabled)
425+int-import-graph=
426+
427+# Force import order to recognize a module as part of the standard
428+# compatibility libraries.
429+known-standard-library=
430+
431+# Force import order to recognize a module as part of a third party library.
432+known-third-party=enchant
433+
434+# Analyse import fallback blocks. This can be used to support both Python 2 and
435+# 3 compatible code, which means that the block might have code that exists
436+# only in one or another interpreter, leading to false positives when analysed.
437+analyse-fallback-blocks=no
438+
439+
440+[EXCEPTIONS]
441+
442+# Exceptions that will emit a warning when being caught. Defaults to
443+# "Exception"
444+overgeneral-exceptions=Exception
445
446=== modified file 'requirements.txt'
447--- requirements.txt 2017-02-06 10:36:22 +0000
448+++ requirements.txt 2017-02-08 14:28:57 +0000
449@@ -1,2 +1,2 @@
450-nose >= 1.3.7
451-xmlrunner >= 1.7.7
452+pexpect
453+selenium
454
455=== added file 'run_pylint'
456--- run_pylint 1970-01-01 00:00:00 +0000
457+++ run_pylint 2017-02-08 14:28:57 +0000
458@@ -0,0 +1,22 @@
459+#!/bin/bash
460+
461+virtualenv -p python3 ve_pylint
462+. ve_pylint/bin/activate
463+
464+proxy=$1
465+if [ "$proxy" ]; then
466+ echo "Using proxy: $proxy to install dependencies"
467+ pip install --proxy $proxy pylint
468+ pip install --proxy $proxy -r requirements.txt
469+else
470+ pip install pylint
471+ pip install -r requirements.txt
472+fi
473+
474+ve_pylint/bin/python3 -m pylint snappy_ecosystem_tests --reports=y --rcfile=pylint.cfg > pylint-results.txt
475+
476+result=$?
477+
478+deactivate
479+
480+if [ $result != 0 ] && [ $result != 4 ]; then exit 1; fi
481
482=== renamed directory 'tests' => 'snappy_ecosystem_tests'
483=== added file 'snappy_ecosystem_tests/data/__init__.py'
484--- snappy_ecosystem_tests/data/__init__.py 1970-01-01 00:00:00 +0000
485+++ snappy_ecosystem_tests/data/__init__.py 2017-02-08 14:28:57 +0000
486@@ -0,0 +1,19 @@
487+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
488+
489+#
490+# Snappy Ecosystem Tests
491+# Copyright (C) 2017 Canonical
492+#
493+# This program is free software: you can redistribute it and/or modify
494+# it under the terms of the GNU General Public License as published by
495+# the Free Software Foundation, either version 3 of the License, or
496+# (at your option) any later version.
497+#
498+# This program is distributed in the hope that it will be useful,
499+# but WITHOUT ANY WARRANTY; without even the implied warranty of
500+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
501+# GNU General Public License for more details.
502+#
503+# You should have received a copy of the GNU General Public License
504+# along with this program. If not, see <http://www.gnu.org/licenses/>.
505+#
506
507=== modified file 'snappy_ecosystem_tests/helpers/__init__.py'
508--- tests/helpers/__init__.py 2017-02-06 10:40:05 +0000
509+++ snappy_ecosystem_tests/helpers/__init__.py 2017-02-08 14:28:57 +0000
510@@ -17,124 +17,3 @@
511 # You should have received a copy of the GNU General Public License
512 # along with this program. If not, see <http://www.gnu.org/licenses/>.
513 #
514-
515-import unittest
516-
517-from selenium import webdriver
518-from selenium.webdriver.support.ui import WebDriverWait
519-from selenium.webdriver.support import expected_conditions as EC
520-from selenium.common.exceptions import TimeoutException
521-from selenium.webdriver.common.by import By
522-
523-from tests import storeconfig
524-
525-LOGIN_EMAIL, LOGIN_PASSWORD = storeconfig.get_store_credentials()
526-STORE_URL = storeconfig.get_store_web_url()
527-
528-# default PAGE and ELEMENTS load timeout
529-PAGE_LOAD_TIMEOUT = 30
530-
531-
532-class UbuntuStoreWebTestsBase(unittest.TestCase):
533-
534- def setUp(self):
535- # TODO - add support for multiple type browsers including Chrome, FF and IE
536- options = webdriver.ChromeOptions()
537- options.add_argument("--start-maximized")
538- self.driver = webdriver.Chrome(chrome_options=options)
539-
540- def wait_for_element(self, locator, timeout=PAGE_LOAD_TIMEOUT):
541- """Wait of element to be loaded for the given timeout,
542- default timeout is as per PAGE_LOAD_TIMEOUT variable"""
543- wait = WebDriverWait(self.driver, timeout)
544- try:
545- element_present = EC.presence_of_element_located(locator)
546- wait.until(element_present)
547- except TimeoutException:
548- print ("Timed out waiting for "+locator[1]+" page")
549-
550- def wait_for_page_title(self, title, timeout=PAGE_LOAD_TIMEOUT):
551- """Wait for the target page title for given timeout,
552- default timeout is as per PAGE_LOAD_TIMEOUT variable"""
553- wait = WebDriverWait(self.driver, timeout)
554- try:
555-
556- find_title = EC.title_is(title)
557- wait.until(find_title)
558-
559- except TimeoutException:
560- print ("Timed out waiting for "+title+ " page")
561-
562- def wait_for_visible(self, locator, timeout=PAGE_LOAD_TIMEOUT):
563- """Wait for the element to be visible for given timeout,
564- default timeout is as per PAGE_LOAD_TIMEOUT variable"""
565- wait = WebDriverWait(self.driver, timeout)
566- try:
567- element_visible = EC.visibility_of_element_located((By.XPATH, "/html/body/nav/div/div[1]/span"))
568- wait.until(element_visible)
569- except TimeoutException:
570- print ("Timed out waiting for element to be visible")
571-
572- def wait_for_clickable(self, locator, timeout=PAGE_LOAD_TIMEOUT):
573- """Wait for the element to be visible for given timeout,
574- default timeout is as per PAGE_LOAD_TIMEOUT variable"""
575- wait = WebDriverWait(self.driver, timeout)
576- try:
577- element_clickable = EC.element_to_be_clickable((By.XPATH, "/html/body/nav/div/div[1]/span"))
578- wait.until(element_clickable)
579- except TimeoutException:
580- print ("Timed out waiting for element to be clickable")
581-
582- def login(self):
583- """Login to web interface, following the UI flow which end user would use"""
584- driver = self.driver
585- driver.get(STORE_URL)
586-
587- signin_link = driver.find_element_by_link_text("Sign in or register")
588- signin_link.click()
589- self.wait_for_element((By.ID, 'login-form'))
590- login_form = driver.find_element_by_id("login-form")
591- email = login_form.find_element_by_id("id_email")
592- email.send_keys(LOGIN_EMAIL)
593- password = login_form.find_element_by_id("id_password")
594- password.send_keys(LOGIN_PASSWORD)
595- login_form.submit()
596- self.wait_for_element((By.NAME, 'decideform'))
597- decide_form = driver.find_element_by_name("decideform")
598- decide_form.submit()
599- self.wait_for_page_title("Your packages")
600-
601- def logout(self):
602- """Logout of web interface, following the UI flow which end user would use"""
603- driver = self.driver
604- self.wait_for_element((By.CLASS_NAME, "b-dropdown__arrow_light"))
605- #
606- # extremely ugly way to reach the desired element by xpath, a bug will be
607- # raised to uniquely identify the dropdown arrows
608- self.wait_for_clickable((By.XPATH, "/html/body/nav/div/div[1]/span"))
609- down_arrow = driver.find_element_by_xpath("/html/body/nav/div/div[1]/span")
610- #
611- # There is a bug with Firefox webdriver when clicking elements,
612- # as sometime click doesn't have any effect, to workaround that
613- # multiple attempts are made. However everything works fine with chrome webdriver.
614-
615- for t in range(0,2):
616- wait = WebDriverWait(self.driver, 1)
617- try:
618- down_arrow.click()
619- element_present = EC.presence_of_element_located((By.CLASS_NAME, "b-dropdown_open"))
620- wait.until(element_present)
621- break
622- except TimeoutException:
623- print ("Failed to open the accounts dropdown menu card, Trying again")
624-
625-
626- self.wait_for_visible((By.LINK_TEXT, "Log out"))
627- logout_link = driver.find_element_by_link_text("Log out")
628- logout_link.click()
629-
630- self.wait_for_page_title("Sign in to see your packages")
631-
632- def tearDown(self):
633- self.driver.close()
634- self.driver.quit()
635
636=== added file 'snappy_ecosystem_tests/helpers/ubuntu_store_tests_base.py'
637--- snappy_ecosystem_tests/helpers/ubuntu_store_tests_base.py 1970-01-01 00:00:00 +0000
638+++ snappy_ecosystem_tests/helpers/ubuntu_store_tests_base.py 2017-02-08 14:28:57 +0000
639@@ -0,0 +1,19 @@
640+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
641+
642+#
643+# Snappy Ecosystem Tests
644+# Copyright (C) 2017 Canonical
645+#
646+# This program is free software: you can redistribute it and/or modify
647+# it under the terms of the GNU General Public License as published by
648+# the Free Software Foundation, either version 3 of the License, or
649+# (at your option) any later version.
650+#
651+# This program is distributed in the hope that it will be useful,
652+# but WITHOUT ANY WARRANTY; without even the implied warranty of
653+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
654+# GNU General Public License for more details.
655+#
656+# You should have received a copy of the GNU General Public License
657+# along with this program. If not, see <http://www.gnu.org/licenses/>.
658+#
659
660=== added file 'snappy_ecosystem_tests/helpers/ubuntu_store_web_test_base.py'
661--- snappy_ecosystem_tests/helpers/ubuntu_store_web_test_base.py 1970-01-01 00:00:00 +0000
662+++ snappy_ecosystem_tests/helpers/ubuntu_store_web_test_base.py 2017-02-08 14:28:57 +0000
663@@ -0,0 +1,145 @@
664+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
665+
666+#
667+# Snappy Ecosystem Tests
668+# Copyright (C) 2017 Canonical
669+#
670+# This program is free software: you can redistribute it and/or modify
671+# it under the terms of the GNU General Public License as published by
672+# the Free Software Foundation, either version 3 of the License, or
673+# (at your option) any later version.
674+#
675+# This program is distributed in the hope that it will be useful,
676+# but WITHOUT ANY WARRANTY; without even the implied warranty of
677+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
678+# GNU General Public License for more details.
679+#
680+# You should have received a copy of the GNU General Public License
681+# along with this program. If not, see <http://www.gnu.org/licenses/>.
682+#
683+
684+"""Web-Ui related functionality for testing web pages using selenium"""
685+
686+import unittest
687+
688+from selenium import webdriver
689+from selenium.webdriver.support.ui import WebDriverWait
690+from selenium.webdriver.support import expected_conditions as EC
691+from selenium.common.exceptions import TimeoutException
692+from selenium.webdriver.common.by import By
693+
694+from snappy_ecosystem_tests import storeconfig
695+
696+LOGIN_EMAIL, LOGIN_PASSWORD = storeconfig.get_store_credentials()
697+STORE_URL = storeconfig.get_store_web_url()
698+
699+# default PAGE and ELEMENTS load timeout
700+PAGE_LOAD_TIMEOUT = 30
701+
702+
703+class UbuntuStoreWebTestsBase(unittest.TestCase):
704+ """Base class to represent a Web-UI test case.
705+ Contain basic functionality for locating web elements and interacting with a page
706+ """
707+ def setUp(self):
708+ # TODO - add support for multiple type browsers including Chrome, FF and IE
709+ options = webdriver.ChromeOptions()
710+ options.add_argument("--start-maximized")
711+ self.driver = webdriver.Chrome(chrome_options=options)
712+
713+ def wait_for_element(self, locator, timeout=PAGE_LOAD_TIMEOUT):
714+ """Wait of element to be loaded for the given timeout,
715+ default timeout is as per PAGE_LOAD_TIMEOUT variable"""
716+ wait = WebDriverWait(self.driver, timeout)
717+ try:
718+ element_present = EC.presence_of_element_located(locator)
719+ wait.until(element_present)
720+ except TimeoutException:
721+ print("Timed out waiting for "+locator[1]+" page")
722+
723+ def wait_for_page_title(self, title, timeout=PAGE_LOAD_TIMEOUT):
724+ """Wait for the target page title for given timeout,
725+ default timeout is as per PAGE_LOAD_TIMEOUT variable"""
726+ wait = WebDriverWait(self.driver, timeout)
727+ try:
728+ find_title = EC.title_is(title)
729+ wait.until(find_title)
730+ except TimeoutException:
731+ print("Timed out waiting for "+title + " page")
732+
733+ def wait_for_visible(self, timeout=PAGE_LOAD_TIMEOUT):
734+ # TODO: re-implement to allow any locator as parameter
735+ """Wait for the element to be visible for given timeout,
736+ default timeout is as per PAGE_LOAD_TIMEOUT variable"""
737+ wait = WebDriverWait(self.driver, timeout)
738+ try:
739+ element_visible = EC.visibility_of_element_located(
740+ (By.XPATH, "/html/body/nav/div/div[1]/span"))
741+ wait.until(element_visible)
742+ except TimeoutException:
743+ print("Timed out waiting for element to be visible")
744+
745+ def wait_for_clickable(self, timeout=PAGE_LOAD_TIMEOUT):
746+ # TODO: re-implement to allow any locator as parameter
747+ """Wait for the element to be visible for given timeout,
748+ default timeout is as per PAGE_LOAD_TIMEOUT variable"""
749+ wait = WebDriverWait(self.driver, timeout)
750+ try:
751+ element_clickable = EC.element_to_be_clickable(
752+ (By.XPATH, "/html/body/nav/div/div[1]/span"))
753+ wait.until(element_clickable)
754+ except TimeoutException:
755+ print("Timed out waiting for element to be clickable")
756+
757+ def login(self):
758+ """Login to web interface, following the UI flow which end user would use"""
759+ driver = self.driver
760+ driver.get(STORE_URL)
761+
762+ signin_link = driver.find_element_by_link_text("Sign in or register")
763+ signin_link.click()
764+ self.wait_for_element((By.ID, 'login-form'))
765+ login_form = driver.find_element_by_id("login-form")
766+ email = login_form.find_element_by_id("id_email")
767+ email.send_keys(LOGIN_EMAIL)
768+ password = login_form.find_element_by_id("id_password")
769+ password.send_keys(LOGIN_PASSWORD)
770+ login_form.submit()
771+ self.wait_for_element((By.NAME, 'decideform'))
772+ decide_form = driver.find_element_by_name("decideform")
773+ decide_form.submit()
774+ self.wait_for_page_title("Your packages")
775+
776+ def logout(self):
777+ """Logout of web interface, following the UI flow which end user would use"""
778+ driver = self.driver
779+ self.wait_for_element((By.CLASS_NAME, "b-dropdown__arrow_light"))
780+ #
781+ # extremely ugly way to reach the desired element by xpath, a bug will be
782+ # raised to uniquely identify the dropdown arrows
783+ self.wait_for_clickable()
784+ down_arrow = driver.find_element_by_xpath("/html/body/nav/div/div[1]/span")
785+ #
786+ # There is a bug with Firefox webdriver when clicking elements,
787+ # as sometime click doesn't have any effect, to workaround that
788+ # multiple attempts are made. However everything works fine with chrome webdriver.
789+
790+ for _ in range(0, 2):
791+ wait = WebDriverWait(self.driver, 1)
792+ try:
793+ down_arrow.click()
794+ element_present = EC.presence_of_element_located((By.CLASS_NAME, "b-dropdown_open"))
795+ wait.until(element_present)
796+ break
797+ except TimeoutException:
798+ print("Failed to open the accounts dropdown menu card, Trying again")
799+
800+ self.wait_for_visible()
801+ logout_link = driver.find_element_by_link_text("Log out")
802+ logout_link.click()
803+
804+ self.wait_for_page_title("Sign in to see your packages")
805+
806+ def tearDown(self):
807+ self.driver.close()
808+ self.driver.quit()
809
810=== added file 'snappy_ecosystem_tests/pageobjects/__init__.py'
811--- snappy_ecosystem_tests/pageobjects/__init__.py 1970-01-01 00:00:00 +0000
812+++ snappy_ecosystem_tests/pageobjects/__init__.py 2017-02-08 14:28:57 +0000
813@@ -0,0 +1,19 @@
814+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
815+
816+#
817+# Snappy Ecosystem Tests
818+# Copyright (C) 2017 Canonical
819+#
820+# This program is free software: you can redistribute it and/or modify
821+# it under the terms of the GNU General Public License as published by
822+# the Free Software Foundation, either version 3 of the License, or
823+# (at your option) any later version.
824+#
825+# This program is distributed in the hope that it will be useful,
826+# but WITHOUT ANY WARRANTY; without even the implied warranty of
827+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
828+# GNU General Public License for more details.
829+#
830+# You should have received a copy of the GNU General Public License
831+# along with this program. If not, see <http://www.gnu.org/licenses/>.
832+#
833
834=== modified file 'snappy_ecosystem_tests/storeconfig.py'
835--- tests/storeconfig.py 2017-02-07 11:35:30 +0000
836+++ snappy_ecosystem_tests/storeconfig.py 2017-02-08 14:28:57 +0000
837@@ -18,6 +18,8 @@
838 # along with this program. If not, see <http://www.gnu.org/licenses/>.
839 #
840
841+"""Helpers to retrieve store configuration data like: credentials, urls, etc"""
842+
843 import os
844
845 KEY_ENVIRON_STORE_LOGIN_EMAIL = 'UBUNTU_STORE_LOGIN_EMAIL'
846
847=== added file 'snappy_ecosystem_tests/test_store_login.py'
848--- snappy_ecosystem_tests/test_store_login.py 1970-01-01 00:00:00 +0000
849+++ snappy_ecosystem_tests/test_store_login.py 2017-02-08 14:28:57 +0000
850@@ -0,0 +1,47 @@
851+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
852+
853+#
854+# Snappy Ecosystem Tests
855+# Copyright (C) 2017 Canonical
856+#
857+# This program is free software: you can redistribute it and/or modify
858+# it under the terms of the GNU General Public License as published by
859+# the Free Software Foundation, either version 3 of the License, or
860+# (at your option) any later version.
861+#
862+# This program is distributed in the hope that it will be useful,
863+# but WITHOUT ANY WARRANTY; without even the implied warranty of
864+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
865+# GNU General Public License for more details.
866+#
867+# You should have received a copy of the GNU General Public License
868+# along with this program. If not, see <http://www.gnu.org/licenses/>.
869+#
870+
871+"""Test for Login to the Store via Web Interface, snapcraft and snapd"""
872+
873+from snappy_ecosystem_tests.utils.snapcraft import Snapcraft
874+from snappy_ecosystem_tests.helpers.ubuntu_store_web_test_base import UbuntuStoreWebTestsBase
875+
876+
877+class StoreLoginTestCase(UbuntuStoreWebTestsBase):
878+ def setUp(self):
879+ super().setUp()
880+
881+ def test_login_logout(self):
882+ """Test login and logout functionality of snapcraft, web interface
883+ and snapd."""
884+ try:
885+ sc = Snapcraft()
886+ sc.login()
887+ sc.logout()
888+ except ValueError as err:
889+ self.fail(msg=err)
890+
891+ self.login()
892+ self.assertEqual(self.driver.title, "Your packages", "Failed to login")
893+ # TODO - fragile as there is no unique way to identify the dropdown arrow
894+ self.logout()
895+ self.assertEqual(
896+ self.driver.title, "Sign in to see your packages",
897+ "Failed to logout")
898
899=== added directory 'snappy_ecosystem_tests/tests'
900=== added file 'snappy_ecosystem_tests/tests/__init__.py'
901--- snappy_ecosystem_tests/tests/__init__.py 1970-01-01 00:00:00 +0000
902+++ snappy_ecosystem_tests/tests/__init__.py 2017-02-08 14:28:57 +0000
903@@ -0,0 +1,19 @@
904+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
905+
906+#
907+# Snappy Ecosystem Tests
908+# Copyright (C) 2017 Canonical
909+#
910+# This program is free software: you can redistribute it and/or modify
911+# it under the terms of the GNU General Public License as published by
912+# the Free Software Foundation, either version 3 of the License, or
913+# (at your option) any later version.
914+#
915+# This program is distributed in the hope that it will be useful,
916+# but WITHOUT ANY WARRANTY; without even the implied warranty of
917+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
918+# GNU General Public License for more details.
919+#
920+# You should have received a copy of the GNU General Public License
921+# along with this program. If not, see <http://www.gnu.org/licenses/>.
922+#
923
924=== modified file 'snappy_ecosystem_tests/utils/snapcraft.py'
925--- tests/utils/snapcraft.py 2017-02-06 10:40:05 +0000
926+++ snappy_ecosystem_tests/utils/snapcraft.py 2017-02-08 14:28:57 +0000
927@@ -18,13 +18,17 @@
928 # along with this program. If not, see <http://www.gnu.org/licenses/>.
929 #
930
931+"""Snapcraft related helpers to configure the snapcraft environment: staging or production
932+and other specific functions inside Snapcraft class
933+"""
934+
935 import os
936-
937 import pexpect
938
939-from tests import storeconfig
940
941 # login credentials exported by shell environment
942+from snappy_ecosystem_tests import storeconfig
943+
944 LOGIN_EMAIL, LOGIN_PASSWORD = storeconfig.get_store_credentials()
945
946
947@@ -36,7 +40,8 @@
948 os.environ["UBUNTU_STORE_SEARCH_ROOT_URL"] = 'https://search.apps.staging.ubuntu.com/'
949 os.environ["UBUNTU_STORE_UPLOAD_ROOT_URL"] = 'https://upload.apps.staging.ubuntu.com/'
950 os.environ["UBUNTU_SSO_API_ROOT_URL"] = 'https://login.staging.ubuntu.com/api/v2/'
951- os.environ["UBUNTU_STORE_API_ROOT_URL"] = 'https://myapps.developer.staging.ubuntu.com/dev/api/'
952+ os.environ["UBUNTU_STORE_API_ROOT_URL"] = \
953+ 'https://myapps.developer.staging.ubuntu.com/dev/api/'
954 else:
955 os.environ["UBUNTU_STORE_SEARCH_ROOT_URL"] = 'https://search.apps.ubuntu.com/'
956 os.environ["UBUNTU_STORE_UPLOAD_ROOT_URL"] = 'https://upload.apps.ubuntu.com/'
957@@ -45,6 +50,7 @@
958
959
960 class Snapcraft(object):
961+ """Contain Snapcraft specific functionality to use via command line interface"""
962 def __init__(self):
963 """Create new snapcraft instance."""
964 self._login = False
965@@ -52,6 +58,7 @@
966 self._cleanup()
967
968 def _cleanup(self):
969+ """Perform cleanup actions"""
970 self.logout()
971
972 def logout(self):
973@@ -78,10 +85,8 @@
974
975 self._login = True
976
977- def listRegistered(self):
978+ def list_registered(self):
979 """call snapcraft list-registered command, raise exception if not logged in"""
980 if self._login is False:
981 raise ValueError("User is not logged in, please login before using this command")
982 return pexpect.spawnu("snapcraft list-registered").read()
983-
984-
985
986=== removed file 'tests/helpers/ubuntu-store-tests-base.py'
987--- tests/helpers/ubuntu-store-tests-base.py 2017-02-06 10:40:05 +0000
988+++ tests/helpers/ubuntu-store-tests-base.py 1970-01-01 00:00:00 +0000
989@@ -1,19 +0,0 @@
990-# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
991-
992-#
993-# Snappy Ecosystem Tests
994-# Copyright (C) 2017 Canonical
995-#
996-# This program is free software: you can redistribute it and/or modify
997-# it under the terms of the GNU General Public License as published by
998-# the Free Software Foundation, either version 3 of the License, or
999-# (at your option) any later version.
1000-#
1001-# This program is distributed in the hope that it will be useful,
1002-# but WITHOUT ANY WARRANTY; without even the implied warranty of
1003-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1004-# GNU General Public License for more details.
1005-#
1006-# You should have received a copy of the GNU General Public License
1007-# along with this program. If not, see <http://www.gnu.org/licenses/>.
1008-#
1009
1010=== removed file 'tests/test-store-login.py'
1011--- tests/test-store-login.py 2017-02-06 10:40:05 +0000
1012+++ tests/test-store-login.py 1970-01-01 00:00:00 +0000
1013@@ -1,58 +0,0 @@
1014-# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
1015-
1016-#
1017-# Snappy Ecosystem Tests
1018-# Copyright (C) 2017 Canonical
1019-#
1020-# This program is free software: you can redistribute it and/or modify
1021-# it under the terms of the GNU General Public License as published by
1022-# the Free Software Foundation, either version 3 of the License, or
1023-# (at your option) any later version.
1024-#
1025-# This program is distributed in the hope that it will be useful,
1026-# but WITHOUT ANY WARRANTY; without even the implied warranty of
1027-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1028-# GNU General Public License for more details.
1029-#
1030-# You should have received a copy of the GNU General Public License
1031-# along with this program. If not, see <http://www.gnu.org/licenses/>.
1032-#
1033-
1034-import unittest
1035-
1036-import xmlrunner
1037-
1038-from tests.helpers import UbuntuStoreWebTestsBase
1039-from tests.utils.snapcraft import Snapcraft
1040-
1041-
1042-class StoreLoginTests(UbuntuStoreWebTestsBase):
1043-
1044- def setUp(self):
1045- super().setUp()
1046-
1047- def test_login_logout(self):
1048- """Test login and logout functionality of snapcraft, web interface
1049- and snapd."""
1050- try:
1051- sc = Snapcraft()
1052- sc.login()
1053- sc.logout()
1054- except ValueError as err:
1055- self.fail(err.message)
1056-
1057- self.login()
1058- self.assertEqual(self.driver.title, "Your packages", "Failed to login")
1059- # TODO - fragile as there is no unique way to identify the dropdown arrow # NOQA
1060- self.logout()
1061- self.assertEqual(
1062- self.driver.title, "Sign in to see your packages",
1063- "Failed to logout")
1064-
1065-
1066-if __name__ == '__main__':
1067- unittest.main(
1068- testRunner=xmlrunner.XMLTestRunner(output='test-reports'),
1069- # these make sure that some options that are not applicable
1070- # remain hidden from the help menu.
1071- failfast=False, buffer=False, catchbreak=False)

Subscribers

People subscribed via source and target branches