Ejemplo n.º 1
0
"""Responds to flow generation HTTP requests."""

import bottle
from aist_common.log import get_logger
from bottle import request
from services.test_generator_service import TestGeneratorService

LOGGER = get_logger('test_generator_controller')


class TestGeneratorController:
    """Responds to flow generation HTTP requests."""
    def __init__(self, app):
        """ Initializes the TestGeneratorController class.

        :param app: The Bottle app.
        """

        self._app = app
        self._service = TestGeneratorService()

    def add_routes(self):
        """ Add request routes to the Bottle app.
        """

        self._app.route('/v1/status', method="GET", callback=self.get_status)
        self._app.route('/v1/predict', method="POST", callback=self.predict)

    @staticmethod
    def get_status():
        """ Get service status.
Ejemplo n.º 2
0
""" Combines information from page classifiers along with an abstract test
    flow to generate possible concrete test flows for the SUT."""

import itertools

from flow_execution.concrete_test_flow import ConcreteTestFlow

from aist_common.log import get_logger

LOGGER = get_logger('flow-planner')


class FlowPlanner:
    """ Combines information from page classifiers along with an abstract test
        flow to generate possible concrete test flows for the SUT."""
    def __init__(self):
        """ Initializes the FlowPlanner class.
        """

        self._klass = __class__.__name__

    @staticmethod
    def plan(abstract_state, page_analysis, abstract_flow):
        """ Given an abstract test flow and widget classifications, produces a list of
            possibly executable concrete test flows.

        :param abstract_state: The current abstract state (where a concrete test flow execution would begin from).
        :param page_analysis: The page analysis output for the current abstract state (element classifications).
        :param abstract_flow: The abstract test flow to process.
         
        :return: A list of concrete test flows.
Ejemplo n.º 3
0
"""The ConcreteStateFeaturizer class (responsible for extracting features from a concrete state)
    and accompanying helper functions."""

import math
import re

import numpy as np
import pandas as pd
from colormath.color_conversions import convert_color
from colormath.color_diff import delta_e_cie2000
from colormath.color_objects import sRGBColor, LabColor

from aist_common.log import get_logger

LOGGER = get_logger('concrete_state_featurizer')

color_re = re.compile(r'(rgb|rgba)\(([0-9]+?), ([0-9]+?), ([0-9]+?)([,)])')

base_colors = [
    ('black', np.array([0, 0, 0])),
    ('white', np.array([255, 255, 255])),
    ('red', np.array([255, 0, 0])),
    ('blue', np.array([0, 0, 255])),
    ('grey', np.array([128, 128, 128])),
    ('yellow', np.array([255, 255, 0])),
    ('orange', np.array([255, 165, 0])),
    ('green', np.array([0, 255, 0])),
    ('purple', np.array([128, 0, 128])),
]

