<commit_before>from django.test.testcases import TestCase

from classytags.tests import DummyParser, DummyTokens

from ..models.productmodel import Product
from ..templatetags.shop_tags import Products

class ProductsTestCase(TestCase):
    """Tests for the Products templatetag."""

    def _create_fixture(self):
        Product.objects.create(
            name='product 1', slug='product-1', active=True, unit_price=42)
        Product.objects.create(
            name='product 2', slug='product-2', active=True, unit_price=42)
        Product.objects.create(
            name='product 3', slug='product-3', active=False, unit_price=42)

    def test01_should_return_all_active_products(self):
        self._create_fixture()
        tag = Products(DummyParser(), DummyTokens())
        result = tag.get_context({}, None)
        self.assertTrue(result.has_key('products'))
        self.assertEqual(len(result['products']), 2)

    def test02_should_return_objects_given_as_argument(self):
        self._create_fixture()
        tag = Products(DummyParser(), DummyTokens())
        arg_objects = Product.objects.filter(active=False)
        result = tag.get_context({}, arg_objects)
        self.assertTrue(result.has_key('products'))
        self.assertEqual(len(result['products']), 1)

<commit_msg>added test for last commit<commit_after>from django.test.testcases import TestCase

from classytags.tests import DummyParser, DummyTokens

from ..models.productmodel import Product
from ..templatetags.shop_tags import Products

class ProductsTestCase(TestCase):
    """Tests for the Products templatetag."""

    def _create_fixture(self):
        Product.objects.create(
            name='product 1', slug='product-1', active=True, unit_price=42)
        Product.objects.create(
            name='product 2', slug='product-2', active=True, unit_price=42)
        Product.objects.create(
            name='product 3', slug='product-3', active=False, unit_price=42)

    def test01_should_return_all_active_products(self):
        self._create_fixture()
        tag = Products(DummyParser(), DummyTokens())
        result = tag.get_context({}, None)
        self.assertTrue(result.has_key('products'))
        self.assertEqual(len(result['products']), 2)

    def test02_should_return_objects_given_as_argument(self):
        self._create_fixture()
        tag = Products(DummyParser(), DummyTokens())
        arg_objects = Product.objects.filter(active=False)
        result = tag.get_context({}, arg_objects)
        self.assertTrue(result.has_key('products'))
        self.assertEqual(len(result['products']), 1)

    def test03_should_return_empty_array_if_no_objects_found(self):
        self._create_fixture()
        tag = Products(DummyParser(), DummyTokens())
        arg_objects = Product.objects.filter(slug='non-existant-slug')
        result = tag.get_context({}, arg_objects)
        self.assertEqual(len(result['products']), 0)
<|endoftext|>


<commit_before><commit_msg>[fix] return HTTP 200 instead of 404 when rendering template<commit_after><|endoftext|>


<commit_before>import json
import logging

from ryu.app import simple_switch_13
from webob import Response
from ryu.controller import ofp_event
from ryu.controller.handler import CONFIG_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.app.wsgi import ControllerBase, WSGIApplication, route
from ryu.lib import dpid as dpid_lib

simple_switch_instance_name = 'simple_switch_api_app'
url = '/v1/simpleswitch/mactable/{dpid}'

class SimpleSwitchRest13(simple_switch_13.SimpleSwitch13):

    _CONTEXTS = { 'wsgi': WSGIApplication }

    def __init__(self, *args, **kwargs):
        super(SimpleSwitchRest13, self).__init__(*args, **kwargs)
        self.switches = {}
        wsgi = kwargs['wsgi']
        wsgi.register(SimpleSwitchController, {simple_switch_instance_name : self})

    @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
    def switch_features_handler(self, ev):
        super(SimpleSwitchRest13, self).switch_features_handler(ev)
        datapath = ev.msg.datapath
        self.switches[datapath.id] = datapath
        self.mac_to_port.setdefault(datapath.id, {})

    def set_mac_to_port(self, dpid, entry):
        mac_table = self.mac_to_port.setdefault(dpid, {})
        datapath = self.switches.get(dpid)

        entry_port = entry['port']
        entry_mac = entry['mac']

        if datapath is not None:
            parser = datapath.ofproto_parser
            if entry_port not in mac_table.values():

                for mac, port in mac_table.items():

                    # from known device to new device
                    actions = [parser.OFPActionOutput(entry_port)]
                    match = parser.OFPMatch(in_port=port, eth_dst=entry_mac)
                    self.add_flow(datapath, 1, match, actions)

                    # from new device to known device
                    actions = [parser.OFPActionOutput(port)]
                    match = parser.OFPMatch(in_port=entry_port, eth_dst=mac)
                    self.add_flow(datapath, 1, match, actions)

                mac_table.update({entry_mac : entry_port})
        return mac_table

class SimpleSwitchController(ControllerBase):

    def __init__(self, req, link, data, **config):
        super(SimpleSwitchController, self).__init__(req, link, data, **config)
        self.simpl_switch_spp = data[simple_switch_instance_name]

    @route('simpleswitch', url, methods=['GET'], requirements={'dpid': dpid_lib.DPID_PATTERN})
    def list_mac_table(self, req, **kwargs):

        simple_switch = self.simpl_switch_spp
        dpid = dpid_lib.str_to_dpid(kwargs['dpid'])

        if dpid not in simple_switch.mac_to_port:
            return Response(status=404)

        mac_table = simple_switch.mac_to_port.get(dpid, {})
        body = json.dumps(mac_table)
        return Response(content_type='application/json', body=body)

    @route('simpleswitch', url, methods=['PUT'], requirements={'dpid': dpid_lib.DPID_PATTERN})
    def put_mac_table(self, req, **kwargs):

        simple_switch = self.simpl_switch_spp
        dpid = dpid_lib.str_to_dpid(kwargs['dpid'])
        new_entry = eval(req.body)

        if dpid not in simple_switch.mac_to_port:
            return Response(status=404)

        try:
            mac_table = simple_switch.set_mac_to_port(dpid, new_entry)
            body = json.dumps(mac_table)
            return Response(content_type='application/json', body=body)
        except Exception as e:
            return Response(status=500)

<commit_msg> en: rest_api: Fix url<commit_after>import json
import logging

from ryu.app import simple_switch_13
from webob import Response
from ryu.controller import ofp_event
from ryu.controller.handler import CONFIG_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.app.wsgi import ControllerBase, WSGIApplication, route
from ryu.lib import dpid as dpid_lib

simple_switch_instance_name = 'simple_switch_api_app'
url = '/simpleswitch/mactable/{dpid}'

class SimpleSwitchRest13(simple_switch_13.SimpleSwitch13):

    _CONTEXTS = { 'wsgi': WSGIApplication }

    def __init__(self, *args, **kwargs):
        super(SimpleSwitchRest13, self).__init__(*args, **kwargs)
        self.switches = {}
        wsgi = kwargs['wsgi']
        wsgi.register(SimpleSwitchController, {simple_switch_instance_name : self})

    @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
    def switch_features_handler(self, ev):
        super(SimpleSwitchRest13, self).switch_features_handler(ev)
        datapath = ev.msg.datapath
        self.switches[datapath.id] = datapath
        self.mac_to_port.setdefault(datapath.id, {})

    def set_mac_to_port(self, dpid, entry):
        mac_table = self.mac_to_port.setdefault(dpid, {})
        datapath = self.switches.get(dpid)

        entry_port = entry['port']
        entry_mac = entry['mac']

        if datapath is not None:
            parser = datapath.ofproto_parser
            if entry_port not in mac_table.values():

                for mac, port in mac_table.items():

                    # from known device to new device
                    actions = [parser.OFPActionOutput(entry_port)]
                    match = parser.OFPMatch(in_port=port, eth_dst=entry_mac)
                    self.add_flow(datapath, 1, match, actions)

                    # from new device to known device
                    actions = [parser.OFPActionOutput(port)]
                    match = parser.OFPMatch(in_port=entry_port, eth_dst=mac)
                    self.add_flow(datapath, 1, match, actions)

                mac_table.update({entry_mac : entry_port})
        return mac_table

class SimpleSwitchController(ControllerBase):

    def __init__(self, req, link, data, **config):
        super(SimpleSwitchController, self).__init__(req, link, data, **config)
        self.simpl_switch_spp = data[simple_switch_instance_name]

    @route('simpleswitch', url, methods=['GET'], requirements={'dpid': dpid_lib.DPID_PATTERN})
    def list_mac_table(self, req, **kwargs):

        simple_switch = self.simpl_switch_spp
        dpid = dpid_lib.str_to_dpid(kwargs['dpid'])

        if dpid not in simple_switch.mac_to_port:
            return Response(status=404)

        mac_table = simple_switch.mac_to_port.get(dpid, {})
        body = json.dumps(mac_table)
        return Response(content_type='application/json', body=body)

    @route('simpleswitch', url, methods=['PUT'], requirements={'dpid': dpid_lib.DPID_PATTERN})
    def put_mac_table(self, req, **kwargs):

        simple_switch = self.simpl_switch_spp
        dpid = dpid_lib.str_to_dpid(kwargs['dpid'])
        new_entry = eval(req.body)

        if dpid not in simple_switch.mac_to_port:
            return Response(status=404)

        try:
            mac_table = simple_switch.set_mac_to_port(dpid, new_entry)
            body = json.dumps(mac_table)
            return Response(content_type='application/json', body=body)
        except Exception as e:
            return Response(status=500)

<|endoftext|>


<commit_before>from network_tools_app.search_command import SearchCommand
from network_tools_app import pyspeedtest
import sys

class Speedtest(SearchCommand):

    def __init__(self, runs=1, server=None):
        SearchCommand.__init__(self, run_in_preview=True, logger_name="speedtest")

        try:
            self.params = {
                'runs' : int(runs),
                'host' : server
            }
        except ValueError:
            sys.stderr.write('The runs parameter must be an integer')
            return

        self.logger.info("Speedtest running")

    def handle_results(self, results, in_preview, session_key):

        # FYI: we ignore results since this is a generating command

        # Do the speedtest
        result = {}

        st = pyspeedtest.SpeedTest(**self.params)
        result['ping'] = round(st.ping(),2)
        result['download'] = round(st.download(),2)
        result['download_readable'] = pyspeedtest.pretty_speed(st.download())

        result['upload'] = round(st.upload(),2)
        result['upload_readable'] = pyspeedtest.pretty_speed(st.upload())

        result['server'] = st.host

        # Output the results
        self.output_results([result])

if __name__ == '__main__':
    Speedtest.execute()<commit_msg>Improved error handling in the speedtest command<commit_after>from network_tools_app.search_command import SearchCommand
from network_tools_app import pyspeedtest

