class TestConfiguration(unittest.TestCase):

    def setUp(self):
        super(TestConfiguration, self).setUp()
        self.filename = os.path.join(os.path.dirname(__file__), 'test_param.json')
        self.parameters = PluginParameters(self.filename)

    def tearDown(self):
        super(TestConfiguration, self).tearDown()

    def test_constructor(self):
        conf = PluginParameters(self.filename)
        self.assertTrue(conf is not None)

    def test_entry_count(self):
        self.parameters.load()
        self.assertEquals(self.parameters.get_entry_count(), 4, "Entry count does not match")

    def test_items(self):
        self.parameters.load()
        items = self.parameters.get_items()
        self.assertEqual(len(items), 4)
        self.assertEquals(items[0]['name'], "Echo foo")
        self.assertEquals(items[0]['pollInterval'], 5)
        self.assertEquals(items[0]['command'], 'scripts/random.sh 0 99')
        self.assertEquals(items[1]['name'], "Echo bar")
        self.assertEquals(items[1]['pollInterval'], 5)
        self.assertEquals(items[1]['command'], 'scripts/random.sh 0 99')

    def test_empty_items(self):
        self.assertIsNone(self.parameters.get_items())
class PluginRunner(object):
    def __init__(self):
        self.module_name = None
        self.class_name = None
        self.meter_plugin = None
        self.parameters = PluginParameters()
        self.collectors = []
        self.levels = {"debug": logging.DEBUG,
                       "info": logging.INFO,
                       "warn": logging.WARN,
                       "error": logging.ERROR,
                       "critical": logging.CRITICAL}

    @staticmethod
    def usage():
        """
        Method to output the usage of plugin runner
        :return: None
        """
        sys.stderr.write("usage PluginRunner: <module name> <class name>\n")
        sys.exit(1)

    def load_plugin(self):
        """
        Dynamically load the class from the specified module that implements the Plugin
        :return:
        """
        sys.path.append(os.path.curdir)
        logger.debug('loading plugin: {0} from {1}'.format(self.class_name, self.module_name))
        module = __import__(self.module_name)
        class_ = getattr(module, self.class_name)
        meter_plugin = class_()
        meter_plugin.initialize()
        self.meter_plugin = meter_plugin

    def create_collectors(self):
        """
        Generate the collectors from each of the parameter items
        :return: None
        """

        for item in self.parameters.get_items():
            collector = self.meter_plugin.create_collector(item)
            self.collectors.append(collector)

    def start_collectors(self):
        """
        Spawn a thread for each collector
        :return:
        """
        for collector in self.collectors:
            collector.setDaemon(True)
            collector.start()

    def parse_arguments(self):
        parser = argparse.ArgumentParser(description='Plugin Runner')

        parser.add_argument('-l', '--log-level', dest='log_level', action='store', required=False,
                            choices=['debug', 'info', 'warning', 'error', 'critical'],
                            help='Sets logging level to one of debug,info,warning,error,critical. ' +
                                 'Default is logging is disabled')

        parser.add_argument('-c', '--class-name', dest='class_name', action='store',
                            required=True, metavar="class_name",
                            help='Name of the class that implements the plugin')

        parser.add_argument('-m', '--module-name', dest='module_name', action='store', default='plugin',
                            required=False, metavar="module_name",
                            help='Name of the module that contains the Plugin class')

        args = parser.parse_args()

        if args.log_level is not None:
            logging.basicConfig(stream=sys.stderr,
                            format='[%(levelname)s] (%(threadName)-s) %(message)s',
                            level=self.levels[args.log_level])

        self.class_name = args.class_name
        self.module_name = args.module_name

    def run(self):
        """
        1) Loads the class derived from Plugin
        2) Initializes and then runs Plugin
        :return: None
        """
        self.parse_arguments()
        self.parameters.load()
        self.load_plugin()
        self.meter_plugin.parameters_loaded(self.parameters)
        self.create_collectors()
        self.meter_plugin.starting()
        self.start_collectors()

        try:
            while True:
                sleep(0.1)
        except KeyboardInterrupt:
            for collector in self.collectors:
                collector.end()

            for collector in self.collectors:
                collector.join()