diff --git a/.pylintrc b/.pylintrc index 76f042c633..fb3b657e18 100644 --- a/.pylintrc +++ b/.pylintrc @@ -22,7 +22,7 @@ disable=C0103,C0201,C0301,C0302,C0330,W0105,W0107,W0707,W1202,W1203,R0801 # R0801: similar lines, # too granular [IMPORTS] -ignored-modules=aiohttp,defusedxml,gym,fetch,matplotlib,memory_profiler,numpy,oef,openapi_core,psutil,tensorflow,temper,skimage,vyper,web3,aioprometheus +ignored-modules=bech32,ecdsa,lru,eth_typing,eth_keys,eth_account,ipfshttpclient,werkzeug,openapi_spec_validator,aiohttp,yoti_python_sdk,defusedxml,gym,fetch,matplotlib,memory_profiler,numpy,oef,openapi_core,psutil,tensorflow,temper,skimage,vyper,web3,aioprometheus [DESIGN] min-public-methods=1 diff --git a/aea/cli/core.py b/aea/cli/core.py index 899901d3b9..96feecac3e 100644 --- a/aea/cli/core.py +++ b/aea/cli/core.py @@ -60,8 +60,6 @@ from aea.cli.transfer import transfer from aea.cli.upgrade import upgrade from aea.cli.utils.click_utils import registry_path_option -from aea.cli.utils.config import get_or_create_cli_config -from aea.cli.utils.constants import AUTHOR_KEY from aea.cli.utils.context import Context from aea.cli.utils.loggers import logger, simple_verbosity_option from aea.helpers.win32 import enable_ctrl_c_support @@ -96,36 +94,6 @@ def cli( enable_ctrl_c_support() -@cli.command() -@click.option("-p", "--port", default=8080) -@click.option("--local", is_flag=True, help="For using local folder.") -@click.pass_context -def gui( # pylint: disable=unused-argument - click_context: click.Context, port: int, local: bool -) -> None: # pragma: no cover - """Run the CLI GUI.""" - _init_gui() - import aea.cli_gui # pylint: disable=import-outside-toplevel,redefined-outer-name - - click.echo("Running the GUI.....(press Ctrl+C to exit)") - aea.cli_gui.run(port) - - -def _init_gui() -> None: - """ - Initialize GUI before start. - - :return: None - :raisees: ClickException if author is not set up. - """ - config_ = get_or_create_cli_config() - author = config_.get(AUTHOR_KEY, None) - if author is None: - raise click.ClickException( - "Author is not set up. Please run 'aea init' and then restart." - ) - - cli.add_command(_list) cli.add_command(add_key) cli.add_command(add) diff --git a/aea/cli_gui/__init__.py b/aea/cli_gui/__init__.py deleted file mode 100644 index 51b0bbd579..0000000000 --- a/aea/cli_gui/__init__.py +++ /dev/null @@ -1,457 +0,0 @@ -# -*- coding: utf-8 -*- -# ------------------------------------------------------------------------------ -# -# Copyright 2018-2019 Fetch.AI Limited -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# ------------------------------------------------------------------------------ -"""Key pieces of functionality for CLI GUI.""" - -import glob -import os -import sys -import threading -from typing import Any, Dict, List, Tuple, Union - -import connexion -import flask -from click import ClickException - -from aea.cli.add import add_item as cli_add_item -from aea.cli.create import create_aea as cli_create_aea -from aea.cli.delete import delete_aea as cli_delete_aea -from aea.cli.fetch import fetch_agent_locally as cli_fetch_agent_locally -from aea.cli.list import list_agent_items as cli_list_agent_items -from aea.cli.registry.fetch import fetch_agent as cli_fetch_agent -from aea.cli.remove import remove_item as cli_remove_item -from aea.cli.scaffold import scaffold_item as cli_scaffold_item -from aea.cli.search import search_items as cli_search_items -from aea.cli.search import setup_search_ctx as cli_setup_search_ctx -from aea.cli.utils.config import try_to_load_agent_config -from aea.cli.utils.context import Context -from aea.cli.utils.formatting import sort_items -from aea.cli_gui.utils import ( - AppContext, - ProcessState, - call_aea_async, - get_process_status, - is_agent_dir, - read_error, - read_tty, - stop_agent_process, - terminate_processes, -) -from aea.common import JSONLike -from aea.configurations.base import PublicId -from aea.configurations.constants import AGENT, CONNECTION, CONTRACT, PROTOCOL, SKILL - - -elements = [ - ["local", AGENT, "localAgents"], - ["registered", PROTOCOL, "registeredProtocols"], - ["registered", CONNECTION, "registeredConections"], - ["registered", SKILL, "registeredSkills"], - ["local", PROTOCOL, "localProtocols"], - ["local", CONNECTION, "localConnections"], - ["local", CONTRACT, "localContracts"], - ["local", SKILL, "localSkills"], -] - - -max_log_lines = 100 - - -app_context = AppContext() - - -def get_agents() -> List[Dict]: - """Return list of all local agents.""" - file_list = glob.glob(os.path.join(app_context.agents_dir, "*")) - - agent_list = [] - - for path in file_list: - if is_agent_dir(path): - _head, tail = os.path.split(path) - agent_list.append( - { - "public_id": tail, # it is not a public_id actually, just a folder name. - # the reason it's called here so is the view that is used to represent items with public_ids - # used also for agent displaying - # change it when we will have a separate view for an agent. - "description": "placeholder description", - } - ) - - return agent_list - - -def get_registered_items( - item_type: str, -) -> Union[Tuple[List[Dict[Any, Any]], int], Tuple[Dict[str, str], int]]: - """Create a new AEA project.""" - # need to place ourselves one directory down so the cher can find the packages - ctx = Context(cwd=app_context.agents_dir) - try: - cli_setup_search_ctx(ctx, local=app_context.local) - result, _ = cli_search_items(ctx, item_type, query="", page=1) - except ClickException: - return {"detail": "Failed to search items."}, 400 # 400 Bad request - else: - sorted_items = sort_items(result) - return sorted_items, 200 # 200 (Success) - - -def search_registered_items( - item_type: str, search_term: str -) -> Union[Tuple[str, int], Tuple[Dict[str, Any], int]]: - """Create a new AEA project.""" - # need to place ourselves one directory down so the searcher can find the packages - ctx = Context(cwd=app_context.agents_dir) - try: - cli_setup_search_ctx(ctx, local=app_context.local) - result, _ = cli_search_items(ctx, item_type, query=search_term, page=1) - except ClickException: - return {"detail": "Failed to search items."}, 400 # 400 Bad request - else: - sorted_items = sort_items(result) - response = { - "search_result": sorted_items, - "item_type": item_type, - "search_term": search_term, - } - return response, 200 # 200 (Success) - - -def create_agent(agent_id: str) -> Union[Tuple[str, int], Tuple[Dict[str, str], int]]: - """Create a new AEA project.""" - ctx = Context(cwd=app_context.agents_dir) - try: - cli_create_aea(ctx, agent_id, local=app_context.local) - except ClickException as e: - return ( - {"detail": "Failed to create Agent. {}".format(str(e))}, - 400, - ) # 400 Bad request - else: - return agent_id, 201 # 201 (Created) - - -def delete_agent(agent_id: str) -> Union[Tuple[str, int], Tuple[Dict[str, str], int]]: - """Delete an existing AEA project.""" - ctx = Context(cwd=app_context.agents_dir) - try: - cli_delete_aea(ctx, agent_id) - except ClickException: - return ( - {"detail": "Failed to delete Agent {} - it may not exist".format(agent_id)}, - 400, - ) # 400 Bad request - else: - return "Agent {} deleted".format(agent_id), 200 # 200 (OK) - - -def add_item( - agent_id: str, item_type: str, item_id: str -) -> Union[Tuple[str, int], Tuple[Dict[str, str], int]]: - """Add a protocol, skill or connection to the register to a local agent.""" - ctx = Context(cwd=os.path.join(app_context.agents_dir, agent_id)) - ctx.set_config("is_local", app_context.local) - try: - try_to_load_agent_config(ctx) - cli_add_item(ctx, item_type, PublicId.from_str(item_id)) - except ClickException as e: - return ( - { - "detail": "Failed to add {} {} to agent {}. {}".format( - item_type, item_id, agent_id, str(e) - ) - }, - 400, - ) # 400 Bad request - else: - return agent_id, 201 # 200 (OK) - - -def fetch_agent(agent_id: str) -> Union[Tuple[str, int], Tuple[Dict[str, str], int]]: - """Fetch an agent.""" - ctx = Context(cwd=app_context.agents_dir) - fetch_agent_ = cli_fetch_agent_locally if app_context.local else cli_fetch_agent - try: - agent_public_id = PublicId.from_str(agent_id) - fetch_agent_(ctx, agent_public_id) - except ClickException as e: - return ( - {"detail": "Failed to fetch an agent {}. {}".format(agent_id, str(e))}, - 400, - ) # 400 Bad request - else: - return agent_public_id.name, 201 # 200 (OK) - - -def remove_local_item( - agent_id: str, item_type: str, item_id: str -) -> Union[Tuple[str, int], Tuple[Dict[str, str], int]]: - """Remove a protocol, skill or connection from a local agent.""" - agent_dir = os.path.join(app_context.agents_dir, agent_id) - ctx = Context(cwd=agent_dir) - try: - try_to_load_agent_config(ctx) - cli_remove_item(ctx, item_type, PublicId.from_str(item_id)) - except ClickException: - return ( - { - "detail": "Failed to remove {} {} from agent {}".format( - item_type, item_id, agent_id - ) - }, - 400, - ) # 400 Bad request - else: - return agent_id, 201 # 200 (OK) - - -def get_local_items(agent_id: str, item_type: str) -> Tuple[List[Dict[Any, Any]], int]: - """ - Return a list of protocols, skills or connections supported by a local agent. - - :param agent_id: the id of the agent - :param item_type: the type of item - """ - if agent_id == "NONE": - return [], 200 # 200 (Success) - - # need to place ourselves one directory down so the searcher can find the packages - ctx = Context(cwd=os.path.join(app_context.agents_dir, agent_id)) - try: - try_to_load_agent_config(ctx) - result = cli_list_agent_items(ctx, item_type) - except ClickException: - return [{"detail": "Failed to list agent items."}], 400 # 400 Bad request - else: - sorted_items = sort_items(result) - return sorted_items, 200 # 200 (Success) - - -def scaffold_item( - agent_id: str, item_type: str, item_id: str -) -> Union[Tuple[str, int], Tuple[Dict[str, str], int]]: - """Scaffold a moslty empty item on an agent (either protocol, skill or connection).""" - agent_dir = os.path.join(app_context.agents_dir, agent_id) - ctx = Context(cwd=agent_dir) - try: - try_to_load_agent_config(ctx) - cli_scaffold_item(ctx, item_type, item_id) - except ClickException: - return ( - { - "detail": "Failed to scaffold a new {} in to agent {}".format( - item_type, agent_id - ) - }, - 400, - ) # 400 Bad request - else: - return agent_id, 201 # 200 (OK) - - -def start_agent( - agent_id: str, connection_id: PublicId -) -> Union[Tuple[str, int], Tuple[Dict[str, str], int]]: - """Start a local agent running.""" - # Test if it is already running in some form - if agent_id in app_context.agent_processes: - if ( - get_process_status(app_context.agent_processes[agent_id]) - != ProcessState.RUNNING - ): # pragma: no cover - if app_context.agent_processes[agent_id] is not None: - app_context.agent_processes[agent_id].terminate() - app_context.agent_processes[agent_id].wait() - del app_context.agent_processes[agent_id] - del app_context.agent_tty[agent_id] - del app_context.agent_error[agent_id] - else: - return ( - {"detail": "Agent {} is already running".format(agent_id)}, - 400, - ) # 400 Bad request - - agent_dir = os.path.join(app_context.agents_dir, agent_id) - - if connection_id is not None and connection_id != "": - connections = get_local_items(agent_id, CONNECTION)[0] - has_named_connection = False - for element in connections: - if element["public_id"] == connection_id: - has_named_connection = True - if has_named_connection: - agent_process = call_aea_async( - [ - sys.executable, - "-m", - "aea.cli", - "run", - "--connections", - str(connection_id), - ], - agent_dir, - ) - else: - return ( - { - "detail": "Trying to run agent {} with non-existent connection: {}".format( - agent_id, connection_id - ) - }, - 400, - ) # 400 Bad request - else: - agent_process = call_aea_async( - [sys.executable, "-m", "aea.cli", "run", "--install-deps"], agent_dir - ) - - if agent_process is None: - return ( - {"detail": "Failed to run agent {}".format(agent_id)}, - 400, - ) # 400 Bad request - app_context.agent_processes[agent_id] = agent_process - app_context.agent_tty[agent_id] = [] - app_context.agent_error[agent_id] = [] - - # we don't seem to ever join this - tty_read_thread = threading.Thread( - target=read_tty, - args=(app_context.agent_processes[agent_id], app_context.agent_tty[agent_id],), - ) - tty_read_thread.start() - - # we don't seem to ever join this - error_read_thread = threading.Thread( - target=read_error, - args=( - app_context.agent_processes[agent_id], - app_context.agent_error[agent_id], - ), - ) - error_read_thread.start() - - return agent_id, 201 # 200 (OK) - - -def get_agent_status(agent_id: str) -> Tuple[JSONLike, int]: - """Get the status of the running agent Node.""" - status_str = str(ProcessState.NOT_STARTED).replace("ProcessState.", "") - tty_str = "" - error_str = "" - - # agent_id will not be in lists if we haven't run it yet - if ( - agent_id in app_context.agent_processes - and app_context.agent_processes[agent_id] is not None - ): - status_str = str( - get_process_status(app_context.agent_processes[agent_id]) - ).replace("ProcessState.", "") - - if agent_id in app_context.agent_tty: - total_num_lines = len(app_context.agent_tty[agent_id]) - for i in range(max(0, total_num_lines - max_log_lines), total_num_lines): - tty_str += app_context.agent_tty[agent_id][i] - - else: - tty_str = "" - - tty_str = tty_str.replace("\n", "
") - - if agent_id in app_context.agent_error: - total_num_lines = len(app_context.agent_error[agent_id]) - for i in range(max(0, total_num_lines - max_log_lines), total_num_lines): - error_str += app_context.agent_error[agent_id][i] - - else: - error_str = "" - - error_str = error_str.replace("\n", "
") - - return {"status": status_str, "tty": tty_str, "error": error_str}, 200 # (OK) - - -def stop_agent(agent_id: str) -> Tuple[str, int]: - """Stop agent running.""" - # pass to private function to make it easier to mock - return stop_agent_process(agent_id, app_context) - - -def create_app() -> connexion.FlaskApp: - """Run the flask server.""" - CUR_DIR = os.path.abspath(os.path.dirname(__file__)) - app = connexion.FlaskApp(__name__, specification_dir=CUR_DIR) - global app_context # pylint: disable=global-statement - app_context = AppContext() - - app_context.agent_processes = {} - app_context.agent_tty = {} - app_context.agent_error = {} - app_context.ui_is_starting = False - app_context.agents_dir = os.path.abspath(os.getcwd()) - app_context.module_dir = os.path.join( - os.path.abspath(os.path.dirname(__file__)), "../../" - ) - - app.add_api("aea_cli_rest.yaml") - - @app.route("/") - def home() -> str: # pylint: disable=unused-variable - """Respond to browser URL: localhost:5000/.""" - return flask.render_template( - "home.html", len=len(elements), htmlElements=elements - ) - - @app.route("/static/js/home.js") - def homejs() -> str: # pylint: disable=unused-variable - """Serve the home.js file (as it needs templating).""" - return flask.render_template( - "home.js", len=len(elements), htmlElements=elements - ) - - @app.route("/favicon.ico") - def favicon() -> str: # pylint: disable=unused-variable - """Return an icon to be displayed in the browser.""" - return flask.send_from_directory( - os.path.join(app.root_path, "static"), - "favicon.ico", - mimetype="image/vnd.microsoft.icon", - ) - - return app - - -def run(port: int, host: str = "127.0.0.1") -> connexion.FlaskApp: - """Run the GUI.""" - - app = create_app() - try: - app.run(host=host, port=port, debug=False) - finally: - terminate_processes() - - return app - - -def run_test() -> connexion.FlaskApp: - """Run the gui in the form where we can run tests against it.""" - app = create_app() - return app.app.test_client() diff --git a/aea/cli_gui/__main__.py b/aea/cli_gui/__main__.py deleted file mode 100644 index 7bed31763d..0000000000 --- a/aea/cli_gui/__main__.py +++ /dev/null @@ -1,46 +0,0 @@ -# -*- coding: utf-8 -*- -# ------------------------------------------------------------------------------ -# -# Copyright 2018-2019 Fetch.AI Limited -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# ------------------------------------------------------------------------------ - -"""Main entry point for CLI GUI.""" # pragma: no cover - -import argparse # pragma: no cover - -import aea.cli_gui # pragma: no cover - - -parser = argparse.ArgumentParser( - description="Launch the gui through python" -) # pragma: no cover -parser.add_argument( - "-p", "--port", help="Port that the web server listens on", type=int, default=8080 -) # pragma: no cover - -parser.add_argument( - "-H", - "--host", - help="host that the web server serves from", - type=str, - default="127.0.0.1", -) # pragma: no cover - -args, unknown = parser.parse_known_args() # pragma: no cover - -# If we're running in stand alone mode, run the application -if __name__ == "__main__": # pragma: no cover - aea.cli_gui.run(args.port, args.host) diff --git a/aea/cli_gui/aea_cli_rest.yaml b/aea/cli_gui/aea_cli_rest.yaml deleted file mode 100644 index 5bde8807ef..0000000000 --- a/aea/cli_gui/aea_cli_rest.yaml +++ /dev/null @@ -1,343 +0,0 @@ -swagger: "2.0" -info: - description: This is the swagger file that goes with our server code - version: "1.0.0" - title: Swagger Rest Article -consumes: - - application/json -produces: - - application/json - -basePath: /api - -# Paths supported by the server application -paths: - /agent: - get: - operationId: aea.cli_gui.get_agents - tags: - - agents - summary: Return list of all aea projects - description: List of local folders under the user name (which correspond to aea projects) - responses: - 200: - description: Successfully read agent list operation - schema: - type: array - items: - type: string - post: - operationId: aea.cli_gui.create_agent - tags: - - People - summary: Create a new AEA project (an agent) - parameters: - - name: agent_id - in: body - description: Name of aea project to create - required: True - schema: - type: string - - responses: - 201: - description: Successfully created person in list - - 400: - description: Cannot create agent - schema: - type: string - - /agent/{agent_id}: - delete: - operationId: aea.cli_gui.delete_agent - tags: - - agents - summary: Delete an aea project - parameters: - - name: agent_id - in: path - description: id of agent to delete - type: string - required: True - responses: - 200: - description: Agent deleted successfully - schema: - type: string - - 400: - description: Cannot delete agent - schema: - type: string - - /agent/{agent_id}/{item_type}: - post: - operationId: aea.cli_gui.add_item - tags: - - agents - summary: Fetch a protocol from the registry to the currently selected agent - parameters: - - name: agent_id - in: path - description: id of agent to add protocol to - type: string - required: True - - name: item_type - in: path - description: type of item to add ("protocol", "connection" or "skill") - type: string - required: True - - name: item_id - in: body - description: id of protocol to add - schema: - type: string - required: True - responses: - 201: - description: Protocol added successfully - schema: - type: string - - 400: - description: Cannot add protocol to agent - schema: - type: string - get: - operationId: aea.cli_gui.get_local_items - tags: - - agents - summary: Return list of all items if a given type supported by this agent - parameters: - - name: agent_id - in: path - description: id of agent to searh in - type: string - required: True - - name: item_type - in: path - description: type of item to list ("protocol", "connection" or "skill") - type: string - required: True - - responses: - 200: - description: Successfully read protocol list operation - schema: - type: array - items: - type: string - 400: - description: Cannot find protocols in agent - schema: - type: string - - /agent/{agent_id}/{item_type}/remove: - post: - operationId: aea.cli_gui.remove_local_item - tags: - - agents - summary: Delete a protocol, connection or skill from an agent - parameters: - - name: agent_id - in: path - description: id of agent to delete - type: string - required: True - - name: item_type - in: path - description: type of item to remove - type: string - required: True - - name: item_id - in: body - description: id of item to remove - schema: - type: string - required: True - - responses: - 201: - description: Agent deleted successfully - schema: - type: string - - 400: - description: Cannot delete agent - schema: - type: string - - /agent/{agent_id}/{item_type}/scaffold: - post: - operationId: aea.cli_gui.scaffold_item - tags: - - agents - summary: Scaffold a new (mostly empty) item (either a protocol, connection or skill) on to an agent - parameters: - - name: agent_id - in: path - description: id of agent to delete - type: string - required: True - - name: item_type - in: path - description: type of item to remove - type: string - required: True - - name: item_id - in: body - description: id of item to scaffold - schema: - type: string - required: True - - responses: - 201: - description: Agent deleted successfully - schema: - type: string - - 400: - description: Cannot delete agent - schema: - type: string - - /fetch-agent: - post: - operationId: aea.cli_gui.fetch_agent - tags: - - agents - summary: Fetch an agent from the registry - parameters: - - name: agent_id - in: body - description: id of agent to fetch - schema: - type: string - required: True - responses: - 201: - description: Agent fetched successfully - schema: - type: string - - 400: - description: Cannot fetch agent - schema: - type: string - - /{item_type}: - get: - operationId: aea.cli_gui.get_registered_items - tags: - - agents - summary: Return list of all registered items (protocols, connections, skills) - parameters: - - name: item_type - in: path - description: type of item to remove - type: string - required: True - responses: - 200: - description: Successfully read item list operation - schema: - type: array - items: - type: string - - /{item_type}/{search_term}: - get: - operationId: aea.cli_gui.search_registered_items - tags: - - agents - summary: Return list of all registered items (protocols, connections, skills) - parameters: - - name: item_type - in: path - description: type of item to remove - type: string - required: True - - name: search_term - in: path - description: type of item to remove - type: string - required: True - responses: - 200: - description: Successfully read item list operation - schema: - type: object - - /agent/{agent_id}/run: - post: - operationId: aea.cli_gui.start_agent - tags: - - agents - summary: Start an agent - parameters: - - name: agent_id - in: path - description: id of agent to run - type: string - required: True - - name: connection_id - in: body - description: id f the connection to activate when running - schema: - type: string - required: True - responses: - 201: - description: Start the agent - schema: - type: string - 400: - description: Cannot start agent - schema: - type: string - get: - operationId: aea.cli_gui.get_agent_status - tags: - - agents - summary: Get status of a running agent - parameters: - - name: agent_id - in: path - description: get status of agent - type: string - required: True - responses: - 200: - description: successfully got status data - schema: - type: string - - 400: - description: Cannot get status data - schema: - type: string - - delete: - operationId: aea.cli_gui.stop_agent - tags: - - agents - summary: Stops an agent - parameters: - - name: agent_id - in: path - description: id of agent to stop - type: string - required: True - - responses: - 200: - description: successfully started agent - schema: - type: string - - 400: - description: Cannot stop agent - schema: - type: string diff --git a/aea/cli_gui/static/css/home.css b/aea/cli_gui/static/css/home.css deleted file mode 100644 index e392c656a6..0000000000 --- a/aea/cli_gui/static/css/home.css +++ /dev/null @@ -1,157 +0,0 @@ -hr { - border: 1px solid #FFFFFF; - opacity: 1; -} - -nav { - background: #1E2844 0% 0% no-repeat padding-box; - height: 80px; -} - -body { - background: #161E33 0% 0% no-repeat padding-box; -} - -table { - color: #A1B6C0 !important; - border-color: #A1B6C0; -} - -thead { - color: #FFFFFF; -} - -button { - height: 26px; - border-radius: 2px; - text-align: center; - letter-spacing: -0.14px; - color: #FFFFFF; - border: none; -} - -button:hover { - color: #161E33; - background: #FFFFFF; -} - -input[type="text"] { - height: 23px; - border-radius: 2px; - border: 1px solid #FFFFFF; - color: #FFFFFF; - background: transparent; - text-indent: 4px; -} - -input[type="radio"] { - width: 19px; - height: 19px; - border: 1px solid #FFFFFF; -} - -input:focus { - outline: none !important; -} - -::selection { - color: #FFFFFF; - background: #b3d7ff; -} - -/* header items */ -.fetchai-logo { - width: auto; - margin-left: 40px; - top: 20px; - left: 47px; - width: 164px; - height: 51px; -} - -.app-title { - text-align: right; - letter-spacing: -0.2px; - color: #FFFFFF !important; -} - -/* boxes */ -.app-box { - border-radius: 4px; -} - -.app-box-green { - background: rgba(0, 185, 162, 0.1) 0% 0% no-repeat padding-box; -} - -.app-box-blue { - background: rgba(76, 130, 220, 0.1) 0% 0% no-repeat padding-box; -} - -.app-box-violet { - background: rgba(164, 90, 149, 0.1) 0% 0% no-repeat padding-box; -} - -.box-title { - text-align: center; - letter-spacing: -0.18px; -} - -/* buttons */ -.app-btn-green { - background-color: rgba(0, 185, 162, 1); -} - -.app-btn-blue { - background-color: rgba(76, 130, 220, 1); -} - -.app-btn-s { - width: 82px; -} - -.app-btn-m { - width: 110px; -} - -.app-btn-l { - width: 172px; -} - -/* inputs */ -.app-create-agent-input { - width: 183px; -} - -.app-search-input { - width: 203px; -} - -.app-connection-id-input { - width: 183px; -} - -/* miscellaneous */ -.app-output { - height: 230px; - border: 1px solid #FFFFFF; - border-radius: 4px; - overflow: auto !important; -} - -.error { - position: fixed; - /* Sit on top of the page content */ - width: 100%; - /* Full width (cover the whole page) */ - height: 10%; - /* A bit of the page */ - bottom: 0; - visibility: hidden; - border: 1px solid lightgrey; - border-radius: 0px; - background-color: #fbbd; - text-align: center; - font-weight: bold; - opacity: 50%; -} diff --git a/aea/cli_gui/static/favicon.ico b/aea/cli_gui/static/favicon.ico deleted file mode 100644 index 7b45f6eedb..0000000000 Binary files a/aea/cli_gui/static/favicon.ico and /dev/null differ diff --git a/aea/cli_gui/static/logo.png b/aea/cli_gui/static/logo.png deleted file mode 100644 index 051c4501f5..0000000000 Binary files a/aea/cli_gui/static/logo.png and /dev/null differ diff --git a/aea/cli_gui/templates/home.html b/aea/cli_gui/templates/home.html deleted file mode 100644 index 104c61a51e..0000000000 --- a/aea/cli_gui/templates/home.html +++ /dev/null @@ -1,276 +0,0 @@ - - - - - - AEA GUI - - - - - - - - - - - - - - -
- - -
- -
- - -
-
-

Local

-
- - -
-
-
- -
-
- -
-
- -
-
-
- -
- - -
Local agents
-
- - - - - - -
Agent nameDescription
-
- - Selected agent: NONE -
-
- -
- -
- - -
-
-

Registry

-
-
Search in Registry
- - -
- - -
-
- -
-
- -
-
- -
-
- - -
-
-
- -
-
- -
-
- - -
-
- -
-
- -
-
- -
-
- -
- -
- - -
Search results
-
- - - - - - - -
NONE IDDescription
- -
- - -
-
-
- -
-
- -
-
- -
-
-
- -
-
- -
- -
- - -
- -
- - -
-
- - - {% for i in range(0, len) %} - {% if htmlElements[i][0] == "local" and htmlElements[i][1] != "agent" %} -
- -

NONE's {{htmlElements[i][1]}}s

- - - - - - -
{{htmlElements[i][1]}} IDDescription
- - -
-
-
- -
-
- -
-
-
- -
- {% endif %} - {% endfor %} - -
-
- -
- -
- - -
-
-

Run "NONE" agent

-
- - -
-
-
- -
- - - -
-
- - -
-
-
- -
-
-
- - -
- Agent status: NONE -
- - -
- - -
-
-
- -
- -
- -
- - -

- - - - - - - - - - diff --git a/aea/cli_gui/templates/home.js b/aea/cli_gui/templates/home.js deleted file mode 100644 index 849e937414..0000000000 --- a/aea/cli_gui/templates/home.js +++ /dev/null @@ -1,696 +0,0 @@ -/* - * JavaScript file for the application to demonstrate - * using the API - */ - -// Create the namespace instance -var ns = {}; - -// Get elements passed in from python as this is how they need to be passed into the html -// so best to have it in one place -var elements = [] - -{%for i in range(0, len)%} - elements.push({"location": "{{htmlElements[i][0]}}", "type": "{{htmlElements[i][1]}}", "combined": "{{htmlElements[i][2]}}"}); - {% endfor %} - - - -'use strict'; - -class Model{ - constructor(){ - this.$event_pump = $('body'); - } - - readData(element) { - // This is massively hacky! - if (element["location"] == "local" && element["type"] != "agent"){ - return; - } - var ajax_options = { - type: 'GET', - url: 'api/' + element["type"], - accepts: 'application/json', - dataType: 'json' - }; - var self = this; - $.ajax(ajax_options) - .done(function(data) { - self.$event_pump.trigger('model_' + element["combined"] + 'ReadSuccess', [data]); - }) - .fail(function(xhr, textStatus, errorThrown) { - self.$event_pump.trigger('model_error', [xhr, textStatus, errorThrown]); - }) - } - - searchItems(itemType, searchTerm){ - var ajax_options = { - type: 'GET', - url: 'api/' + itemType + "/" + searchTerm, - accepts: 'application/json', - dataType: 'json' - }; - var self = this; - $.ajax(ajax_options) - .done(function(data) { - self.$event_pump.trigger('model_searchReadSuccess', [data]); - }) - .fail(function(xhr, textStatus, errorThrown) { - self.$event_pump.trigger('model_error', [xhr, textStatus, errorThrown]); - }) - } - - readAgentStatus(agentId) { - var ajax_options = { - type: 'GET', - url: 'api/agent/' + agentId + '/run', - accepts: 'application/json', - contentType: 'plain/text' - }; - var self = this; - $.ajax(ajax_options) - .done(function(data) { - self.$event_pump.trigger('model_AgentStatusReadSuccess', [data]); - }) - .fail(function(xhr, textStatus, errorThrown) { - self.$event_pump.trigger('model_error', [xhr, textStatus, errorThrown]); - }) - } - - createItem(element, id){ - var ajax_options = { - type: 'POST', - url: 'api/' + element["type"], - accepts: 'application/json', - contentType: 'application/json', - dataType: 'json', - data: JSON.stringify(id) - }; - var self = this; - $.ajax(ajax_options) - .done(function(data) { - self.$event_pump.trigger('model_' + element["combined"] + 'CreateSuccess', [data]); - }) - .fail(function(xhr, textStatus, errorThrown) { - self.$event_pump.trigger('model_error', [xhr, textStatus, errorThrown]); - }) - } - - deleteItem(element, id){ - var ajax_options = { - type: 'DELETE', - url: 'api/' + element["type"] +'/' + id, - accepts: 'application/json', - contentType: 'plain/text' - }; - var self = this; - $.ajax(ajax_options) - .done(function(data) { - self.$event_pump.trigger('model_' + element["combined"] + 'DeleteSuccess', [data]); - }) - .fail(function(xhr, textStatus, errorThrown) { - self.$event_pump.trigger('model_error', [xhr, textStatus, errorThrown]); - }) - } - - addItem(element, agentId, itemId) { - var propertyName = element["type"] + "_id" - var ajax_options = { - type: 'POST', - url: 'api/agent/' + agentId + '/' + element["type"], - accepts: 'application/json', - contentType: 'application/json', - dataType: 'json', - data: JSON.stringify(itemId) - }; - var self = this; - $.ajax(ajax_options) - .done(function(data) { - self.$event_pump.trigger('model_' + element["combined"] + 'AddSuccess', [data]); - }) - .fail(function(xhr, textStatus, errorThrown) { - self.$event_pump.trigger('model_error', [xhr, textStatus, errorThrown]); - }) - } - - fetchAgent(agentId) { - var ajax_options = { - type: 'POST', - url: 'api/fetch-agent', - accepts: 'application/json', - contentType: 'application/json', - dataType: 'json', - data: JSON.stringify(agentId) - }; - var self = this; - $.ajax(ajax_options) - .done(function(data) { - var element = {"type": $("#searchItemTypeSelected").html(), "combined": "localSkills"} - self.$event_pump.trigger('model_' + element["combined"] + 'AddSuccess', [data]); - }) - .fail(function(xhr, textStatus, errorThrown) { - self.$event_pump.trigger('model_error', [xhr, textStatus, errorThrown]); - }) - } - - - removeItem(element, agentId, itemId) { - var propertyName = element["type"] + "_id" - var ajax_options = { - type: 'POST', - url: 'api/agent/' + agentId + '/' + element["type"]+ '/remove', - accepts: 'application/json', - contentType: 'application/json', - dataType: 'json', - data: JSON.stringify(itemId) - }; - var self = this; - $.ajax(ajax_options) - .done(function(data) { - self.$event_pump.trigger('model_' + element["combined"] + 'RemoveSuccess', [data]); - }) - .fail(function(xhr, textStatus, errorThrown) { - self.$event_pump.trigger('model_error', [xhr, textStatus, errorThrown]); - }) - } - - readLocalData(element, agentId) { - var ajax_options = { - type: 'GET', - url: 'api/agent/'+agentId+'/' + element["type"], - accepts: 'application/json', - dataType: 'json' - }; - var self = this; - $.ajax(ajax_options) - .done(function(data) { - self.$event_pump.trigger('model_' + element["combined"] + 'ReadSuccess', [data]); - }) - .fail(function(xhr, textStatus, errorThrown) { - self.$event_pump.trigger('model_error', [xhr, textStatus, errorThrown]); - }) - } - scaffoldItem(element, agentId, itemId){ - var ajax_options = { - type: 'POST', - url: 'api/agent/' + agentId + "/" + element["type"] + "/scaffold", - accepts: 'application/json', - contentType: 'application/json', - dataType: 'json', - data: JSON.stringify(itemId) - }; - var self = this; - $.ajax(ajax_options) - .done(function(data) { - self.$event_pump.trigger('model_' + element["combined"] + 'ScaffoldSuccess', [data]); - }) - .fail(function(xhr, textStatus, errorThrown) { - self.$event_pump.trigger('model_error', [xhr, textStatus, errorThrown]); - }) - } - startAgent(agentId, runConnectionId){ - var ajax_options = { - type: 'POST', - url: 'api/agent/' + agentId + '/run', - accepts: 'application/json', - contentType: 'application/json', - dataType: 'json', - data: JSON.stringify(runConnectionId) - }; - var self = this; - $.ajax(ajax_options) - .done(function(data) { - self.$event_pump.trigger('model_StartAgentSuccess', [data]); - }) - .fail(function(xhr, textStatus, errorThrown) { - self.$event_pump.trigger('model_error', [xhr, textStatus, errorThrown]); - }) - } - stopAgent(agentId){ - var ajax_options = { - type: 'DELETE', - url: 'api/agent/' + agentId + '/run', - accepts: 'application/json', - contentType: 'plain/text' - }; - var self = this; - $.ajax(ajax_options) - .done(function(data) { - self.$event_pump.trigger('model_StopAgentSuccess', [data]); - }) - .fail(function(xhr, textStatus, errorThrown) { - self.$event_pump.trigger('model_error', [xhr, textStatus, errorThrown]); - }) - } - - -} - -class View{ - constructor(){ - this.$event_pump = $('body'); - - } - setAgentStatus(status){ - $('#agentStatus').html(status); - } - setAgentTTY(tty){ - $('#agentTTY').html(tty); - $('#agentTTY').scrollTop($('#agentTTY')[0].scrollHeight); - } - setAgentError(error){ - $('#agentError').html(error); - $('#agentError').scrollTop($('#agentError')[0].scrollHeight); - } - setSearchType(itemType){ - $('#searchItemTypeTable').html(itemType); - $('#searchItemTypeSelected').html(itemType); - } - - setCreateId(tag, id) { - $('#'+tag+'CreateId').val(id); - } - - setSelectedId(tag, id) { - $('#'+tag+'SelectionId').html(id); - } - - setScaffoldId(tag, id) { - $('#'+tag+'ScaffoldId').val(id); - } - - build_table(data, tableName) { - var rows = '' - - // clear the table - $('.' + tableName + ' table > tbody').empty(); - - // did we get a people array? - if (tableName) { - for (let i=0, l=data.length; i < l; i++) { - rows += `${data[i].public_id}${data[i].description}`; - } - $('.' + tableName + ' table > tbody').append(rows); - } - } - - error(error_msg) { - $('.error') - .html("
" + error_msg) - .css('visibility', 'visible'); - setTimeout(function() { - $('.error').css('visibility', 'hidden'); - }, 3000) - } - -} - -class Controller{ - constructor(m, v){ - this.model = m; - this.view = v; - this.$event_pump = $('body'); - - // Get the data from the model after the controller is done initializing - var self = this; - setTimeout(function() { - for (var i = 0; i < elements.length; ++i){ - self.model.readData(elements[i]); - } - }, 100) - - // Go through each of the element types setting up call-back and table building functions on the - // Items which exist - var self = this; - for (var i = 0; i < elements.length; i++) { - var element = elements[i] - var combineName = element["combined"] - $('#' + combineName + 'Create').click({el: element}, function(e){ - var id =$('#' + e.data.el["combined"] + 'CreateId').val(); - - e.preventDefault(); - - if (self.validateId(id)){ - self.model.createItem(e.data.el, id) - } else { - alert('Error: Problem with id'); - } - }); - - $('#' + combineName + 'Delete').click({el: element}, function(e) { - var id =$('#' + e.data.el["combined"] + 'SelectionId').html(); - if (confirm("This will completely remove agent: " + id + "'s code and is non-recoverable. Press OK to do this - otherwise press cancel")){ - - e.preventDefault(); - - if (self.validateId(id)) { - self.model.deleteItem(e.data.el, id) - self.view.setSelectedId(e.data.el["combined"], "NONE") - } else { - alert('Error: Problem with selected id'); - } - e.preventDefault(); - } - }); - - $('#' + combineName + 'Add').click({el: element}, function(e) { - var agentId = $('#localAgentsSelectionId').html(); - var itemId =$('#' + e.data.el["combined"] + 'SelectionId').html(); - - e.preventDefault(); - - if (self.validateId(agentId) && self.validateId(itemId) ) { - self.model.addItem(e.data.el, agentId, itemId) - self.view.setSelectedId(e.data.el["combined"], "NONE") - var tableBody = $("."+ e.data.el["combined"] +"registeredTable"); - self.clearTable(tableBody); - - - } else { - alert('Error: Problem with one of the selected ids (either agent or ' + element['type']); - } - e.preventDefault(); - }); - $('#' + combineName + 'Remove').click({el: element}, function(e) { - var agentId = $('#localAgentsSelectionId').html(); - var itemId =$('#' + e.data.el["combined"] + 'SelectionId').html(); - - e.preventDefault(); - - if (self.validateId(agentId) && self.validateId(itemId) ) { - self.model.removeItem(e.data.el, agentId, itemId) - self.view.setSelectedId(e.data.el["combined"], "NONE") - - - } else { - alert('Error: Problem with one of the selected ids (either agent or ' + element['type']); - } - e.preventDefault(); - }); - - $('.' + combineName + ' table > tbody ').on('click', 'tr', {el: element}, function(e) { - - var $target = $(e.target), - id, - description; - - id = $target - .parent() - .find('td.id') - .text(); - - - self.view.setSelectedId(e.data.el["combined"], id); - - // Select the appropriate row - var tableBody = $(e.target).closest("."+ e.data.el["combined"] +"registeredTable"); - self.clearTable(tableBody); - - $(this).addClass("aea_selected") - if (e.data.el["combined"] == "localAgents"){ - self.refreshAgentData(id) - } - self.handleButtonStates() - }); - - $('#' + combineName + 'Scaffold').click({el: element}, function(e){ - var agentId = $('#localAgentsSelectionId').html(); - var itemId =$('#' + e.data.el["combined"] + 'ScaffoldId').val(); - - e.preventDefault(); - - if (self.validateId(agentId) && self.validateId(itemId)){ - self.model.scaffoldItem(e.data.el, agentId, itemId) - } else { - alert('Error: Problem with id'); - } - }); - - // Handle the model events - this.$event_pump.on('model_'+ combineName + 'ReadSuccess', {el: element}, function(e, data) { - self.view.build_table(data, e.data.el["combined"]); - }); - - this.$event_pump.on('model_'+ combineName + 'CreateSuccess', {el: element}, function(e, data) { - self.model.readData(e.data.el); - self.view.setSelectedId(e.data.el["combined"], data) - self.view.setCreateId(e.data.el["combined"], "") - self.refreshAgentData(data) - self.handleButtonStates() - }); - - this.$event_pump.on('model_'+ combineName + 'DeleteSuccess', {el: element}, function(e, data) { - self.model.readData(e.data.el); - - self.refreshAgentData("NONE") - self.handleButtonStates() - - }); - this.$event_pump.on('model_'+ combineName + 'AddSuccess', {el: element}, function(e, data) { - self.refreshAgentData(data) - self.handleButtonStates() - - }); - this.$event_pump.on('model_'+ combineName + 'RemoveSuccess', {el: element}, function(e, data) { - self.refreshAgentData(data) - self.handleButtonStates() - - }); - this.$event_pump.on('model_'+ combineName + 'ScaffoldSuccess', {el: element}, function(e, data) { - self.refreshAgentData(data) - self.view.setScaffoldId(e.data.el["combined"], "") - self.handleButtonStates() - }); - - } - - this.$event_pump.on('model_AgentStatusReadSuccess', function(e, data) { - self.view.setAgentStatus("Agent Status: " + data["status"]) - self.view.setAgentTTY(data["tty"]) - self.view.setAgentError(data["error"]) - self.handleButtonStates() - }); - - this.$event_pump.on('model_searchReadSuccess', function(e, data) { - self.view.setSearchType(data["item_type"]) - self.view.build_table(data["search_result"], 'searchItemsTable'); - self.handleButtonStates() - }); - - $('#startAgent').click({el: element}, function(e) { - e.preventDefault(); - var agentId = $('#localAgentsSelectionId').html() - var connectionId = $('#runConnectionId').val() - if (self.validateId(agentId)){ - self.model.startAgent(agentId, connectionId) - } - else{ - alert('Error: Attempting to start agent with ID: ' + agentId); - } - - e.preventDefault(); - }); - $('#stopAgent').click({el: element}, function(e) { - e.preventDefault(); - var agentId = $('#localAgentsSelectionId').html() - if (self.validateId(agentId)){ - self.model.stopAgent(agentId) - } - else{ - alert('Error: Attempting to stop agent with ID: ' + agentId); - } - - e.preventDefault(); - }); - $('#searchInputButton').click({el: element}, function(e) { - e.preventDefault(); - var searchTerm = $('#searchInput').val() - if (self.validateId(searchTerm)){ - var itemType = $("input[name='itemType']:checked").attr('id') - self.model.searchItems(itemType, searchTerm) - } - else{ - alert('Error: Attempting to stop search for: ' + searchTerm); - } - - e.preventDefault(); - }); - - $('.searchItemsTable table > tbody ').on('click', 'tr', {el: element}, function(e) { - - var $target = $(e.target), - id, - description; - - id = $target - .parent() - .find('td.id') - .text(); - - - self.view.setSelectedId("searchItemsTable", id); - - // Select the appropriate row - var tableBody = $(e.target).closest(".searchItemsTableRegisteredTable"); - self.clearTable(tableBody); - - $(this).addClass("aea_selected") - - self.handleButtonStates() - }); - - - $('#searchItemsAdd').click({el: element}, function(e) { - var agentId = $('#localAgentsSelectionId').html(); - var itemId = $('#searchItemsTableSelectionId').html(); - // It doesn't matter too much what the combined name is as long as it exists - var itemType = {"type": $("#searchItemTypeSelected").html(), "combined": "localSkills"} - - e.preventDefault(); - - if (self.validateId(agentId) && self.validateId(itemId) ) { - self.model.addItem(itemType, agentId, itemId) - self.view.setSelectedId("searchItemsTable", "NONE") - var tableBody = $(e.target).closest(".searchItemsTableRegisteredTable"); - self.clearTable(tableBody); - } else { - alert('Error: Problem with one of the selected ids (either agent or ' + itemType); - } - e.preventDefault(); - }); - - $('#searchAgentsFetch').click({el: element}, function(e) { - var agentId = $('#searchItemsTableSelectionId').html(); - // It doesn't matter too much what the combined name is as long as it exists - var itemType = {"type": $("#searchItemTypeSelected").html(), "combined": "localSkills"} - - e.preventDefault(); - - if (self.validateId(agentId) ) { - self.model.fetchAgent(agentId) - self.view.setSelectedId("searchItemsTable", "NONE") - var tableBody = $(e.target).closest(".searchItemsTableRegisteredTable"); - self.clearTable(tableBody); - } else { - alert('Error: Problem with one of the selected ids (either agent or ' + itemType); - } - e.preventDefault(); - }); - - - this.$event_pump.on('model_error', {el: element}, function(e, xhr, textStatus, errorThrown) { - var error_msg = textStatus + ': ' + errorThrown + ' - ' + xhr.responseJSON.detail; - self.view.error(error_msg); - console.log(error_msg); - }) - - this.handleButtonStates(this); - - - $('#localAgentsCreateId').on('input', function(e){ - self.handleButtonStates() - }); - $('#localAgentsSelectionId').on('input', function(e){ - self.handleButtonStates() - }); - $('#searchInput').on('input', function(e){ - self.handleButtonStates() - }); - - for (var j = 0; j < elements.length; j++) { - $('#'+ elements[j]["combined"] + 'ScaffoldId').on('input', function(e){ - self.handleButtonStates()}); - } - - this.getAgentStatus(); - - } - - clearTable (tableBody) { - tableBody.children().each(function(i) { - $(this).removeClass("aea_selected") - }); - } - - handleButtonStates(){ - var agentCreateId = $('#localAgentsCreateId').val(); - var agentSelectionId = $('#localAgentsSelectionId').html(); - $('#localAgentsCreate').prop('disabled', !this.validateId(agentCreateId)); - $('#localAgentsDelete').prop('disabled', !this.validateId(agentSelectionId)); - - for (var j = 0; j < elements.length; j++) { - if (elements[j]["location"] == "local" && elements[j]["type"] != "agent"){ - var itemSelectionId = $('#' + elements[j]["combined"] + 'SelectionId').html(); - var isDisabled = !this.validateId(itemSelectionId); - $('#' + elements[j]["combined"] + 'Remove').prop('disabled', isDisabled); - - var itemScaffoldId = $('#' + elements[j]["combined"] + 'ScaffoldId').val(); - $('#' + elements[j]["combined"] + 'Scaffold').prop('disabled', - !this.validateId(itemScaffoldId) || - !this.validateId(agentSelectionId)); - - - } - if (elements[j]["location"] == "registered"){ - var itemSelectionId = $('#' + elements[j]["combined"] + 'SelectionId').html(); - var isDisabled = !this.validateId(itemSelectionId) || !this.validateId(agentSelectionId); - $('#' + elements[j]["combined"] + 'Add').prop('disabled', isDisabled); - } - } - // Search buttons - var searchTerm = $('#searchInput').val(); - $('#searchInputButton').prop('disabled', !this.validateId(searchTerm)); - var searchItem = $('#searchItemsTableSelectionId').html(); - var itemType = $("#searchItemTypeSelected").html(); - var isDisabled = !this.validateId(searchItem) || !this.validateId(agentSelectionId) || (itemType == "agent"); - $('#searchItemsAdd').prop('disabled', isDisabled); - - var isDisabled = !this.validateId(searchItem) || (itemType != "agent"); - $('#searchAgentsFetch').prop('disabled', isDisabled); - if (agentSelectionId != "NONE"){ - $('.localItemHeading').html(agentSelectionId); - } - else{ - $('.localItemHeading').html("Local"); - - } - } - - getAgentStatus(){ - var agentId = $('#localAgentsSelectionId').html() - self = this - if (self.validateId(agentId)){ - this.model.readAgentStatus(agentId) - } - else{ - self.view.setAgentStatus("Agent Status: NONE") - self.view.setAgentTTY("




") - self.view.setAgentError("




") - } - setTimeout(function() { - self.getAgentStatus() - }, 500) - - } - - // Update lists of protocols, connections and skills for the selected agent - refreshAgentData(agentId){ - for (var j = 0; j < elements.length; j++) { - if (elements[j]["location"] == "local" && elements[j]["type"] != "agent"){ - this.model.readLocalData(elements[j], agentId); - } - } - } - - - validateId(agentId){ - return agentId != "" && agentId != "NONE"; - } - - -} - -$( document ).ready(function() { - c = new Controller(new Model(), new View()) -}); diff --git a/aea/cli_gui/utils.py b/aea/cli_gui/utils.py deleted file mode 100644 index 4003c97881..0000000000 --- a/aea/cli_gui/utils.py +++ /dev/null @@ -1,193 +0,0 @@ -# -*- coding: utf-8 -*- -# ------------------------------------------------------------------------------ -# -# Copyright 2018-2020 Fetch.AI Limited -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# ------------------------------------------------------------------------------ -"""Module with utils for CLI GUI.""" - -import io -import logging -import os -import subprocess # nosec -import sys -import threading -from enum import Enum -from typing import Any, Dict, List, Optional, Set, Tuple - - -class AppContext: # pylint: disable=too-few-public-methods - """Store useful global information about the app. - - Can't add it into the app object itself because mypy complains. - """ - - agent_processes: Dict[str, subprocess.Popen] = {} - agent_tty: Dict[str, List[str]] = {} - agent_error: Dict[str, List[str]] = {} - - ui_is_starting = False - agents_dir = os.path.abspath(os.getcwd()) - module_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)), "../../") - - local = "--local" in sys.argv # a hack to get "local" option from cli args - - -class ProcessState(Enum): - """The state of execution of the agent.""" - - NOT_STARTED = "Not started yet" - RUNNING = "Running" - STOPPING = "Stopping" - FINISHED = "Finished" - FAILED = "Failed" - - -_processes = set() # type: Set[subprocess.Popen] -lock = threading.Lock() - - -def _call_subprocess(*args: Any, timeout: Optional[float] = None, **kwargs: Any) -> int: - """ - Create a subprocess.Popen, but with error handling. - - :return the exit code, or -1 if the call raises exception. - """ - process = subprocess.Popen(*args) # nosec - ret = -1 - try: - ret = process.wait(timeout=timeout) - except subprocess.TimeoutExpired: - logging.exception( - "TimeoutError occurred when calling with args={} and kwargs={}".format( - args, kwargs - ) - ) - finally: - _terminate_process(process) - return ret - - -def is_agent_dir(dir_name: str) -> bool: - """Return true if this directory contains an AEA project (an agent).""" - if not os.path.isdir(dir_name): - return False - return os.path.isfile(os.path.join(dir_name, "aea-config.yaml")) - - -def call_aea_async(param_list: List[str], dir_arg: str) -> subprocess.Popen: - """Call the aea in a subprocess.""" - # Should lock here to prevent multiple calls coming in at once and changing the current working directory weirdly - with lock: - old_cwd = os.getcwd() - - os.chdir(dir_arg) - env = os.environ.copy() - env["PYTHONUNBUFFERED"] = "1" - ret = subprocess.Popen( # nosec - param_list, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env - ) - _processes.add(ret) - os.chdir(old_cwd) - return ret - - -def read_tty(pid: subprocess.Popen, str_list: List[str]) -> None: - """ - Read tty. - - :param pid: the process id - :param str_list: the output list to append to. - """ - for line in io.TextIOWrapper(pid.stdout, encoding="utf-8"): - out = line.replace("\n", "") - logging.info("stdout: {}".format(out)) - str_list.append(line) - - str_list.append("process terminated\n") - - -def read_error(pid: subprocess.Popen, str_list: List[str]) -> None: - """ - Read error. - - :param pid: the process id - :param str_list: the output list to append to. - """ - for line in io.TextIOWrapper(pid.stderr, encoding="utf-8"): - out = line.replace("\n", "") - logging.error("stderr: {}".format(out)) - str_list.append(line) - - str_list.append("process terminated\n") - - -def stop_agent_process(agent_id: str, app_context: AppContext) -> Tuple[str, int]: - """ - Stop an agent processs. - - :param agent_id: the agent id - :param app_context: the app context - """ - # Test if we have the process id - if agent_id not in app_context.agent_processes: - return ( - "detail: Agent {} is not running".format(agent_id), - 400, - ) # 400 Bad request - - app_context.agent_processes[agent_id].terminate() - app_context.agent_processes[agent_id].wait() - del app_context.agent_processes[agent_id] - - return "stop_agent: All fine {}".format(agent_id), 200 # 200 (OK) - - -def _terminate_process(process: subprocess.Popen) -> None: - """Try to process gracefully.""" - poll = process.poll() - if poll is None: - # send SIGTERM - process.terminate() - try: - # wait for termination - process.wait(3) - except subprocess.TimeoutExpired: - # send SIGKILL - process.kill() - - -def terminate_processes() -> None: - """Terminate all the (async) processes instantiated by the GUI.""" - logging.info("Cleaning up...") - for process in _processes: # pragma: no cover - _terminate_process(process) - - -def get_process_status(process_id: subprocess.Popen) -> ProcessState: - """ - Return the state of the execution. - - :param process_id: the process id - """ - if process_id is None: # pragma: nocover - raise ValueError("Process id cannot be None!") - - return_code = process_id.poll() - if return_code is None: - return ProcessState.RUNNING - if return_code <= 0: - return ProcessState.FINISHED - return ProcessState.FAILED diff --git a/docs/assets/cli_gui01_clean.png b/docs/assets/cli_gui01_clean.png deleted file mode 100644 index 85b985a332..0000000000 Binary files a/docs/assets/cli_gui01_clean.png and /dev/null differ diff --git a/docs/assets/cli_gui02_sequence_01.png b/docs/assets/cli_gui02_sequence_01.png deleted file mode 100644 index 8d5bdb083b..0000000000 Binary files a/docs/assets/cli_gui02_sequence_01.png and /dev/null differ diff --git a/docs/assets/cli_gui02_sequence_02.png b/docs/assets/cli_gui02_sequence_02.png deleted file mode 100644 index 85437ba335..0000000000 Binary files a/docs/assets/cli_gui02_sequence_02.png and /dev/null differ diff --git a/docs/assets/cli_gui03_oef_node.png b/docs/assets/cli_gui03_oef_node.png deleted file mode 100644 index 9113921cf5..0000000000 Binary files a/docs/assets/cli_gui03_oef_node.png and /dev/null differ diff --git a/docs/assets/cli_gui04_new_agent.png b/docs/assets/cli_gui04_new_agent.png deleted file mode 100644 index 87dc151533..0000000000 Binary files a/docs/assets/cli_gui04_new_agent.png and /dev/null differ diff --git a/docs/assets/cli_gui05_full_running_agent.png b/docs/assets/cli_gui05_full_running_agent.png deleted file mode 100644 index b2ca910b60..0000000000 Binary files a/docs/assets/cli_gui05_full_running_agent.png and /dev/null differ diff --git a/docs/cli-commands.md b/docs/cli-commands.md index f4114bff19..c909e1a774 100644 --- a/docs/cli-commands.md +++ b/docs/cli-commands.md @@ -19,7 +19,6 @@ | `get-address [ledger_id]` | Get the address associated with the private key. | | `get-multiaddress [ledger_id]...` | Get the multiaddress associated with a private key or connection. | | `get-wealth [ledger_id]` | Get the wealth associated with the private key. | -| `gui` | Run the GUI. | | `init` | Initialize your AEA configurations. (With `--author` to define author.) | | `install [-r ]` | Install the dependencies. (With `--install-deps` to install dependencies.) | | `interact` | Interact with a running AEA via the stub connection. | diff --git a/docs/cli-gui.md b/docs/cli-gui.md deleted file mode 100644 index 00e3b33e07..0000000000 --- a/docs/cli-gui.md +++ /dev/null @@ -1,56 +0,0 @@ -You can invoke the AEA Command Line Interface (CLI) from a Graphical User Interface (GUI) accessed from a web browser. - -These instructions will take you through building an AEA and running the AEA - all from the GUI. - -## Preliminaries - -Follow the Preliminaries and Installation instructions here. - -Install the extra dependencies for the CLI GUI. - -``` bash -pip install aea[cli_gui] -``` - - -## Starting the GUI - -Go to the directory in which you will create new AEAs. If you followed the quick start guide, this will be `my_aea`. It is important to start the GUI not from within an agent project but its parent directory instead. - -Start the local web-server. -``` bash -aea gui -``` -Open this page in a browser: http://127.0.0.1:8001 - -You should see the following page. - -new gui screen - -On the left-hand side we can see any AEAs you have created and beneath that the protocols, connections and skills they have. Initially this will be empty - unless you have followed the quick start guide previously and not deleted those AEAs. - -On the right-hand side is a search interface to the Registry which gives you access to protocols, connections, and skills which are available to add to your AEA. - -To create a new AEA and run it, follow these steps. - -gui sequence - -1. In the [Create Agent id] box on the left. type the name of your AEA - e.g. `my_new_aea`. -2. Click the [Create Agent] button - the newly created AEA should appear in the [Local Agents] table. This should now be the currently selected AEA - but you can click on its name in the list to make sure. -3. Click in the search input box and type "echo" -4. Click the [Search] button - this will list all the skills with echo in their name or description. Note that at present this search functionality is not working and it will list all the skills - -gui sequence - -5. Find the Echo skill and click on it - this will select it. -6. Click on the [Add skill] button - which should now say "Add echo skill to `my_new_aea` agent". - -7. Start the AEA running by clicking on the [start agent] button. You should see the output from the echo AEA appearing on the screen. - -start AEA - -This is how your whole page should look if you followed the instructions correctly. - -whole screen running - -
diff --git a/mkdocs.yml b/mkdocs.yml index ac801766a1..5b74188af3 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -93,8 +93,7 @@ nav: - Installation: 'cli-how-to.md' - Commands: 'cli-commands.md' - File structure: 'package-imports.md' - - Generating wealth: 'wealth.md' - - GUI: 'cli-gui.md' + - Generating wealth: 'wealth.md' - Benchmarks: - Performance benchmark: 'performance-benchmark.md' - API: diff --git a/plugins/aea-crypto-cosmos/aea_crypto_cosmos/cosmos.py b/plugins/aea-crypto-cosmos/aea_crypto_cosmos/cosmos.py index eb98c4f8bf..8cb41ffed4 100644 --- a/plugins/aea-crypto-cosmos/aea_crypto_cosmos/cosmos.py +++ b/plugins/aea-crypto-cosmos/aea_crypto_cosmos/cosmos.py @@ -32,9 +32,17 @@ from pathlib import Path from typing import Any, BinaryIO, Collection, Dict, List, Optional, Tuple, cast -from bech32 import bech32_decode, bech32_encode, convertbits -from ecdsa import SECP256k1, SigningKey, VerifyingKey -from ecdsa.util import sigencode_string_canonize +from bech32 import ( # pylint: disable=wrong-import-order + bech32_decode, + bech32_encode, + convertbits, +) +from ecdsa import ( # pylint: disable=wrong-import-order + SECP256k1, + SigningKey, + VerifyingKey, +) +from ecdsa.util import sigencode_string_canonize # pylint: disable=wrong-import-order from aea.common import Address, JSONLike from aea.crypto.base import Crypto, FaucetApi, Helper, LedgerApi diff --git a/plugins/aea-crypto-fetchai/aea_crypto_fetchai/_cosmos.py b/plugins/aea-crypto-fetchai/aea_crypto_fetchai/_cosmos.py index eb98c4f8bf..8cb41ffed4 100644 --- a/plugins/aea-crypto-fetchai/aea_crypto_fetchai/_cosmos.py +++ b/plugins/aea-crypto-fetchai/aea_crypto_fetchai/_cosmos.py @@ -32,9 +32,17 @@ from pathlib import Path from typing import Any, BinaryIO, Collection, Dict, List, Optional, Tuple, cast -from bech32 import bech32_decode, bech32_encode, convertbits -from ecdsa import SECP256k1, SigningKey, VerifyingKey -from ecdsa.util import sigencode_string_canonize +from bech32 import ( # pylint: disable=wrong-import-order + bech32_decode, + bech32_encode, + convertbits, +) +from ecdsa import ( # pylint: disable=wrong-import-order + SECP256k1, + SigningKey, + VerifyingKey, +) +from ecdsa.util import sigencode_string_canonize # pylint: disable=wrong-import-order from aea.common import Address, JSONLike from aea.crypto.base import Crypto, FaucetApi, Helper, LedgerApi diff --git a/scripts/generate_api_docs.py b/scripts/generate_api_docs.py index db36bdbead..c013afa83d 100755 --- a/scripts/generate_api_docs.py +++ b/scripts/generate_api_docs.py @@ -50,7 +50,6 @@ IGNORE_NAMES = {r"^__init__\.py$", r"^__version__\.py$", r"^py\.typed$", r"^.*_pb2.py$"} IGNORE_PREFIXES = { - Path("aea", "cli_gui"), Path("aea", "cli"), Path("aea", "connections", "scaffold"), Path("aea", "contracts", "scaffold"), diff --git a/scripts/whitelist.py b/scripts/whitelist.py index a727fdd31c..1de4439340 100644 --- a/scripts/whitelist.py +++ b/scripts/whitelist.py @@ -32,7 +32,6 @@ _.tick # unused property (aea/agent.py:186) AgentLoopException # unused class (aea/agent_loop.py:134) set_command # unused function (aea/cli/config.py:53) -gui # unused function (aea/cli/core.py:84) all_command # unused function (aea/cli/list.py:47) _.type_cast_value # unused method (aea/cli/utils/click_utils.py:37) _.get_metavar # unused method (aea/cli/utils/click_utils.py:79) @@ -42,25 +41,6 @@ _.convert # unused method (aea/cli/utils/click_utils.py:129) _.formatter # unused attribute (aea/cli/utils/loggers.py:92) is_item_present_unified # unused function (aea/cli/utils/package_utils:394) -ui_is_starting # unused variable (aea/cli_gui/__init__.py:86) -module_dir # unused variable (aea/cli_gui/__init__.py:88) -get_agents # unused function (aea/cli_gui/__init__.py:96) -get_registered_items # unused function (aea/cli_gui/__init__.py:118) -search_registered_items # unused function (aea/cli_gui/__init__.py:132) -create_agent # unused function (aea/cli_gui/__init__.py:151) -delete_agent # unused function (aea/cli_gui/__init__.py:165) -remove_local_item # unused function (aea/cli_gui/__init__.py:215) -start_agent # unused function (aea/cli_gui/__init__.py:273) -get_agent_status # unused function (aea/cli_gui/__init__.py:358) -stop_agent # unused function (aea/cli_gui/__init__.py:396) -_.ui_is_starting # unused attribute (aea/cli_gui/__init__.py:412) -_.module_dir # unused attribute (aea/cli_gui/__init__.py:414) -homejs # unused function (aea/cli_gui/__init__.py:427) -favicon # unused function (aea/cli_gui/__init__.py:434) -run_test # unused function (aea/cli_gui/__init__.py:458) -unknown # unused variable (aea/cli_gui/__main__.py:41) -STOPPING # unused variable (aea/cli_gui/utils.py:35) -_call_subprocess # unused function (aea/cli_gui/utils.py:44) _.latest # unused property (aea/configurations/base.py:384) _.to_any # unused property (aea/configurations/base.py:442) _.to_latest # unused property (aea/configurations/base.py:442) diff --git a/setup.py b/setup.py index a8269e36e2..e9a2077155 100644 --- a/setup.py +++ b/setup.py @@ -36,11 +36,8 @@ def get_all_extras() -> Dict: "packaging>=20.3", ] - cli_gui = ["flask", "connexion[swagger-ui]>=2.4.0", *cli_deps] - extras = { "cli": cli_deps, - "cli_gui": cli_gui, "test_tools": cli_deps, } diff --git a/tests/test_cli/test_core.py b/tests/test_cli/test_core.py deleted file mode 100644 index 865043f859..0000000000 --- a/tests/test_cli/test_core.py +++ /dev/null @@ -1,44 +0,0 @@ -# -*- coding: utf-8 -*- -# ------------------------------------------------------------------------------ -# -# Copyright 2018-2020 Fetch.AI Limited -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# ------------------------------------------------------------------------------ -"""This test module contains the tests for CLI core methods.""" - -from unittest import TestCase, mock - -from click import ClickException - -from aea.cli.core import _init_gui -from aea.cli.utils.constants import AUTHOR_KEY - - -@mock.patch("aea.cli.core.get_or_create_cli_config") -class InitGuiTestCase(TestCase): - """Test case for _init_gui method.""" - - def test__init_gui_positive(self, get_or_create_cli_config_mock): - """Test _init_gui method for positive result.""" - config = {AUTHOR_KEY: "author"} - get_or_create_cli_config_mock.return_value = config - - _init_gui() - - def test__init_gui_negative(self, get_or_create_cli_config_mock): - """Test _init_gui method for negative result.""" - get_or_create_cli_config_mock.return_value = {} - with self.assertRaises(ClickException): - _init_gui() diff --git a/tests/test_cli/test_gui.py b/tests/test_cli/test_gui.py deleted file mode 100644 index 09981670d3..0000000000 --- a/tests/test_cli/test_gui.py +++ /dev/null @@ -1,89 +0,0 @@ -# -*- coding: utf-8 -*- -# ------------------------------------------------------------------------------ -# -# Copyright 2018-2019 Fetch.AI Limited -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# ------------------------------------------------------------------------------ -"""This test module contains the tests for the `aea gui` sub-command.""" -import json -import os -import shutil -import sys -import tempfile -from pathlib import Path - -import jsonschema -import pytest -from jsonschema import Draft4Validator - -from aea.cli import cli -from aea.configurations.loader import make_jsonschema_base_uri -from aea.test_tools.click_testing import CliRunner - -from tests.common.pexpect_popen import PexpectWrapper -from tests.conftest import ( - AGENT_CONFIGURATION_SCHEMA, - AUTHOR, - CLI_LOG_OPTION, - CONFIGURATION_SCHEMA_DIR, - MAX_FLAKY_RERUNS, - tcpping, -) - - -class TestGui: - """Test that the command 'aea gui' works as expected.""" - - def setup(self): - """Set the test up.""" - self.runner = CliRunner() - self.schema = json.load(open(AGENT_CONFIGURATION_SCHEMA)) - self.resolver = jsonschema.RefResolver( - make_jsonschema_base_uri(Path(CONFIGURATION_SCHEMA_DIR).absolute()), - self.schema, - ) - self.validator = Draft4Validator(self.schema, resolver=self.resolver) - - self.agent_name = "myagent" - self.cwd = os.getcwd() - self.t = tempfile.mkdtemp() - os.chdir(self.t) - result = self.runner.invoke( - cli, [*CLI_LOG_OPTION, "init", "--local", "--author", AUTHOR], - ) - - assert result.exit_code == 0 - - @pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS) - def test_gui(self): - """Test that the gui process has been spawned correctly.""" - self.proc = PexpectWrapper( # nosec - [sys.executable, "-m", "aea.cli", "-v", "DEBUG", "gui"], - encoding="utf-8", - logfile=sys.stdout, - ) - self.proc.expect_exact(["Running on http://"], timeout=40) - - assert tcpping("127.0.0.1", 8080) - - def teardown(self): - """Tear the test down.""" - self.proc.terminate() - self.proc.wait_to_complete(10) - os.chdir(self.cwd) - try: - shutil.rmtree(self.t) - except OSError: - pass diff --git a/tests/test_cli/test_misc.py b/tests/test_cli/test_misc.py index 193256153b..5a1b2aaa10 100644 --- a/tests/test_cli/test_misc.py +++ b/tests/test_cli/test_misc.py @@ -77,7 +77,6 @@ def test_flag_help(): get-address Get the address associated with a private key of the... get-multiaddress Get the multiaddress associated with a private key or... get-wealth Get the wealth associated with the private key of the... - gui Run the CLI GUI. init Initialize your AEA configurations. install Install the dependencies of the agent. interact Interact with the running agent via the stub... diff --git a/tests/test_cli_gui/__init__.py b/tests/test_cli_gui/__init__.py deleted file mode 100644 index 4bbd0b1527..0000000000 --- a/tests/test_cli_gui/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- coding: utf-8 -*- -# ------------------------------------------------------------------------------ -# -# Copyright 2018-2019 Fetch.AI Limited -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# ------------------------------------------------------------------------------ - -"""The tests for the cli gui.""" diff --git a/tests/test_cli_gui/test_add.py b/tests/test_cli_gui/test_add.py deleted file mode 100644 index 28957b12c4..0000000000 --- a/tests/test_cli_gui/test_add.py +++ /dev/null @@ -1,72 +0,0 @@ -# -*- coding: utf-8 -*- -# ------------------------------------------------------------------------------ -# -# Copyright 2018-2019 Fetch.AI Limited -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# ------------------------------------------------------------------------------ - -"""This test module contains the tests for the `aea gui` sub-commands.""" -import json -from unittest.mock import patch - -from tests.test_cli.tools_for_testing import raise_click_exception -from tests.test_cli_gui.test_base import create_app - - -@patch("aea.cli_gui.cli_add_item") -@patch("aea.cli_gui.try_to_load_agent_config") -def test_add_item(*mocks): - """Test remove a skill/connection/protocol. - - Actually we just do connection as code coverage is the same. - """ - app = create_app() - - agent_name = "test_agent_id" - connection_id = "author/test_connection:0.1.0" - - # Ensure there is now one agent - response_remove = app.post( - "api/agent/" + agent_name + "/connection", - content_type="application/json", - data=json.dumps(connection_id), - ) - assert response_remove.status_code == 201 - data = json.loads(response_remove.get_data(as_text=True)) - assert data == agent_name - - -@patch("aea.cli_gui.cli_add_item", raise_click_exception) -@patch("aea.cli_gui.try_to_load_agent_config") -def test_add_fail(*mocks): - """Test remove a skill/connection/protocol when it fails. - - Actually we just do connection as code coverage is the same. - """ - app = create_app() - - agent_name = "test_agent_id" - connection_id = "author/test_connection:0.1.0" - - response_remove = app.post( - "api/agent/" + agent_name + "/connection", - content_type="application/json", - data=json.dumps(connection_id), - ) - assert response_remove.status_code == 400 - data = json.loads(response_remove.get_data(as_text=True)) - assert data["detail"] == "Failed to add connection {} to agent {}. Message".format( - connection_id, agent_name - ) diff --git a/tests/test_cli_gui/test_base.py b/tests/test_cli_gui/test_base.py deleted file mode 100644 index cf13461168..0000000000 --- a/tests/test_cli_gui/test_base.py +++ /dev/null @@ -1,74 +0,0 @@ -# -*- coding: utf-8 -*- -# ------------------------------------------------------------------------------ -# -# Copyright 2018-2019 Fetch.AI Limited -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# ------------------------------------------------------------------------------ - -"""This test module contains the tests for the `aea gui` sub-commands.""" -import io -import os -import shutil -import tempfile - -import aea.cli_gui - - -def create_app(): - """Create a debug version of the flask app for testing against.""" - app = aea.cli_gui.run_test() - app.debug = True - app.testing = True - return app - - -class DummyPID: - """Mimics the behaviour of a process id.""" - - def __init__(self, return_code, stdout_str, stderr_str): - """Initialise the class.""" - self.return_code = return_code - self.stdout = io.BytesIO(stdout_str.encode(encoding="UTF-8")) - self.stderr = io.BytesIO(stderr_str.encode(encoding="UTF-8")) - - def poll(self): - """Mimic the process id poll function.""" - return self.return_code - - -class TempCWD: - """Create a temporary current working directory.""" - - def __init__(self): - """Initialise the class.""" - self.temp_dir = tempfile.mkdtemp() - self.cwd = os.getcwd() - os.chdir(self.temp_dir) - - def __enter__(self): - """Create the empty directory in a context manager.""" - return self - - def __exit__(self, exc_type, exc_val, exc_tb): - """Restore the initial conditions.""" - self.destroy() - - def destroy(self): - """Destroy the cwd and restore the old one.""" - os.chdir(self.cwd) - try: - shutil.rmtree(self.temp_dir) - except (OSError, IOError): - pass diff --git a/tests/test_cli_gui/test_create.py b/tests/test_cli_gui/test_create.py deleted file mode 100644 index 5be16113f2..0000000000 --- a/tests/test_cli_gui/test_create.py +++ /dev/null @@ -1,104 +0,0 @@ -# -*- coding: utf-8 -*- -# ------------------------------------------------------------------------------ -# -# Copyright 2018-2019 Fetch.AI Limited -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# ------------------------------------------------------------------------------ - -"""This test module contains the tests for the `aea gui` sub-commands.""" -import json -import shutil -import time -from pathlib import Path -from unittest.mock import patch - -from aea.cli.create import create_aea -from aea.cli.utils.context import Context -from aea.test_tools.constants import DEFAULT_AUTHOR - -from tests.conftest import CUR_PATH -from tests.test_cli.tools_for_testing import raise_click_exception -from tests.test_cli_gui.test_base import TempCWD, create_app - - -@patch("aea.cli_gui.cli_create_aea") -def test_create_agent(*mocks): - """Test creating an agent.""" - app = create_app() - agent_name = "test_agent_id" - - # Ensure there is now one agent - response_create = app.post( - "api/agent", content_type="application/json", data=json.dumps(agent_name) - ) - assert response_create.status_code == 201 - data = json.loads(response_create.get_data(as_text=True)) - assert data == agent_name - - -@patch("aea.cli_gui.cli_create_aea", raise_click_exception) -def test_create_agent_fail(*mocks): - """Test creating an agent and failing.""" - app = create_app() - agent_name = "test_agent_id" - - response_create = app.post( - "api/agent", content_type="application/json", data=json.dumps(agent_name) - ) - assert response_create.status_code == 400 - data = json.loads(response_create.get_data(as_text=True)) - assert data["detail"] == "Failed to create Agent. Message" - - -def test_real_create_local(*mocks): - """Really create an agent (have to test the call_aea at some point).""" - # Set up a temporary current working directory to make agents in - with TempCWD() as temp_cwd: - app = create_app() - - # copy the 'packages' directory in the parent of the agent folder. - shutil.copytree( - Path(CUR_PATH, "..", "packages"), Path(temp_cwd.temp_dir, "packages") - ) - - agent_id = "test_agent_id" - - # Make an agent - # We do it programmatically as we need to create an agent with default author - # that was prevented from GUI. - ctx = Context(cwd=temp_cwd.temp_dir) - create_aea(ctx, agent_id, local=True, author=DEFAULT_AUTHOR) - - # Give it a bit of time so the polling funcionts get called - time.sleep(1) - - # Check that we can actually see this agent too - response_agents = app.get( - "api/agent", data=None, content_type="application/json", - ) - data = json.loads(response_agents.get_data(as_text=True)) - assert response_agents.status_code == 200 - assert len(data) == 1 - assert data[0]["public_id"] == agent_id - assert data[0]["description"] == "placeholder description" - - # do same but this time find that this is not an agent directory. - with patch("os.path.isdir", return_value=False): - response_agents = app.get( - "api/agent", data=None, content_type="application/json", - ) - data = json.loads(response_agents.get_data(as_text=True)) - assert response_agents.status_code == 200 - assert len(data) == 0 diff --git a/tests/test_cli_gui/test_delete.py b/tests/test_cli_gui/test_delete.py deleted file mode 100644 index b55b93281a..0000000000 --- a/tests/test_cli_gui/test_delete.py +++ /dev/null @@ -1,56 +0,0 @@ -# -*- coding: utf-8 -*- -# ------------------------------------------------------------------------------ -# -# Copyright 2018-2019 Fetch.AI Limited -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# ------------------------------------------------------------------------------ - -"""This test module contains the tests for the `aea gui` sub-commands.""" -import json -from unittest.mock import patch - -from tests.test_cli.tools_for_testing import raise_click_exception -from tests.test_cli_gui.test_base import create_app - - -@patch("aea.cli_gui.cli_delete_aea") -def test_delete_agent(*mocks): - """Test creating an agent.""" - app = create_app() - agent_name = "test_agent_id" - - # Ensure there is now one agent - response_delete = app.delete( - "api/agent/" + agent_name, data=None, content_type="application/json" - ) - assert response_delete.status_code == 200 - data = json.loads(response_delete.get_data(as_text=True)) - assert data == "Agent {} deleted".format(agent_name) - - -@patch("aea.cli_gui.cli_delete_aea", raise_click_exception) -def test_delete_agent_fail(*mocks): - """Test creating an agent and failing.""" - app = create_app() - agent_name = "test_agent_id" - - response_delete = app.delete( - "api/agent/" + agent_name, data=None, content_type="application/json" - ) - assert response_delete.status_code == 400 - data = json.loads(response_delete.get_data(as_text=True)) - assert data["detail"] == "Failed to delete Agent {} - it may not exist".format( - agent_name - ) diff --git a/tests/test_cli_gui/test_fetch.py b/tests/test_cli_gui/test_fetch.py deleted file mode 100644 index e48df518ca..0000000000 --- a/tests/test_cli_gui/test_fetch.py +++ /dev/null @@ -1,61 +0,0 @@ -# -*- coding: utf-8 -*- -# ------------------------------------------------------------------------------ -# -# Copyright 2018-2020 Fetch.AI Limited -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# ------------------------------------------------------------------------------ - -"""This test module contains the tests for the `aea gui` sub-commands.""" - -import json -from unittest.mock import patch - -from tests.test_cli.tools_for_testing import raise_click_exception -from tests.test_cli_gui.test_base import create_app - - -@patch("aea.cli_gui.cli_fetch_agent") -def test_fetch_agent(*mocks): - """Test fetch an agent.""" - app = create_app() - - agent_name = "test_agent_name" - agent_id = "author/{}:0.1.0".format(agent_name) - - # Ensure there is now one agent - resp = app.post( - "api/fetch-agent", content_type="application/json", data=json.dumps(agent_id), - ) - assert resp.status_code == 201 - data = json.loads(resp.get_data(as_text=True)) - assert data == agent_name - - -@patch("aea.cli_gui.cli_fetch_agent", raise_click_exception) -def test_fetch_agent_fail(*mocks): - """Test fetch agent fail.""" - app = create_app() - - agent_name = "test_agent_name" - agent_id = "author/{}:0.1.0".format(agent_name) - - resp = app.post( - "api/fetch-agent", content_type="application/json", data=json.dumps(agent_id), - ) - assert resp.status_code == 400 - data = json.loads(resp.get_data(as_text=True)) - assert data["detail"] == "Failed to fetch an agent {}. {}".format( - agent_id, "Message" - ) diff --git a/tests/test_cli_gui/test_get_items.py b/tests/test_cli_gui/test_get_items.py deleted file mode 100644 index 3522a5cae0..0000000000 --- a/tests/test_cli_gui/test_get_items.py +++ /dev/null @@ -1,97 +0,0 @@ -# -*- coding: utf-8 -*- -# ------------------------------------------------------------------------------ -# -# Copyright 2018-2020 Fetch.AI Limited -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# ------------------------------------------------------------------------------ -"""Test module for get registered items with CLI GUI.""" - -import json -from unittest import TestCase, mock - -from tests.test_cli.tools_for_testing import raise_click_exception -from tests.test_cli_gui.test_base import create_app - - -class GetRegisteredItemsTestCase(TestCase): - """Test case for get_registered_items API.""" - - def setUp(self): - """Set up test case.""" - self.app = create_app() - - @mock.patch("aea.cli_gui.cli_setup_search_ctx") - @mock.patch( - "aea.cli_gui.cli_search_items", return_value=([{"name": "some-connection"}], 1) - ) - def test_get_registered_items_positive( - self, cli_setup_search_ctx_mock, cli_search_items_mock - ): - """Test case for get_registered_items API positive response.""" - response = self.app.get("api/connection") - self.assertEqual(response.status_code, 200) - - result = json.loads(response.get_data(as_text=True)) - expected_result = [{"name": "some-connection"}] - self.assertEqual(result, expected_result) - - cli_setup_search_ctx_mock.assert_called_once() - cli_search_items_mock.assert_called_once() - - @mock.patch("aea.cli_gui.cli_setup_search_ctx", raise_click_exception) - def test_get_registered_items_negative(self, *mocks): - """Test case for get_registered_items API negative response.""" - response = self.app.get("api/connection") - self.assertEqual(response.status_code, 400) - - result = json.loads(response.get_data(as_text=True)) - expected_result = "Failed to search items." - self.assertEqual(result["detail"], expected_result) - - -class GetLocalItemsTestCase(TestCase): - """Test case for get_local_items API.""" - - def setUp(self): - """Set up test case.""" - self.app = create_app() - - @mock.patch("aea.cli_gui.try_to_load_agent_config") - @mock.patch( - "aea.cli_gui.cli_list_agent_items", return_value=[{"name": "some-connection"}] - ) - def test_get_local_items_positive(self, *mocks): - """Test case for get_local_items API positive response.""" - response = self.app.get("api/agent/NONE/connection") - self.assertEqual(response.status_code, 200) - result = json.loads(response.get_data(as_text=True)) - self.assertEqual(result, []) - - response = self.app.get("api/agent/agent_id/connection") - self.assertEqual(response.status_code, 200) - - result = json.loads(response.get_data(as_text=True)) - expected_result = [{"name": "some-connection"}] - self.assertEqual(result, expected_result) - - @mock.patch("aea.cli_gui.try_to_load_agent_config", raise_click_exception) - def test_get_local_items_negative(self, *mocks): - """Test case for get_local_items API negative response.""" - response = self.app.get("api/agent/agent_id/connection") - self.assertEqual(response.status_code, 400) - - result = json.loads(response.get_data(as_text=True)) - expected_result = "Failed to list agent items." - self.assertEqual(result[0]["detail"], expected_result) diff --git a/tests/test_cli_gui/test_list.py b/tests/test_cli_gui/test_list.py deleted file mode 100644 index 72c854489c..0000000000 --- a/tests/test_cli_gui/test_list.py +++ /dev/null @@ -1,39 +0,0 @@ -# -*- coding: utf-8 -*- -# ------------------------------------------------------------------------------ -# -# Copyright 2018-2019 Fetch.AI Limited -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# ------------------------------------------------------------------------------ - -"""This test module contains the tests for the `aea gui` sub-commands.""" - -import json -from unittest.mock import patch - -from tests.test_cli_gui.test_base import create_app - - -@patch("aea.cli_gui.cli_list_agent_items", return_value=[{"name": "some-connection"}]) -@patch("aea.cli_gui.try_to_load_agent_config") -def test_list_connections(*mocks): - """Test list localConnections.""" - app = create_app() - - response = app.get("api/agent/agent_name/connection") - assert response.status_code == 200 - - result = json.loads(response.get_data(as_text=True)) - expected_result = [{"name": "some-connection"}] - assert result == expected_result diff --git a/tests/test_cli_gui/test_misc.py b/tests/test_cli_gui/test_misc.py deleted file mode 100644 index eefd7c22f7..0000000000 --- a/tests/test_cli_gui/test_misc.py +++ /dev/null @@ -1,72 +0,0 @@ -# -*- coding: utf-8 -*- -# ------------------------------------------------------------------------------ -# -# Copyright 2018-2019 Fetch.AI Limited -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# ------------------------------------------------------------------------------ -"""This test module contains the tests for the `aea gui` sub-commands.""" - -import unittest.mock - -from flask import Flask - -import aea.cli_gui - -from tests.common.mocks import ctx_mock_Popen -from tests.test_cli_gui.test_base import create_app - - -def test_home_page_exits(): - """Test that the home-page exits.""" - app = create_app() - - # sends HTTP GET request to the application - # on the specified path - result = app.get("/") - - # assert the status code of the response - assert result.status_code == 200 - assert "AEA GUI" in str(result.data) - - -def test_icon(): - """Test that the home-page exits.""" - app = create_app() - - # sends HTTP GET request to the application - # on the specified path - result = app.get("/favicon.ico") - - # assert the status code of the response - assert result.status_code == 200 - - -def test_js(): - """Test that the home-page exits.""" - app = create_app() - - # sends HTTP GET request to the application - # on the specified path - result = app.get("/static/js/home.js") - - # assert the status code of the response - assert result.status_code == 200 - - -def test_run_app(): - """Test that running the app in non-test mode works.""" - with ctx_mock_Popen(): - with unittest.mock.patch.object(Flask, "run", return_value=None): - aea.cli_gui.run(8080) diff --git a/tests/test_cli_gui/test_remove.py b/tests/test_cli_gui/test_remove.py deleted file mode 100644 index b598bf78f5..0000000000 --- a/tests/test_cli_gui/test_remove.py +++ /dev/null @@ -1,70 +0,0 @@ -# -*- coding: utf-8 -*- -# ------------------------------------------------------------------------------ -# -# Copyright 2018-2019 Fetch.AI Limited -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# ------------------------------------------------------------------------------ - -"""This test module contains the tests for the `aea gui` sub-commands.""" -import json -from unittest.mock import patch - -from tests.test_cli.tools_for_testing import raise_click_exception -from tests.test_cli_gui.test_base import create_app - - -@patch("aea.cli_gui.cli_remove_item") -@patch("aea.cli_gui.try_to_load_agent_config") -def test_remove_item(*mocks): - """Test remove a skill/connection/protocol. - - Actually we just do connection as code coverage is the same. - """ - app = create_app() - - agent_name = "test_agent_id" - connection_name = "fetchai/test_connection:0.1.0" - - response_remove = app.post( - "api/agent/" + agent_name + "/connection/remove", - content_type="application/json", - data=json.dumps(connection_name), - ) - assert response_remove.status_code == 201 - data = json.loads(response_remove.get_data(as_text=True)) - assert data == agent_name - - -@patch("aea.cli_gui.cli_remove_item", raise_click_exception) -def test_remove_item_fail(*mocks): - """Test remove a skill/connection/protocol when it fails. - - Actually we just do connection as code coverage is the same. - """ - app = create_app() - - agent_name = "test_agent_id" - connection_name = "fetchai/test_connection:0.1.0" - - response_remove = app.post( - "api/agent/" + agent_name + "/connection/remove", - content_type="application/json", - data=json.dumps(connection_name), - ) - assert response_remove.status_code == 400 - data = json.loads(response_remove.get_data(as_text=True)) - assert data["detail"] == "Failed to remove connection {} from agent {}".format( - connection_name, agent_name - ) diff --git a/tests/test_cli_gui/test_run_agent.py b/tests/test_cli_gui/test_run_agent.py deleted file mode 100644 index fd4717c9b0..0000000000 --- a/tests/test_cli_gui/test_run_agent.py +++ /dev/null @@ -1,225 +0,0 @@ -# -*- coding: utf-8 -*- -# ------------------------------------------------------------------------------ -# -# Copyright 2018-2019 Fetch.AI Limited -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# ------------------------------------------------------------------------------ - -"""This test module contains the tests for the `aea gui` sub-commands.""" -import json -import shutil -import sys -import time -from pathlib import Path -from unittest.mock import patch - -import pytest - -import aea -from aea.cli.create import create_aea -from aea.cli.utils.context import Context -from aea.test_tools.constants import DEFAULT_AUTHOR - -from packages.fetchai.connections.stub.connection import ( - PUBLIC_ID as STUB_CONNECTION_PUBLIC_ID, -) - -from tests.conftest import CUR_PATH, MAX_FLAKY_RERUNS -from tests.test_cli_gui.test_base import TempCWD, create_app - - -@pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS) -def test_create_and_run_agent(): - """Test for running and agent, reading TTY and errors.""" - # Set up a temporary current working directory in which to make agents - with TempCWD() as temp_cwd: - app = create_app() - - # copy the 'packages' directory in the parent of the agent folder. - shutil.copytree( - Path(CUR_PATH, "..", "packages"), Path(temp_cwd.temp_dir, "packages") - ) - - agent_id = "test_agent" - - # Make an agent - # We do it programmatically as we need to create an agent with default author - # that was prevented from GUI. - ctx = Context(cwd=temp_cwd.temp_dir) - ctx.set_config("is_local", True) - create_aea(ctx, agent_id, local=True, author=DEFAULT_AUTHOR) - - # Add the stub connection - with patch("aea.cli_gui.app_context.local", True): - response_add = app.post( - "api/agent/" + agent_id + "/connection", - content_type="application/json", - data=json.dumps(str(STUB_CONNECTION_PUBLIC_ID)), - ) - assert response_add.status_code == 201 - - # Get the running status before we have run it - response_status = app.get( - "api/agent/" + agent_id + "/run", - data=None, - content_type="application/json", - ) - assert response_status.status_code == 200 - data = json.loads(response_status.get_data(as_text=True)) - assert "NOT_STARTED" in data["status"] - - # run the agent with a non existent connection - response_run = app.post( - "api/agent/" + agent_id + "/run", - content_type="application/json", - data=json.dumps("author/non-existent-connection:0.1.0"), - ) - assert response_run.status_code == 400 - - # run the agent with default connection - should be something in the error output? - response_run = app.post( - "api/agent/" + agent_id + "/run", - content_type="application/json", - data=json.dumps(""), - ) - assert response_run.status_code == 201 - time.sleep(2) - - # Stop the agent running - response_stop = app.delete( - "api/agent/" + agent_id + "/run", - data=None, - content_type="application/json", - ) - assert response_stop.status_code == 200 - time.sleep(2) - - # run the agent with stub connection - response_run = app.post( - "api/agent/" + agent_id + "/run", - content_type="application/json", - data=json.dumps(str(STUB_CONNECTION_PUBLIC_ID)), - ) - assert response_run.status_code == 201 - - time.sleep(2) - - # Try running it again (this should fail) - response_run = app.post( - "api/agent/" + agent_id + "/run", - content_type="application/json", - data=json.dumps(str(STUB_CONNECTION_PUBLIC_ID)), - ) - assert response_run.status_code == 400 - - # Get the running status - response_status = app.get( - "api/agent/" + agent_id + "/run", - data=None, - content_type="application/json", - ) - assert response_status.status_code == 200 - data = json.loads(response_status.get_data(as_text=True)) - - assert data["error"] == "" - assert "RUNNING" in data["status"] - app.delete( - "api/agent/" + agent_id + "/run", - data=None, - content_type="application/json", - ) - time.sleep(1) - - # Get the running status - response_status = app.get( - "api/agent/" + agent_id + "/run", - data=None, - content_type="application/json", - ) - assert response_status.status_code == 200 - data = json.loads(response_status.get_data(as_text=True)) - assert "process terminate" in data["error"] - assert "NOT_STARTED" in data["status"] - - # run the agent again (takes a different path through code) - response_run = app.post( - "api/agent/" + agent_id + "/run", - content_type="application/json", - data=json.dumps(str(STUB_CONNECTION_PUBLIC_ID)), - ) - assert response_run.status_code == 201 - - time.sleep(2) - - # Get the running status - response_status = app.get( - "api/agent/" + agent_id + "/run", - data=None, - content_type="application/json", - ) - assert response_status.status_code == 200 - data = json.loads(response_status.get_data(as_text=True)) - - assert data["error"] == "" - assert "RUNNING" in data["status"] - - # Stop the agent running - response_stop = app.delete( - "api/agent/" + agent_id + "/run", - data=None, - content_type="application/json", - ) - assert response_stop.status_code == 200 - time.sleep(2) - - # Get the running status - response_status = app.get( - "api/agent/" + agent_id + "/run", - data=None, - content_type="application/json", - ) - assert response_status.status_code == 200 - data = json.loads(response_status.get_data(as_text=True)) - assert "process terminate" in data["error"] - assert "NOT_STARTED" in data["status"] - - # Stop a none existent agent running - response_stop = app.delete( - "api/agent/" + agent_id + "_NOT" + "/run", - data=None, - content_type="application/json", - ) - assert response_stop.status_code == 400 - time.sleep(2) - - genuine_func = aea.cli_gui.call_aea_async - - def _dummycall_aea_async(param_list, dir_arg): - assert param_list[0] == sys.executable - assert param_list[1] == "-m" - assert param_list[2] == "aea.cli" - if param_list[3] == "run": - return None - else: - return genuine_func(param_list, dir_arg) - - # Run when process files (but other call - such as status should not fail) - with patch("aea.cli_gui.call_aea_async", _dummycall_aea_async): - response_run = app.post( - "api/agent/" + agent_id + "/run", - content_type="application/json", - data=json.dumps(str(STUB_CONNECTION_PUBLIC_ID)), - ) - assert response_run.status_code == 400 diff --git a/tests/test_cli_gui/test_scaffold.py b/tests/test_cli_gui/test_scaffold.py deleted file mode 100644 index 44c882ebcb..0000000000 --- a/tests/test_cli_gui/test_scaffold.py +++ /dev/null @@ -1,71 +0,0 @@ -# -*- coding: utf-8 -*- -# ------------------------------------------------------------------------------ -# -# Copyright 2018-2019 Fetch.AI Limited -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# ------------------------------------------------------------------------------ - -"""This test module contains the tests for the `aea gui` sub-commands.""" -import json -from unittest.mock import patch - -from tests.test_cli.tools_for_testing import raise_click_exception -from tests.test_cli_gui.test_base import create_app - - -@patch("aea.cli_gui.cli_scaffold_item") -@patch("aea.cli_gui.try_to_load_agent_config") -def test_scaffold_item(*mocks): - """Test remove a skill/connection/protocol. - - Actually we just do connection as code coverage is the same. - """ - app = create_app() - - agent_name = "test_agent_id" - connection_name = "fetchai/test_connection:0.1.0" - - response_remove = app.post( - "api/agent/" + agent_name + "/connection/scaffold", - content_type="application/json", - data=json.dumps(connection_name), - ) - assert response_remove.status_code == 201 - data = json.loads(response_remove.get_data(as_text=True)) - assert data == agent_name - - -@patch("aea.cli_gui.cli_scaffold_item", raise_click_exception) -@patch("aea.cli_gui.try_to_load_agent_config") -def test_scaffold_agent_fail(*mocks): - """Test remove a skill/connection/protocol when it fails. - - Actually we just do connection as code coverage is the same. - """ - app = create_app() - - agent_name = "test_agent_id" - connection_name = "fetchai/test_connection:0.1.0" - - response_remove = app.post( - "api/agent/" + agent_name + "/connection/scaffold", - content_type="application/json", - data=json.dumps(connection_name), - ) - assert response_remove.status_code == 400 - data = json.loads(response_remove.get_data(as_text=True)) - assert data[ - "detail" - ] == "Failed to scaffold a new connection in to agent {}".format(agent_name) diff --git a/tests/test_cli_gui/test_search.py b/tests/test_cli_gui/test_search.py deleted file mode 100644 index 9bc710a650..0000000000 --- a/tests/test_cli_gui/test_search.py +++ /dev/null @@ -1,56 +0,0 @@ -# -*- coding: utf-8 -*- -# ------------------------------------------------------------------------------ -# -# Copyright 2018-2019 Fetch.AI Limited -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# ------------------------------------------------------------------------------ - -"""This test module contains the tests for the `aea gui` sub-commands.""" - -import json -from unittest.mock import patch - -from tests.test_cli.tools_for_testing import raise_click_exception -from tests.test_cli_gui.test_base import create_app - - -@patch("aea.cli_gui.cli_list_agent_items", return_value=[{"name": "some-connection"}]) -def test_search_connections(*mocks): - """Test list localConnections.""" - app = create_app() - - response = app.get("api/connection/query") - assert response.status_code == 200 - - result = json.loads(response.get_data(as_text=True)) - expected_result = { - "item_type": "connection", - "search_result": [], - "search_term": "query", - } - assert result == expected_result - - -@patch("aea.cli_gui.cli_setup_search_ctx", raise_click_exception) -def test_search_connections_negative(*mocks): - """Test list localConnections negative response.""" - app = create_app() - - response = app.get("api/connection/query") - assert response.status_code == 400 - - result = json.loads(response.get_data(as_text=True)) - expected_result = "Failed to search items." - assert result["detail"] == expected_result diff --git a/tests/test_cli_gui/test_utils.py b/tests/test_cli_gui/test_utils.py deleted file mode 100644 index fa0bad2aa5..0000000000 --- a/tests/test_cli_gui/test_utils.py +++ /dev/null @@ -1,145 +0,0 @@ -# -*- coding: utf-8 -*- -# ------------------------------------------------------------------------------ -# -# Copyright 2018-2020 Fetch.AI Limited -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# ------------------------------------------------------------------------------ -"""Test module for utils of CLI GUI.""" - -from subprocess import TimeoutExpired # nosec -from unittest import TestCase, mock - -from aea.cli_gui.utils import ( - ProcessState, - _call_subprocess, - _terminate_process, - get_process_status, - read_error, - read_tty, -) - - -def _raise_timeout_expired(*args, **kwargs): - raise TimeoutExpired("cmd", None) - - -@mock.patch("aea.cli_gui.utils._terminate_process") -@mock.patch("aea.cli_gui.utils.logging.exception") -@mock.patch("aea.cli_gui.utils.subprocess.Popen") -class CallSubprocessTestCase(TestCase): - """Test case for _call_subprocess method.""" - - def test__call_subprocess_positive(self, popen_mock, exc_mock, terminate_mock): - """Test _call_subprocess for positive result.""" - proc_mock = mock.Mock() - proc_mock.wait = mock.Mock(return_value="wait-return") - popen_mock.return_value = proc_mock - - result = _call_subprocess("arg1") - expected_result = "wait-return" - - self.assertEqual(result, expected_result) - popen_mock.assert_called_once_with("arg1") - proc_mock.wait.assert_called_once() - exc_mock.assert_not_called() - terminate_mock.assert_called_once_with(proc_mock) - - def test__call_subprocess_negative(self, popen_mock, exc_mock, terminate_mock): - """Test _call_subprocess for negative result.""" - proc_mock = mock.Mock() - proc_mock.wait = _raise_timeout_expired - popen_mock.return_value = proc_mock - - result = _call_subprocess("arg1") - expected_result = -1 - - self.assertEqual(result, expected_result) - popen_mock.assert_called_once_with("arg1") - exc_mock.assert_called_once() - terminate_mock.assert_called_once_with(proc_mock) - - -@mock.patch("aea.cli_gui.utils.logging.info") -@mock.patch("aea.cli_gui.utils.io.TextIOWrapper") -class ReadTtyTestCase(TestCase): - """Test case for read_tty method.""" - - def test_read_tty_positive(self, text_wrapper_mock, logging_info_mock): - """Test read_tty method for positive result.""" - text_wrapper_mock.return_value = ["line3", "line4"] - pid_mock = mock.Mock() - pid_mock.stdout = "stdout" - - str_list = ["line1", "line2"] - read_tty(pid_mock, str_list) - expected_result = ["line1", "line2", "line3", "line4", "process terminated\n"] - self.assertEqual(str_list, expected_result) - text_wrapper_mock.assert_called_once_with("stdout", encoding="utf-8") - - -@mock.patch("aea.cli_gui.utils.logging.error") -@mock.patch("aea.cli_gui.utils.io.TextIOWrapper") -class ReadErrorTestCase(TestCase): - """Test case for read_error method.""" - - def test_read_error_positive(self, text_wrapper_mock, logging_error_mock): - """Test read_error method for positive result.""" - text_wrapper_mock.return_value = ["line3", "line4"] - pid_mock = mock.Mock() - pid_mock.stderr = "stderr" - - str_list = ["line1", "line2"] - read_error(pid_mock, str_list) - expected_result = ["line1", "line2", "line3", "line4", "process terminated\n"] - self.assertEqual(str_list, expected_result) - text_wrapper_mock.assert_called_once_with("stderr", encoding="utf-8") - - -class TerminateProcessTestCase(TestCase): - """Test case for _terminate_process method.""" - - def test__terminate_process_positive(self): - """Test _terminate_process for positive result.""" - process_mock = mock.Mock() - process_mock.poll = mock.Mock(return_value="Not None") - _terminate_process(process_mock) - - process_mock.poll = mock.Mock(return_value=None) - process_mock.terminate = mock.Mock() - process_mock.wait = _raise_timeout_expired - process_mock.kill = mock.Mock() - - _terminate_process(process_mock) - process_mock.poll.assert_called_once() - process_mock.terminate.assert_called_once() - process_mock.kill() - - -class GetProcessStatusTestCase(TestCase): - """Test case for get_process_status method.""" - - def test_get_process_status_positive(self): - """Test get_process_status for positive result.""" - proc_id_mock = mock.Mock() - - proc_id_mock.poll = mock.Mock(return_value=-1) - result = get_process_status(proc_id_mock) - expected_result = ProcessState.FINISHED - self.assertEqual(result, expected_result) - - proc_id_mock.poll = mock.Mock(return_value=1) - result = get_process_status(proc_id_mock) - expected_result = ProcessState.FAILED - self.assertEqual(result, expected_result) diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-cli-gui.md b/tests/test_docs/test_bash_yaml/md_files/bash-cli-gui.md deleted file mode 100644 index d0ca57ee94..0000000000 --- a/tests/test_docs/test_bash_yaml/md_files/bash-cli-gui.md +++ /dev/null @@ -1,6 +0,0 @@ -``` bash -pip install aea[cli_gui] -``` -``` bash -aea gui -``` diff --git a/tox.ini b/tox.ini index 5db003e606..98246d12f4 100644 --- a/tox.ini +++ b/tox.ini @@ -217,16 +217,6 @@ whitelist_externals = /bin/sh skipsdist = True deps = pylint==2.5.2 pytest==5.3.5 - ipfshttpclient==0.6.1 - yoti==2.14.0 - ; plugin deps - ; aea_crypto_cosmos/aea_crypto_fetchai - ecdsa>=0.16 - bech32==1.2.0 - ; aea_crypto_ethereum - web3==5.12.0 - ipfshttpclient==0.6.1 - eth-account==0.5.2 commands = python -m pip install --no-deps file://{toxinidir}/plugins/aea-crypto-ethereum