class Speedtest(SearchCommand):

    def __init__(self, runs=1, server=None):
        SearchCommand.__init__(self, run_in_preview=True, logger_name="speedtest")

        self.params = {
                'host' : server
        }

        try:
            self.params['runs'] = int(runs)
        except ValueError:
            raise ValueError('The runs parameter must be an integer')

        self.logger.info("Speedtest running")

    def handle_results(self, results, in_preview, session_key):

        # FYI: we ignore results since this is a generating command

        # Do the speedtest
        result = {}

        st = pyspeedtest.SpeedTest(**self.params)
        result['ping'] = round(st.ping(),2)
        result['download'] = round(st.download(),2)
        result['download_readable'] = pyspeedtest.pretty_speed(st.download())

        result['upload'] = round(st.upload(),2)
        result['upload_readable'] = pyspeedtest.pretty_speed(st.upload())

        result['server'] = st.host

        # Output the results
        self.output_results([result])

if __name__ == '__main__':
    Speedtest.execute()<|endoftext|>


<commit_before>import logging

logger = logging.getLogger(__name__)

def get_identifiers_url(db_name, db_id):
    """Return an identifiers.org URL for a given database name and ID.

    Parameters
    ----------
    db_name : str
        An internal database name: HGNC, UP, CHEBI, etc.
    db_id : str
        An identifier in the given database.

    Returns
    -------
    url : str
        An identifiers.org URL corresponding to the given database name and ID.
    """
    identifiers_url = 'http://identifiers.org/'
    bel_scai_url = 'https://arty.scai.fraunhofer.de/artifactory/bel/namespace/'
    if db_name == 'UP':
        url = identifiers_url + 'uniprot/%s' % db_id
    elif db_name == 'HGNC':
        url = identifiers_url + 'hgnc/HGNC:%s' % db_id
    elif db_name == 'IP':
        url = identifiers_url + 'interpro/%s' % db_id
    elif db_name == 'IPR':
        url = identifiers_url + 'interpro/%s' % db_id
    elif db_name == 'CHEBI':
        url = identifiers_url + 'chebi/%s' % db_id
    elif db_name == 'NCIT':
        url = identifiers_url + 'ncit/%s' % db_id
    elif db_name == 'GO':
        url = identifiers_url + 'go/%s' % db_id
    elif db_name in ('PUBCHEM', 'PCID'):  # Assuming PCID = PubChem compound ID
        if db_id.startswith('PUBCHEM:'):
            db_id = db_id[8:]
        elif db_id.startswith('PCID:'):
            db_id = db_id[5:]
        url = identifiers_url + 'pubchem.compound/%s' % db_id
    elif db_name == 'PF':
        url = identifiers_url + 'pfam/%s' % db_id
    elif db_name == 'MIRBASEM':
        url = identifiers_url + 'mirbase.mature/%s' % db_id
    elif db_name == 'MIRBASE':
        url = identifiers_url + 'mirbase/%s' % db_id
    elif db_name == 'MESH':
        url = identifiers_url + 'mesh/%s' % db_id
    elif db_name == 'EGID':
        url = identifiers_url + 'ncbigene/%s' % db_id
    elif db_name == 'HMDB':
        url = identifiers_url + 'hmdb/%s' % db_id
    elif db_name == 'LINCS':
        if db_id.startswith('LSM-'):  # Lincs Small Molecule ID
            url = identifiers_url + 'lincs.smallmolecule:%s' % db_id
        elif db_id.startswith('LCL-'):  # Lincs Cell Line ID
            url = identifiers_url + 'lincs.cell:%s' % db_id
        else:  # Assume LINCS Protein
            url = identifiers_url + 'lincs.protein:%s' % db_id
    elif db_name == 'HMS-LINCS':
        url = identifiers_url + 'lincs.protein:%s' % db_id

    # Special cases with no identifiers entry
    elif db_name == 'SCHEM':
        url = bel_scai_url + 'selventa-legacy-chemicals/' + \
            'selventa-legacy-chemicals-20150601.belns'
    elif db_name == 'SCOMP':
        url = bel_scai_url + 'selventa-named-complexes/' + \
            'selventa-named-complexes-20150601.belns'
    elif db_name == 'SFAM':
        url = bel_scai_url + 'selventa-protein-families/' + \
            'selventa-protein-families-20150601.belns'
    elif db_name == 'FPLX':
        url = 'http://identifiers.org/fplx/%s' % db_id
    elif db_name == 'LNCRNADB':
        if db_id.startswith('ENSG'):
            url = 'http://www.lncrnadb.org/search/?q=%s' % db_id
        else:  # Assmuing HGNC symbol
            url = 'http://www.lncrnadb.org/%s/' % db_id
    elif db_name == 'NXPFA':
        url = 'https://www.nextprot.org/term/FA-%s' % db_id
    elif db_name in ('UN', 'WDI', 'FAO'):
        url = 'https://github.com/clulab/eidos/wiki/JSON-LD#Grounding/%s' % \
                db_id
    elif db_name == 'HUME':
        url = ('https://github.com/BBN-E/Hume/blob/master/resource/ontologies/'
               'hume_ontology/%s' % db_id)
    elif db_name == 'CWMS':
        url = 'http://trips.ihmc.us/%s' % db_id
    elif db_name == 'SIGNOR':  # Assuming db_id == Primary ID
        url = 'https://signor.uniroma2.it/relation_result.php?id' % db_id
    elif db_name == 'SOFIA':
        url = 'http://cs.cmu.edu/sofia/%s' % db_id
    elif db_name == 'CHEMBL':
        if not db_id.startswith('CHEMBL'):
            db_id = 'CHEMBL%s' % db_id
        url = identifiers_url + 'chembl.compound/%s' % db_id
    elif db_name == 'NONCODE':
        url = 'http://www.noncode.org/show_gene.php?id=NONHSAG%s' % db_id
    elif db_name == 'TEXT':
        return None
    else:
        logger.warning('Unhandled name space %s' % db_name)
        url = None
    return url
<commit_msg>Fix error in SIGNOR URL creation<commit_after>import logging

logger = logging.getLogger(__name__)

def get_identifiers_url(db_name, db_id):
    """Return an identifiers.org URL for a given database name and ID.

    Parameters
    ----------
    db_name : str
        An internal database name: HGNC, UP, CHEBI, etc.
    db_id : str
        An identifier in the given database.

    Returns
    -------
    url : str
        An identifiers.org URL corresponding to the given database name and ID.
    """
    identifiers_url = 'http://identifiers.org/'
    bel_scai_url = 'https://arty.scai.fraunhofer.de/artifactory/bel/namespace/'
    if db_name == 'UP':
        url = identifiers_url + 'uniprot/%s' % db_id
    elif db_name == 'HGNC':
        url = identifiers_url + 'hgnc/HGNC:%s' % db_id
    elif db_name == 'IP':
        url = identifiers_url + 'interpro/%s' % db_id
    elif db_name == 'IPR':
        url = identifiers_url + 'interpro/%s' % db_id
    elif db_name == 'CHEBI':
        url = identifiers_url + 'chebi/%s' % db_id
    elif db_name == 'NCIT':
        url = identifiers_url + 'ncit/%s' % db_id
    elif db_name == 'GO':
        url = identifiers_url + 'go/%s' % db_id
    elif db_name in ('PUBCHEM', 'PCID'):  # Assuming PCID = PubChem compound ID
        if db_id.startswith('PUBCHEM:'):
            db_id = db_id[8:]
        elif db_id.startswith('PCID:'):
            db_id = db_id[5:]
        url = identifiers_url + 'pubchem.compound/%s' % db_id
    elif db_name == 'PF':
        url = identifiers_url + 'pfam/%s' % db_id
    elif db_name == 'MIRBASEM':
        url = identifiers_url + 'mirbase.mature/%s' % db_id
    elif db_name == 'MIRBASE':
        url = identifiers_url + 'mirbase/%s' % db_id
    elif db_name == 'MESH':
        url = identifiers_url + 'mesh/%s' % db_id
    elif db_name == 'EGID':
        url = identifiers_url + 'ncbigene/%s' % db_id
    elif db_name == 'HMDB':
        url = identifiers_url + 'hmdb/%s' % db_id
    elif db_name == 'LINCS':
        if db_id.startswith('LSM-'):  # Lincs Small Molecule ID
            url = identifiers_url + 'lincs.smallmolecule:%s' % db_id
        elif db_id.startswith('LCL-'):  # Lincs Cell Line ID
            url = identifiers_url + 'lincs.cell:%s' % db_id
        else:  # Assume LINCS Protein
            url = identifiers_url + 'lincs.protein:%s' % db_id
    elif db_name == 'HMS-LINCS':
        url = identifiers_url + 'lincs.protein:%s' % db_id

    # Special cases with no identifiers entry
    elif db_name == 'SCHEM':
        url = bel_scai_url + 'selventa-legacy-chemicals/' + \
            'selventa-legacy-chemicals-20150601.belns'
    elif db_name == 'SCOMP':
        url = bel_scai_url + 'selventa-named-complexes/' + \
            'selventa-named-complexes-20150601.belns'
    elif db_name == 'SFAM':
        url = bel_scai_url + 'selventa-protein-families/' + \
            'selventa-protein-families-20150601.belns'
    elif db_name == 'FPLX':
        url = 'http://identifiers.org/fplx/%s' % db_id
    elif db_name == 'LNCRNADB':
        if db_id.startswith('ENSG'):
            url = 'http://www.lncrnadb.org/search/?q=%s' % db_id
        else:  # Assmuing HGNC symbol
            url = 'http://www.lncrnadb.org/%s/' % db_id
    elif db_name == 'NXPFA':
        url = 'https://www.nextprot.org/term/FA-%s' % db_id
    elif db_name in ('UN', 'WDI', 'FAO'):
        url = 'https://github.com/clulab/eidos/wiki/JSON-LD#Grounding/%s' % \
                db_id
    elif db_name == 'HUME':
        url = ('https://github.com/BBN-E/Hume/blob/master/resource/ontologies/'
               'hume_ontology/%s' % db_id)
    elif db_name == 'CWMS':
        url = 'http://trips.ihmc.us/%s' % db_id
    elif db_name == 'SIGNOR':  # Assuming db_id == Primary ID
        url = 'https://signor.uniroma2.it/relation_result.php?id=%s' % db_id
    elif db_name == 'SOFIA':
        url = 'http://cs.cmu.edu/sofia/%s' % db_id
    elif db_name == 'CHEMBL':
        if not db_id.startswith('CHEMBL'):
            db_id = 'CHEMBL%s' % db_id
        url = identifiers_url + 'chembl.compound/%s' % db_id
    elif db_name == 'NONCODE':
        url = 'http://www.noncode.org/show_gene.php?id=NONHSAG%s' % db_id
    elif db_name == 'TEXT':
        return None
    else:
        logger.warning('Unhandled name space %s' % db_name)
        url = None
    return url