basic_html_tags = [
Ejemplo n.º 4
0
"""A client that communicates with and provides the capabilities of the flow generation service."""
import os

import requests
import urllib3

from aist_common.log import get_logger

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

LOGGER = get_logger('flow-generator-client')


class FlowGeneratorClient:
    """A client that communicates with and provides the capabilities of the flow generation service."""

    FLOW_GEN_URL = "{}/v1/predict"

    def __init__(self):
        """ Initializes the FlowGeneratorClient class.
        """

        self._klass = "FlowGeneratorClient"
        self._set_envs()

    def _set_envs(self):
        """ Loads environment variables.
        """

        self.SERVICE_URL = 'http://flow-generator'
        if 'FLOW_GENERATION_URL' in os.environ:
Ejemplo n.º 5
0
"""A client that communicates with and provides the capabilities of the runner service."""
import json
import os
import time

from aeoncloud import get_session_factory
from aeoncloud.exceptions.aeon_session_error import AeonSessionError

from aist_common.log import get_logger

LOGGER = get_logger('runner-client')


class RunnerClient:
    """A client that communicates with and provides the capabilities of the runner service."""

    GET_DOCUMENT_LOC = "return document.location.href;"
    HAS_JQUERY_SCRIPT = "if(window.jQuery) return true; return false;"
    FIX_JQUERY_SCRIPT = "if(window.jQuery && !window.jquery) window.jquery = window.jQuery;"

    def __init__(self, runner_url):
        """ Initializes the RunnerClient class.

        :param runner_url: The URL to the Aeon runner to be used.
        """

        self._klass = "RunnerClient"
        self.RUNNER_URL = runner_url
        self.session = None
        self.aeon = get_session_factory()
Ejemplo n.º 6
0
"""Responds to gateway HTTP requests."""

import bottle
from aist_common.log import get_logger
from bottle import request
from services.gateway_service import GatewayService

LOGGER = get_logger('gateway-controller')


class GatewayController:
    """Responds to gateway HTTP requests."""
    def __init__(self, app):
        """ Initializes the GatewayController class.

        :param app: The Bottle app.
        """

        self._app = app
        self._service = GatewayService()

    def add_routes(self):
        """ Add request routes to the Bottle app.
        """
        self._app.route('/v1/status', method="GET", callback=self.get_status)
        self._app.route('/v1/start',
                        method="POST",
                        callback=self.start_session)
        self._app.route('/v1/stop', method="POST", callback=self.stop_session)

    @staticmethod
Ejemplo n.º 7
0
"""A client that communicates with and provides the capabilities of the page analysis service."""
import os

import requests
import urllib3

from aist_common.log import get_logger

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

LOGGER = get_logger('page-analysis-client')


class PageAnalysisClient:
    """A client that communicates with and provides the capabilities of the page analysis service."""

    ANALYSIS_RUN_URL = "{}/v1/pageAnalysis/state/concrete"

    def __init__(self):
        """ Initializes the PageAnalysisClient class.
        """

        self._klass = "PageAnalysisClient"
        self._set_envs()

    def _set_envs(self):
        """ Loads environment variables.
        """

        self.SERVICE_URL = 'http://page-analyzer'
        if 'PAGE_ANALYSIS_URL' in os.environ:
Ejemplo n.º 8
0
from clients.flow_generation_client import FlowGeneratorClient
from clients.form_expert_client import FormExpertClient
from clients.page_analysis_client import PageAnalysisClient
from clients.runner_client import RunnerClient
from defects.defect_reporter import DefectReporter
from flow_execution.flow_executor import FlowExecutor
from flow_execution.flow_planner import FlowPlanner
from memory.priority_memory import PriorityMemory
from outbound_tasks import PlannedFlowPublisher
from perceive.label_extraction import LabelExtraction
from perceive.state_observer import StateObserver
from aist_common.log import get_logger

from memory.agent_memory import *

LOGGER = get_logger('agent-loop')


class AgentLoop:
    """ Responsible for implementing the core control flow of the agent.
        Observes the SUT environment, plans, and acts upon the environment."""

    NUM_ITERATIONS = 300

    def __init__(self,
                 sut_url,
                 runner_url,
                 form_expert_client=None,
                 runner_client=None,
                 page_analysis_client=None,
                 flow_generator_client=None,
Ejemplo n.º 9
0
"""Handles abstract test flow generation requests."""
import os
import random

import json
import numpy as np
import tensorflow as tf
from aist_common.log import get_logger
from keras.models import load_model

LOGGER = get_logger('test-generator-service')

BASE_PATH = os.path.abspath(
    os.path.join(os.path.dirname(__file__), '..', 'data'))


class TestGeneratorService:
    """Handles abstract test flow generation requests."""
    def __init__(self):
        """ Initializes the TestGeneratorService class.
        """

        with open("{}/embedding.json".format(BASE_PATH)) as f:
            data = json.load(f)
            self.char_indices = data['char_indices']
            self.indices_char = data['indices_char']

        self.maxlen = 11
        self.chars = self.char_indices.values()

        self.model = load_model("{}/lstm.h5".format(BASE_PATH))
Ejemplo n.º 10
0
"""Responds to page analysis HTTP requests."""

import json

import bottle
from aist_common.log import get_logger
from bottle import request
from services.page_analysis_service import PageAnalysisService

LOGGER = get_logger('page_analysis_controller')


class PageAnalysisController:
    """Responds to page analysis HTTP requests."""
    def __init__(self, app, service=None):
        """ Initializes the PageAnalysisController class.

        :param app: The Bottle app.
        :param service: An instance of the PageAnalysisService class.
        """

        self._app = app
        if service is not None:
            self._service = service
        else:
            self._service = PageAnalysisService()

    def add_routes(self):
        """ Add request routes to the Bottle app.
        """
Ejemplo n.º 11
0
"""Executes a concrete test flow."""
from form_strategies.fill_entire_form import FillEntireForm

from aist_common.log import get_logger

LOGGER = get_logger('flow-executor')


class FlowExecutor:
    """Executes a concrete test flow."""
    def __init__(self, form_expert, page_analyzer, state_abstracter,
                 label_extracter, observer, defect_rep):
        """ Initializes the FlowExecutor class.
        
        :param form_expert: An instance of the form expert client.
        :param page_analyzer: An instance of the page analyzer client.
        :param state_abstracter: An instance of the StateAbstracter class.
        :param label_extracter: An instance of the LabelExtraction class.
        :param observer: An instance of the StateObserver class.
        :param defect_rep: An instance of the DefectReporter class.
        """

        self.form_expert = form_expert
        self.page_analyzer = page_analyzer
        self.state_abstracter = state_abstracter
        self.ext_labels = label_extracter
        self.observer = observer
        self.defect_rep = defect_rep
        self.form_fill_strategy = FillEntireForm(form_expert)
        self._klass = __class__.__name__
Ejemplo n.º 12
0
"""A form filling strategy that attempts to fill out all settable form fields with valid values."""

from aist_common.log import get_logger

LOGGER = get_logger('fill-entire-form-strategy')


class FillEntireForm:
    """A form filling strategy that attempts to fill out all settable form fields with valid values."""

    def __init__(self, form_expert):
        """ Initializes the FillEntireForm class.
        :param form_expert: An instance of the form expert client.
        """

        self.form_expert = form_expert
        self._klass = __class__.__name__

    def execute(self, runner, abstract_state):
        """ Executes the form filling strategy against a given abstract state.

        :param runner: An instance of the runner client (that holds an active runner session).
        :param abstract_state: The current abstract state for the page that needs to be filled out.

        :return: True if all settable form fields were successfully filled.
        """

        actionable_widgets = [w for w in abstract_state.widgets if 'set' in w['actions']]
        actionable_widgets = self.form_expert.get_concrete_values(actionable_widgets)

        for actionable_widget in actionable_widgets:
Ejemplo n.º 13
0
"""Acts a single entry-point to all other services, handling requests and routing accordingly to other services."""

import uuid

from aist_common.CeleryConfig.celery_app import create_app
from aist_common.log import get_logger

LOGGER = get_logger('gateway-service')


class GatewayService:
    """Acts a single entry-point to all other services, handling requests and routing accordingly to other services."""
    @staticmethod
    def start_session(request_payload):
        """ Handles a request to start an exploration/testing session.

        :param request_payload: A payload which contains the information necessary to start a session.

        :return: The session ID for the newly started session.
        """

        app = create_app([])

        @app.task(name='test_agent.start_session',
                  queue="agent_broadcast_tasks")
        def start_agent_session(_):
            pass

        session_id = uuid.uuid4().hex
        request = {'SUT_URL': request_payload['SUT_URL']}
Ejemplo n.º 14
0
"""The main Agent entry-point. Contains all necessary Celery plumbing code."""

import threading
import uuid

import celery.worker
from aist_common.CeleryConfig.celery_app import create_app
from aist_common.log import get_logger

LOGGER = get_logger('agent-explore-and-test')


def main():
    LOGGER.info("Starting agent...")

    app = create_app(['inbound_tasks', 'outbound_tasks'])

    worker = celery.worker.WorkController(
        app=app,
        hostname="test-agent-" + uuid.uuid4().hex,
        pool_cls='solo',
        queues=['test_agent_queue', 'agent_broadcast_tasks'])

    threading.Thread(target=worker.start).start()

    LOGGER.info("Celery started.")
    LOGGER.info("Agent started.")


if __name__ == '__main__':
    main()
Ejemplo n.º 15
0
"""Contains all inbound Celery tasks."""

import os
import jsonpickle

from aist_common.CeleryConfig.celery_app import create_app
from aist_common.log import get_logger

from memory.agent_memory import *
from loop.agent_loop import AgentLoop

LOGGER = get_logger('inbound-tasks')

app = create_app([])

# INBOUND TASKS.


@app.task(name='test_agent.start_session', queue="agent_broadcast_tasks")
def start_session(session_start_data):
    """ A Celery task that starts an agent session.

    :param session_start_data: The request payload.
    :return: False if environment variable RUNNER_URL not setup properly; otherwise, True.
    """

    LOGGER.info("Starting session.")

    sut_url = session_start_data['SUT_URL']

    if 'RUNNER_URL' not in os.environ:
Ejemplo n.º 16
0
import pandas as pd

from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, classification_report, confusion_matrix

from services.concrete_state_featurizer import ConcreteStateFeaturize
from services.confusion_matrix import print_cm
from services.frame_mapper import FrameMapper

from aist_common.log import get_logger
from aist_common.pickler import ReadWritePickles

RUN_LIVE = True
BASE_PATH = os.path.abspath(
    os.path.join(os.path.dirname(__file__), '..', 'data'))
LOGGER = get_logger('page_analysis_service')
PICKLER = ReadWritePickles()


class PageAnalysisService:
    """Handles web-page element classification and training requests."""
    def __init__(self, base_path=None):
        """ Initializes the PageAnalysisService class.

        :param base_path: An optionally provided base path from which to load pickled classifiers from.
        """

        self.__featurize = ConcreteStateFeaturize()
        self.__frame_mapper = FrameMapper()

        self.feature_mapping = {
Ejemplo n.º 17
0
"""Provides methods for retrieving best matches for form fields"""

import random
import sys

from Levenshtein import seqratio

from aist_common.log import get_logger

LOGGER = get_logger('classifier')


def levenshtein_distance(a, b):
    """ calculates the Levenshtein distance of two instances

    :param a: The first instance to compare.
    :param b: The second instance to compare.

    :return: The Levenshtein distance of the two instances.
    """

    ratio = seqratio(a, b['features'])
    return 1 - ratio


def get_neighbor(training_set, test_instance):
    """ Returns a nearest neighbor out of a given set. If there are multiple neighbors
    with the same smallest distance, one is chosen randomly.

    :param training_set: The set of instances to choose from.
    :param test_instance: The instance to which a nearest neighbor should be found.
Ejemplo n.º 18
0
"""The main Agent entry-point. Contains all necessary Celery plumbing code."""

import threading

import celery.worker
from aist_common.CeleryConfig.celery_app import create_app
from aist_common.log import get_logger

LOGGER = get_logger('agent-coordinator')


def main():

    LOGGER.info("Starting agent...")

    app = create_app(['inbound_tasks', 'outbound_tasks'])

    worker = celery.worker.WorkController(app=app,
                                          hostname="test-coordinator",
                                          pool_cls='solo',
                                          queues=['test_coordinator_queue'])

    threading.Thread(target=worker.start).start()

    LOGGER.info("Celery started.")
    LOGGER.info("Agent started.")


if __name__ == '__main__':
    main()
Ejemplo n.º 19
0
import json
import random
import requests
import os

from aist_common.log import get_logger

LOGGER = get_logger('form-expert-client')


class FormExpertClient:
    def __init__(self):
        self.FORM_EXPERT_URL = 'http://form-expert'
        if 'FORM_EXPERT_URL' in os.environ:
            self.FORM_EXPERT_URL = os.environ['FORM_EXPERT_URL']

        self.FILL_FORM_URL = '{}/api/v1/fill_form'.format(self.FORM_EXPERT_URL)

    @staticmethod
    def get_input_types():
        return [
            'VALID', 'BLANK', 'WHITESPACE', 'INVALID_LONG',
            'INVALID_SPECIAL_CHARACTERS', 'INVALID_XSR'
        ]

    def get_concrete_inputs(self, label, input_class):
        if input_class == 'VALID':
            return self.get_concrete_value(label)
        elif input_class == 'BLANK':
            values = ['']
            return random.choice(values)