Skip to content

Commit

Permalink
tests: amend ping & workflows tests
Browse files Browse the repository at this point in the history
* Use of mock api client for ping, workflows and file command tests.
  Closes #186

Signed-off-by: Rokas Maciulaitis <rokas.maciulaitis@cern.ch>
Co-authored-by: Diego Rodriguez diego.rodriguez@cern.ch
  • Loading branch information
Rokas Maciulaitis committed Nov 6, 2018
1 parent 4422c17 commit 2a3f6a0
Show file tree
Hide file tree
Showing 9 changed files with 432 additions and 18 deletions.
1 change: 0 additions & 1 deletion reana_client/api/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ def ping(self):
def get_workflows(self, access_token):
"""List all existing workflows."""
try:

response, http_response = self._client.api.\
get_workflows(access_token=access_token).result()
if http_response.status_code == 200:
Expand Down
14 changes: 9 additions & 5 deletions reana_client/cli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,12 @@
class Config(object):
"""Configuration object to share across commands."""

def __init__(self):
"""Initialize config variables."""
self.client = None
def __init__(self, client=None):
"""Initialize config variables.
:param client: :reana_commons:`reana_commons.api_client.BaseAPIClient`.
"""
self.client = client


@click.group()
Expand All @@ -38,13 +41,14 @@ def __init__(self):
type=click.Choice(['DEBUG', 'INFO', 'WARNING']),
default='WARNING')
@click.pass_context
def cli(ctx, loglevel):
@click.pass_obj
def cli(obj, ctx, loglevel):
"""REANA client for interacting with REANA server."""
logging.basicConfig(
format=DEBUG_LOG_FORMAT if loglevel == 'DEBUG' else LOG_FORMAT,
stream=sys.stderr,
level=loglevel)
ctx.obj = Config()
ctx.obj = obj or Config()

commands = []
commands.extend(workflow.workflow.commands.values())
Expand Down
2 changes: 1 addition & 1 deletion reana_client/cli/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
def add_access_token_options(func):
"""Adds access token related options to click commands."""
@click.option('-at', '--access-token',
default=os.environ.get('REANA_ACCESS_TOKEN', None),
default=os.getenv('REANA_ACCESS_TOKEN', None),
help='Access token of the current user.')
@functools.wraps(func)
def wrapper(*args, **kwargs):
Expand Down
10 changes: 7 additions & 3 deletions reana_client/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import os
import sys

import click
from click.core import Context

from reana_client.api import Client
Expand All @@ -31,17 +32,20 @@ def wrapper(*args, **kwargs):
server_url = os.environ.get('REANA_SERVER_URL', None)

if not server_url:
logging.error(
click.secho(
'REANA client is not connected to any REANA cluster.\n'
'Please set REANA_SERVER_URL environment variable to '
'the remote REANA cluster you would like to connect to.\n'
'For example: export '
'REANA_SERVER_URL=https://reana.cern.ch/')
'REANA_SERVER_URL=https://reana.cern.ch/',
fg='red',
err=True)
sys.exit(1)

logging.info('REANA server URL ($REANA_SERVER_URL) is: {}'
.format(server_url))
ctx.obj.client = Client('reana-server')
if not ctx.obj.client:
ctx.obj.client = Client('reana-server')
else:
raise Exception(
'This decorator should be used after click.pass_context.')
Expand Down
5 changes: 3 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@
'docutils>=0.14',
'isort>=4.2.2',
'pydocstyle>=1.0.0',
'pytest>=3.8.0,<4.0.0',
'pytest-cache>=1.0',
'pytest-cov>=1.8.0',
'pytest-pep8>=1.0.6',
'pytest>=2.8.0,<3.0.0'
'pytest-reana>=0.4.0.dev20181105,<0.5.0',
]