<|endoftext|>


<commit_before>"""Utility functions to parse/create OpenFlow messages."""

# Copyright (C) 2013 Nippon Telegraph and Telephone Corporation.
# Copyright (C) 2015 Brad Cowie, Christopher Lorier and Joe Stringer.
# Copyright (C) 2015 Research and Education Advanced Network New Zealand Ltd.
#
# 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" BASISo
# 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.

from collections import namedtuple

from ryu.lib import ofctl_v1_3 as ofctl
from ryu.ofproto import ether
from ryu.ofproto import ofproto_v1_3 as ofp
from ryu.ofproto import ofproto_v1_3_parser as parser

VLAN_GROUP_OFFSET = 4096
ROUTE_GROUP_OFFSET = VLAN_GROUP_OFFSET * 2

def ignore_port(port_num):
    """Return True if FAUCET should ignore this port.

    Args:
        port_num (int): switch port.
    Returns:
        bool: True if FAUCET should ignore this port.
    """
    # 0xF0000000 and up are not physical ports.
    return port_num > 0xF0000000

def apply_actions(actions):
    """Return instruction that applies action list.

    Args:
        actions (list): list of OpenFlow actions.
    Returns:
        ryu.ofproto.ofproto_v1_3_parser.OFPInstruction: instruction of actions.
    """
    return parser.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, actions)

def goto_table(table_id):
    """Return instruction to goto table.

    Args:
        table_id (int): table to goto.
    Returns:
        ryu.ofproto.ofproto_v1_3_parser.OFPInstruction: goto instruction.
    """
    return parser.OFPInstructionGotoTable(table_id)

def set_eth_src(eth_src):
    """Return action to set source Ethernet MAC address.

    Args:
        eth_src (str): source Ethernet MAC address.
    Returns:
        ryu.ofproto.ofproto_v1_3_parser.OFPActionSetField: set field action.
    """
    return parser.OFPActionSetField(eth_src=eth_src)

def set_eth_dst(eth_dst):
    """Return action to set destination Ethernet MAC address.

    Args:
        eth_src (str): destination Ethernet MAC address.
    Returns:
        ryu.ofproto.ofproto_v1_3_parser.OFPActionSetField: set field action.
    """
    return parser.OFPActionSetField(eth_dst=eth_dst)

def vid_present(vid):
    """Return VLAN VID with VID_PRESENT flag set.

    Args:
        vid (int): VLAN VID
    Returns:
        int: VLAN VID with VID_PRESENT.
    """
    return vid | ofp.OFPVID_PRESENT

def push_vlan_act(vlan_vid):
    """Return OpenFlow action list to push Ethernet 802.1Q header with VLAN VID.

    Args:
        vid (int): VLAN VID
    Returns:
        list: actions to push 802.1Q header with VLAN VID set.
    """
    return [
        parser.OFPActionPushVlan(ether.ETH_TYPE_8021Q),
        parser.OFPActionSetField(vlan_vid=vid_present(vlan_vid))
    ]

def dec_ip_ttl():
    """Return OpenFlow action to decrement IP TTL.

    Returns:
        ryu.ofproto.ofproto_v1_3_parser.OFPActionDecNwTtl: decrement IP TTL.
    """
    return parser.OFPActionDecNwTtl()

def pop_vlan():
    """Return OpenFlow action to pop outermost Ethernet 802.1Q VLAN header.

    Returns:
        ryu.ofproto.ofproto_v1_3_parser.OFPActionPopVlan: Pop VLAN.
    """
    return parser.OFPActionPopVlan()

def output_port(port_num, max_len=0):
    """Return OpenFlow action to output to a port.

    Args:
        port_num (int): port to output to.
        max_len (int): maximum length of packet to output (default no maximum).
    Returns:
        ryu.ofproto.ofproto_v1_3_parser.OFPActionOutput: output to port action.
    """
    return parser.OFPActionOutput(port_num, max_len=max_len)

def output_in_port():
    """Return OpenFlow action to output out input port.

    Returns:
       ryu.ofproto.ofproto_v1_3_parser.OFPActionOutput.
    """
    return output_port(ofp.OFPP_IN_PORT)

def output_controller():
    """Return OpenFlow action to packet in to the controller (max 256 bytes).

    Returns:
        ryu.ofproto.ofproto_v1_3_parser.OFPActionOutput: packet in action.
    """
    return output_port(ofp.OFPP_CONTROLLER, 256)

def packetout(port_num, data):
    """Return OpenFlow action to packet out to dataplane from controller.

    Args:
        port_num (int): port to output to.
        data (str): raw packet to output.
    Returns:
        ryu.ofproto.ofproto_v1_3_parser.OFPActionOutput: packet out action.
    """
    return parser.OFPPacketOut(
        datapath=None,
        buffer_id=ofp.OFP_NO_BUFFER,
        in_port=ofp.OFPP_CONTROLLER,
        actions=[output_port(port_num)],
        data=data)

def barrier():
    """Return OpenFlow barrier request.

    Returns:
        ryu.ofproto.ofproto_v1_3_parser.OFPBarrierRequest: barrier request.
    """
    return parser.OFPBarrierRequest(None)

def table_features(body):
    return parser.OFPTableFeaturesStatsRequest(
        datapath=None, body=body)

def match(match_fields):
    """Return OpenFlow matches from dict.

    Args:
        match_fields (dict): match fields and values.
    Returns:
        ryu.ofproto.ofproto_v1_3_parser.OFPMatch: matches.
    """
    return parser.OFPMatch(**match_fields)

def match_from_dict(match_dict):
    null_dp = namedtuple('null_dp', 'ofproto_parser')
    null_dp.ofproto_parser = parser
    acl_match = ofctl.to_match(null_dp, match_dict)
    return acl_match

def build_match_dict(in_port=None, vlan=None,
                     eth_type=None, eth_src=None,
                     eth_dst=None, eth_dst_mask=None,
                     ipv6_nd_target=None, icmpv6_type=None,
                     nw_proto=None,
                     nw_src=None, nw_dst=None):
    match_dict = {}
    if in_port is not None:
        match_dict['in_port'] = in_port
    if vlan is not None:
        if vlan.vid == ofp.OFPVID_NONE:
            match_dict['vlan_vid'] = ofp.OFPVID_NONE
        else:
            match_dict['vlan_vid'] = vid_present(vlan.vid)
    if eth_src is not None:
        match_dict['eth_src'] = eth_src
    if eth_dst is not None:
        if eth_dst_mask is not None:
            match_dict['eth_dst'] = (eth_dst, eth_dst_mask)
        else:
            match_dict['eth_dst'] = eth_dst
    if nw_proto is not None:
        match_dict['ip_proto'] = nw_proto
    if nw_src is not None:
        match_dict['ipv4_src'] = (str(nw_src.ip), str(nw_src.netmask))
    if icmpv6_type is not None:
        match_dict['icmpv6_type'] = icmpv6_type
    if ipv6_nd_target is not None:
        match_dict['ipv6_nd_target'] = str(ipv6_nd_target.ip)
    if nw_dst is not None:
        nw_dst_masked = (str(nw_dst.ip), str(nw_dst.netmask))
        if eth_type == ether.ETH_TYPE_ARP:
            match_dict['arp_tpa'] = nw_dst_masked
        elif eth_type == ether.ETH_TYPE_IP:
            match_dict['ipv4_dst'] = nw_dst_masked
        else:
            match_dict['ipv6_dst'] = nw_dst_masked
    if eth_type is not None:
        match_dict['eth_type'] = eth_type
    return match_dict

def flowmod(cookie, command, table_id, priority, out_port, out_group,
            match_fields, inst, hard_timeout, idle_timeout):
    return parser.OFPFlowMod(
        datapath=None,
        cookie=cookie,
        command=command,
        table_id=table_id,
        priority=priority,
        out_port=out_port,
        out_group=out_group,
        match=match_fields,
        instructions=inst,
        hard_timeout=hard_timeout,
        idle_timeout=idle_timeout)

def group_act(group_id):
    return parser.OFPActionGroup(group_id)

def bucket(weight=0, watch_port=ofp.OFPP_ANY,
           watch_group=ofp.OFPG_ANY, actions=None):
    return parser.OFPBucket(
        weight=weight,
        watch_port=watch_port,
        watch_group=watch_group,
        actions=actions)

def groupmod(datapath=None, type_=ofp.OFPGT_ALL, group_id=0, buckets=None):
    return parser.OFPGroupMod(
        datapath,
        ofp.OFPGC_MODIFY,
        type_,
        group_id,
        buckets)

def groupadd(datapath=None, type_=ofp.OFPGT_ALL, group_id=0, buckets=None):
    return parser.OFPGroupMod(
        datapath,
        ofp.OFPGC_ADD,
        type_,
        group_id,
        buckets)

def groupdel(datapath=None, group_id=ofp.OFPG_ALL):
    return parser.OFPGroupMod(
        datapath,
        ofp.OFPGC_DELETE,
        0,
        group_id)
<commit_msg>flowdel.<commit_after>"""Utility functions to parse/create OpenFlow messages."""

# Copyright (C) 2013 Nippon Telegraph and Telephone Corporation.
# Copyright (C) 2015 Brad Cowie, Christopher Lorier and Joe Stringer.
# Copyright (C) 2015 Research and Education Advanced Network New Zealand Ltd.
#
# 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" BASISo
# 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.

from collections import namedtuple

from ryu.lib import ofctl_v1_3 as ofctl
from ryu.ofproto import ether
from ryu.ofproto import ofproto_v1_3 as ofp
from ryu.ofproto import ofproto_v1_3_parser as parser

VLAN_GROUP_OFFSET = 4096
ROUTE_GROUP_OFFSET = VLAN_GROUP_OFFSET * 2

def ignore_port(port_num):
    """Return True if FAUCET should ignore this port.

    Args:
        port_num (int): switch port.
    Returns:
        bool: True if FAUCET should ignore this port.
    """
    # 0xF0000000 and up are not physical ports.
    return port_num > 0xF0000000

def apply_actions(actions):
    """Return instruction that applies action list.

    Args:
        actions (list): list of OpenFlow actions.
    Returns:
        ryu.ofproto.ofproto_v1_3_parser.OFPInstruction: instruction of actions.
    """
    return parser.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, actions)

def goto_table(table_id):
    """Return instruction to goto table.

    Args:
        table_id (int): table to goto.
    Returns:
        ryu.ofproto.ofproto_v1_3_parser.OFPInstruction: goto instruction.
    """
    return parser.OFPInstructionGotoTable(table_id)

