I am fine as long as data is not parsed/filtered within helper method
On Tue, Feb 7, 2017 at 7:48 PM, Omer Akram <email address hidden> wrote:
> Replied inline. > > Diff comments: > > > > > === modified file 'tests/utils/snapd.py' > > --- tests/utils/snapd.py 2017-02-06 14:05:03 +0000 > > +++ tests/utils/snapd.py 2017-02-06 14:05:03 +0000 > > @@ -17,3 +17,138 @@ > > # You should have received a copy of the GNU General Public License > > # along with this program. If not, see <http://www.gnu.org/licenses/>. > > # > > + > > +import getpass > > +import os > > +import subprocess > > +import sys > > +import shlex > > +import shutil > > +import tempfile > > + > > +import pexpect > > +import yaml > > + > > +PATH_SNAP = '/usr/bin/snap' > > +COMMAND_DOWNLOAD = 'download {snap} --channel={channel}' > > +COMMAND_FIND = 'find {search_term}' > > +COMMAND_INFO = 'info {snap}' > > +COMMAND_INSTALL = 'install {snap} --channel={channel}' > > +COMMAND_LOGIN = 'login {email}' > > +COMMAND_LOGOUT = 'logout' > > +COMMAND_REFRESH = 'refresh {snap} --channel={channel}' > > +CHANNEL_STABLE = 'stable' > > +PASSWORD_ROOT = 'changed' > > + > > + > > +def is_root_user(): > > + """Return bool representing if the current user is root.""" > > + return os.getuid() == 0 > > + > > + > > +def run_snapd_command(parameters, return_output=False, cwd=None): > > + """ Run the request snapd cli command. > > + > > + :param parameters: the snapd sub-command and their parameters. > > + example: install core --beta > > + :param return_output: Whether to return the stdout of the command. > > + :param cwd: The current working directory for the command, defaults > to > > + pwd. > > + :return: Optionally return the stdout of the command, depending if > > + the value of `return_output` was True. > > + """ > > + command = '{} {}'.format(PATH_SNAP, parameters) > > + if return_output: > > + raw_output = subprocess.check_output( > > + shlex.split(command), universal_newlines=True, cwd=cwd) > > + return raw_output.strip().split('\n') > > + subprocess.check_call(shlex.split(command), cwd=cwd) > > + > > + > > +def login(email, password): > > + """Login to snapd. > > + > > + :param email: Ubuntu SSO account email address. > > + :param password: Ubuntu SSO account password. > > + """ > > + command = '{} {}'.format(COMMAND_LOGIN, email) > > + if is_root_user(): > > + p = pexpect.spawnu(command, logfile=sys.stdout) > > + else: > > + p = pexpect.spawnu('{} {}'.format('sudo', command), > logfile=sys.stdout) > > + p.expect_exact( > > + '[sudo] password for {}: '.format(getpass.getuser())) > > + p.sendline(PASSWORD_ROOT) > > + p.expect_exact('Password of "{}": '.format(email)) > > + p.sendline(password) > > + p.wait() > > + > > I added an assert to ensure the login was successful. > > > + > > +def logout(): > > + run_snapd_command(COMMAND_LOGOUT) > > + > > + > > +def download(snap, channel=CHANNEL_STABLE, path=None): > > + """Download the requested snap. > > + > > + :param snap: name of the snap to download. > > + :param channel: name of the release channel to download from. > > + :param path: The path to which the downloaded snap be saved to, > defaults > > + to pwd. > > + """ > > + command = COMMAND_DOWNLOAD.format(snap=snap, channel=channel) > > + if path and os.path.isdir(path): > > + with tempfile.TemporaryDirectory() as tempdir: > > + run_snapd_command(command, cwd=tempdir) > > + for file in os.listdir(tempdir): > > + shutil.move(os.path.join(tempdir, file), path) > > + else: > > + run_snapd_command(command) > > + > > + > > +def install(snap, channel=CHANNEL_STABLE): > > + """Install the requested snap.""" > > + run_snapd_command(COMMAND_INSTALL.format(snap=snap, > channel=channel)) > > + > > + > > +def info(snap, verbose=False): > > + """Query the Ubuntu store of the information about a snap. > > + > > + :param snap: Name of the snap for which the info is required. > > + :param verbose: Whether to information should be detailed. > > + :return: Return a dictionary containing information about the snap. > > + """ > > + command = COMMAND_INFO.format(snap=snap) > > + if verbose: > > + command = ' '.join([command, '--verbose']) > > + output = run_snapd_command(command, return_output=True) > > + return yaml.load("""{}""".format(output)) > > + > > + > > +def refresh(snap, channel=CHANNEL_STABLE): > > + """Refresh the requested snap.""" > > + run_snapd_command(COMMAND_REFRESH.format(snap=snap, > channel=channel)) > > + > > + > > +def find(keyword, **client_side_filters): > > + """Find snaps based on the provided filters > > + > > + :param keyword: Keyword to use for the query. > > + :param client_side_filters: Whether to filter the results based on > > + additional constraints that are not supported by the server. > > + :return: Return a list of dictionaries containing information about > > + snaps matching the find criteria. > > + """ > > + raw_output = run_snapd_command( > > + COMMAND_FIND.format(search_term=keyword), return_output=True) > > + headers = [header.lower() for header in raw_output.pop(0).split()] > > + organized_data = [dict(zip(headers, line.split())) for line in > raw_output] > > + if len(client_side_filters) > 0: > > + filtered_result = organized_data.copy() > > + for item in organized_data: > > + for key, value in client_side_filters.items(): > > + if item.get(key) != value: > > + filtered_result.remove(item) > > + continue > > + return filtered_result > > + return organized_data > > We might want to consider making an exception in this case, the raw data > is returned in the form: > > Name Version Developer Notes Summary > hello-world-om26er 0.2 om26er - A great snap > crossbar-om26er 0.15.0 om26er - Crossbar.io - WAMP > application router > omegat-cat 4.1.0-1 jz - OmegaT, the free (GPL) > translation memory tool > oman 0.1 kalikiana - Read manpages from the web > on your local machine > > This is find for human eyes but each test would have to loop through lines > and get what its looking for, on the contrary what our method does is, it > returns items in the form: > > [{'summary': 'A', 'name': 'hello-world-om26er', 'version': '0.2', > 'developer': 'om26er', 'notes': '-'}, {'summary': 'Crossbar.io', 'name': > 'crossbar-om26er', 'version': '0.15.0', 'developer': 'om26er', 'notes': > '-'}, {'summary': 'OmegaT,', 'name': 'omegat-cat', 'version': '4.1.0-1', > 'developer': 'jz', 'notes': '-'}, {'summary': 'Read', 'name': 'oman', > 'version': '0.1', 'developer': 'kalikiana', 'notes': '-'}] > > Note: no data loss, rather the same data, but serialized. We can also call > find('om26er', developer='om26er') and it will locally filter the results > and look of the form: > > [{'summary': 'A', 'name': 'hello-world-om26er', 'version': '0.2', > 'developer': 'om26er', 'notes': '-'}, {'summary': 'Crossbar.io', 'name': > 'crossbar-om26er', 'version': '0.15.0', 'developer': 'om26er', 'notes': > '-'}] > > Now if we really have a requirement to return raw data, we could probably > add a raw=True default parameter to the method so that it returns raw text > by default and optionally returns serialized data. (Or the other way > around). Thoughts ? > > > > -- > https://code.launchpad.net/~canonical-platform-qa/snappy- > ecosystem-tests/helpers_for_snapd_cli/+merge/316459 > You are reviewing the proposed merge of lp:~canonical-platform-qa/ > snappy-ecosystem-tests/helpers_for_snapd_cli into > lp:snappy-ecosystem-tests. >
« Back to merge proposal
I am fine as long as data is not parsed/filtered within helper method
On Tue, Feb 7, 2017 at 7:48 PM, Omer Akram <email address hidden> wrote:
> Replied inline. utils/snapd. py' snapd.py 2017-02-06 14:05:03 +0000 snapd.py 2017-02-06 14:05:03 +0000 www.gnu. org/licenses/>. {channel} ' {channel} ' {channel} ' command( parameters, return_ output= False, cwd=None): PATH_SNAP, parameters) check_output( command) , universal_ newlines= True, cwd=cwd) strip() .split( '\n') check_call( shlex.split( command) , cwd=cwd) COMMAND_ LOGIN, email) spawnu( command, logfile=sys.stdout) getpass. getuser( ))) PASSWORD_ ROOT) exact(' Password of "{}": '.format(email)) password) command( COMMAND_ LOGOUT) CHANNEL_ STABLE, path=None): DOWNLOAD. format( snap=snap, channel=channel) isdir(path) : TemporaryDirect ory() as tempdir: command( command, cwd=tempdir) tempdir) : move(os. path.join( tempdir, file), path) command( command) CHANNEL_ STABLE) : command( COMMAND_ INSTALL. format( snap=snap, INFO.format( snap=snap) command( command, return_output=True) """{}"" ".format( output) ) CHANNEL_ STABLE) : command( COMMAND_ REFRESH. format( snap=snap, side_filters) : side_filters: Whether to filter the results based on FIND.format( search_ term=keyword) , return_output=True) pop(0). split() ] side_filters) > 0: data.copy( ) side_filters. items() : result. remove( item) world-om26er' , 'version': '0.2', world-om26er' , 'version': '0.2', /code.launchpad .net/~canonical -platform- qa/snappy- tests/helpers_ for_snapd_ cli/+merge/ 316459 ecosystem- tests/helpers_ for_snapd_ cli into
>
> Diff comments:
>
> >
> > === modified file 'tests/
> > --- tests/utils/
> > +++ tests/utils/
> > @@ -17,3 +17,138 @@
> > # You should have received a copy of the GNU General Public License
> > # along with this program. If not, see <http://
> > #
> > +
> > +import getpass
> > +import os
> > +import subprocess
> > +import sys
> > +import shlex
> > +import shutil
> > +import tempfile
> > +
> > +import pexpect
> > +import yaml
> > +
> > +PATH_SNAP = '/usr/bin/snap'
> > +COMMAND_DOWNLOAD = 'download {snap} --channel=
> > +COMMAND_FIND = 'find {search_term}'
> > +COMMAND_INFO = 'info {snap}'
> > +COMMAND_INSTALL = 'install {snap} --channel=
> > +COMMAND_LOGIN = 'login {email}'
> > +COMMAND_LOGOUT = 'logout'
> > +COMMAND_REFRESH = 'refresh {snap} --channel=
> > +CHANNEL_STABLE = 'stable'
> > +PASSWORD_ROOT = 'changed'
> > +
> > +
> > +def is_root_user():
> > + """Return bool representing if the current user is root."""
> > + return os.getuid() == 0
> > +
> > +
> > +def run_snapd_
> > + """ Run the request snapd cli command.
> > +
> > + :param parameters: the snapd sub-command and their parameters.
> > + example: install core --beta
> > + :param return_output: Whether to return the stdout of the command.
> > + :param cwd: The current working directory for the command, defaults
> to
> > + pwd.
> > + :return: Optionally return the stdout of the command, depending if
> > + the value of `return_output` was True.
> > + """
> > + command = '{} {}'.format(
> > + if return_output:
> > + raw_output = subprocess.
> > + shlex.split(
> > + return raw_output.
> > + subprocess.
> > +
> > +
> > +def login(email, password):
> > + """Login to snapd.
> > +
> > + :param email: Ubuntu SSO account email address.
> > + :param password: Ubuntu SSO account password.
> > + """
> > + command = '{} {}'.format(
> > + if is_root_user():
> > + p = pexpect.
> > + else:
> > + p = pexpect.spawnu('{} {}'.format('sudo', command),
> logfile=sys.stdout)
> > + p.expect_exact(
> > + '[sudo] password for {}: '.format(
> > + p.sendline(
> > + p.expect_
> > + p.sendline(
> > + p.wait()
> > +
>
> I added an assert to ensure the login was successful.
>
> > +
> > +def logout():
> > + run_snapd_
> > +
> > +
> > +def download(snap, channel=
> > + """Download the requested snap.
> > +
> > + :param snap: name of the snap to download.
> > + :param channel: name of the release channel to download from.
> > + :param path: The path to which the downloaded snap be saved to,
> defaults
> > + to pwd.
> > + """
> > + command = COMMAND_
> > + if path and os.path.
> > + with tempfile.
> > + run_snapd_
> > + for file in os.listdir(
> > + shutil.
> > + else:
> > + run_snapd_
> > +
> > +
> > +def install(snap, channel=
> > + """Install the requested snap."""
> > + run_snapd_
> channel=channel))
> > +
> > +
> > +def info(snap, verbose=False):
> > + """Query the Ubuntu store of the information about a snap.
> > +
> > + :param snap: Name of the snap for which the info is required.
> > + :param verbose: Whether to information should be detailed.
> > + :return: Return a dictionary containing information about the snap.
> > + """
> > + command = COMMAND_
> > + if verbose:
> > + command = ' '.join([command, '--verbose'])
> > + output = run_snapd_
> > + return yaml.load(
> > +
> > +
> > +def refresh(snap, channel=
> > + """Refresh the requested snap."""
> > + run_snapd_
> channel=channel))
> > +
> > +
> > +def find(keyword, **client_
> > + """Find snaps based on the provided filters
> > +
> > + :param keyword: Keyword to use for the query.
> > + :param client_
> > + additional constraints that are not supported by the server.
> > + :return: Return a list of dictionaries containing information about
> > + snaps matching the find criteria.
> > + """
> > + raw_output = run_snapd_command(
> > + COMMAND_
> > + headers = [header.lower() for header in raw_output.
> > + organized_data = [dict(zip(headers, line.split())) for line in
> raw_output]
> > + if len(client_
> > + filtered_result = organized_
> > + for item in organized_data:
> > + for key, value in client_
> > + if item.get(key) != value:
> > + filtered_
> > + continue
> > + return filtered_result
> > + return organized_data
>
> We might want to consider making an exception in this case, the raw data
> is returned in the form:
>
> Name Version Developer Notes Summary
> hello-world-om26er 0.2 om26er - A great snap
> crossbar-om26er 0.15.0 om26er - Crossbar.io - WAMP
> application router
> omegat-cat 4.1.0-1 jz - OmegaT, the free (GPL)
> translation memory tool
> oman 0.1 kalikiana - Read manpages from the web
> on your local machine
>
> This is find for human eyes but each test would have to loop through lines
> and get what its looking for, on the contrary what our method does is, it
> returns items in the form:
>
> [{'summary': 'A', 'name': 'hello-
> 'developer': 'om26er', 'notes': '-'}, {'summary': 'Crossbar.io', 'name':
> 'crossbar-om26er', 'version': '0.15.0', 'developer': 'om26er', 'notes':
> '-'}, {'summary': 'OmegaT,', 'name': 'omegat-cat', 'version': '4.1.0-1',
> 'developer': 'jz', 'notes': '-'}, {'summary': 'Read', 'name': 'oman',
> 'version': '0.1', 'developer': 'kalikiana', 'notes': '-'}]
>
> Note: no data loss, rather the same data, but serialized. We can also call
> find('om26er', developer='om26er') and it will locally filter the results
> and look of the form:
>
> [{'summary': 'A', 'name': 'hello-
> 'developer': 'om26er', 'notes': '-'}, {'summary': 'Crossbar.io', 'name':
> 'crossbar-om26er', 'version': '0.15.0', 'developer': 'om26er', 'notes':
> '-'}]
>
> Now if we really have a requirement to return raw data, we could probably
> add a raw=True default parameter to the method so that it returns raw text
> by default and optionally returns serialized data. (Or the other way
> around). Thoughts ?
>
>
>
> --
> https:/
> ecosystem-
> You are reviewing the proposed merge of lp:~canonical-platform-qa/
> snappy-
> lp:snappy-ecosystem-tests.
>