extras_require = {
Expand All @@ -53,7 +54,7 @@
'click>=7,<8',
'cwltool==1.0.20180912090223',
'pyOpenSSL==17.3.0', # FIXME remove once yadage-schemas solves deps.
'reana-commons>=0.4.0.dev20181017,<0.5.0',
'reana-commons>=0.4.0.dev20181105,<0.5.0',
'rfc3987==1.3.7', # FIXME remove once yadage-schemas solves deps.
'strict-rfc3339==0.7', # FIXME remove once yadage-schemas solves deps.
'tablib>=0.12.1,<0.13',
Expand Down
54 changes: 52 additions & 2 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,56 @@

from __future__ import absolute_import, print_function

import os

import pytest
from mock import Mock
from pytest_reana.test_utils import make_mock_api_client

from reana_client.api.client import Client


@pytest.fixture()
def mock_base_api_client():
"""Create mocked api client."""
def _make_mock_api_client(status_code=200,
response=None,
component='reana-server'):
mock_http_response, mock_response = Mock(), Mock()
mock_http_response.status_code = status_code
mock_http_response.raw_bytes = str(response).encode()
mock_response = response
reana_server_client = make_mock_api_client(
component)(mock_response, mock_http_response)
reana_client_server_api = Client(component)
reana_client_server_api._client = reana_server_client
return reana_client_server_api
return _make_mock_api_client


@pytest.fixture()
def create_yaml_workflow_schema():
"""Return dummy yaml workflow schema."""
reana_yaml_schema = \
'''
version: 0.3.0
inputs:
files:
- code/helloworld.py
- inputs/names.txt
parameters:
sleeptime: 2
inputfile: inputs/names.txt
helloworld: code/helloworld.py
outputfile: outputs/greetings.txt
outputs:
files:
- outputs/greetings.txt
workflow:
type: serial
specification:
steps:
- environment: 'python:2.7'
commands:
- python "${helloworld}" --sleeptime ${sleeptime} \
--inputfile "${inputfile}" --outputfile "${outputfile}"
'''
return reana_yaml_schema
118 changes: 118 additions & 0 deletions tests/test_cli_files.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# -*- coding: utf-8 -*-
#
# This file is part of REANA.
# Copyright (C) 2017, 2018 CERN.
#
# REANA is free software; you can redistribute it and/or modify it
# under the terms of the MIT License; see LICENSE file for more details.

"""REANA client files tests."""

import hashlib
import json
import os

from click.testing import CliRunner

from reana_client.cli import Config, cli


def test_list_files_server_not_reachable():
"""Test list workflow workspace files when not connected to any cluster."""
message = 'REANA client is not connected to any REANA cluster.'
runner = CliRunner()
result = runner.invoke(cli, ['list'])
assert result.exit_code == 1
assert message in result.output


def test_list_files_server_no_token():
"""Test list workflow workspace files when access token is not set."""
message = 'Please provide your access token'
env = {'REANA_SERVER_URL': 'localhost'}
runner = CliRunner(env=env)
result = runner.invoke(cli, ['list'])
assert result.exit_code == 1
assert message in result.output


def test_list_files_ok(mock_base_api_client):
"""Test list workflow workspace files successfull."""
status_code = 200
response = [
{
"last-modified": "string",
"name": "string",
"size": 0
}
]
reana_token = '000000'
env = {'REANA_SERVER_URL': 'localhost'}
mocked_api_client = mock_base_api_client(status_code,
response,
'reana-server')
config = Config(mocked_api_client)
runner = CliRunner(env=env)
result = runner.invoke(
cli,
['list', '-at', reana_token, '--workflow', 'mytest.1', '--json'],
obj=config
)
json_response = json.loads(result.output)
assert result.exit_code == 0
assert isinstance(json_response, list)
assert len(json_response) == 1
assert json_response[0]['name'] in response[0]['name']


def test_download_file(mock_base_api_client):
"""Test file downloading."""
status_code = 200
reana_token = '000000'
env = {'REANA_SERVER_URL': 'localhost'}
response = 'Content of file to download'
response_md5 = hashlib.md5(response.encode('utf-8')).hexdigest()
file = 'dummy_file.txt'
message = 'File {0} downloaded to'.format(file)
mocked_api_client = mock_base_api_client(status_code,
response,
'reana-server')
config = Config(mocked_api_client)
runner = CliRunner(env=env)
result = runner.invoke(
cli,
['download', '-at', reana_token, '--workflow', 'mytest.1', file],
obj=config
)
assert result.exit_code == 0
assert os.path.isfile(file) is True
file_md5 = hashlib.md5(open(file, 'rb').read()).hexdigest()
assert file_md5 == response_md5
assert message in result.output


def test_upload_file(mock_base_api_client, create_yaml_workflow_schema):
"""Test upload file."""
status_code = 200
reana_token = '000000'
env = {'REANA_SERVER_URL': 'localhost'}
file = 'file.txt'
response = [file]
message = 'was successfully uploaded.'
mocked_api_client = mock_base_api_client(status_code,
response,
'reana-server')
config = Config(mocked_api_client)
runner = CliRunner(env=env)
with runner.isolated_filesystem():
with open(file, 'w') as f:
f.write('test')
with open('reana.yaml', 'w') as reana_schema:
reana_schema.write(create_yaml_workflow_schema)
result = runner.invoke(
cli,
['upload', '-at', reana_token, '--workflow', 'mytest.1', file],
obj=config
)
assert result.exit_code == 0
assert message in result.output
35 changes: 31 additions & 4 deletions tests/test_cli_ping.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,36 @@

from click.testing import CliRunner

from reana_client.cli import cli
from reana_client.cli import Config, cli


def test_ping():
"""Test ping command."""
assert True
def test_ping_server_not_set():
"""Test ping when server is not set."""
runner = CliRunner()
result = runner.invoke(cli, ['ping'])
message = 'REANA client is not connected to any REANA cluster.'
assert message in result.output


def test_ping_server_not_reachable():
"""Test ping when server is set, but unreachable."""
env = {'REANA_SERVER_URL': 'localhot'}
runner = CliRunner(env=env)
result = runner.invoke(cli, ['ping'])
message = 'Could not connect to the selected'
assert message in result.output


def test_ping_ok(mock_base_api_client):
"""Test ping server is set and reachable."""
env = {'REANA_SERVER_URL': 'localhost'}
status_code = 200
response = {"status": 200, "message": "OK"}
mocked_api_client = mock_base_api_client(status_code,
response,
'reana-server')
config = Config(mocked_api_client)
runner = CliRunner(env=env)
result = runner.invoke(cli, ['ping'], obj=config)
message = 'Server is running'
assert message in result.output

0 comments on commit 2a3f6a0

Please sign in to comment.