def set_eth_src(eth_src):
    """Return action to set source Ethernet MAC address.

    Args:
        eth_src (str): source Ethernet MAC address.
    Returns:
        ryu.ofproto.ofproto_v1_3_parser.OFPActionSetField: set field action.
    """
    return parser.OFPActionSetField(eth_src=eth_src)

def set_eth_dst(eth_dst):
    """Return action to set destination Ethernet MAC address.

    Args:
        eth_src (str): destination Ethernet MAC address.
    Returns:
        ryu.ofproto.ofproto_v1_3_parser.OFPActionSetField: set field action.
    """
    return parser.OFPActionSetField(eth_dst=eth_dst)

def vid_present(vid):
    """Return VLAN VID with VID_PRESENT flag set.

    Args:
        vid (int): VLAN VID
    Returns:
        int: VLAN VID with VID_PRESENT.
    """
    return vid | ofp.OFPVID_PRESENT

def push_vlan_act(vlan_vid):
    """Return OpenFlow action list to push Ethernet 802.1Q header with VLAN VID.

    Args:
        vid (int): VLAN VID
    Returns:
        list: actions to push 802.1Q header with VLAN VID set.
    """
    return [
        parser.OFPActionPushVlan(ether.ETH_TYPE_8021Q),
        parser.OFPActionSetField(vlan_vid=vid_present(vlan_vid))
    ]

def dec_ip_ttl():
    """Return OpenFlow action to decrement IP TTL.

    Returns:
        ryu.ofproto.ofproto_v1_3_parser.OFPActionDecNwTtl: decrement IP TTL.
    """
    return parser.OFPActionDecNwTtl()

def pop_vlan():
    """Return OpenFlow action to pop outermost Ethernet 802.1Q VLAN header.

    Returns:
        ryu.ofproto.ofproto_v1_3_parser.OFPActionPopVlan: Pop VLAN.
    """
    return parser.OFPActionPopVlan()

def output_port(port_num, max_len=0):
    """Return OpenFlow action to output to a port.

    Args:
        port_num (int): port to output to.
        max_len (int): maximum length of packet to output (default no maximum).
    Returns:
        ryu.ofproto.ofproto_v1_3_parser.OFPActionOutput: output to port action.
    """
    return parser.OFPActionOutput(port_num, max_len=max_len)

def output_in_port():
    """Return OpenFlow action to output out input port.

    Returns:
       ryu.ofproto.ofproto_v1_3_parser.OFPActionOutput.
    """
    return output_port(ofp.OFPP_IN_PORT)

def output_controller():
    """Return OpenFlow action to packet in to the controller (max 256 bytes).

    Returns:
        ryu.ofproto.ofproto_v1_3_parser.OFPActionOutput: packet in action.
    """
    return output_port(ofp.OFPP_CONTROLLER, 256)

def packetout(port_num, data):
    """Return OpenFlow action to packet out to dataplane from controller.

    Args:
        port_num (int): port to output to.
        data (str): raw packet to output.
    Returns:
        ryu.ofproto.ofproto_v1_3_parser.OFPActionOutput: packet out action.
    """
    return parser.OFPPacketOut(
        datapath=None,
        buffer_id=ofp.OFP_NO_BUFFER,
        in_port=ofp.OFPP_CONTROLLER,
        actions=[output_port(port_num)],
        data=data)

def barrier():
    """Return OpenFlow barrier request.

    Returns:
        ryu.ofproto.ofproto_v1_3_parser.OFPBarrierRequest: barrier request.
    """
    return parser.OFPBarrierRequest(None)

def table_features(body):
    return parser.OFPTableFeaturesStatsRequest(
        datapath=None, body=body)

def match(match_fields):
    """Return OpenFlow matches from dict.

    Args:
        match_fields (dict): match fields and values.
    Returns:
        ryu.ofproto.ofproto_v1_3_parser.OFPMatch: matches.
    """
    return parser.OFPMatch(**match_fields)

def match_from_dict(match_dict):
    null_dp = namedtuple('null_dp', 'ofproto_parser')
    null_dp.ofproto_parser = parser
    acl_match = ofctl.to_match(null_dp, match_dict)
    return acl_match

def build_match_dict(in_port=None, vlan=None,
                     eth_type=None, eth_src=None,
                     eth_dst=None, eth_dst_mask=None,
                     ipv6_nd_target=None, icmpv6_type=None,
                     nw_proto=None,
                     nw_src=None, nw_dst=None):
    match_dict = {}
    if in_port is not None:
        match_dict['in_port'] = in_port
    if vlan is not None:
        if vlan.vid == ofp.OFPVID_NONE:
            match_dict['vlan_vid'] = ofp.OFPVID_NONE
        else:
            match_dict['vlan_vid'] = vid_present(vlan.vid)
    if eth_src is not None:
        match_dict['eth_src'] = eth_src
    if eth_dst is not None:
        if eth_dst_mask is not None:
            match_dict['eth_dst'] = (eth_dst, eth_dst_mask)
        else:
            match_dict['eth_dst'] = eth_dst
    if nw_proto is not None:
        match_dict['ip_proto'] = nw_proto
    if nw_src is not None:
        match_dict['ipv4_src'] = (str(nw_src.ip), str(nw_src.netmask))
    if icmpv6_type is not None:
        match_dict['icmpv6_type'] = icmpv6_type
    if ipv6_nd_target is not None:
        match_dict['ipv6_nd_target'] = str(ipv6_nd_target.ip)
    if nw_dst is not None:
        nw_dst_masked = (str(nw_dst.ip), str(nw_dst.netmask))
        if eth_type == ether.ETH_TYPE_ARP:
            match_dict['arp_tpa'] = nw_dst_masked
        elif eth_type == ether.ETH_TYPE_IP:
            match_dict['ipv4_dst'] = nw_dst_masked
        else:
            match_dict['ipv6_dst'] = nw_dst_masked
    if eth_type is not None:
        match_dict['eth_type'] = eth_type
    return match_dict

def flowmod(cookie, command, table_id, priority, out_port, out_group,
            match_fields, inst, hard_timeout, idle_timeout):
    return parser.OFPFlowMod(
        datapath=None,
        cookie=cookie,
        command=command,
        table_id=table_id,
        priority=priority,
        out_port=out_port,
        out_group=out_group,
        match=match_fields,
        instructions=inst,
        hard_timeout=hard_timeout,
        idle_timeout=idle_timeout)

def group_act(group_id):
    return parser.OFPActionGroup(group_id)

def bucket(weight=0, watch_port=ofp.OFPP_ANY,
           watch_group=ofp.OFPG_ANY, actions=None):
    return parser.OFPBucket(
        weight=weight,
        watch_port=watch_port,
        watch_group=watch_group,
        actions=actions)

def groupmod(datapath=None, type_=ofp.OFPGT_ALL, group_id=0, buckets=None):
    return parser.OFPGroupMod(
        datapath,
        ofp.OFPGC_MODIFY,
        type_,
        group_id,
        buckets)

def groupadd(datapath=None, type_=ofp.OFPGT_ALL, group_id=0, buckets=None):
    return parser.OFPGroupMod(
        datapath,
        ofp.OFPGC_ADD,
        type_,
        group_id,
        buckets)

def groupdel(datapath=None, group_id=ofp.OFPG_ALL):
    return parser.OFPGroupMod(
        datapath,
        ofp.OFPGC_DELETE,
        0,
        group_id)
<|endoftext|>


<commit_before>import os
import base64
import inspect
import urllib.parse

from jinja2 import Environment, ChoiceLoader, FileSystemLoader

from seedbox import config

class BaseIgnitionPackage(object):
    name = None
    template_context = {}

    def get_files(self):
        return ()

    def get_units(self):
        return ()

    def get_unit(self, name, enable=False, dropins=None):
        if dropins:
            return {
                'name': name,
                'enable': enable,
                'dropins': [{
                    'name': dropin,
                    'contents': self.render_template(dropin),
                } for dropin in dropins],
            }
        else:
            return {
                'name': name,
                'enable': enable,
                'contents': self.render_template(name),
            }

    def get_template_context(self):
        context = dict(self.template_context)
        context.setdefault('config', config)
        return context

    def render_template(self, name):
        jinja = Environment(loader=self.get_template_loader(),
                            keep_trailing_newline=True,
                            autoescape=False)
        return jinja.get_template(name).render(self.get_template_context())

    def get_template_loader(self):
        template_roots = []

        cls = self.__class__
        while True:
            template_roots.append(os.path.dirname(inspect.getfile(cls)))
            cls = get_base_class(cls)
            if cls in (BaseIgnitionPackage, None):
                break

        return ChoiceLoader([FileSystemLoader(root) for root in template_roots])

    @staticmethod
    def to_data_url(data, mediatype='', b64=False):
        if b64:
            if not isinstance(data, bytes):
                data = data.encode('utf-8')
            return 'data:{};base64,{}'.format(mediatype, base64.b64encode(data).decode('ascii'))
        else:
            return 'data:{},{}'.format(mediatype, urllib.parse.quote(data))

def get_base_class(cls):
    for base in cls.__bases__:
        if issubclass(base, BaseIgnitionPackage):
            return base
    return None
<commit_msg>cache jinja env<commit_after>import os
import base64
import inspect
import urllib.parse

from flask.helpers import locked_cached_property
from jinja2 import Environment, ChoiceLoader, FileSystemLoader

from seedbox import config

class BaseIgnitionPackage(object):
    name = None
    template_context = {}

    def get_files(self):
        return ()

    def get_units(self):
        return ()

    def get_unit(self, name, enable=False, dropins=None):
        if dropins:
            return {
                'name': name,
                'enable': enable,
                'dropins': [{
                    'name': dropin,
                    'contents': self.render_template(dropin),
                } for dropin in dropins],
            }
        else:
            return {
                'name': name,
                'enable': enable,
                'contents': self.render_template(name),
            }

    def get_template_context(self):
        context = dict(self.template_context)
        context.setdefault('config', config)
        return context

    def render_template(self, name):
        return self.jinja_env.get_template(name).render(self.get_template_context())

    @locked_cached_property
    def jinja_env(self):
        return Environment(loader=self.create_template_loader(),
                           keep_trailing_newline=True,
                           autoescape=False)

    def create_template_loader(self):
        template_roots = []

        cls = self.__class__
        while True:
            template_roots.append(os.path.dirname(inspect.getfile(cls)))
            cls = get_base_class(cls)
            if cls in (BaseIgnitionPackage, None):
                break

        return ChoiceLoader([FileSystemLoader(root) for root in template_roots])

    @staticmethod
    def to_data_url(data, mediatype='', b64=False):
        if b64:
            if not isinstance(data, bytes):
                data = data.encode('utf-8')
            return 'data:{};base64,{}'.format(mediatype, base64.b64encode(data).decode('ascii'))
        else:
            return 'data:{},{}'.format(mediatype, urllib.parse.quote(data))

def get_base_class(cls):
    for base in cls.__bases__:
        if issubclass(base, BaseIgnitionPackage):
            return base
    return None
<|endoftext|>


<commit_before>"""
Command line interface implementation.

Andrew DeOrio <awdeorio@umich.edu>
"""
from __future__ import print_function
import sys
import socket
import configparser
import smtplib
import jinja2
import click
from .template_message import TemplateMessage
from .sendmail_client import SendmailClient
from .utils import MailmergeError

# Python 2 pathlib support requires backport
try:
    from pathlib2 import Path
except ImportError:
    from pathlib import Path

# Python 2 UTF8 support requires csv backport
try:
    from backports import csv
except ImportError:
    import csv

@click.command(context_settings={"help_option_names": ['-h', '--help']})
@click.version_option()  # Auto detect version from setup.py
@click.option(
    "--sample", is_flag=True, default=False,
    help="Create sample database, template email, and config",
)
@click.option(
    "--dry-run/--no-dry-run", default=True,
    help="Don't send email, just print (True)",
)
@click.option(
    "--limit", is_flag=False, default=1,
    help="Limit the number of messages (1)",
)
@click.option(
    "--no-limit", is_flag=True, default=False,
    help="Do not limit the number of messages",
)
@click.option(
    "--template", "template_path",
    default="mailmerge_template.txt",
    type=click.Path(),
    help="template email file name (mailmerge_template.txt)"
)
@click.option(
    "--database", "database_path",
    default="mailmerge_database.csv",
    type=click.Path(),
    help="database CSV file name (mailmerge_database.csv)",
)
@click.option(
    "--config", "config_path",
    default="mailmerge_server.conf",
    type=click.Path(),
    help="configuration file name (mailmerge_server.conf)",
)
def cli(sample, dry_run, limit, no_limit,
        database_path, template_path, config_path):
    """
    Mailmerge is a simple, command line mail merge tool.

    For examples and formatting features, see:
    https://github.com/awdeorio/mailmerge
    """
    # We need an argument for each command line option.  That also means a lot
    # of local variables.
    # pylint: disable=too-many-arguments, too-many-locals

    # Convert paths from string to Path objects
    # https://github.com/pallets/click/issues/405
    template_path = Path(template_path)
    database_path = Path(database_path)
    config_path = Path(config_path)

    check_input_files(template_path, database_path, config_path, sample)

    # Limit must be >= 0
    if limit < 0:
        print("Error: limit must be greater than zero.")
        sys.exit(1)

    # No limit is an alias for limit=-1
    if no_limit:
        limit = -1

    try:
        template_message = TemplateMessage(template_path)
        csv_database = read_csv_database(database_path)
        sendmail_client = SendmailClient(config_path, dry_run)
        for i, row in enumerate_limit(csv_database, limit):
            sender, recipients, message = template_message.render(row)
            sendmail_client.sendmail(sender, recipients, message)
            print(">>> message {}".format(i))
            print(message.as_string())
            for filename in get_attachment_filenames(message):
                print(">>> attached {}".format(filename))
            print(">>> sent message {}".format(i))
    except jinja2.exceptions.TemplateError as err:
        print(">>> Error in Jinja2 template: {}".format(err))
        sys.exit(1)
    except csv.Error as err:
        print(">>> Error reading CSV file: {}".format(err))
        sys.exit(1)
    except smtplib.SMTPAuthenticationError as err:
        print(">>> Authentication error: {}".format(err))
        sys.exit(1)
    except configparser.Error as err:
        print(">>> Error reading config file {}: {}".format(config_path, err))
        sys.exit(1)
    except smtplib.SMTPException as err:
        print(">>> Error sending message", err, sep=' ', file=sys.stderr)
        sys.exit(1)
    except socket.error:
        print(">>> Error connecting to server")
        sys.exit(1)
    except MailmergeError as err:
        print(">>> {}".format(err))

    # Hints for user
    if not no_limit:
        print(
            ">>> Limit was {} messages.  "
            "To remove the limit, use the --no-limit option."
            .format(limit)
        )
    if dry_run:
        print(
            ">>> This was a dry run.  "
            "To send messages, use the --no-dry-run option."
        )

if __name__ == "__main__":
    # No value for parameter, that's how click works
    # pylint: disable=no-value-for-parameter
    cli()

def check_input_files(template_path, database_path, config_path, sample):
    """Check if input files are present and hint the user."""
    if sample:
        create_sample_input_files(
            template_path,
            database_path,
            config_path,
        )
        sys.exit(0)
    if not template_path.exists():
        print("Error: can't find template email {}".format(template_path))
        print("Create a sample (--sample) or specify a file (--template)")
        print("")
        print("See https://github.com/awdeorio/mailmerge for examples.")
        sys.exit(1)
    if not database_path.exists():
        print("Error: can't find database_path {}".format(database_path))
        print("Create a sample (--sample) or specify a file (--database)")
        sys.exit(1)

def create_sample_input_files(template_path,
                              database_path,
                              config_path):
    """Create sample template email and database."""
    print("Creating sample template email {}".format(template_path))
    if template_path.exists():
        print("Error: file exists: {}".format(template_path))
        sys.exit(1)
    with template_path.open("w") as template_file:
        template_file.write(
            u"TO: {{email}}\n"
            u"SUBJECT: Testing mailmerge\n"
            u"FROM: My Self <myself@mydomain.com>\n"
            u"\n"
            u"Hi, {{name}},\n"
            u"\n"
            u"Your number is {{number}}.\n"
        )
    print("Creating sample database {}".format(database_path))
    if database_path.exists():
        print("Error: file exists: {}".format(database_path))
        sys.exit(1)
    with database_path.open("w") as database_file:
        database_file.write(
            u'email,name,number\n'
            u'myself@mydomain.com,"Myself",17\n'
            u'bob@bobdomain.com,"Bob",42\n'
        )
    print("Creating sample config file {}".format(config_path))
    if config_path.exists():
        print("Error: file exists: {}".format(config_path))
        sys.exit(1)
    with config_path.open("w") as config_file:
        config_file.write(
            u"# Example: GMail\n"
            u"[smtp_server]\n"
            u"host = smtp.gmail.com\n"
            u"port = 465\n"
            u"security = SSL/TLS\n"
            u"username = YOUR_USERNAME_HERE\n"
            u"#\n"
            u"# Example: Wide open\n"
            u"# [smtp_server]\n"
            u"# host = open-smtp.example.com\n"
            u"# port = 25\n"
            u"# security = Never\n"
            u"#\n"
            u"# Example: University of Michigan\n"
            u"# [smtp_server]\n"
            u"# host = smtp.mail.umich.edu\n"
            u"# port = 465\n"
            u"# security = SSL/TLS\n"
            u"# username = YOUR_USERNAME_HERE\n"
            u"#\n"
            u"# Example: University of Michigan EECS Dept., with STARTTLS security\n"  # noqa: E501
            u"# [smtp_server]\n"
            u"# host = newman.eecs.umich.edu\n"
            u"# port = 25\n"
            u"# security = STARTTLS\n"
            u"# username = YOUR_USERNAME_HERE\n"
            u"#\n"
            u"# Example: University of Michigan EECS Dept., with no encryption\n"  # noqa: E501
            u"# [smtp_server]\n"
            u"# host = newman.eecs.umich.edu\n"
            u"# port = 25\n"
            u"# security = Never\n"
            u"# username = YOUR_USERNAME_HERE\n"
        )
    print("Edit these files, and then run mailmerge again")

def read_csv_database(database_path):
    """Read database CSV file, providing one line at a time."""
    with database_path.open("r") as database_file:
        reader = csv.DictReader(database_file)
        for row in reader:
            yield row

def enumerate_limit(iterable, limit):
    """Enumerate iterable, stopping after limit iterations.

    When limit == -1, enumerate entire iterable.
    """
    for i, value in enumerate(iterable):
        if limit != -1 and i >= limit:
            return
        yield i, value

def get_attachment_filenames(message):
    """Return a list of attachment filenames."""
    if message.get_content_maintype() != "multipart":
        return []

    filenames = []
    for part in message.walk():
        if part.get_content_maintype() == "multipart":
            continue
        if part.get_content_maintype() == "text":
            continue
        if part.get("Content-Disposition") == "inline":
            continue
        if part.get("Content-Disposition") is None:
            continue
        filenames.append(part.get_filename())
    return filenames
<commit_msg>fix error output<commit_after>"""
Command line interface implementation.

Andrew DeOrio <awdeorio@umich.edu>
"""
from __future__ import print_function
import sys
import socket
import configparser
import smtplib
import jinja2
import click
from .template_message import TemplateMessage
from .sendmail_client import SendmailClient
from .utils import MailmergeError

# Python 2 pathlib support requires backport
try:
    from pathlib2 import Path
except ImportError:
    from pathlib import Path

# Python 2 UTF8 support requires csv backport
try:
    from backports import csv
except ImportError:
    import csv

@click.command(context_settings={"help_option_names": ['-h', '--help']})
@click.version_option()  # Auto detect version from setup.py
@click.option(
    "--sample", is_flag=True, default=False,
    help="Create sample database, template email, and config",
)
@click.option(
    "--dry-run/--no-dry-run", default=True,
    help="Don't send email, just print (True)",
)
@click.option(
    "--limit", is_flag=False, default=1,
    help="Limit the number of messages (1)",
)
@click.option(
    "--no-limit", is_flag=True, default=False,
    help="Do not limit the number of messages",
)
@click.option(
    "--template", "template_path",
    default="mailmerge_template.txt",
    type=click.Path(),
    help="template email file name (mailmerge_template.txt)"
)
@click.option(
    "--database", "database_path",
    default="mailmerge_database.csv",
    type=click.Path(),
    help="database CSV file name (mailmerge_database.csv)",
)
@click.option(
    "--config", "config_path",
    default="mailmerge_server.conf",
    type=click.Path(),
    help="configuration file name (mailmerge_server.conf)",
)
def cli(sample, dry_run, limit, no_limit,
        database_path, template_path, config_path):
    """
    Mailmerge is a simple, command line mail merge tool.

    For examples and formatting features, see:
    https://github.com/awdeorio/mailmerge
    """
    # We need an argument for each command line option.  That also means a lot
    # of local variables.
    # pylint: disable=too-many-arguments, too-many-locals

    # Convert paths from string to Path objects
    # https://github.com/pallets/click/issues/405
    template_path = Path(template_path)
    database_path = Path(database_path)
    config_path = Path(config_path)

    check_input_files(template_path, database_path, config_path, sample)

    # Limit must be >= 0
    if limit < 0:
        print("Error: limit must be greater than zero.")
        sys.exit(1)

    # No limit is an alias for limit=-1
    if no_limit:
        limit = -1

    try:
        template_message = TemplateMessage(template_path)
        csv_database = read_csv_database(database_path)
        sendmail_client = SendmailClient(config_path, dry_run)
        for i, row in enumerate_limit(csv_database, limit):
            sender, recipients, message = template_message.render(row)
            sendmail_client.sendmail(sender, recipients, message)
            print(">>> message {}".format(i))
            print(message.as_string())
            for filename in get_attachment_filenames(message):
                print(">>> attached {}".format(filename))
            print(">>> sent message {}".format(i))
    except jinja2.exceptions.TemplateError as err:
        print(">>> Error in Jinja2 template: {}".format(err))
        sys.exit(1)
    except csv.Error as err:
        print(">>> Error reading CSV file: {}".format(err))
        sys.exit(1)
    except smtplib.SMTPAuthenticationError as err:
        print(">>> Authentication error: {}".format(err))
        sys.exit(1)
    except configparser.Error as err:
        print(">>> Error reading config file {}: {}".format(config_path, err))
        sys.exit(1)
    except smtplib.SMTPException as err:
        print(">>> Error sending message", err, sep=' ', file=sys.stderr)
        sys.exit(1)
    except socket.error:
        print(">>> Error connecting to server")
        sys.exit(1)
    except MailmergeError as err:
        print(">>> {}".format(err))

    # Hints for user
    if not no_limit:
        print(
            ">>> Limit was {} messages.  "
            "To remove the limit, use the --no-limit option."
            .format(limit)
        )
    if dry_run:
        print(
            ">>> This was a dry run.  "
            "To send messages, use the --no-dry-run option."
        )

if __name__ == "__main__":
    # No value for parameter, that's how click works
    # pylint: disable=no-value-for-parameter
    cli()

def check_input_files(template_path, database_path, config_path, sample):
    """Check if input files are present and hint the user."""
    if sample:
        create_sample_input_files(
            template_path,
            database_path,
            config_path,
        )
        sys.exit(0)
    if not template_path.exists():
        print("Error: can't find template {}".format(template_path))
        print("Create a sample (--sample) or specify a file (--template)")
        print("")
        print("See https://github.com/awdeorio/mailmerge for examples.")
        sys.exit(1)
    if not database_path.exists():
        print("Error: can't find database {}".format(database_path))
        print("Create a sample (--sample) or specify a file (--database)")
        print("")
        print("See https://github.com/awdeorio/mailmerge for examples.")
        sys.exit(1)
    if not config_path.exists():
        print("Error: can't find config {}".format(config_path))
        print("Create a sample (--sample) or specify a file (--config)")
        print("")
        print("See https://github.com/awdeorio/mailmerge for examples.")
        sys.exit(1)

def create_sample_input_files(template_path,
                              database_path,
                              config_path):
    """Create sample template email and database."""
    print("Creating sample template email {}".format(template_path))
    if template_path.exists():
        print("Error: file exists: {}".format(template_path))
        sys.exit(1)
    with template_path.open("w") as template_file:
        template_file.write(
            u"TO: {{email}}\n"
            u"SUBJECT: Testing mailmerge\n"
            u"FROM: My Self <myself@mydomain.com>\n"
            u"\n"
            u"Hi, {{name}},\n"
            u"\n"
            u"Your number is {{number}}.\n"
        )
    print("Creating sample database {}".format(database_path))
    if database_path.exists():
        print("Error: file exists: {}".format(database_path))
        sys.exit(1)
    with database_path.open("w") as database_file:
        database_file.write(
            u'email,name,number\n'
            u'myself@mydomain.com,"Myself",17\n'
            u'bob@bobdomain.com,"Bob",42\n'
        )
    print("Creating sample config file {}".format(config_path))
    if config_path.exists():
        print("Error: file exists: {}".format(config_path))
        sys.exit(1)
    with config_path.open("w") as config_file:
        config_file.write(
            u"# Example: GMail\n"
            u"[smtp_server]\n"
            u"host = smtp.gmail.com\n"
            u"port = 465\n"
            u"security = SSL/TLS\n"
            u"username = YOUR_USERNAME_HERE\n"
            u"#\n"
            u"# Example: Wide open\n"
            u"# [smtp_server]\n"
            u"# host = open-smtp.example.com\n"
            u"# port = 25\n"
            u"# security = Never\n"
            u"#\n"
            u"# Example: University of Michigan\n"
            u"# [smtp_server]\n"
            u"# host = smtp.mail.umich.edu\n"
            u"# port = 465\n"
            u"# security = SSL/TLS\n"
            u"# username = YOUR_USERNAME_HERE\n"
            u"#\n"
            u"# Example: University of Michigan EECS Dept., with STARTTLS security\n"  # noqa: E501
            u"# [smtp_server]\n"
            u"# host = newman.eecs.umich.edu\n"
            u"# port = 25\n"
            u"# security = STARTTLS\n"
            u"# username = YOUR_USERNAME_HERE\n"
            u"#\n"
            u"# Example: University of Michigan EECS Dept., with no encryption\n"  # noqa: E501
            u"# [smtp_server]\n"
            u"# host = newman.eecs.umich.edu\n"
            u"# port = 25\n"
            u"# security = Never\n"
            u"# username = YOUR_USERNAME_HERE\n"
        )
    print("Edit these files, and then run mailmerge again")

def read_csv_database(database_path):
    """Read database CSV file, providing one line at a time."""
    with database_path.open("r") as database_file:
        reader = csv.DictReader(database_file)
        for row in reader:
            yield row

def enumerate_limit(iterable, limit):
    """Enumerate iterable, stopping after limit iterations.

    When limit == -1, enumerate entire iterable.
    """
    for i, value in enumerate(iterable):
        if limit != -1 and i >= limit:
            return
        yield i, value

def get_attachment_filenames(message):
    """Return a list of attachment filenames."""
    if message.get_content_maintype() != "multipart":
        return []

    filenames = []
    for part in message.walk():
        if part.get_content_maintype() == "multipart":
            continue
        if part.get_content_maintype() == "text":
            continue
        if part.get("Content-Disposition") == "inline":
            continue
        if part.get("Content-Disposition") is None:
            continue
        filenames.append(part.get_filename())
    return filenames
<|endoftext|>


<commit_before># Copyright (c) 2013 Rackspace Hosting, Inc.
#
# 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.

from __future__ import print_function
import functools
import sys

from marconi.openstack.common.gettextutils import _
from marconi.openstack.common import log as logging

LOG = logging.getLogger(__name__)

def _fail(returncode, ex):
    """Handles terminal errors.

    :param returncode: process return code to pass to sys.exit
    :param ex: the error that occurred
    """

    print(ex, file=sys.stderr)
    LOG.exception(ex)
    sys.exit(returncode)

def runnable(func):
    """Entry point wrapper.

    Note: This call blocks until the process is killed
          or interrupted.
    """

    @functools.wraps(func)
    def _wrapper():
        try:
            logging.setup('marconi')
            func()
        except KeyboardInterrupt:
            LOG.info(_(u'Terminating'))
        except Exception as ex:
            _fail(1, ex)

    return _wrapper
<commit_msg>fix(cli): Print statement in global error handler<commit_after># Copyright (c) 2013 Rackspace Hosting, Inc.
#
# 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.

from __future__ import print_function
import functools
import sys

from marconi.openstack.common.gettextutils import _
from marconi.openstack.common import log as logging

LOG = logging.getLogger(__name__)

def _fail(returncode, ex):
    """Handles terminal errors.

    :param returncode: process return code to pass to sys.exit
    :param ex: the error that occurred
    """

    LOG.exception(ex)
    sys.exit(returncode)

def runnable(func):
    """Entry point wrapper.

    Note: This call blocks until the process is killed
          or interrupted.
    """

    @functools.wraps(func)
    def _wrapper():
        try:
            logging.setup('marconi')
            func()
        except KeyboardInterrupt:
            LOG.info(_(u'Terminating'))
        except Exception as ex:
            _fail(1, ex)

    return _wrapper
<|endoftext|>


<commit_before>__version_info__ = {
    'major': 0,
    'minor': 6,
    'micro': 2,
    'releaselevel': 'final',
    'serial': 1
}

def get_version():
    vers = ["%(major)i.%(minor)i" % __version_info__, ]

    if __version_info__['micro']:
        vers.append(".%(micro)i" % __version_info__)
    if __version_info__['releaselevel'] != 'final':
        vers.append('%(releaselevel)s%(serial)i' % __version_info__)
    return ''.join(vers)

__version__ = get_version()
<commit_msg>Bumped the version to 0.6.3<commit_after>__version_info__ = {
    'major': 0,
    'minor': 6,
    'micro': 3,
    'releaselevel': 'final',
    'serial': 1
}

def get_version():
    vers = ["%(major)i.%(minor)i" % __version_info__, ]

    if __version_info__['micro']:
        vers.append(".%(micro)i" % __version_info__)
    if __version_info__['releaselevel'] != 'final':
        vers.append('%(releaselevel)s%(serial)i' % __version_info__)
    return ''.join(vers)

__version__ = get_version()
<|endoftext|>


<commit_before>import os
import shutil
import sys
import time
from selenium.webdriver.remote.errorhandler import NoAlertPresentException
from seleniumbase import BaseCase
from seleniumbase.core.style_sheet import style
from masterqa import settings

LATEST_REPORT_DIR = "latest_report"
ARCHIVE_DIR = "report_archives"
RESULTS_PAGE = "results.html"
BAD_PAGE_LOG = "results_table.csv"
DEFAULT_VALIDATION_MESSAGE = settings.DEFAULT_VALIDATION_MESSAGE
WAIT_TIME_BEFORE_VERIFY = settings.WAIT_TIME_BEFORE_VERIFY
START_IN_FULL_SCREEN_MODE = settings.START_IN_FULL_SCREEN_MODE
MAX_IDLE_TIME_BEFORE_QUIT = settings.MAX_IDLE_TIME_BEFORE_QUIT

# This tool allows testers to quickly verify pages while assisted by automation

class __MasterQATestCase__(BaseCase):

    def get_timestamp(self):
        return str(int(time.time() * 1000))

    def manual_check_setup(self):
        self.manual_check_count = 0
        self.manual_check_successes = 0
        self.incomplete_runs = 0
        self.page_results_list = []
        self.clear_out_old_logs(archive_past_runs=False)

    def clear_out_old_logs(self, archive_past_runs=True, get_log_folder=False):
        abs_path = os.path.abspath('.')
        file_path = abs_path + "/%s" % LATEST_REPORT_DIR
        if not os.path.exists(file_path):
            os.makedirs(file_path)

        if archive_past_runs:
            archive_timestamp = int(time.time())
            if not os.path.exists("%s/../%s/" % (file_path, ARCHIVE_DIR)):
                os.makedirs("%s/../%s/" % (file_path, ARCHIVE_DIR))
            archive_dir = "%s/../%s/log_%s" % (
                file_path, ARCHIVE_DIR, archive_timestamp)
            shutil.move(file_path, archive_dir)
            os.makedirs(file_path)
            if get_log_folder:
                return archive_dir
        else:
            # Just delete bad pages to make room for the latest run.
            filelist = [f for f in os.listdir(
                "./%s" % LATEST_REPORT_DIR) if f.startswith("failed_") or (
                f == RESULTS_PAGE) or (f.startswith("automation_failure")) or (
                f == BAD_PAGE_LOG)]
            for f in filelist:
                os.remove("%s/%s" % (file_path, f))

    def manual_page_check(self, *args):
        if not args:
            instructions = DEFAULT_VALIDATION_MESSAGE
        else:
            instructions = str(args[0])

        # Give the human enough time to see the page first
        wait_time_before_verify = WAIT_TIME_BEFORE_VERIFY
        if self.verify_delay:
            wait_time_before_verify = float(self.verify_delay)
        time.sleep(wait_time_before_verify)
        question = "Approve?"
        if instructions and "?" not in instructions:
            question = instructions + " Approve?"
        elif instructions and "?" in instructions:
            question = instructions

        if self.browser == 'ie':
            text = self.execute_script(
                '''if(confirm("%s")){return "Success!"}
                else{return "Failure!"}''' % question)
        elif self.browser == 'chrome':
            self.execute_script('''if(confirm("%s"))
                {window.master_qa_result="Success!"}
                else{window.master_qa_result="Failure!"}''' % question)
            text = self.execute_script('''return window.master_qa_result''')
        else:
            self.execute_script('''if(confirm("%s")){window.alert("Success!")}
                else{window.alert("Failure!")}''' % question)
            time.sleep(0.05)
            self.wait_for_special_alert_absent()
            text = self.wait_for_and_accept_alert()
        self.manual_check_count += 1
        if "Success!" in text:
            self.manual_check_successes += 1
            self.page_results_list.append(
                '"%s","%s","%s","%s","%s","%s","%s","%s"' % (
                    self.manual_check_count,
                    "Success",
                    "-",
                    self.driver.current_url,
                    self.browser,
                    self.get_timestamp()[:-3],
                    instructions,
                    "*"))
            return 1
        else:
            bad_page_name = "failed_check_%s.jpg" % self.manual_check_count
            self.save_screenshot(bad_page_name, folder=LATEST_REPORT_DIR)
            self.page_results_list.append(
                '"%s","%s","%s","%s","%s","%s","%s","%s"' % (
                    self.manual_check_count,
                    "FAILED!",
                    bad_page_name,
                    self.driver.current_url,
                    self.browser,
                    self.get_timestamp()[:-3],
                    instructions,
                    "*"))
            return 0

    def wait_for_special_alert_absent(self, timeout=MAX_IDLE_TIME_BEFORE_QUIT):
        for x in range(int(timeout * 20)):
            try:
                alert = self.driver.switch_to_alert()
                dummy_variable = alert.text  # Raises exception if no alert
                if "?" not in dummy_variable:
                    return
                time.sleep(0.05)
            except NoAlertPresentException:
                return
        self.driver.quit()
        raise Exception(
            "%s seconds passed without human action! Stopping..." % timeout)

    def add_failure(self, exception=None):
        exc_info = None
        if exception:
            if hasattr(exception, 'msg'):
                exc_info = exception.msg
            elif hasattr(exception, 'message'):
                exc_info = exception.message
            else:
                exc_info = '(Unknown Exception)'

        self.incomplete_runs += 1
        error_page = "automation_failure_%s.jpg" % self.incomplete_runs
        self.save_screenshot(error_page, folder=LATEST_REPORT_DIR)
        self.page_results_list.append(
            '"%s","%s","%s","%s","%s","%s","%s","%s"' % (
                "ERR",
                "ERROR!",
                error_page,
                self.driver.current_url,
                self.browser,
                self.get_timestamp()[:-3],
                "-",
                exc_info))
        try:
            # Return to the original window if another was opened
            self.driver.switch_to_window(self.driver.window_handles[1])
            self.driver.close()
            self.driver.switch_to_window(self.driver.window_handles[0])
        except Exception:
            pass

    def add_bad_page_log_file(self):
        abs_path = os.path.abspath('.')
        file_path = abs_path + "/%s" % LATEST_REPORT_DIR
        log_file = "%s/%s" % (file_path, BAD_PAGE_LOG)
        f = open(log_file, 'w')
        h_p1 = '''"Num","Result","Screenshot","URL","Browser","Epoch Time",'''
        h_p2 = '''"Verification Instructions","Additional Info"\n'''
        page_header = h_p1 + h_p2
        f.write(page_header)
        for line in self.page_results_list:
            f.write("%s\n" % line)
        f.close()

    def add_results_page(self, html):
        abs_path = os.path.abspath('.')
        file_path = abs_path + "/%s" % LATEST_REPORT_DIR
        results_file_name = RESULTS_PAGE
        results_file = "%s/%s" % (file_path, results_file_name)
        f = open(results_file, 'w')
        f.write(html)
        f.close()
        return results_file

    def process_manual_check_results(self, auto_close_results_page=False):
        perfection = True
        failures_count = self.manual_check_count - self.manual_check_successes
        print "\n\n*** Test Result: ***"
        if self.manual_check_successes == self.manual_check_count:
            pass
        else:
            print "WARNING!!! There were page issues detected!"
            perfection = False

        if self.incomplete_runs > 0:
            print "WARNING!!! Not all tests finished running!"
            perfection = False

        if perfection:
            print "SUCCESS!!! Everything checks out OKAY!"
        else:
            pass
        self.add_bad_page_log_file()  # Includes successful results

        log_string = self.clear_out_old_logs(get_log_folder=True)
        log_folder = log_string.split('/')[-1]
        abs_path = os.path.abspath('.')
        file_path = abs_path + "/%s" % ARCHIVE_DIR
        log_path = "%s/%s" % (file_path, log_folder)
        web_log_path = "file://%s" % log_path

        tf_color = "#11BB11"
        if failures_count > 0:
            tf_color = "#EE3A3A"

        ir_color = "#11BB11"
        if self.incomplete_runs > 0:
            ir_color = "#EE3A3A"

        summary_table = '''

              TESTING SUMMARY

CHECKS PASSED: %s

CHECKS FAILED: %s

TOTAL VERIFICATIONS: %s

INCOMPLETE TEST RUNS: %s

''' % (self.manual_check_successes,
                                     tf_color,
                                     failures_count,
                                     self.manual_check_count,
                                     ir_color,
                                     self.incomplete_runs)

        summary_table = '''

                     %s
''' % summary_table

        log_link_shown = '../%s%s/' % (
            ARCHIVE_DIR, web_log_path.split(ARCHIVE_DIR)[1])
        csv_link = '%s/%s' % (web_log_path, BAD_PAGE_LOG)
        csv_link_shown = '%s' % BAD_PAGE_LOG
        log_table = '''

LOG FILES LINK:  %s

RESULTS TABLE:  %s

''' % (
            web_log_path, log_link_shown, csv_link, csv_link_shown)

        failure_table = '

'
        any_screenshots = False
        for line in self.page_results_list:
            line = line.split(',')
            if line[1] == '"FAILED!"' or line[1] == '"ERROR!"':
                if not any_screenshots:
                    any_screenshots = True
                    failure_table += '''

SCREENSHOT FILE

                        	LOCATION OF FAILURE

'''
                line = '%s' % (
                    "file://" + log_path + '/' + line[2], line[2]) + '''

                    ''' + '%s' % (line[3], line[3])
                line = line.replace('"', '')
                failure_table += '
%s
\n' % line
        failure_table += '

'
        powered_by = '''

            MasterQA is powered by SeleniumBase
'''
        table_view = '%s%s%s%s' % (
            summary_table, log_table, failure_table, powered_by)
        report_html = '%s%s' % (
            style, table_view)
        results_file = self.add_results_page(report_html)
        archived_results_file = log_path + '/' + RESULTS_PAGE
        shutil.copyfile(results_file, archived_results_file)
        print "\n*** The results html page is located at: ***\n" + results_file
        self.open("file://%s" % archived_results_file)
        if auto_close_results_page:
            # Long enough to notice the results before closing the page
            wait_time_before_verify = WAIT_TIME_BEFORE_VERIFY
            if self.verify_delay:
                wait_time_before_verify = float(self.verify_delay)
            time.sleep(wait_time_before_verify)
        else:
            # The user can decide when to close the results page
            print "\n*** Close the html report window to continue ***"
            while len(self.driver.window_handles):
                time.sleep(0.1)

class MasterQA(__MasterQATestCase__):

    def setUp(self):
        self.auto_close_results_page = False
        super(__MasterQATestCase__, self).setUp()
        self.manual_check_setup()
        if START_IN_FULL_SCREEN_MODE:
            self.maximize_window()

    def verify(self, *args):
        self.manual_page_check(*args)

    def auto_close_results(self):
        ''' If this method is called, the results page will automatically close
        at the end of the test run, rather than waiting on the user to close
        the results page manually.
        '''
        self.auto_close_results_page = True

    def tearDown(self):
        if sys.exc_info()[1]:
            self.add_failure(sys.exc_info()[1])
        self.process_manual_check_results(self.auto_close_results_page)
        super(__MasterQATestCase__, self).tearDown()
<commit_msg>Fix MasterQA Chrome bug<commit_after>import os
import shutil
import sys
import time
from selenium.webdriver.remote.errorhandler import NoAlertPresentException
from seleniumbase import BaseCase
from seleniumbase.core.style_sheet import style
from masterqa import settings

LATEST_REPORT_DIR = "latest_report"
ARCHIVE_DIR = "report_archives"
RESULTS_PAGE = "results.html"
BAD_PAGE_LOG = "results_table.csv"
DEFAULT_VALIDATION_MESSAGE = settings.DEFAULT_VALIDATION_MESSAGE
WAIT_TIME_BEFORE_VERIFY = settings.WAIT_TIME_BEFORE_VERIFY
START_IN_FULL_SCREEN_MODE = settings.START_IN_FULL_SCREEN_MODE
MAX_IDLE_TIME_BEFORE_QUIT = settings.MAX_IDLE_TIME_BEFORE_QUIT

# This tool allows testers to quickly verify pages while assisted by automation

class __MasterQATestCase__(BaseCase):

    def get_timestamp(self):
        return str(int(time.time() * 1000))

    def manual_check_setup(self):
        self.manual_check_count = 0
        self.manual_check_successes = 0
        self.incomplete_runs = 0
        self.page_results_list = []
        self.clear_out_old_logs(archive_past_runs=False)

    def clear_out_old_logs(self, archive_past_runs=True, get_log_folder=False):
        abs_path = os.path.abspath('.')
        file_path = abs_path + "/%s" % LATEST_REPORT_DIR
        if not os.path.exists(file_path):
            os.makedirs(file_path)

        if archive_past_runs:
            archive_timestamp = int(time.time())
            if not os.path.exists("%s/../%s/" % (file_path, ARCHIVE_DIR)):
                os.makedirs("%s/../%s/" % (file_path, ARCHIVE_DIR))
            archive_dir = "%s/../%s/log_%s" % (
                file_path, ARCHIVE_DIR, archive_timestamp)
            shutil.move(file_path, archive_dir)
            os.makedirs(file_path)
            if get_log_folder:
                return archive_dir
        else:
            # Just delete bad pages to make room for the latest run.
            filelist = [f for f in os.listdir(
                "./%s" % LATEST_REPORT_DIR) if f.startswith("failed_") or (
                f == RESULTS_PAGE) or (f.startswith("automation_failure")) or (
                f == BAD_PAGE_LOG)]
            for f in filelist:
                os.remove("%s/%s" % (file_path, f))

    def manual_page_check(self, *args):
        if not args:
            instructions = DEFAULT_VALIDATION_MESSAGE
        else:
            instructions = str(args[0])

        # Give the human enough time to see the page first
        wait_time_before_verify = WAIT_TIME_BEFORE_VERIFY
        if self.verify_delay:
            wait_time_before_verify = float(self.verify_delay)
        time.sleep(wait_time_before_verify)
        question = "Approve?"
        if instructions and "?" not in instructions:
            question = instructions + " Approve?"
        elif instructions and "?" in instructions:
            question = instructions

        if self.browser == 'ie':
            text = self.execute_script(
                '''if(confirm("%s")){return "Success!"}
                else{return "Failure!"}''' % question)
        elif self.browser == 'chrome':
            self.execute_script('''if(confirm("%s"))
                {window.master_qa_result="Success!"}
                else{window.master_qa_result="Failure!"}''' % question)
            time.sleep(0.05)
            self.wait_for_special_alert_absent()
            text = self.execute_script('''return window.master_qa_result''')
        else:
            self.execute_script('''if(confirm("%s")){window.alert("Success!")}
                else{window.alert("Failure!")}''' % question)
            time.sleep(0.05)
            self.wait_for_special_alert_absent()
            text = self.wait_for_and_accept_alert()
        self.manual_check_count += 1
        if "Success!" in text:
            self.manual_check_successes += 1
            self.page_results_list.append(
                '"%s","%s","%s","%s","%s","%s","%s","%s"' % (
                    self.manual_check_count,
                    "Success",
                    "-",
                    self.driver.current_url,
                    self.browser,
                    self.get_timestamp()[:-3],
                    instructions,
                    "*"))
            return 1
        else:
            bad_page_name = "failed_check_%s.jpg" % self.manual_check_count
            self.save_screenshot(bad_page_name, folder=LATEST_REPORT_DIR)
            self.page_results_list.append(
                '"%s","%s","%s","%s","%s","%s","%s","%s"' % (
                    self.manual_check_count,
                    "FAILED!",
                    bad_page_name,
                    self.driver.current_url,
                    self.browser,
                    self.get_timestamp()[:-3],
                    instructions,
                    "*"))
            return 0

    def wait_for_special_alert_absent(self, timeout=MAX_IDLE_TIME_BEFORE_QUIT):
        for x in range(int(timeout * 20)):
            try:
                alert = self.driver.switch_to_alert()
                dummy_variable = alert.text  # Raises exception if no alert
                if "?" not in dummy_variable:
                    return
                time.sleep(0.05)
            except NoAlertPresentException:
                return
        self.driver.quit()
        raise Exception(
            "%s seconds passed without human action! Stopping..." % timeout)

    def add_failure(self, exception=None):
        exc_info = None
        if exception:
            if hasattr(exception, 'msg'):
                exc_info = exception.msg
            elif hasattr(exception, 'message'):
                exc_info = exception.message
            else:
                exc_info = '(Unknown Exception)'

        self.incomplete_runs += 1
        error_page = "automation_failure_%s.jpg" % self.incomplete_runs
        self.save_screenshot(error_page, folder=LATEST_REPORT_DIR)
        self.page_results_list.append(
            '"%s","%s","%s","%s","%s","%s","%s","%s"' % (
                "ERR",
                "ERROR!",
                error_page,
                self.driver.current_url,
                self.browser,
                self.get_timestamp()[:-3],
                "-",
                exc_info))
        try:
            # Return to the original window if another was opened
            self.driver.switch_to_window(self.driver.window_handles[1])
            self.driver.close()
            self.driver.switch_to_window(self.driver.window_handles[0])
        except Exception:
            pass

    def add_bad_page_log_file(self):
        abs_path = os.path.abspath('.')
        file_path = abs_path + "/%s" % LATEST_REPORT_DIR
        log_file = "%s/%s" % (file_path, BAD_PAGE_LOG)
        f = open(log_file, 'w')
        h_p1 = '''"Num","Result","Screenshot","URL","Browser","Epoch Time",'''
        h_p2 = '''"Verification Instructions","Additional Info"\n'''
        page_header = h_p1 + h_p2
        f.write(page_header)
        for line in self.page_results_list:
            f.write("%s\n" % line)
        f.close()

    def add_results_page(self, html):
        abs_path = os.path.abspath('.')
        file_path = abs_path + "/%s" % LATEST_REPORT_DIR
        results_file_name = RESULTS_PAGE
        results_file = "%s/%s" % (file_path, results_file_name)
        f = open(results_file, 'w')
        f.write(html)
        f.close()
        return results_file

    def process_manual_check_results(self, auto_close_results_page=False):
        perfection = True
        failures_count = self.manual_check_count - self.manual_check_successes
        print "\n\n*** Test Result: ***"
        if self.manual_check_successes == self.manual_check_count:
            pass
        else:
            print "WARNING!!! There were page issues detected!"
            perfection = False

        if self.incomplete_runs > 0:
            print "WARNING!!! Not all tests finished running!"
            perfection = False

        if perfection:
            print "SUCCESS!!! Everything checks out OKAY!"
        else:
            pass
        self.add_bad_page_log_file()  # Includes successful results

        log_string = self.clear_out_old_logs(get_log_folder=True)
        log_folder = log_string.split('/')[-1]
        abs_path = os.path.abspath('.')
        file_path = abs_path + "/%s" % ARCHIVE_DIR
        log_path = "%s/%s" % (file_path, log_folder)
        web_log_path = "file://%s" % log_path

        tf_color = "#11BB11"
        if failures_count > 0:
            tf_color = "#EE3A3A"

        ir_color = "#11BB11"
        if self.incomplete_runs > 0:
            ir_color = "#EE3A3A"

        summary_table = '''

              TESTING SUMMARY

CHECKS PASSED: %s

CHECKS FAILED: %s

TOTAL VERIFICATIONS: %s

INCOMPLETE TEST RUNS: %s

''' % (self.manual_check_successes,
                                     tf_color,
                                     failures_count,
                                     self.manual_check_count,
                                     ir_color,
                                     self.incomplete_runs)

        summary_table = '''

                     %s
''' % summary_table

        log_link_shown = '../%s%s/' % (
            ARCHIVE_DIR, web_log_path.split(ARCHIVE_DIR)[1])
        csv_link = '%s/%s' % (web_log_path, BAD_PAGE_LOG)
        csv_link_shown = '%s' % BAD_PAGE_LOG
        log_table = '''

LOG FILES LINK:  %s

RESULTS TABLE:  %s

''' % (
            web_log_path, log_link_shown, csv_link, csv_link_shown)

        failure_table = '

'
        any_screenshots = False
        for line in self.page_results_list:
            line = line.split(',')
            if line[1] == '"FAILED!"' or line[1] == '"ERROR!"':
                if not any_screenshots:
                    any_screenshots = True
                    failure_table += '''

SCREENSHOT FILE

                        	LOCATION OF FAILURE

'''
                line = '%s' % (
                    "file://" + log_path + '/' + line[2], line[2]) + '''

                    ''' + '%s' % (line[3], line[3])
                line = line.replace('"', '')
                failure_table += '
%s
\n' % line
        failure_table += '

'
        powered_by = '''

            MasterQA is powered by SeleniumBase
'''
        table_view = '%s%s%s%s' % (
            summary_table, log_table, failure_table, powered_by)
        report_html = '%s%s' % (
            style, table_view)
        results_file = self.add_results_page(report_html)
        archived_results_file = log_path + '/' + RESULTS_PAGE
        shutil.copyfile(results_file, archived_results_file)
        print "\n*** The results html page is located at: ***\n" + results_file
        self.open("file://%s" % archived_results_file)
        if auto_close_results_page:
            # Long enough to notice the results before closing the page
            wait_time_before_verify = WAIT_TIME_BEFORE_VERIFY
            if self.verify_delay:
                wait_time_before_verify = float(self.verify_delay)
            time.sleep(wait_time_before_verify)
        else:
            # The user can decide when to close the results page
            print "\n*** Close the html report window to continue ***"
            while len(self.driver.window_handles):
                time.sleep(0.1)

class MasterQA(__MasterQATestCase__):

    def setUp(self):
        self.auto_close_results_page = False
        super(__MasterQATestCase__, self).setUp()
        self.manual_check_setup()
        if START_IN_FULL_SCREEN_MODE:
            self.maximize_window()

    def verify(self, *args):
        self.manual_page_check(*args)

    def auto_close_results(self):
        ''' If this method is called, the results page will automatically close
        at the end of the test run, rather than waiting on the user to close
        the results page manually.
        '''
        self.auto_close_results_page = True

    def tearDown(self):
        if sys.exc_info()[1]:
            self.add_failure(sys.exc_info()[1])
        self.process_manual_check_results(self.auto_close_results_page)
        super(__MasterQATestCase__, self).tearDown()
<|endoftext|>