def test_uninstall_all(self):
        before_handlers_root = root.handlers[:]
        before_handlers_child = child.handlers[:]

        l1 = LogCapture()
        l2 = LogCapture('one.child')

        # We can see that the LogCaptures have changed the
        # handlers, removing existing ones and installing
        # their own:

        assert len(root.handlers) == 1
        assert root.handlers != before_handlers_root
        assert len(child.handlers) == 1
        assert child.handlers != before_handlers_child

        # Now we show the function in action:

        LogCapture.uninstall_all()

        # ...and we can see the handlers are back as
        # they were beefore:

        assert before_handlers_root == root.handlers
        assert before_handlers_child == child.handlers
 def test_simple(self):
     root.info('before')
     l = LogCapture()
     root.info('during')
     l.uninstall()
     root.info('after')
     assert str(l) == "root INFO\n  during"
Example #3
0
    def test_clear_global_state(self):
        from logging import _handlers, _handlerList

        capture = LogCapture()
        capture.uninstall()
        self.assertFalse(capture in _handlers)
        self.assertFalse(capture in _handlerList)
def connectTo():
    gearkey = "qnlgzsPUUxYeyQP"
    gearsecret = "1euJPvxybllEPQZzq2u9wpRJXDbjM7"
    appid = "testNo3"    
    client.create(gearkey, gearsecret, appid, {'debugmode': "True"})
    
    def on_connected():
        print("connect")
    def on_closed():
        print("close")  
    def on_rejected():
        print("reject")     
    def on_error():
        print("error")  
    def on_message():
        print("message")  
    def on_present():
        print("present")
    def on_absent():
        print("absent") 
    client.on_connect = on_connected
    client.on_error = on_error
    client.on_present = on_present
    client.on_absent = on_absent
    client.on_rejected = on_rejected
    client.on_closed = on_closed
    client.on_message = on_message
    logs = LogCapture()
    client.connect()
    print(logs)
    logs.check(('root', 'DEBUG', 'Check stored token.'))
class ExperimentRunningMock(test_integration_mock.GatewayCodeMock):

    """ Create environment for running experiments """

    def setUp(self):
        super(ExperimentRunningMock, self).setUp()
        # config experiment and create folder
        self.g_m._create_user_exp_folders(USER, EXP_ID)
        self.log_error = LogCapture('gateway_code', level=logging.ERROR)

    def tearDown(self):
        super(ExperimentRunningMock, self).tearDown()
        self.g_m._destroy_user_exp_folders(USER, EXP_ID)
        self.log_error.uninstall()

    @staticmethod
    def send_n_cmds(command, num_times, step=0.5):
        """ Send a command multiple times and return array of answers """
        answers = []
        cmd = command.split()
        for _itr in range(0, num_times):  # pylint:disable=unused-variable
            ans = OpenNodeConnection.send_one_command(cmd)
            ans = ' '.join(ans) if ans is not None else None
            answers.append(ans)
            time.sleep(step)
        return answers
Example #6
0
class UserSignupTests(TestCase):

    def setUp(self):
        self.handler = LogCapture()
        self.formatter = JsonLogFormatter(logger_name='testpilot.newuser')

        self.username = '******'
        self.password = '******'
        self.email = '*****@*****.**' % self.username

        self.user = User.objects.create_user(
            username=self.username,
            email=self.email,
            password=self.password)

        UserProfile.objects.filter(user=self.user).delete()

    def tearDown(self):
        self.handler.uninstall()

    def test_newuser_log_event(self):
        """testpilot.newuser log event should be emitted on signup"""
        self.user.is_active = True
        user_signed_up.send(sender=self.user.__class__,
                            request=None,
                            user=self.user)

        self.assertEquals(len(self.handler.records), 1)
        record = self.handler.records[0]

        details = json.loads(self.formatter.format(record))
        self.assertTrue('Fields' in details)

        fields = details['Fields']
        self.assertEqual(fields['uid'], self.user.id)
class Test(unittest.TestCase):

    def setUp(self):
        from testfixtures import LogCapture
        self.log_capture = LogCapture()
        self.log_group  = "phidgeter.ir_temperature"
        self.lvl = "DEBUG"

    def tearDown(self):
        self.log_capture.uninstall()

    def test_log_captures(self):
        # verification of log matching functionality
        from logging import getLogger
        getLogger().info("a message")
        self.log_capture.check(("root", "INFO", "a message"))

    def test_sensor_is_available(self):
        ir_temp = IRSensor()
        assert ir_temp.open_phidget() == True
        assert ir_temp.get_temperature() >= 0.0
        assert ir_temp.close_phidget() == True

    def test_sensor_is_room_temperature(self):
        ir_temp = IRSensor()
        assert ir_temp.open_phidget() == True
        print ir_temp.get_temperature()
        assert ir_temp.get_temperature() >= 20.0
        assert ir_temp.close_phidget() == True
Example #8
0
class TopLevelFormatterTest(unittest.TestCase):

    def setUp(self):
        self.handler = LogCapture()
        self.handler.addFilter(TopLevelFormatter(['test']))

    def test_top_level_logger(self):
        logger = logging.getLogger('test')
        with self.handler as l:
            logger.warning('test log msg')

        l.check(('test', 'WARNING', 'test log msg'))

    def test_children_logger(self):
        logger = logging.getLogger('test.test1')
        with self.handler as l:
            logger.warning('test log msg')

        l.check(('test', 'WARNING', 'test log msg'))

    def test_overlapping_name_logger(self):
        logger = logging.getLogger('test2')
        with self.handler as l:
            logger.warning('test log msg')

        l.check(('test2', 'WARNING', 'test log msg'))

    def test_different_name_logger(self):
        logger = logging.getLogger('different')
        with self.handler as l:
            logger.warning('test log msg')

        l.check(('different', 'WARNING', 'test log msg'))
Example #9
0
class TopLevelFormatterTest(unittest.TestCase):
    def setUp(self):
        self.handler = LogCapture()
        self.handler.addFilter(TopLevelFormatter(["test"]))

    def test_top_level_logger(self):
        logger = logging.getLogger("test")
        with self.handler as l:
            logger.warning("test log msg")

        l.check(("test", "WARNING", "test log msg"))

    def test_children_logger(self):
        logger = logging.getLogger("test.test1")
        with self.handler as l:
            logger.warning("test log msg")

        l.check(("test", "WARNING", "test log msg"))

    def test_overlapping_name_logger(self):
        logger = logging.getLogger("test2")
        with self.handler as l:
            logger.warning("test log msg")

        l.check(("test2", "WARNING", "test log msg"))

    def test_different_name_logger(self):
        logger = logging.getLogger("different")
        with self.handler as l:
            logger.warning("test log msg")

        l.check(("different", "WARNING", "test log msg"))
 def test_simple_manual_install(self):
     l = LogCapture(install=False)
     root.info('before')
     l.install()
     root.info('during')
     l.uninstall()
     root.info('after')
     assert str(l) == "root INFO\n  during"
class TestPickleSerializer(unittest.TestCase):

    layer = ZAMQP_FUNCTIONAL_TESTING

    def setUp(self):
        from testfixtures import LogCapture
        self.l = LogCapture("c.zamqp.tests")

    def tearDown(self):
        self.l.uninstall()

    def _testDeclareQueue(self):
        rabbitctl = self.layer['rabbitctl']
        self.assertIn("my.picklequeue\t0",
                      rabbitctl('list_queues')[0].split("\n"))

    def testDeclareQueue(self):
        runAsyncTest(self._testDeclareQueue)

    def _testDeclareQueueAgain(self):
        rabbitctl = self.layer['rabbitctl']
        self.assertIn("my.picklequeue\t0",
                      rabbitctl('list_queues')[0].split("\n"))

    def testDeclareQueueAgain(self):
        runAsyncTest(self._testDeclareQueueAgain)

    def _testPublishToQueue(self):
        rabbitctl = self.layer['rabbitctl']
        self.assertIn("my.picklequeue\t1",
                      rabbitctl('list_queues')[0].split("\n"))

    def _testPublishToQueueAndConsumeIt(self):
        rabbitctl = self.layer['rabbitctl']
        self.assertIn("my.picklequeue\t0",
                      rabbitctl('list_queues')[0].split("\n"))

    def testPublishToQueueAndConsumeIt(self):
        runAsyncTest(self._testDeclareQueue)

        from zope.component import getUtility
        from collective.zamqp.interfaces import IProducer
        producer = getUtility(IProducer, name="my.picklequeue")
        producer.publish({"key": "value"})

        runAsyncTest(self._testPublishToQueue)
        runAsyncTest(self._testPublishToQueueAndConsumeIt)
        self.l.check(
            ('c.zamqp.tests', 'INFO',
             "<BasicProperties(['delivery_mode=2', "
             "'content_type=application/x-python-serialize'])>"),
            ('c.zamqp.tests', 'INFO', "{'key': 'value'}"),
            ('c.zamqp.tests', 'INFO', "<type 'dict'>")
        )
 def test_multiple_loggers(self):
     l = LogCapture(('one.child','two'))
     root.info('1')
     one.info('2')
     two.info('3')
     child.info('4')
     l.uninstall()
     assert str(l) == (
         "two INFO\n  3\n"
         "one.child INFO\n  4"
     )
 def test_specific_logger(self):
     l = LogCapture('one')
     root.info('1')
     one.info('2')
     two.info('3')
     child.info('4')
     l.uninstall()
     assert str(l) == (
         "one INFO\n  2\n"
         "one.child INFO\n  4"
     )
Example #14
0
class TestElfTargetIsCompatibleWithNode(unittest.TestCase):
    """Test elftarget.is_compatible_with_node."""

    def setUp(self):
        self.m3_class = mock.Mock()
        self.m3_class.ELF_TARGET = ('ELFCLASS32', 'EM_ARM')
        self.log = LogCapture('gateway_code', level=logging.DEBUG)

    def tearDown(self):
        self.log.uninstall()

    def test_m3_like_elf_check(self):
        """Test elftarget for an m3 like node."""
        ret = elftarget.is_compatible_with_node(firmware('idle_m3.elf'),
                                                self.m3_class)
        self.assertTrue(ret)
        self.log.check()

        # invalid target
        ret = elftarget.is_compatible_with_node(firmware('node.z1'),
                                                self.m3_class)
        self.assertFalse(ret)
        self.log.check()

        # invalid, not elf file
        ret = elftarget.is_compatible_with_node(
            firmware('wsn430_print_uids.hex'), self.m3_class)
        self.assertFalse(ret)
        self.log.check(('gateway_code', 'WARNING',
                        'Invalid firmware: Not a valid elf file'))
Example #15
0
    def setUp(self):
        super(BaseTestCase, self).setUp()

        self.handler = LogCapture()

        self.username = '******'
        self.password = '******'
        self.email = '*****@*****.**' % self.username

        self.user = User.objects.create_user(
            username=self.username,
            email=self.email,
            password=self.password)

        self.users = dict((obj.username, obj) for obj in (
            User.objects.create_user(
                username='******' % idx,
                email='*****@*****.**' % idx,
                password='******' % idx
            ) for idx in range(0, 5)))

        self.experiments = dict((obj.slug, obj) for (obj, created) in (
            Experiment.objects.get_or_create(
                slug="test-%s" % idx, defaults=dict(
                    order=idx,
                    title="Longer Test Title %s" % idx,
                    short_title="Test %s" % idx,
                    description="This is a test",
                    introduction="<h1>Hello, Test!</h1>",
                    addon_id="*****@*****.**" % idx
                )) for idx in range(1, 4)))
Example #16
0
 def setUp(self):
   # webtest
   if self.use_cookie:
     cookiejar = cookielib.CookieJar()
   else:
     cookiejar = None
   self.app = TestApp(self.application, domain=self.domain, cookiejar=cookiejar)
   # os.environ
   self.origin_environ = dict()
   if "HTTP_HOST" not in self.environ.viewkeys():
     self.environ["HTTP_HOST"] = "localhost"
   for key, value in self.environ.viewitems():
     self.origin_environ[key], os.environ[key] = os.environ.get(key), value
   # testbed
   self.testbed = testbed.Testbed()
   self.testbed.activate()
   self.testbed.init_datastore_v3_stub(
     consistency_policy=datastore_stub_util.PseudoRandomHRConsistencyPolicy(probability=0),
     root_path=self.root_path,
   )
   self.testbed.init_blobstore_stub()
   self.testbed.init_files_stub()
   self.testbed.init_memcache_stub()
   self.testbed.init_taskqueue_stub(root_path=self.root_path)
   self.testbed.init_urlfetch_stub()
   self.testbed.init_user_stub()
   # logging
   self.log = LogCapture(level=logging.WARNING)
   self.log.install()
    def test_socat_needs_sigkill(self):
        """Test cases where send_signal must be called multiple times."""
        log = LogCapture('gateway_code', level=logging.WARNING)
        self.addCleanup(log.uninstall)

        only_sigkill = os.path.join(CURRENT_DIR, 'only_sigkill.py')
        only_sigkill = 'python %s' % only_sigkill

        with mock.patch.object(SerialRedirection, 'SOCAT', only_sigkill):
            self.redirect = SerialRedirection(self.tty, self.baud)
            self.redirect.start()
            time.sleep(1)
            self.redirect.stop()

        log.check(('gateway_code', 'WARNING',
                   'SerialRedirection signal: escalading to SIGKILL'))
 def setUp(self):
     self.dir = TempDirectory()
     self.db_path = self.dir.getpath('test.db')
     self.conn = sqlite3.connect(self.db_path)
     self.conn.execute('create table notes '
                       '(filename varchar, text varchar)')
     self.conn.commit()
     self.log = LogCapture()
Example #19
0
def test_query_sanitazion(query_sanitazion):
    app_client = query_sanitazion.app.test_client()
    l = LogCapture()

    url = '/v1.0/greeting'
    response = app_client.post(url, data={'name': 'Jane Doe'})
    # This is ugly. The reason for asserting the logging in this way
    # is that in order to use LogCapture().check, we'd have to assert that
    # a specific sequence of logging has occurred. This is too restricting
    # for future development, and we are really only interested in the fact
    # a single message is logged.
    messages = [x.strip() for x in str(l).split("\n")]
    assert "FormData parameter 'name' in function arguments" in messages
    assert "Query Parameter 'name' in function arguments" not in messages
    assert "Function argument 'name' not defined in specification" not in messages
    assert response.status_code == 200
    l.uninstall()
Example #20
0
    def test_atexit(self):
        m = Mock()
        with Replacer() as r:
            # make sure the marker is false, other tests will
            # probably have set it
            r.replace('testfixtures.LogCapture.atexit_setup', False)
            r.replace('atexit.register', m.register)

            l = LogCapture()

            expected = [call.register(l.atexit)]

            compare(expected, m.mock_calls)

            with catch_warnings(record=True) as w:
                l.atexit()
                self.assertTrue(len(w), 1)
                compare(str(w[0].message), ( # pragma: no branch
                    "LogCapture instances not uninstalled by shutdown, "
                    "loggers captured:\n"
                    "(None,)"
                    ))
                
            l.uninstall()

            compare(set(), LogCapture.instances)
            
            # check re-running has no ill effects
            l.atexit()
class TestJsonLogFormatter(unittest2.TestCase):

    def setUp(self):
        self.handler = LogCapture()
        self.formatter = JsonLogFormatter()

    def tearDown(self):
        self.handler.uninstall()

    def test_basic_operation(self):
        logging.debug("simple test")
        self.assertEquals(len(self.handler.records), 1)
        details = json.loads(self.formatter.format(self.handler.records[0]))
        self.assertEquals(details["message"], "simple test")
        self.assertEquals(details["name"], "root")
        self.assertEquals(details["pid"], os.getpid())
        self.assertEquals(details["op"], "root")
        self.assertEquals(details["v"], 1)
        self.assertTrue("time" in details)

    def test_custom_paramters(self):
        logger = logging.getLogger("mozsvc.test.test_logging")
        logger.warn("custom test %s", "one", extra={
            "more": "stuff",
            "op": "mytest",
        })
        self.assertEquals(len(self.handler.records), 1)
        details = json.loads(self.formatter.format(self.handler.records[0]))
        self.assertEquals(details["message"], "custom test one")
        self.assertEquals(details["name"], "mozsvc.test.test_logging")
        self.assertEquals(details["op"], "mytest")
        self.assertEquals(details["more"], "stuff")

    def test_logging_error_tracebacks(self):
        try:
            raise ValueError("\n")
        except Exception:
            logging.exception("there was an error")
        self.assertEquals(len(self.handler.records), 1)
        details = json.loads(self.formatter.format(self.handler.records[0]))
        self.assertEquals(details["message"], "there was an error")
        self.assertEquals(details["error"], "ValueError('\\n',)")
        tblines = details["traceback"].strip().split("\n")
        self.assertEquals(tblines[-1], details["error"])
        self.assertEquals(tblines[-2], "<type 'exceptions.ValueError'>")
Example #22
0
class TestRequest(unittest.TestCase):
    def setUp(self):
        self.log_capture = LogCapture()
        self.request = api.web.request.SciTranRequest({})

    def tearDown(self):
        LogCapture.uninstall_all()

    def test_request_id(self):
        self.assertEqual(len(self.request.id), 19)

    def test_request_logger_adapter(self):
        test_log_message = "test log message"
        self.request.logger.error(test_log_message)
        expected_log_output = "{0} request_id={1}".format(
            test_log_message, self.request.id
        )
        self.log_capture.check(('scitran.api', 'ERROR', expected_log_output))
Example #23
0
    def setup(self):

        self.log_capture = LogCapture()

        self.running_procs = []

        for p in self.processes:
            self.running_procs.append(sp.Popen(p,
                                               stderr=sp.DEVNULL,
                                               stdout=sp.DEVNULL))
    def test_two_logcaptures_on_same_logger(self):
        # If you create more than one LogCapture on a single
        # logger, the 2nd one installed will stop the first
        # one working!

        l1 = LogCapture()
        root.info('1st message')
        assert str(l1) == "root INFO\n  1st message"
        l2 = LogCapture()
        root.info('2nd message')

        # So, l1 missed this message:
        assert str(l1) == "root INFO\n  1st message"

        # ...because l2 kicked it out and recorded the message:

        assert str(l2) == "root INFO\n  2nd message"

        LogCapture.uninstall_all()
 def setUp(self):
     self.config = testing.setUp()
     settings = {}
     load_into_settings(self.get_ini(), settings)
     self.config.add_settings(settings)
     self.config.include("tokenserver")
     load_and_register("tokenserver", self.config)
     self.backend = self.config.registry.getUtility(INodeAssignment)
     self.backend.add_service(SERVICE, "{node}/{version}/{uid}")
     self.backend.add_node(SERVICE, "https://phx12", 100)
     self.logs = LogCapture()
Example #26
0
    def setup(self):
        self.log_capture = LogCapture()
        self.verbose_tester = BaseTester(verbose=True,
                                         item='verbose_test')

        self.default_tester = BaseTester(item='default_test')

        self.verbose_logname = '{}.{}.verbose_test'.format('servercheck',
                                                           self.verbose_tester.__class__.__name__)  # nopep8
        self.default_logname = '{}.{}.default_test'.format('servercheck',
                                                        self.default_tester.__class__.__name__)  # nopep8
Example #27
0
    def setup(self):

        self.log_capture = LogCapture()

        self.running_procs = []

        with open('/dev/null', 'w') as DEVNULL:
            for p in self.processes:
                self.running_procs.append(sp.Popen(p,
                                                   stderr=DEVNULL,
                                                   stdout=DEVNULL))
Example #28
0
    def setUp(self):
        self.all_calls = {}
        self.create_calls = {}

        # HACK: don't allow other apps to mess with us or vice versa...
        self.old_cbs = djhookbox.views._callbacks
        djhookbox.views._callbacks = []
        djhookbox.whcallback(self._cb_all)
        djhookbox.whcallback('create')(self._cb_create)

        User.objects.create_user('a', '*****@*****.**', 'a').save()

        self.logcap = LogCapture()
Example #29
0
class TestCheck(TestCase):

    def setUp(self):
        self.r = Replacer()
        self.l = LogCapture()

    def tearDown(self):
        self.l.uninstall()
        self.r.restore()

    def checker_returns(self,output):
        resolve = Mock()
        self.r.replace('checker.resolve',resolve)
        def the_checker(config_folder,param):
            return output
        resolve.return_value = the_checker
        return resolve
        
    def test_bad_checker(self):
        from checker import check
        check = should_raise(check,ImportError('No module named unknown'))
        check('/config','unknown',None)

    def test_normal(self):
        m = self.checker_returns('some output')
        check('/config','achecker',None)
        compare(m.call_args_list,[
                (('checker.checkers.achecker.check',), {})
                ])

    def test_log_newline(self):
        self.checker_returns('some output\n')
        check('/config','achecker','aparam')
        self.l.check(
            ('root', 'INFO', 'some output'),
            )

    def test_log_no_newline(self):
        self.checker_returns('some output')
        check('/config','achecker','aparam')
        self.l.check(
            ('root', 'INFO', 'some output'),
            )
        
    def test_no_log_empty(self):
        self.checker_returns('')
        check('/config','achecker','aparam')
        self.l.check()
Example #30
0
class RequestSummaryLoggingTests(TestCase):

    def setUp(self):
        super(RequestSummaryLoggingTests, self).setUp()
        self.handler = LogCapture()

    def tearDown(self):
        self.handler.uninstall()

    def test_unblackisted_are_logged(self):
        self.handler.records = []
        url = '/__version__'
        resp = self.client.get(url)
        self.assertEqual(200, resp.status_code)
        record = self.handler.records[0]
        self.assertEqual(url, record.path)

    def test_blacklisted_are_not_logged(self):
        self.handler.records = []
        url = '/__heartbeat__'
        resp = self.client.get(url)
        self.assertEqual(200, resp.status_code)
        self.assertEqual(0, len(self.handler.records))
Example #31
0
 def setUp(self):
     self.console_printer = ConsolePrinter(print_colored=False)
     self.logs = LogCapture()
     self.logs.__enter__()
Example #32
0
class TestPanoptesPluginWithEnrichmentRunner(TestPanoptesPluginRunner):
    @patch('redis.StrictRedis', panoptes_mock_redis_strict_client)
    @patch('kazoo.client.KazooClient', panoptes_mock_kazoo_client)
    def setUp(self):
        super(TestPanoptesPluginWithEnrichmentRunner, self).setUp()
        self._panoptes_resource = PanoptesResource(
            resource_site="test",
            resource_class="test",
            resource_subclass="test",
            resource_type="test",
            resource_id="test",
            resource_endpoint="test",
            resource_creation_timestamp=_TIMESTAMP,
            resource_plugin="test")
        self._runner_class = PanoptesPluginWithEnrichmentRunner

    def test_basic_operations(self):
        # Test where enrichment is None
        mock_panoptes_enrichment_cache = Mock(return_value=None)
        with patch(
                'yahoo_panoptes.framework.plugins.runner.PanoptesEnrichmentCache',
                mock_panoptes_enrichment_cache):
            runner = self._runner_class(
                "Test Polling Plugin", "polling", PanoptesPollingPlugin,
                PanoptesPluginInfo, self._panoptes_resource,
                self._panoptes_context, PanoptesTestKeyValueStore,
                PanoptesTestKeyValueStore, PanoptesTestKeyValueStore,
                "plugin_logger", PanoptesMetricsGroupSet, _callback)
            runner.execute_plugin()

            self._log_capture.check_present((
                'panoptes.tests.test_runner', 'ERROR',
                '[Test Polling Plugin] [plugin|test|site|test|class|test|subclass|test|'
                'type|test|id|test|endpoint|test] '
                'Could not set up context for plugin'))
            self._log_capture.uninstall()

        self._log_capture = LogCapture(attributes=self.extract)
        # Test with enrichment
        runner = self._runner_class(
            "Test Polling Plugin", "polling", PanoptesPollingPlugin,
            PanoptesPluginInfo, self._panoptes_resource,
            self._panoptes_context, PanoptesTestKeyValueStore,
            PanoptesTestKeyValueStore, PanoptesTestKeyValueStore,
            "plugin_logger", PanoptesMetricsGroupSet, _callback)
        runner.execute_plugin()

        self._log_capture.check_present(
            ('panoptes.tests.test_runner', 'INFO',
             'Attempting to execute plugin "Test Polling Plugin"'),
            ('panoptes.tests.test_runner', 'DEBUG',
             '''Starting Plugin Manager for "polling" plugins with the following '''
             '''configuration: {'polling': <class'''
             """ 'yahoo_panoptes.polling.polling_plugin.PanoptesPollingPlugin'>}, """
             """['tests/plugins/polling'], panoptes-plugin"""),
            ('panoptes.tests.test_runner', 'DEBUG', 'Found 3 plugins'),
            ('panoptes.tests.test_runner', 'DEBUG', 'Loaded plugin '
             '"Test Polling Plugin", version "0.1" of type "polling"'
             ', category "polling"'),
            ('panoptes.tests.test_runner', 'DEBUG',
             'Loaded plugin "Test Polling Plugin 2", '
             'version "0.1" of type "polling", category "polling"'),
            ('panoptes.tests.test_runner', 'DEBUG',
             'Loaded plugin "Test Polling Plugin Second Instance", '
             'version "0.1" of type "polling", category "polling"'),
            ('panoptes.tests.test_runner', 'INFO',
             '[Test Polling Plugin] [plugin|test|site|test|class|test|subclass|test|'
             'type|test|id|test|endpoint|test] Attempting to get lock for plugin '
             '"Test Polling Plugin"'),
            ('panoptes.tests.test_runner', 'DEBUG',
             'Attempting to get lock for plugin "Test Polling Plugin", with lock path and '
             'identifier in seconds'),
            ('panoptes.tests.test_runner', 'INFO',
             '[Test Polling Plugin] [plugin|test|site|test|class|test|subclass|test|'
             'type|test|id|test|endpoint|test] Acquired lock'),
            ('panoptes.tests.test_runner', 'INFO',
             '[Test Polling Plugin] [plugin|test|site|test|class|test|subclass|test|'
             'type|test|id|test|endpoint|test]'
             ' Ran in seconds'),
            ('panoptes.tests.test_runner', 'INFO',
             '[Test Polling Plugin] [plugin|test|site|test|class|test|subclass|test|'
             'type|test|id|test|endpoint|test] Released lock'),
            ('panoptes.tests.test_runner', 'INFO',
             '[Test Polling Plugin] [plugin|test|site|test|class|test|subclass|test|'
             'type|test|id|test|endpoint|test] Plugin returned'
             ' a result set with 1 members'),
            ('panoptes.tests.test_runner', 'INFO',
             '[Test Polling Plugin] [plugin|test|site|test|class|test|subclass|test|'
             'type|test|id|test|endpoint|test]'
             ' Callback function ran in seconds'),
            ('panoptes.tests.test_runner', 'INFO',
             '[Test Polling Plugin] [plugin|test|site|test|class|test|subclass|test|type|'
             'test|id|test|endpoint|test] GC took seconds. There are garbage objects.'
             ),
            ('panoptes.tests.test_runner', 'ERROR',
             'No enrichment data found on KV store for plugin Test Polling Plugin '
             'resource test namespace test using key test'),
            ('panoptes.tests.test_runner', 'DEBUG',
             'Successfully created PanoptesEnrichmentCache enrichment_data {} for plugin '
             'Test Polling Plugin'),
            order_matters=False)

    def test_callback_failure(self):
        runner = self._runner_class(
            "Test Polling Plugin", "polling", PanoptesPollingPlugin,
            PanoptesPluginInfo, self._panoptes_resource,
            self._panoptes_context, PanoptesTestKeyValueStore,
            PanoptesTestKeyValueStore, PanoptesTestKeyValueStore,
            "plugin_logger", PanoptesMetricsGroupSet, _callback_with_exception)
        runner.execute_plugin()

        self._log_capture.check_present((
            'panoptes.tests.test_runner', 'ERROR', '[Test Polling Plugin] '
            '[plugin|test|site|test|class|test|subclass|test|'
            'type|test|id|test|endpoint|test] Results callback function failed'
        ))

    # 'pass' is needed for these methods because the only difference in their logging output from
    # TestPanoptesPluginRunner is the presence of the PanoptesResource in some log messages.
    def test_lock_no_lock_object(self):
        pass

    def test_lock_is_none(self):
        pass

    def test_lock_is_not_locked(self):
        pass

    def test_plugin_failure(self):
        pass

    def test_plugin_wrong_result_type(self):
        runner = self._runner_class("Test Polling Plugin 2", "polling",
                                    PanoptesPollingPlugin, PanoptesPluginInfo,
                                    None, self._panoptes_context,
                                    PanoptesTestKeyValueStore,
                                    PanoptesTestKeyValueStore,
                                    PanoptesTestKeyValueStore, "plugin_logger",
                                    PanoptesMetric, _callback)
        runner.execute_plugin()

        self._log_capture.check_present((
            'panoptes.tests.test_runner', 'ERROR',
            '[Test Polling Plugin 2] [None] Could not set up context for plugin'
        ))
Example #33
0
class TestPanoptesPluginRunner(unittest.TestCase):
    @staticmethod
    def extract(record):
        message = record.getMessage()
        match_obj = re.match(r'(?P<name>.*):\w+(?P<body>.*)', message)
        if match_obj:
            message = match_obj.group('name') + match_obj.group('body')

        match_obj = re.match(
            r'(?P<start>.*[R|r]an in\s)\d+\.?\d*.*(?P<end>seconds.*)', message)
        if match_obj:
            return record.name, record.levelname, match_obj.group(
                'start') + match_obj.group('end')

        match_obj = re.match(
            r'(?P<start>.*took\s*)\d+\.?\d*.*(?P<seconds>seconds.*)\d+\s(?P<end>garbage objects.*)',
            message)
        if match_obj:
            return record.name, record.levelname, match_obj.group('start') + match_obj.group('seconds') + \
                   match_obj.group('end')

        match_obj = re.match(
            r'(?P<start>Attempting to get lock for plugin .*with lock path) \".*\".*(?P<id> and identifier).*'
            r'(?P<in> in) \d\.?\d*(?P<seconds> seconds)', message)
        if match_obj:
            return record.name, record.levelname, match_obj.group('start') + match_obj.group('id') + \
                   match_obj.group('in') + match_obj.group('seconds')

        return record.name, record.levelname, message

    @patch('redis.StrictRedis', panoptes_mock_redis_strict_client)
    @patch('kazoo.client.KazooClient', panoptes_mock_kazoo_client)
    def setUp(self):
        self.my_dir, self.panoptes_test_conf_file = get_test_conf_file()
        self._panoptes_context = PanoptesContext(
            self.panoptes_test_conf_file,
            key_value_store_class_list=[PanoptesTestKeyValueStore],
            create_message_producer=False,
            async_message_producer=False,
            create_zookeeper_client=True)

        self._runner_class = PanoptesPluginRunner
        self._log_capture = LogCapture(attributes=self.extract)

    def tearDown(self):
        self._log_capture.uninstall()

    def test_logging_methods(self):
        runner = self._runner_class("Test Polling Plugin", "polling",
                                    PanoptesPollingPlugin, PanoptesPluginInfo,
                                    None, self._panoptes_context,
                                    PanoptesTestKeyValueStore,
                                    PanoptesTestKeyValueStore,
                                    PanoptesTestKeyValueStore, "plugin_logger",
                                    PanoptesMetricsGroupSet, _callback)

        #  Ensure logging methods run:
        runner.info(PanoptesTestPluginNoLock(), "Test Info log message")
        runner.warn(PanoptesTestPluginNoLock(), "Test Warning log message")
        runner.error(PanoptesTestPluginNoLock(), "Test Error log message",
                     Exception)
        runner.exception(PanoptesTestPluginNoLock(),
                         "Test Exception log message")

        self._log_capture.check(
            ('panoptes.tests.test_runner', 'INFO',
             '[None] [{}] Test Info log message'),
            ('panoptes.tests.test_runner', 'WARNING',
             '[None] [{}] Test Warning log message'),
            ('panoptes.tests.test_runner', 'ERROR',
             "[None] [{}] Test Error log message: <type 'exceptions.Exception'>"
             ), ('panoptes.tests.test_runner', 'ERROR',
                 '[None] [{}] Test Exception log message'))

    def test_basic_operations(self):
        runner = self._runner_class("Test Polling Plugin", "polling",
                                    PanoptesPollingPlugin, PanoptesPluginInfo,
                                    None, self._panoptes_context,
                                    PanoptesTestKeyValueStore,
                                    PanoptesTestKeyValueStore,
                                    PanoptesTestKeyValueStore, "plugin_logger",
                                    PanoptesMetricsGroupSet, _callback)

        runner.execute_plugin()

        self._log_capture.check_present(
            ('panoptes.tests.test_runner', 'INFO',
             'Attempting to execute plugin "Test Polling Plugin"'),
            ('panoptes.tests.test_runner', 'DEBUG',
             '''Starting Plugin Manager for "polling" plugins with the following '''
             '''configuration: {'polling': <class'''
             """ 'yahoo_panoptes.polling.polling_plugin.PanoptesPollingPlugin'>}, """
             """['tests/plugins/polling'], panoptes-plugin"""),
            ('panoptes.tests.test_runner', 'DEBUG', 'Found 3 plugins'),
            ('panoptes.tests.test_runner', 'DEBUG', 'Loaded plugin '
             '"Test Polling Plugin", version "0.1" of type "polling"'
             ', category "polling"'),
            ('panoptes.tests.test_runner', 'DEBUG',
             'Loaded plugin "Test Polling Plugin 2", '
             'version "0.1" of type "polling", category "polling"'),
            ('panoptes.tests.test_runner', 'DEBUG',
             'Loaded plugin "Test Polling Plugin Second Instance", '
             'version "0.1" of type "polling", category "polling"'),
            ('panoptes.tests.test_runner', 'INFO',
             '''[Test Polling Plugin] [None] '''
             '''Attempting to get lock for plugin "Test Polling Plugin"'''),
            ('panoptes.tests.test_runner', 'DEBUG',
             'Attempting to get lock for plugin "Test Polling Plugin", with lock path and '
             'identifier in seconds'),
            ('panoptes.tests.test_runner', 'INFO',
             '[Test Polling Plugin] [None] Acquired lock'),
            ('panoptes.tests.test_runner', 'INFO',
             '[Test Polling Plugin] [None]'
             ' Ran in seconds'),
            ('panoptes.tests.test_runner', 'INFO',
             '[Test Polling Plugin] [None] Released lock'),
            ('panoptes.tests.test_runner', 'INFO',
             '[Test Polling Plugin] [None] Plugin returned'
             ' a result set with 1 members'),
            ('panoptes.tests.test_runner', 'INFO',
             '[Test Polling Plugin] [None]'
             ' Callback function ran in seconds'),
            ('panoptes.tests.test_runner', 'INFO',
             '[Test Polling Plugin] [None] GC took seconds. There are garbage objects.'
             ), ('panoptes.tests.test_runner', 'DEBUG',
                 'Deleting module: yapsy_loaded_plugin_Test_Polling_Plugin_0'),
            ('panoptes.tests.test_runner', 'DEBUG',
             'Deleting module: yapsy_loaded_plugin_Test_Polling_Plugin_Second_Instance_0'
             ),
            order_matters=False)

    def test_nonexistent_plugin(self):
        runner = self._runner_class("Non-existent Plugin", "polling",
                                    PanoptesPollingPlugin, PanoptesPluginInfo,
                                    None, self._panoptes_context,
                                    PanoptesTestKeyValueStore,
                                    PanoptesTestKeyValueStore,
                                    PanoptesTestKeyValueStore, "plugin_logger",
                                    PanoptesMetricsGroupSet, _callback)
        runner.execute_plugin()
        self._log_capture.check_present((
            'panoptes.tests.test_runner', 'INFO',
            'Attempting to execute plugin "Non-existent Plugin"'
        ), (
            'panoptes.tests.test_runner', 'DEBUG',
            'Starting Plugin Manager for "polling" plugins with the following '
            "configuration: {'polling': <class 'yahoo_panoptes.polling.polling_plugin."
            "PanoptesPollingPlugin'>}, "
            "['tests/plugins/polling'], panoptes-plugin"
        ), ('panoptes.tests.test_runner', 'DEBUG', 'Found 3 plugins'), (
            'panoptes.tests.test_runner', 'DEBUG',
            'Loaded plugin "Test Polling Plugin", version "0.1" of type "polling", '
            'category "polling"'
        ), ('panoptes.tests.test_runner', 'DEBUG',
            'Loaded plugin "Test Polling Plugin Second Instance", version "0.1" of type '
            '"polling", category "polling"'), (
                'panoptes.tests.test_runner', 'WARNING',
                'No plugin named "Non-existent Plugin" found in "'
                '''['tests/plugins/polling']"'''))

    def test_bad_plugin_type(self):
        runner = self._runner_class("Test Polling Plugin", "bad",
                                    PanoptesPollingPlugin, PanoptesPluginInfo,
                                    None, self._panoptes_context,
                                    PanoptesTestKeyValueStore,
                                    PanoptesTestKeyValueStore,
                                    PanoptesTestKeyValueStore, "plugin_logger",
                                    PanoptesMetricsGroupSet, _callback)
        runner.execute_plugin()

        self._log_capture.check_present((
            'panoptes.tests.test_runner', 'ERROR',
            '''Error trying to load plugin "Test Polling Plugin": KeyError('bad',)'''
        ))

    def test_execute_now_false(self):
        mock_get_plugin_by_name = MagicMock(
            return_value=MockPluginExecuteNow())
        with patch(
                'yahoo_panoptes.framework.plugins.runner.PanoptesPluginManager.getPluginByName',
                mock_get_plugin_by_name):
            runner = self._runner_class(
                "Test Polling Plugin", "polling", PanoptesPollingPlugin,
                PanoptesPluginInfo, None, self._panoptes_context,
                PanoptesTestKeyValueStore, PanoptesTestKeyValueStore,
                PanoptesTestKeyValueStore, "plugin_logger",
                PanoptesMetricsGroupSet, _callback)
            runner.execute_plugin()

            self._log_capture.check_present(
                ('panoptes.tests.test_runner', 'INFO',
                 'Attempting to execute plugin "Test Polling Plugin"'),
                ('panoptes.tests.test_runner', 'DEBUG',
                 '''Starting Plugin Manager for '''
                 '''"polling" plugins with the '''
                 '''following configuration: {'polling': '''
                 """<class 'yahoo_panoptes.polling.polling_plugin.PanoptesPollingPlugin'"""
                 """>}, ['tests/plugins/polling'], panoptes-plugin"""),
                ('panoptes.tests.test_runner', 'DEBUG', 'Found 3 plugins'),
                ('panoptes.tests.test_runner', 'DEBUG', 'Loaded plugin '
                 '"Test Polling Plugin", version "0.1" of type "polling"'
                 ', category "polling"'),
                ('panoptes.tests.test_runner', 'DEBUG',
                 'Loaded plugin "Test Polling Plugin Second Instance", '
                 'version "0.1" of type "polling", category "polling"'))

    def test_callback_failure(self):
        runner = self._runner_class(
            "Test Polling Plugin", "polling", PanoptesPollingPlugin,
            PanoptesPluginInfo, None, self._panoptes_context,
            PanoptesTestKeyValueStore, PanoptesTestKeyValueStore,
            PanoptesTestKeyValueStore, "plugin_logger",
            PanoptesMetricsGroupSet, _callback_with_exception)
        runner.execute_plugin()

        self._log_capture.check_present(
            ('panoptes.tests.test_runner', 'ERROR', '[Test Polling Plugin] '
             '[None] Results callback function failed'))

    def test_lock_no_lock_object(self):
        mock_plugin = MagicMock(return_value=PanoptesTestPluginNoLock)
        mock_get_context = MagicMock(return_value=self._panoptes_context)
        with patch(
                'yahoo_panoptes.framework.plugins.runner.PanoptesPluginManager.getPluginByName',
                mock_plugin):
            with patch(
                    'yahoo_panoptes.framework.plugins.runner.PanoptesPluginRunner._get_context',
                    mock_get_context):
                runner = self._runner_class(
                    "Test Polling Plugin", "polling", PanoptesPollingPlugin,
                    PanoptesPluginInfo, None, self._panoptes_context,
                    PanoptesTestKeyValueStore, PanoptesTestKeyValueStore,
                    PanoptesTestKeyValueStore, "plugin_logger",
                    PanoptesMetricsGroupSet, _callback)
                runner.execute_plugin()

                self._log_capture.check_present(
                    ('panoptes.tests.test_runner', 'ERROR',
                     '[None] [{}] Error in acquiring lock'))

    def test_lock_is_none(self):
        mock_get_plugin_by_name = MagicMock(return_value=MockPluginLockNone())
        mock_get_context = MagicMock(return_value=self._panoptes_context)
        with patch(
                'yahoo_panoptes.framework.plugins.runner.PanoptesPluginManager.getPluginByName',
                mock_get_plugin_by_name):
            with patch(
                    'yahoo_panoptes.framework.plugins.runner.PanoptesPluginRunner._get_context',
                    mock_get_context):
                runner = self._runner_class(
                    "Test Polling Plugin", "polling", PanoptesPollingPlugin,
                    PanoptesPluginInfo, None, self._panoptes_context,
                    PanoptesTestKeyValueStore, PanoptesTestKeyValueStore,
                    PanoptesTestKeyValueStore, "plugin_logger",
                    PanoptesMetricsGroupSet, _callback)
                runner.execute_plugin()

                self._log_capture.check_present(
                    ('panoptes.tests.test_runner', 'INFO',
                     '[None] [{}] Attempting to get lock for plugin'
                     ' "Test Polling Plugin"'))

    def test_lock_is_not_locked(self):
        mock_get_plugin_by_name = MagicMock(
            return_value=MockPluginLockIsNotLocked())
        mock_get_context = MagicMock(return_value=self._panoptes_context)
        with patch(
                'yahoo_panoptes.framework.plugins.runner.PanoptesPluginManager.getPluginByName',
                mock_get_plugin_by_name):
            with patch(
                    'yahoo_panoptes.framework.plugins.runner.PanoptesPluginRunner._get_context',
                    mock_get_context):
                runner = self._runner_class(
                    "Test Polling Plugin", "polling", PanoptesPollingPlugin,
                    PanoptesPluginInfo, None, self._panoptes_context,
                    PanoptesTestKeyValueStore, PanoptesTestKeyValueStore,
                    PanoptesTestKeyValueStore, "plugin_logger",
                    PanoptesMetricsGroupSet, _callback)
                runner.execute_plugin()

                self._log_capture.check_present(
                    ('panoptes.tests.test_runner', 'INFO',
                     '[None] [{}] Attempting to get lock for plugin'
                     ' "Test Polling Plugin"'))

    def test_plugin_failure(self):
        mock_plugin = MagicMock(
            return_value=PanoptesTestPluginRaisePluginReleaseException)
        mock_get_context = MagicMock(return_value=self._panoptes_context)
        with patch(
                'yahoo_panoptes.framework.plugins.runner.PanoptesPluginManager.getPluginByName',
                mock_plugin):
            with patch(
                    'yahoo_panoptes.framework.plugins.runner.PanoptesPluginRunner._get_context',
                    mock_get_context):
                runner = self._runner_class(
                    "Test Polling Plugin", "polling", PanoptesPollingPlugin,
                    PanoptesPluginInfo, None, self._panoptes_context,
                    PanoptesTestKeyValueStore, PanoptesTestKeyValueStore,
                    PanoptesTestKeyValueStore, "plugin_logger",
                    PanoptesMetricsGroupSet, _callback)
                runner.execute_plugin()

                self._log_capture.check_present(
                    ('panoptes.tests.test_runner', 'ERROR',
                     '[None] [{}] Failed to execute plugin'),
                    ('panoptes.tests.test_runner', 'INFO',
                     '[None] [{}] Ran in seconds'),
                    ('panoptes.tests.test_runner', 'ERROR',
                     '[None] [{}] Failed to release lock for plugin'),
                    ('panoptes.tests.test_runner', 'WARNING',
                     '[None] [{}] Plugin did not return any results'))

    def test_plugin_wrong_result_type(self):
        runner = self._runner_class("Test Polling Plugin 2", "polling",
                                    PanoptesPollingPlugin, PanoptesPluginInfo,
                                    None, self._panoptes_context,
                                    PanoptesTestKeyValueStore,
                                    PanoptesTestKeyValueStore,
                                    PanoptesTestKeyValueStore, "plugin_logger",
                                    PanoptesMetricsGroupSet, _callback)
        runner.execute_plugin()

        self._log_capture.check_present((
            'panoptes.tests.test_runner', 'WARNING',
            '[Test Polling Plugin 2] [None] Plugin returned an unexpected result type: '
            '"PanoptesMetricsGroup"'))
Example #34
0
 def test_https_connect_tunnel_error(self):
     crawler = get_crawler(SimpleSpider)
     with LogCapture() as log:
         yield crawler.crawl("https://localhost:99999/status?n=200")
     self._assert_got_tunnel_error(log)
Example #35
0
    def test_publish(self, mock_access_token):  # pylint: disable=unused-argument,too-many-statements
        publisher_course_run = self._create_course_run_for_publication()
        currency = Currency.objects.get(code='USD')

        common_entitlement_kwargs = {
            'course': publisher_course_run.course,
            'currency': currency,
        }
        professional_entitlement = CourseEntitlementFactory(
            mode=CourseEntitlement.PROFESSIONAL, **common_entitlement_kwargs)
        verified_entitlement = CourseEntitlementFactory(
            mode=CourseEntitlement.VERIFIED, **common_entitlement_kwargs)

        common_seat_kwargs = {
            'course_run': publisher_course_run,
            'currency': currency,
        }
        audit_seat = SeatFactory(type=Seat.AUDIT,
                                 upgrade_deadline=None,
                                 **common_seat_kwargs)
        # The credit seat should NOT be published.
        SeatFactory(type=Seat.CREDIT, **common_seat_kwargs)
        professional_seat = SeatFactory(type=Seat.PROFESSIONAL,
                                        **common_seat_kwargs)
        verified_seat = SeatFactory(type=Seat.VERIFIED, **common_seat_kwargs)

        partner = publisher_course_run.course.organizations.first().partner
        self._set_test_client_domain_and_login(partner)

        self._mock_studio_api_success(publisher_course_run)
        self._mock_ecommerce_api(publisher_course_run)
        with LogCapture(LOGGER_NAME) as log:
            url = reverse('publisher:api:v1:course_run-publish',
                          kwargs={'pk': publisher_course_run.pk})
            response = self.client.post(url, {})
            assert response.status_code == 200
            log.check((
                LOGGER_NAME, 'INFO',
                'Published course run with id: [{}] lms_course_id: [{}], user: [{}], date: [{}]'
                .format(publisher_course_run.id,
                        publisher_course_run.lms_course_id, self.user,
                        date.today())))

        assert len(responses.calls) == 3
        expected = {
            'discovery': CourseRunViewSet.PUBLICATION_SUCCESS_STATUS,
            'ecommerce': CourseRunViewSet.PUBLICATION_SUCCESS_STATUS,
            'studio': CourseRunViewSet.PUBLICATION_SUCCESS_STATUS,
        }
        assert response.data == expected

        # Verify the correct deadlines were sent to the E-Commerce API
        ecommerce_body = json.loads(responses.calls[2].request.body)
        expected = [
            serialize_seat_for_ecommerce_api(audit_seat),
            serialize_seat_for_ecommerce_api(professional_seat),
            serialize_seat_for_ecommerce_api(verified_seat),
            serialize_entitlement_for_ecommerce_api(professional_entitlement),
            serialize_entitlement_for_ecommerce_api(verified_entitlement),
        ]
        assert ecommerce_body['products'] == expected
        assert ecommerce_body['verification_deadline'] == serialize_datetime(
            publisher_course_run.end_date_temporary)

        discovery_course_run = CourseRun.objects.get(
            key=publisher_course_run.lms_course_id)
        publisher_course = publisher_course_run.course
        discovery_course = discovery_course_run.course

        assert ecommerce_body['id'] == publisher_course_run.lms_course_id
        assert ecommerce_body['uuid'] == str(discovery_course.uuid)

        # pylint: disable=no-member
        assert discovery_course_run.title_override == publisher_course_run.title_override
        assert discovery_course_run.short_description_override is None
        assert discovery_course_run.full_description_override is None
        assert discovery_course_run.start == publisher_course_run.start_date_temporary
        assert discovery_course_run.end == publisher_course_run.end_date_temporary
        assert discovery_course_run.pacing_type == publisher_course_run.pacing_type_temporary
        assert discovery_course_run.min_effort == publisher_course_run.min_effort
        assert discovery_course_run.max_effort == publisher_course_run.max_effort
        assert discovery_course_run.language == publisher_course_run.language
        assert discovery_course_run.weeks_to_complete == publisher_course_run.length
        assert discovery_course_run.has_ofac_restrictions == publisher_course_run.has_ofac_restrictions
        expected = set(publisher_course_run.transcript_languages.all())
        assert set(discovery_course_run.transcript_languages.all()) == expected
        assert set(discovery_course_run.staff.all()) == set(
            publisher_course_run.staff.all())

        assert discovery_course.canonical_course_run == discovery_course_run
        assert discovery_course.partner == partner
        assert discovery_course.title == publisher_course.title
        assert discovery_course.short_description == publisher_course.short_description
        assert discovery_course.full_description == publisher_course.full_description
        assert discovery_course.level_type == publisher_course.level_type
        assert discovery_course.video == Video.objects.get(
            src=publisher_course.video_link)
        assert discovery_course.image.name is not None
        assert discovery_course.image.url is not None
        assert discovery_course.image.file is not None
        assert discovery_course.image.small.url is not None
        assert discovery_course.image.small.file is not None
        assert discovery_course.outcome == publisher_course.expected_learnings
        assert discovery_course.prerequisites_raw == publisher_course.prerequisites
        assert discovery_course.syllabus_raw == publisher_course.syllabus
        assert discovery_course.learner_testimonials == publisher_course.learner_testimonial
        assert discovery_course.faq == publisher_course.faq
        assert discovery_course.additional_information == publisher_course.additional_information
        expected = list(publisher_course_run.course.organizations.all())
        assert list(discovery_course.authoring_organizations.all()) == expected
        expected = {
            publisher_course.primary_subject,
            publisher_course.secondary_subject
        }
        assert set(discovery_course.subjects.all()) == expected

        common_entitlement_kwargs = {
            'course': discovery_course,
            'currency': currency,
        }
        self.assertEqual(2, DiscoveryCourseEntitlement.objects.all().count())
        DiscoveryCourseEntitlement.objects.get(
            mode=SeatType.objects.get(slug=DiscoverySeat.PROFESSIONAL),
            price=professional_entitlement.price,
            **common_entitlement_kwargs)
        DiscoveryCourseEntitlement.objects.get(
            mode=SeatType.objects.get(slug=DiscoverySeat.VERIFIED),
            price=verified_entitlement.price,
            **common_entitlement_kwargs)

        common_seat_kwargs = {
            'course_run': discovery_course_run,
            'currency': currency,
        }
        DiscoverySeat.objects.get(type=DiscoverySeat.AUDIT,
                                  upgrade_deadline__isnull=True,
                                  **common_seat_kwargs)
        DiscoverySeat.objects.get(type=DiscoverySeat.PROFESSIONAL,
                                  upgrade_deadline__isnull=True,
                                  price=professional_seat.price,
                                  **common_seat_kwargs)
        DiscoverySeat.objects.get(
            type=DiscoverySeat.VERIFIED,
            upgrade_deadline=verified_seat.upgrade_deadline,
            price=verified_seat.price,
            **common_seat_kwargs)
Example #36
0
 def test_no_coupons_found(self):
     """Test that command logs no offer needs to be changed."""
     with LogCapture(LOGGER_NAME) as log:
         call_command('populate_enterprise_id_product_attribute')
         log.check(
             (LOGGER_NAME, 'INFO', 'Found 0 coupon products to update.'))
 def test_nothing_done(self):
     with LogCapture() as capture:
         nothing_done(self.log_printer)
     capture.check(
         ('root', 'WARNING', 'No existent section was targeted or enabled. '
          'Nothing to do.'))
Example #38
0
 def setUp(self):
     self.capture = LogCapture(attributes=('name', 'levelname',
                                           'getMessage', 'shoehorn_event'))
     self.addCleanup(self.capture.uninstall)
class TestBackendParsing(unittest.TestCase):
    
    def setUp(self):
        self.l = LogCapture()
        
    def tearDown(self):
        self.l.uninstall()
    
    def test_that_parse_returns_a_backend_dictionary_if_xml_contains_config_element_including_backends_list(self):
        root = ET.Element('config')
        ET.SubElement(root, 'backends')
        op = BackendParser()
        
        op.parse(root)
        result = op.backends
        
        assert_that(result, is_not(None))
        
    def test_that_config_includes_a_backends_list_if_config_contains_backends_definition(self):
        root = ET.Element('config')
        backends = ET.SubElement(root, 'backends')
        name = 'db'
        plugin = 'mysql'
        ET.SubElement(backends, 'backend', {'name':name, 'plugin':plugin})
        op = BackendParser()
        _dump_xml_as_file(root, 'backend.xml')
        op.parse(root)
        result = op.backends
        
        assert_that(result, is_not(None))
        assert_that(len(result), is_not(0))
        assert_that(result, has_key(name))
        assert_that(result[name].plugin, is_(plugin))
        
    def test_that_config_backend_is_ignored_if_plugin_is_empty(self):
        root = ET.Element('config')
        backends = ET.SubElement(root, 'backends')
        ET.SubElement(backends, 'backend', {'name':'db', 'plugin':''})
        op = BackendParser()
        
        op.parse(root)
        result = op.backends
        
        self.l.check(('root', 'WARNING', "Ignoring invalid backend definition, name = 'db', plugin = ''"))
        assert_that(result, is_not(has_key('db')))
        
    def test_that_config_backend_is_ignored_if_name_is_not_specified(self):
        root = ET.Element('config')
        backends = ET.SubElement(root, 'backends')
        ET.SubElement(backends, 'backend', {'plugin':'mysql'})
        op = BackendParser()
        
        op.parse(root)
        result = op.backends
        
        self.l.check(('root', 'WARNING', "Ignoring invalid backend definition, name = 'None', plugin = 'mysql'"))
        assert_that(len(result), is_(0))
        
    def test_that_backends_are_ignored_if_not_included_in_a_config_element(self):
        root = ET.Element('random_tag')
        ET.SubElement(root, 'backends')
        op = BackendParser()
        
        result = op.parse(root)
        
        assert_that(result, is_(None))
        
    def test_that_dictionary_of_parameters_is_created_if_parameters_specified(self):
        (root, backend) = _create_valid_backend()
        key = 'ip'
        value = '1.2.3.4'
        params = ET.SubElement(backend, 'params')
        param = ET.SubElement(params, key)
        param.text = value   
        op = BackendParser()
        
        op.parse(root)
        result = op.backends
        
        assert_that(result[backend.get('name')].params, has_entry(key, value))
Example #40
0
 def test_msg_is_none(self):
     with LogCapture(attributes=('msg', 'foo')) as log:
         getLogger().info(None, extra=dict(foo='bar'))
     log.check(
         (None, 'bar')
     )
Example #41
0
 def test_missing_attribute(self):
     with LogCapture(attributes=('msg', 'lolwut')) as log:
         getLogger().info('oh %s', 'hai')
     log.check(
         ('oh %s', None)
     )
Example #42
0
 def test_different_attributes(self):
     with LogCapture(attributes=('funcName', 'processName')) as log:
         getLogger().info('oh hai')
     log.check(
         ('test_different_attributes', 'MainProcess')
     )
    def setUp(self):
        """Creates data for testing Planes Anual"""
        super().setUp()

        self.logger = LogCapture()

        self.user = User.objects.create_user(
            email='*****@*****.**',
            password='******',
            first_name='David',
            last_name='Padilla',
            institution='Colegio Benalcazar',
        )

        self.data = {
            'name':
            'Plan Anual1',
            'ano_lectivo':
            '2019-2020',
            'docentes':
            'David Padilla',
            'asignatura':
            self.asignatura.id,
            'curso':
            self.curso_1.id,
            'paralelos':
            'A y C',
            'carga_horaria':
            20,
            'semanas_trabajo':
            20,
            'semanas_imprevistos':
            20,
            'objetivos_generales': [self.general_1.id, self.general_2.id],
            'objetivos_curso': [self.objetivo_1.id, self.objetivo_2.id],
            'objetivos_generales_curso':
            [self.general_1.id, self.general_2.id],
            'ejes_transversales':
            'Lorem ipsum dolor sit amet.',
            'bibliografia':
            'Lorem ipsum dolor sit amet.',
            'aprobado_por':
            'Lorem ipsum dolor sit amet.',
            'revisado_por':
            'Lorem ipsum dolor sit amet.',

            # Formset Elementos curriculares 1
            'desarrollo_unidades-TOTAL_FORMS':
            '2',
            'desarrollo_unidades-INITIAL_FORMS':
            '0',
            'desarrollo_unidades-MIN_NUM_FORMS':
            '0',
            'desarrollo_unidades-MAX_NUM_FORMS':
            '1000',
            'desarrollo_unidades-0-unidad':
            self.unidad_1.id,
            'desarrollo_unidades-0-objetivos':
            [self.objetivo_1.id, self.objetivo_2.id],
            'desarrollo_unidades-0-objetivos_generales':
            [self.general_1.id, self.general_2.id],
            'desarrollo_unidades-0-destrezas':
            [self.destreza_1.id, self.destreza_2.id],
            'desarrollo_unidades-0-orientaciones_metodologicas':
            'lorem ipsum',
            'desarrollo_unidades-0-semanas':
            8,
            'desarrollo_unidades-1-unidad':
            self.unidad_1.id,
            'desarrollo_unidades-1-objetivos':
            [self.objetivo_1.id, self.objetivo_2.id],
            'desarrollo_unidades-1-objetivos_generales':
            [self.general_1.id, self.general_2.id],
            'desarrollo_unidades-1-destrezas':
            [self.destreza_1.id, self.destreza_2.id],
            'desarrollo_unidades-1-orientaciones_metodologicas':
            'lorem ipsum',
            'desarrollo_unidades-1-semanas':
            2,
        }

        self.plan_anual = mixer.blend(PlanAnual, elaborado_por=self.user)

        another_user = mixer.blend(User)
        self.another_plan = mixer.blend(PlanAnual, elaborado_por=another_user)

        self.common_user = mixer.blend(User)
class TestService(unittest.TestCase):
    def get_ini(self):
        return os.path.join(os.path.dirname(__file__), 'test_memorynode.ini')

    def setUp(self):
        self.config = testing.setUp()
        settings = {}
        load_into_settings(self.get_ini(), settings)
        self.config.add_settings(settings)
        self.config.include("tokenserver")
        load_and_register("tokenserver", self.config)
        self.backend = self.config.registry.getUtility(INodeAssignment)
        wsgiapp = self.config.make_wsgi_app()
        self.app = TestApp(wsgiapp)
        # Mock out the verifier to return successfully by default.
        self.mock_browserid_verifier_context = self.mock_browserid_verifier()
        self.mock_browserid_verifier_context.__enter__()
        self.mock_oauth_verifier_context = self.mock_oauth_verifier()
        self.mock_oauth_verifier_context.__enter__()
        self.logs = LogCapture()

    def tearDown(self):
        self.logs.uninstall()
        self.mock_oauth_verifier_context.__exit__(None, None, None)
        self.mock_browserid_verifier_context.__exit__(None, None, None)

    def assertMetricWasLogged(self, key):
        """Check that a metric was logged during the request."""
        for r in self.logs.records:
            if key in r.__dict__:
                break
        else:
            assert False, "metric %r was not logged" % (key, )

    def clearLogs(self):
        del self.logs.records[:]

    def unsafelyParseToken(self, token):
        # For testing purposes, don't check HMAC or anything...
        token = token.encode("utf8")
        return json.loads(decode_token_bytes(token)[:-32].decode("utf8"))

    @contextlib.contextmanager
    def mock_browserid_verifier(self, response=None, exc=None):
        def mock_verify_method(assertion):
            if exc is not None:
                raise exc
            if response is not None:
                return response
            return {
                "status": "okay",
                "email": get_assertion_info(assertion)["principal"]["email"],
            }

        verifier = get_browserid_verifier(self.config.registry)
        orig_verify_method = verifier.__dict__.get("verify", None)
        verifier.__dict__["verify"] = mock_verify_method
        try:
            yield None
        finally:
            if orig_verify_method is None:
                del verifier.__dict__["verify"]
            else:
                verifier.__dict__["verify"] = orig_verify_method

    @contextlib.contextmanager
    def mock_oauth_verifier(self, response=None, exc=None):
        def mock_verify_method(token):
            if exc is not None:
                raise exc
            if response is not None:
                return response
            return {
                "email": token.decode("hex"),
                "idpClaims": {},
            }

        verifier = get_oauth_verifier(self.config.registry)
        orig_verify_method = verifier.__dict__.get("verify", None)
        verifier.__dict__["verify"] = mock_verify_method
        try:
            yield None
        finally:
            if orig_verify_method is None:
                del verifier.__dict__["verify"]
            else:
                verifier.__dict__["verify"] = orig_verify_method

    def _getassertion(self, **kw):
        kw.setdefault('email', '*****@*****.**')
        kw.setdefault('audience', 'http://tokenserver.services.mozilla.com')
        return make_assertion(**kw).encode('ascii')

    def _gettoken(self, email='*****@*****.**'):
        return email.encode('hex')

    def test_unknown_app(self):
        headers = {'Authorization': 'BrowserID %s' % self._getassertion()}
        resp = self.app.get('/1.0/xXx/token', headers=headers, status=404)
        self.assertTrue('errors' in resp.json)

    def test_invalid_client_state(self):
        headers = {'X-Client-State': 'state!'}
        resp = self.app.get('/1.0/sync/1.5', headers=headers, status=400)
        self.assertEquals(resp.json['errors'][0]['location'], 'header')
        self.assertEquals(resp.json['errors'][0]['name'], 'X-Client-State')
        headers = {'X-Client-State': 'foobar\n\r\t'}
        resp = self.app.get('/1.0/sync/1.5', headers=headers, status=400)
        self.assertEquals(resp.json['errors'][0]['location'], 'header')
        self.assertEquals(resp.json['errors'][0]['name'], 'X-Client-State')

    def test_no_auth(self):
        self.app.get('/1.0/sync/1.5', status=401)

    def test_valid_app(self):
        headers = {'Authorization': 'BrowserID %s' % self._getassertion()}
        res = self.app.get('/1.0/sync/1.1', headers=headers)
        self.assertIn('https://example.com/1.1', res.json['api_endpoint'])
        self.assertIn('duration', res.json)
        self.assertEquals(res.json['duration'], 3600)
        self.assertMetricWasLogged('token.assertion.verify_success')
        self.clearLogs()

    def test_unknown_pattern(self):
        # sync 1.5 is defined in the .ini file, but  no pattern exists for it.
        headers = {'Authorization': 'BrowserID %s' % self._getassertion()}
        self.app.get('/1.0/sync/1.5', headers=headers, status=503)

    def test_discovery(self):
        res = self.app.get('/')
        self.assertEqual(
            res.json, {
                'auth': 'http://localhost',
                'services': {
                    'sync': ['1.1', '1.5'],
                },
                'browserid': {
                    'allowed_issuers': None,
                    'trusted_issuers': None,
                },
                'oauth': {
                    'default_issuer': 'api.accounts.firefox.com',
                    'scope': 'https://identity.mozilla.com/apps/oldsync',
                    'server_url': 'https://oauth.accounts.firefox.com/v1',
                }
            })

    def test_version_returns_404_by_default(self):
        with mock.patch('os.path.exists', return_value=False):
            self.app.get('/__version__', status=404)

    def test_version_returns_file_in_current_folder_if_present(self):
        content = {'version': '0.8.1'}
        fake_file = mock.mock_open(read_data=json.dumps(content))
        with mock.patch('os.path.exists'):
            with mock.patch('tokenserver.views.open', fake_file):
                response = self.app.get('/__version__')
                self.assertEquals(response.json, content)

    def test_lbheartbeat(self):
        res = self.app.get('/__lbheartbeat__')
        self.assertEqual(res.json, {})

    def test_unauthorized_error_status(self):
        # Totally busted auth -> generic error.
        headers = {'Authorization': 'Unsupported-Auth-Scheme IHACKYOU'}
        res = self.app.get('/1.0/sync/1.1', headers=headers, status=401)
        self.assertEqual(res.json['status'], 'error')

        # BrowserID verifier errors
        assertion = self._getassertion()
        headers = {'Authorization': 'BrowserID %s' % assertion}
        # Bad signature -> "invalid-credentials"
        errs = browserid.errors
        with self.mock_browserid_verifier(exc=errs.InvalidSignatureError):
            res = self.app.get('/1.0/sync/1.1', headers=headers, status=401)
        self.assertEqual(res.json['status'], 'invalid-credentials')
        # Bad audience -> "invalid-credentials"
        with self.mock_browserid_verifier(exc=errs.AudienceMismatchError):
            res = self.app.get('/1.0/sync/1.1', headers=headers, status=401)
        self.assertEqual(res.json['status'], 'invalid-credentials')
        self.assertMetricWasLogged('token.assertion.verify_failure')
        self.assertMetricWasLogged('token.assertion.audience_mismatch_error')
        self.clearLogs()
        # Expired timestamp -> "invalid-timestamp"
        with self.mock_browserid_verifier(exc=errs.ExpiredSignatureError):
            res = self.app.get('/1.0/sync/1.1', headers=headers, status=401)
        self.assertEqual(res.json['status'], 'invalid-timestamp')
        self.assertTrue('X-Timestamp' in res.headers)
        self.assertMetricWasLogged('token.assertion.verify_failure')
        self.assertMetricWasLogged('token.assertion.expired_signature_error')
        self.clearLogs()
        # Connection error -> 503
        with self.mock_browserid_verifier(exc=errs.ConnectionError):
            res = self.app.get('/1.0/sync/1.1', headers=headers, status=503)
        self.assertMetricWasLogged('token.assertion.verify_failure')
        self.assertMetricWasLogged('token.assertion.connection_error')
        # It should also log a full traceback of the error.
        for r in self.logs.records:
            if r.msg == "Unexpected verification error":
                assert r.exc_info is not None
                break
        else:
            assert False, "failed to log a traceback for ConnectionError"
        self.clearLogs()
        # Some other wacky error -> not captured
        with self.mock_browserid_verifier(exc=ValueError):
            with self.assertRaises(ValueError):
                res = self.app.get('/1.0/sync/1.1', headers=headers)

        # OAuth verifier errors
        token = self._gettoken()
        headers = {'Authorization': 'Bearer %s' % token}
        # Bad token -> "invalid-credentials"
        err = fxa.errors.TrustError({"code": 400, "errno": 123})
        with self.mock_oauth_verifier(exc=err):
            res = self.app.get('/1.0/sync/1.1', headers=headers, status=401)
        self.assertEqual(res.json['status'], 'invalid-credentials')
        # Connection error -> 503
        with self.mock_oauth_verifier(exc=errs.ConnectionError):
            res = self.app.get('/1.0/sync/1.1', headers=headers, status=503)
        self.assertMetricWasLogged('token.oauth.verify_failure')
        self.assertMetricWasLogged('token.oauth.connection_error')
        # It should also log a full traceback of the error.
        for r in self.logs.records:
            if r.msg == "Unexpected verification error":
                assert r.exc_info is not None
                break
        else:
            assert False, "failed to log a traceback for ConnectionError"
        self.clearLogs()
        # Some other wacky error -> not captured
        with self.mock_oauth_verifier(exc=ValueError):
            with self.assertRaises(ValueError):
                res = self.app.get('/1.0/sync/1.1', headers=headers)

    def test_unverified_token(self):
        headers = {'Authorization': 'BrowserID %s' % self._getassertion()}
        # Assertion should not be rejected if fxa-tokenVerified is unset
        mock_response = {
            "status": "okay",
            "email": "*****@*****.**",
            "idpClaims": {}
        }
        with self.mock_browserid_verifier(response=mock_response):
            self.app.get("/1.0/sync/1.1", headers=headers, status=200)
        # Assertion should not be rejected if fxa-tokenVerified is True
        mock_response['idpClaims']['fxa-tokenVerified'] = True
        with self.mock_browserid_verifier(response=mock_response):
            self.app.get("/1.0/sync/1.1", headers=headers, status=200)
        # Assertion should be rejected if fxa-tokenVerified is False
        mock_response['idpClaims']['fxa-tokenVerified'] = False
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get("/1.0/sync/1.1", headers=headers, status=401)
        self.assertEqual(res.json['status'], 'invalid-credentials')

    def test_generation_number_change(self):
        headers = {"Authorization": "BrowserID %s" % self._getassertion()}
        # Start with no generation number.
        mock_response = {"status": "okay", "email": "*****@*****.**"}
        with self.mock_browserid_verifier(response=mock_response):
            res1 = self.app.get("/1.0/sync/1.1", headers=headers)
        # Now send an explicit generation number.
        # The node assignment should not change.
        mock_response["idpClaims"] = {"fxa-generation": 12}
        with self.mock_browserid_verifier(response=mock_response):
            res2 = self.app.get("/1.0/sync/1.1", headers=headers)
        self.assertEqual(res1.json["uid"], res2.json["uid"])
        self.assertEqual(res1.json["api_endpoint"], res2.json["api_endpoint"])
        # Previous generation numbers get an invalid-generation response.
        del mock_response["idpClaims"]
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get("/1.0/sync/1.1", headers=headers, status=401)
        self.assertEqual(res.json["status"], "invalid-generation")
        mock_response["idpClaims"] = {"some-nonsense": "lolwut"}
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get("/1.0/sync/1.1", headers=headers, status=401)
        self.assertEqual(res.json["status"], "invalid-generation")
        mock_response["idpClaims"] = {"fxa-generation": 10}
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get("/1.0/sync/1.1", headers=headers, status=401)
        self.assertEqual(res.json["status"], "invalid-generation")
        # Equal generation numbers are accepted.
        mock_response["idpClaims"] = {"fxa-generation": 12}
        with self.mock_browserid_verifier(response=mock_response):
            res2 = self.app.get("/1.0/sync/1.1", headers=headers)
        self.assertEqual(res1.json["uid"], res2.json["uid"])
        self.assertEqual(res1.json["api_endpoint"], res2.json["api_endpoint"])
        # Later generation numbers are accepted.
        # Again, the node assignment should not change.
        mock_response["idpClaims"] = {"fxa-generation": 13}
        with self.mock_browserid_verifier(response=mock_response):
            res2 = self.app.get("/1.0/sync/1.1", headers=headers)
        self.assertEqual(res1.json["uid"], res2.json["uid"])
        self.assertEqual(res1.json["api_endpoint"], res2.json["api_endpoint"])
        # And that should lock out the previous generation number
        mock_response["idpClaims"] = {"fxa-generation": 12}
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get("/1.0/sync/1.1", headers=headers, status=401)
        self.assertEqual(res.json["status"], "invalid-generation")
        # Various nonsense generation numbers should give errors.
        mock_response["idpClaims"] = {"fxa-generation": "whatswrongwithyour"}
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get("/1.0/sync/1.1", headers=headers, status=401)
        self.assertEqual(res.json["status"], "invalid-generation")
        mock_response["idpClaims"] = {"fxa-generation": None}
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get("/1.0/sync/1.1", headers=headers, status=401)
        self.assertEqual(res.json["status"], "invalid-generation")
        mock_response["idpClaims"] = {"fxa-generation": "42"}
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get("/1.0/sync/1.1", headers=headers, status=401)
        self.assertEqual(res.json["status"], "invalid-generation")
        mock_response["idpClaims"] = {"fxa-generation": ["I", "HACK", "YOU"]}
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get("/1.0/sync/1.1", headers=headers, status=401)
        self.assertEqual(res.json["status"], "invalid-generation")

    def test_client_state_change(self):
        mock_response = {
            "status": "okay",
            "email": "*****@*****.**",
            "idpClaims": {
                "fxa-generation": 1234
            },
        }
        # Start with no client-state header.
        headers = {'Authorization': 'BrowserID %s' % self._getassertion()}
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get('/1.0/sync/1.1', headers=headers)
        uid0 = res.json['uid']
        # No change == same uid.
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get('/1.0/sync/1.1', headers=headers)
        self.assertEqual(res.json['uid'], uid0)
        # Changing client-state header requires changing generation number.
        headers['X-Client-State'] = 'aaaa'
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get('/1.0/sync/1.1', headers=headers, status=401)
        self.assertEqual(res.json['status'], 'invalid-client-state')
        desc = res.json['errors'][0]['description']
        self.assertTrue(desc.endswith('new value with no generation change'))
        # Change the client-state header, get a new uid.
        headers['X-Client-State'] = 'aaaa'
        mock_response["idpClaims"]["fxa-generation"] += 1
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get('/1.0/sync/1.1', headers=headers)
        uid1 = res.json['uid']
        self.assertNotEqual(uid1, uid0)
        # No change == same uid.
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get('/1.0/sync/1.1', headers=headers)
        self.assertEqual(res.json['uid'], uid1)
        # Send a client-state header, get a new uid.
        headers['X-Client-State'] = 'bbbb'
        mock_response["idpClaims"]["fxa-generation"] += 1
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get('/1.0/sync/1.1', headers=headers)
        uid2 = res.json['uid']
        self.assertNotEqual(uid2, uid0)
        self.assertNotEqual(uid2, uid1)
        # No change == same uid.
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get('/1.0/sync/1.1', headers=headers)
        self.assertEqual(res.json['uid'], uid2)
        # Use a previous client-state, get an auth error.
        headers['X-Client-State'] = 'aaaa'
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get('/1.0/sync/1.1', headers=headers, status=401)
        self.assertEqual(res.json['status'], 'invalid-client-state')
        desc = res.json['errors'][0]['description']
        self.assertTrue(desc.endswith('stale value'))
        del headers['X-Client-State']
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get('/1.0/sync/1.1', headers=headers, status=401)
        self.assertEqual(res.json['status'], 'invalid-client-state')
        headers['X-Client-State'] = 'aaaa'
        mock_response["idpClaims"]["fxa-generation"] += 1
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get('/1.0/sync/1.1', headers=headers, status=401)
        self.assertEqual(res.json['status'], 'invalid-client-state')

    def test_client_state_cannot_revert_to_empty(self):
        # Start with a client-state header.
        headers = {
            'Authorization': 'BrowserID %s' % self._getassertion(),
            'X-Client-State': 'aaa',
        }
        res = self.app.get('/1.0/sync/1.1', headers=headers)
        uid0 = res.json['uid']
        # Sending no client-state will fail.
        del headers['X-Client-State']
        res = self.app.get('/1.0/sync/1.1', headers=headers, status=401)
        self.assertEqual(res.json['status'], 'invalid-client-state')
        desc = res.json['errors'][0]['description']
        self.assertTrue(desc.endswith('empty string'))
        headers['X-Client-State'] = ''
        res = self.app.get('/1.0/sync/1.1', headers=headers, status=401)
        self.assertEqual(res.json['status'], 'invalid-client-state')
        desc = res.json['errors'][0]['description']
        self.assertTrue(desc.endswith('empty string'))
        # And the uid will be unchanged.
        headers['X-Client-State'] = 'aaa'
        res = self.app.get('/1.0/sync/1.1', headers=headers)
        self.assertEqual(res.json['uid'], uid0)

    def test_credentials_from_oauth_and_browserid(self):
        # Send initial credentials via oauth.
        headers_oauth = {
            "Authorization": "Bearer %s" % self._gettoken(),
            "X-KeyID": "12-YWFh",
        }
        res1 = self.app.get("/1.0/sync/1.1", headers=headers_oauth)
        # Send the same credentials via BrowserID
        headers_browserid = {
            "Authorization": "BrowserID %s" % self._getassertion(),
            "X-Client-State": "616161",
        }
        mock_response = {
            "status": "okay",
            "email": "*****@*****.**",
            "idpClaims": {
                "fxa-generation": 12
            },
        }
        with self.mock_browserid_verifier(response=mock_response):
            res2 = self.app.get("/1.0/sync/1.1", headers=headers_browserid)
        # They should get the same node assignment.
        self.assertEqual(res1.json["uid"], res2.json["uid"])
        self.assertEqual(res1.json["api_endpoint"], res2.json["api_endpoint"])
        # Earlier generation number via BrowserID -> invalid-generation
        mock_response["idpClaims"]['fxa-generation'] = 11
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get("/1.0/sync/1.1",
                               headers=headers_browserid,
                               status=401)
        self.assertEqual(res.json["status"], "invalid-generation")
        # Earlier generation number via OAuth -> invalid-generation
        headers_oauth['X-KeyID'] = '11-YWFh'
        res = self.app.get("/1.0/sync/1.1", headers=headers_oauth, status=401)
        self.assertEqual(res.json["status"], "invalid-generation")
        # Change client-state via BrowserID.
        headers_browserid['X-Client-State'] = '626262'
        mock_response["idpClaims"]['fxa-generation'] = 42
        with self.mock_browserid_verifier(response=mock_response):
            res1 = self.app.get("/1.0/sync/1.1", headers=headers_browserid)
        # Old OAuth credentials are rejected.
        headers_oauth['X-KeyID'] = '12-YWFh'
        res = self.app.get("/1.0/sync/1.1", headers=headers_oauth, status=401)
        self.assertEqual(res.json["status"], "invalid-client-state")
        headers_oauth['X-KeyID'] = '12-YmJi'
        res = self.app.get("/1.0/sync/1.1", headers=headers_oauth, status=401)
        self.assertEqual(res.json["status"], "invalid-generation")
        # Updated OAuth credentials are accepted.
        headers_oauth['X-KeyID'] = '42-YmJi'
        res2 = self.app.get("/1.0/sync/1.1", headers=headers_oauth)
        # They should again get the same node assignment.
        self.assertEqual(res1.json["uid"], res2.json["uid"])
        self.assertEqual(res1.json["api_endpoint"], res2.json["api_endpoint"])

    def test_client_specified_duration(self):
        headers = {'Authorization': 'BrowserID %s' % self._getassertion()}
        # It's ok to request a shorter-duration token.
        res = self.app.get('/1.0/sync/1.1?duration=12', headers=headers)
        self.assertEquals(res.json['duration'], 12)
        # But you can't exceed the server's default value.
        res = self.app.get('/1.0/sync/1.1?duration=4000', headers=headers)
        self.assertEquals(res.json['duration'], 3600)
        # And nonsense values are ignored.
        res = self.app.get('/1.0/sync/1.1?duration=lolwut', headers=headers)
        self.assertEquals(res.json['duration'], 3600)
        res = self.app.get('/1.0/sync/1.1?duration=-1', headers=headers)
        self.assertEquals(res.json['duration'], 3600)

    def test_allow_new_users(self):
        # New users are allowed by default.
        settings = self.config.registry.settings
        self.assertEquals(settings.get('tokenserver.allow_new_users'), None)
        assertion = self._getassertion(email="*****@*****.**")
        headers = {'Authorization': 'BrowserID %s' % assertion}
        self.app.get('/1.0/sync/1.1', headers=headers, status=200)
        # They're allowed if we explicitly allow them.
        settings['tokenserver.allow_new_users'] = True
        assertion = self._getassertion(email="*****@*****.**")
        headers = {'Authorization': 'BrowserID %s' % assertion}
        self.app.get('/1.0/sync/1.1', headers=headers, status=200)
        # They're not allowed if we explicitly disable them.
        settings['tokenserver.allow_new_users'] = False
        assertion = self._getassertion(email="*****@*****.**")
        headers = {'Authorization': 'BrowserID %s' % assertion}
        res = self.app.get('/1.0/sync/1.1', headers=headers, status=401)
        self.assertEqual(res.json['status'], 'new-users-disabled')
        # But existing users are still allowed.
        assertion = self._getassertion(email="*****@*****.**")
        headers = {'Authorization': 'BrowserID %s' % assertion}
        self.app.get('/1.0/sync/1.1', headers=headers, status=200)
        assertion = self._getassertion(email="*****@*****.**")
        headers = {'Authorization': 'BrowserID %s' % assertion}
        self.app.get('/1.0/sync/1.1', headers=headers, status=200)

    def test_metrics_uid_logging(self):
        assert "fxa.metrics_uid_secret_key" in self.config.registry.settings
        assertion = self._getassertion(email="*****@*****.**")
        headers = {'Authorization': 'BrowserID %s' % assertion}
        self.app.get('/1.0/sync/1.1', headers=headers, status=200)
        self.assertMetricWasLogged('uid')
        self.assertMetricWasLogged('uid.first_seen_at')
        self.assertMetricWasLogged('metrics_uid')
        self.assertMetricWasLogged('metrics_device_id')

    def test_uid_and_kid_from_browserid_assertion(self):
        assertion = self._getassertion(email="*****@*****.**")
        headers_browserid = {
            "Authorization": "BrowserID %s" % (assertion, ),
            "X-Client-State": "616161",
        }
        mock_response = {
            "status": "okay",
            "email": "*****@*****.**",
            "idpClaims": {
                "fxa-generation": 12
            },
        }
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get("/1.0/sync/1.1", headers=headers_browserid)
        token = self.unsafelyParseToken(res.json["id"])
        self.assertEqual(token["uid"], res.json["uid"])
        self.assertEqual(token["fxa_uid"], "testuser")
        self.assertEqual(token["fxa_kid"], "616161")
        self.assertNotEqual(token["hashed_fxa_uid"], token["fxa_uid"])
        self.assertEqual(token["hashed_fxa_uid"], res.json["hashed_fxa_uid"])
        self.assertIn("hashed_device_id", token)

    def test_uid_and_kid_from_oauth_token(self):
        oauth_token = self._gettoken(email="*****@*****.**")
        headers_oauth = {
            "Authorization": "Bearer %s" % (oauth_token, ),
            "X-KeyID": "12-YWFh",
        }
        res = self.app.get("/1.0/sync/1.1", headers=headers_oauth)
        token = self.unsafelyParseToken(res.json["id"])
        self.assertEqual(token["uid"], res.json["uid"])
        self.assertEqual(token["fxa_uid"], "testuser")
        self.assertEqual(token["fxa_kid"], "616161")
        self.assertNotEqual(token["hashed_fxa_uid"], token["fxa_uid"])
        self.assertEqual(token["hashed_fxa_uid"], res.json["hashed_fxa_uid"])
        self.assertIn("hashed_device_id", token)

    def test_metrics_uid_is_returned_in_response(self):
        assert "fxa.metrics_uid_secret_key" in self.config.registry.settings
        assertion = self._getassertion(email="*****@*****.**")
        headers = {'Authorization': 'BrowserID %s' % assertion}
        res = self.app.get('/1.0/sync/1.1', headers=headers, status=200)
        self.assertTrue('hashed_fxa_uid' in res.json)
Example #45
0
    def test_expire(self):
        self._setup_enrollments('student_expired_waiting', None,
                                timezone.now() - timedelta(60))
        self._setup_enrollments('student_waiting', None,
                                timezone.now() - timedelta(59))
        self._setup_enrollments('student_actualized', UserFactory(),
                                timezone.now() - timedelta(90))

        expired_program_enrollment = ProgramEnrollment.objects.get(
            external_user_key='student_expired_waiting')
        expired_course_enrollments = list(
            ProgramCourseEnrollment.objects.filter(
                program_enrollment=expired_program_enrollment))

        # assert deleted enrollments are logged (without pii)
        with LogCapture(log.name) as log_capture:
            expire_waiting_enrollments(60)

            program_enrollment_message_tmpl = u'Found expired program_enrollment (id={}) for program_uuid={}'
            course_enrollment_message_tmpl = (
                u'Found expired program_course_enrollment (id={}) for program_uuid={}, course_key={}'
            )

            log_capture.check_present(
                (log.name, 'INFO',
                 program_enrollment_message_tmpl.format(
                     expired_program_enrollment.id,
                     expired_program_enrollment.program_uuid,
                 )),
                (log.name, 'INFO',
                 course_enrollment_message_tmpl.format(
                     expired_course_enrollments[0].id,
                     expired_program_enrollment.program_uuid,
                     expired_course_enrollments[0].course_key,
                 )),
                (log.name, 'INFO',
                 course_enrollment_message_tmpl.format(
                     expired_course_enrollments[1].id,
                     expired_program_enrollment.program_uuid,
                     expired_course_enrollments[1].course_key,
                 )),
                (log.name, 'INFO', u'Removed 3 expired records:'
                 u' {u\'program_enrollments.ProgramCourseEnrollment\': 2,'
                 u' u\'program_enrollments.ProgramEnrollment\': 1}'),
            )

        program_enrollments = ProgramEnrollment.objects.all()
        program_course_enrollments = ProgramCourseEnrollment.objects.all()
        historical_program_enrollments = ProgramEnrollment.historical_records.all(
        )  # pylint: disable=no-member
        historical_program_course_enrollments = ProgramCourseEnrollment.historical_records.all(
        )  # pylint: disable=no-member

        # assert expired records no longer exist
        with self.assertRaises(ProgramEnrollment.DoesNotExist):
            program_enrollments.get(
                external_user_key='student_expired_waiting')
        self.assertEqual(len(program_course_enrollments), 4)

        # assert fresh waiting records are not affected
        waiting_enrollment = program_enrollments.get(
            external_user_key='student_waiting')
        self.assertEqual(
            len(waiting_enrollment.program_course_enrollments.all()), 2)

        # assert actualized enrollments are not affected
        actualized_enrollment = program_enrollments.get(
            external_user_key='student_actualized')
        self.assertEqual(
            len(actualized_enrollment.program_course_enrollments.all()), 2)

        # assert expired historical records are also removed
        with self.assertRaises(ObjectDoesNotExist):
            historical_program_enrollments.get(
                external_user_key='student_expired_waiting')
        self.assertEqual(
            len(
                historical_program_course_enrollments.filter(
                    program_enrollment_id=expired_program_enrollment.id)), 0)

        # assert other historical records are not affected
        self.assertEqual(len(historical_program_enrollments), 2)
        self.assertEqual(len(historical_program_course_enrollments), 4)
Example #46
0
    def test_superuser_can_assign_local_user_to_group_andor_set_user_as_superuser_but_not_neither(
            self):
        request = self.wagtail_factory.get('/')
        request.user = self.superuser
        request.site = self.wagtail_site
        form_data = {
            'username': '******',
            'email': '*****@*****.**',
            'first_name': 'John',
            'last_name': 'Wagtail',
            'groups': [],
            'is_superuser': True,
            'is_active': True,
        }

        with LogCapture():
            form_data.update({
                'is_superuser': True,
                'groups': [],
                'is_active': True
            })
            form = LocalUserEditForm(request,
                                     self.safe_get_user(self.wagtail_admin),
                                     form_data)
            valid = form.is_valid()
            self.assertTrue(valid)

            form_data.update({
                'is_superuser': True,
                'groups': [self.wagtail_editors_group.pk],
                'is_active': True
            })
            form = LocalUserEditForm(request,
                                     self.safe_get_user(self.wagtail_admin),
                                     form_data)
            valid = form.is_valid()
            self.assertTrue(valid)

            form_data.update({
                'is_superuser': False,
                'groups': [self.wagtail_editors_group.pk],
                'is_active': True
            })
            form = LocalUserEditForm(request,
                                     self.safe_get_user(self.wagtail_admin),
                                     form_data)
            valid = form.is_valid()
            self.assertTrue(valid)

            form_data.update({
                'is_superuser': False,
                'groups': [],
                'is_active': True
            })
            form = LocalUserEditForm(request,
                                     self.safe_get_user(self.wagtail_admin),
                                     form_data)
            valid = form.is_valid()
            self.assertFalse(valid)
            self.assertEqual(form.errors['groups'][0],
                             form.error_messages['group_required_superuser'])
Example #47
0
 def test_https_connect_tunnel(self):
     crawler = get_crawler(SimpleSpider)
     with LogCapture() as log:
         yield crawler.crawl(
             self.mockserver.url("/status?n=200", is_secure=True))
     self._assert_got_response_code(200, log)
    def test_multigeom(self) -> None:
        with LogCapture("tilecloud_chain", level=30) as log_capture:
            self.assert_tiles_generated(
                cmd=
                ".build/venv/bin/generate_tiles -c tilegeneration/test-multigeom.yaml",
                main_func=generate.main,
                directory="/tmp/tiles/",
                tiles_pattern="1.0.0/pp/default/2012/swissgrid_5/%i/%i/%i.png",
                tiles=[
                    (0, 5, 4),
                    (0, 5, 5),
                    (0, 5, 6),
                    (0, 5, 7),
                    (0, 6, 4),
                    (0, 6, 5),
                    (0, 6, 6),
                    (0, 6, 7),
                    (0, 7, 4),
                    (0, 7, 5),
                    (0, 7, 6),
                    (0, 7, 7),
                    (1, 11, 8),
                    (1, 11, 9),
                    (1, 11, 10),
                    (1, 11, 11),
                    (1, 11, 12),
                    (1, 11, 13),
                    (1, 11, 14),
                    (1, 12, 8),
                    (1, 12, 9),
                    (1, 12, 10),
                    (1, 12, 11),
                    (1, 12, 12),
                    (1, 12, 13),
                    (1, 12, 14),
                    (1, 13, 8),
                    (1, 13, 9),
                    (1, 13, 10),
                    (1, 13, 11),
                    (1, 13, 12),
                    (1, 13, 13),
                    (1, 13, 14),
                    (1, 14, 8),
                    (1, 14, 9),
                    (1, 14, 10),
                    (1, 14, 11),
                    (1, 14, 12),
                    (1, 14, 13),
                    (1, 14, 14),
                    (1, 15, 8),
                    (1, 15, 9),
                    (1, 15, 10),
                    (1, 15, 11),
                    (1, 15, 12),
                    (1, 15, 13),
                    (1, 15, 14),
                    (2, 29, 35),
                    (2, 39, 21),
                    (3, 78, 42),
                    (3, 58, 70),
                ],
                regex=True,
                expected=
                r"""The tile generation of layer 'pp \(DATE=2012\)' is finish
    Nb generated tiles: 51
    Nb tiles dropped: 0
    Nb tiles stored: 51
    Nb tiles in error: 0
    Total time: [0-9]+:[0-9][0-9]:[0-9][0-9]
    Total size: [34][0-9] Kio
    Time per tile: [0-9]+ ms
    Size per tile: [79][0-9][0-9] o

    """,
            )
            log_capture.check()
 def setUp(self):
     self.lc = LogCapture()
     self.lc.setLevel(logging.DEBUG)
     self.lc.addFilter(test_common.MyLogCaptureFilter())
     self.addCleanup(self.cleanup)
    def test_zoom_identifier(self) -> None:
        with LogCapture("tilecloud_chain", level=30) as log_capture:
            xy = list(product(range(585, 592), range(429, 432)))
            x = [e[0] for e in xy]
            y = [e[1] for e in xy]
            xy2 = list(product(range(2929, 2936), range(2148, 2152)))
            x2 = [e[0] for e in xy2]
            y2 = [e[1] for e in xy2]
            xy3 = list(product(range(5859, 5864), range(4296, 4304)))
            x3 = [e[0] for e in xy3]
            y3 = [e[1] for e in xy3]
            for d in ("-d", ""):
                self.assert_tiles_generated(
                    cmd=".build/venv/bin/generate_tiles {} "
                    "-c tilegeneration/test-nosns.yaml -t 1 -l polygon2 -z 0".
                    format(d),
                    main_func=generate.main,
                    directory="/tmp/tiles/",
                    tiles_pattern=
                    "1.0.0/%s/default/2012/swissgrid_01/%s/%i/%i.png",
                    tiles=list(
                        zip(repeat("polygon2", len(x)), repeat("1", len(x)), x,
                            y)),
                    regex=True,
                    expected=
                    r"""The tile generation of layer 'polygon2 \(DATE=2012\)' is finish
    Nb generated metatiles: 1
    Nb metatiles dropped: 0
    Nb generated tiles: 64
    Nb tiles dropped: 43
    Nb tiles stored: 21
    Nb tiles in error: 0
    Total time: [0-9]+:[0-9][0-9]:[0-9][0-9]
    Total size: 16 Kio
    Time per tile: [0-9]+ ms
    Size per tile: 788 o

    """,
                )
                self.assert_tiles_generated(
                    cmd=".build/venv/bin/generate_tiles {} "
                    "-c tilegeneration/test-nosns.yaml -t 1 -l polygon2 -z 1".
                    format(d),
                    main_func=generate.main,
                    directory="/tmp/tiles/",
                    tiles_pattern=
                    "1.0.0/%s/default/2012/swissgrid_01/%s/%i/%i.png",
                    tiles=list(
                        zip(repeat("polygon2", len(x2)),
                            repeat("0_2", len(x2)), x2, y2)),
                    regex=True,
                    expected=
                    r"""The tile generation of layer 'polygon2 \(DATE=2012\)' is finish
    Nb generated metatiles: 1
    Nb metatiles dropped: 0
    Nb generated tiles: 64
    Nb tiles dropped: 36
    Nb tiles stored: 28
    Nb tiles in error: 0
    Total time: [0-9]+:[0-9][0-9]:[0-9][0-9]
    Total size: 22 Kio
    Time per tile: [0-9]+ ms
    Size per tile: 806 o

    """,
                )
                self.assert_tiles_generated(
                    cmd=".build/venv/bin/generate_tiles {} "
                    "-c tilegeneration/test-nosns.yaml -t 1 -l polygon2 -z 2".
                    format(d),
                    main_func=generate.main,
                    directory="/tmp/tiles/",
                    tiles_pattern=
                    "1.0.0/%s/default/2012/swissgrid_01/%s/%i/%i.png",
                    tiles=list(
                        zip(repeat("polygon2", len(x3)),
                            repeat("0_1", len(x3)), x3, y3)),
                    regex=True,
                    expected=
                    r"""The tile generation of layer 'polygon2 \(DATE=2012\)' is finish
    Nb generated metatiles: 1
    Nb metatiles dropped: 0
    Nb generated tiles: 64
    Nb tiles dropped: 24
    Nb tiles stored: 40
    Nb tiles in error: 0
    Total time: [0-9]+:[0-9][0-9]:[0-9][0-9]
    Total size: 32 Kio
    Time per tile: [0-9]+ ms
    Size per tile: 818 o

    """,
                )
            log_capture.check()
Example #51
0
def tearDown(test):
    TempDirectory.cleanup_all()
    LogCapture.uninstall_all()
    def test_layer_bbox(self) -> None:
        for d in ("-d", ""):
            with LogCapture("tilecloud_chain", level=30) as log_capture:
                self.assert_tiles_generated(
                    cmd=".build/venv/bin/generate_tiles {} "
                    "-c tilegeneration/test-nosns.yaml -l polygon -z 0".format(
                        d),
                    main_func=generate.main,
                    directory="/tmp/tiles/",
                    tiles_pattern=
                    "1.0.0/polygon/default/2012/swissgrid_5/0/%i/%i.png",
                    tiles=list(product((5, 6, 7), (4, 5, 6, 7))),
                    regex=True,
                    expected=
                    r"""The tile generation of layer 'polygon \(DATE=2012\)' is finish
    Nb generated tiles: 12
    Nb tiles dropped: 0
    Nb tiles stored: 12
    Nb tiles in error: 0
    Total time: [0-9]+:[0-9][0-9]:[0-9][0-9]
    Total size: [0-9.]+ Kio
    Time per tile: [0-9.]+ ms
    Size per tile: [69][0-9][0-9] o

    """,
                )

                self.assert_tiles_generated(
                    cmd=".build/venv/bin/generate_tiles %s "
                    "-c tilegeneration/test-nosns.yaml -l polygon -z 0"
                    " -b 550000 170000 560000 180000" % d,
                    main_func=generate.main,
                    directory="/tmp/tiles/",
                    tiles_pattern=
                    "1.0.0/polygon/default/2012/swissgrid_5/0/%i/%i.png",
                    tiles=[(6, 5), (7, 5)],
                    regex=True,
                    expected=
                    r"""The tile generation of layer 'polygon \(DATE=2012\)' is finish
    Nb generated tiles: 2
    Nb tiles dropped: 0
    Nb tiles stored: 2
    Nb tiles in error: 0
    Total time: [0-9]+:[0-9][0-9]:[0-9][0-9]
    Total size: 1.[6-9] Kio
    Time per tile: [0-9]+ ms
    Size per tile: [89][0-9][0-9] o

    """,
                )

                self.assert_tiles_generated(
                    cmd=".build/venv/bin/generate_tiles %s "
                    "-c tilegeneration/test-nosns.yaml -l polygon -z 0"
                    " -b 550000.0 170000.0 560000.0 180000.0" % d,
                    main_func=generate.main,
                    directory="/tmp/tiles/",
                    tiles_pattern=
                    "1.0.0/polygon/default/2012/swissgrid_5/0/%i/%i.png",
                    tiles=[(6, 5), (7, 5)],
                    regex=True,
                    expected=
                    r"""The tile generation of layer 'polygon \(DATE=2012\)' is finish
    Nb generated tiles: 2
    Nb tiles dropped: 0
    Nb tiles stored: 2
    Nb tiles in error: 0
    Total time: [0-9]+:[0-9][0-9]:[0-9][0-9]
    Total size: 1.[6-9] Kio
    Time per tile: [0-9]+ ms
    Size per tile: [89][0-9][0-9] o

    """,
                )

                self.assert_tiles_generated(
                    cmd=".build/venv/bin/generate_tiles {} "
                    "-c tilegeneration/test-nosns.yaml -l all -z 0".format(d),
                    main_func=generate.main,
                    directory="/tmp/tiles/",
                    tiles_pattern=
                    "1.0.0/all/default/2012/swissgrid_5/0/%i/%i.png",
                    tiles=[(6, 5), (7, 5)],
                    regex=True,
                    expected=
                    r"""The tile generation of layer 'all \(DATE=2012\)' is finish
    Nb generated tiles: 2
    Nb tiles dropped: 0
    Nb tiles stored: 2
    Nb tiles in error: 0
    Total time: [0-9]+:[0-9][0-9]:[0-9][0-9]
    Total size: 1.[6-9] Kio
    Time per tile: [0-9]+ ms
    Size per tile: [89][0-9][0-9] o

    """,
                )
                log_capture.check()
Example #53
0
    def test_basic_operations(self):
        # Test where enrichment is None
        mock_panoptes_enrichment_cache = Mock(return_value=None)
        with patch(
                'yahoo_panoptes.framework.plugins.runner.PanoptesEnrichmentCache',
                mock_panoptes_enrichment_cache):
            runner = self._runner_class(
                "Test Polling Plugin", "polling", PanoptesPollingPlugin,
                PanoptesPluginInfo, self._panoptes_resource,
                self._panoptes_context, PanoptesTestKeyValueStore,
                PanoptesTestKeyValueStore, PanoptesTestKeyValueStore,
                "plugin_logger", PanoptesMetricsGroupSet, _callback)
            runner.execute_plugin()

            self._log_capture.check_present((
                'panoptes.tests.test_runner', 'ERROR',
                '[Test Polling Plugin] [plugin|test|site|test|class|test|subclass|test|'
                'type|test|id|test|endpoint|test] '
                'Could not set up context for plugin'))
            self._log_capture.uninstall()

        self._log_capture = LogCapture(attributes=self.extract)
        # Test with enrichment
        runner = self._runner_class(
            "Test Polling Plugin", "polling", PanoptesPollingPlugin,
            PanoptesPluginInfo, self._panoptes_resource,
            self._panoptes_context, PanoptesTestKeyValueStore,
            PanoptesTestKeyValueStore, PanoptesTestKeyValueStore,
            "plugin_logger", PanoptesMetricsGroupSet, _callback)
        runner.execute_plugin()

        self._log_capture.check_present(
            ('panoptes.tests.test_runner', 'INFO',
             'Attempting to execute plugin "Test Polling Plugin"'),
            ('panoptes.tests.test_runner', 'DEBUG',
             '''Starting Plugin Manager for "polling" plugins with the following '''
             '''configuration: {'polling': <class'''
             """ 'yahoo_panoptes.polling.polling_plugin.PanoptesPollingPlugin'>}, """
             """['tests/plugins/polling'], panoptes-plugin"""),
            ('panoptes.tests.test_runner', 'DEBUG', 'Found 3 plugins'),
            ('panoptes.tests.test_runner', 'DEBUG', 'Loaded plugin '
             '"Test Polling Plugin", version "0.1" of type "polling"'
             ', category "polling"'),
            ('panoptes.tests.test_runner', 'DEBUG',
             'Loaded plugin "Test Polling Plugin 2", '
             'version "0.1" of type "polling", category "polling"'),
            ('panoptes.tests.test_runner', 'DEBUG',
             'Loaded plugin "Test Polling Plugin Second Instance", '
             'version "0.1" of type "polling", category "polling"'),
            ('panoptes.tests.test_runner', 'INFO',
             '[Test Polling Plugin] [plugin|test|site|test|class|test|subclass|test|'
             'type|test|id|test|endpoint|test] Attempting to get lock for plugin '
             '"Test Polling Plugin"'),
            ('panoptes.tests.test_runner', 'DEBUG',
             'Attempting to get lock for plugin "Test Polling Plugin", with lock path and '
             'identifier in seconds'),
            ('panoptes.tests.test_runner', 'INFO',
             '[Test Polling Plugin] [plugin|test|site|test|class|test|subclass|test|'
             'type|test|id|test|endpoint|test] Acquired lock'),
            ('panoptes.tests.test_runner', 'INFO',
             '[Test Polling Plugin] [plugin|test|site|test|class|test|subclass|test|'
             'type|test|id|test|endpoint|test]'
             ' Ran in seconds'),
            ('panoptes.tests.test_runner', 'INFO',
             '[Test Polling Plugin] [plugin|test|site|test|class|test|subclass|test|'
             'type|test|id|test|endpoint|test] Released lock'),
            ('panoptes.tests.test_runner', 'INFO',
             '[Test Polling Plugin] [plugin|test|site|test|class|test|subclass|test|'
             'type|test|id|test|endpoint|test] Plugin returned'
             ' a result set with 1 members'),
            ('panoptes.tests.test_runner', 'INFO',
             '[Test Polling Plugin] [plugin|test|site|test|class|test|subclass|test|'
             'type|test|id|test|endpoint|test]'
             ' Callback function ran in seconds'),
            ('panoptes.tests.test_runner', 'INFO',
             '[Test Polling Plugin] [plugin|test|site|test|class|test|subclass|test|type|'
             'test|id|test|endpoint|test] GC took seconds. There are garbage objects.'
             ),
            ('panoptes.tests.test_runner', 'ERROR',
             'No enrichment data found on KV store for plugin Test Polling Plugin '
             'resource test namespace test using key test'),
            ('panoptes.tests.test_runner', 'DEBUG',
             'Successfully created PanoptesEnrichmentCache enrichment_data {} for plugin '
             'Test Polling Plugin'),
            order_matters=False)
Example #54
0
class TestService(unittest.TestCase):
    def get_ini(self):
        return os.path.join(os.path.dirname(__file__), 'test_memorynode.ini')

    def setUp(self):
        self.config = testing.setUp()
        settings = {}
        load_into_settings(self.get_ini(), settings)
        self.config.add_settings(settings)
        self.config.include("tokenserver")
        load_and_register("tokenserver", self.config)
        self.backend = self.config.registry.getUtility(INodeAssignment)
        wsgiapp = self.config.make_wsgi_app()
        self.app = TestApp(wsgiapp)
        # Mock out the verifier to return successfully by default.
        self.mock_browserid_verifier_context = self.mock_browserid_verifier()
        self.mock_browserid_verifier_context.__enter__()
        self.mock_oauth_verifier_context = self.mock_oauth_verifier()
        self.mock_oauth_verifier_context.__enter__()
        self.logs = LogCapture()

    def tearDown(self):
        self.logs.uninstall()
        self.mock_oauth_verifier_context.__exit__(None, None, None)
        self.mock_browserid_verifier_context.__exit__(None, None, None)

    def assertExceptionWasLogged(self, msg):
        for r in self.logs.records:
            if r.msg == msg:
                assert r.exc_info is not None
                break
        else:
            assert False, "exception with message %r was not logged" % (msg, )

    def assertMessageWasNotLogged(self, msg):
        for r in self.logs.records:
            if r.msg == msg:
                assert False, "message %r was unexpectedly logged" % (msg, )

    def assertMetricWasLogged(self, key):
        """Check that a metric was logged during the request."""
        for r in self.logs.records:
            if key in r.__dict__:
                break
        else:
            assert False, "metric %r was not logged" % (key, )

    def clearLogs(self):
        del self.logs.records[:]

    def unsafelyParseToken(self, token):
        # For testing purposes, don't check HMAC or anything...
        token = token.encode("utf8")
        return json.loads(decode_token_bytes(token)[:-32].decode("utf8"))

    @contextlib.contextmanager
    def mock_browserid_verifier(self, response=None, exc=None):
        def mock_verify_method(assertion):
            if exc is not None:
                raise exc
            if response is not None:
                return response
            return {
                "status": "okay",
                "email": get_assertion_info(assertion)["principal"]["email"],
            }

        verifier = get_browserid_verifier(self.config.registry)
        orig_verify_method = verifier.__dict__.get("verify", None)
        verifier.__dict__["verify"] = mock_verify_method
        try:
            yield None
        finally:
            if orig_verify_method is None:
                del verifier.__dict__["verify"]
            else:
                verifier.__dict__["verify"] = orig_verify_method

    @contextlib.contextmanager
    def mock_oauth_verifier(self, response=None, exc=None):
        def mock_verify_method(token):
            if exc is not None:
                raise exc
            if response is not None:
                return response
            return {
                "email": token.decode("hex"),
                "idpClaims": {},
            }

        verifier = get_oauth_verifier(self.config.registry)
        orig_verify_method = verifier.__dict__.get("verify", None)
        verifier.__dict__["verify"] = mock_verify_method
        try:
            yield None
        finally:
            if orig_verify_method is None:
                del verifier.__dict__["verify"]
            else:
                verifier.__dict__["verify"] = orig_verify_method

    def _getassertion(self, **kw):
        kw.setdefault('email', '*****@*****.**')
        kw.setdefault('audience', 'http://tokenserver.services.mozilla.com')
        return make_assertion(**kw).encode('ascii')

    def _gettoken(self, email='*****@*****.**'):
        return email.encode('hex')

    def test_unknown_app(self):
        headers = {'Authorization': 'BrowserID %s' % self._getassertion()}
        resp = self.app.get('/1.0/xXx/token', headers=headers, status=404)
        self.assertTrue('errors' in resp.json)

    def test_invalid_client_state(self):
        headers = {'X-Client-State': 'state!'}
        resp = self.app.get('/1.0/sync/1.5', headers=headers, status=400)
        self.assertEquals(resp.json['errors'][0]['location'], 'header')
        self.assertEquals(resp.json['errors'][0]['name'], 'X-Client-State')
        headers = {'X-Client-State': 'foobar\n\r\t'}
        resp = self.app.get('/1.0/sync/1.5', headers=headers, status=400)
        self.assertEquals(resp.json['errors'][0]['location'], 'header')
        self.assertEquals(resp.json['errors'][0]['name'], 'X-Client-State')

    def test_no_auth(self):
        self.app.get('/1.0/sync/1.5', status=401)

    def test_valid_app(self):
        headers = {'Authorization': 'BrowserID %s' % self._getassertion()}
        res = self.app.get('/1.0/sync/1.1', headers=headers)
        self.assertIn('https://example.com/1.1', res.json['api_endpoint'])
        self.assertIn('duration', res.json)
        self.assertEquals(res.json['duration'], 3600)
        self.assertMetricWasLogged('token.assertion.verify_success')
        self.clearLogs()

    def test_unknown_pattern(self):
        # sync 1.5 is defined in the .ini file, but  no pattern exists for it.
        headers = {'Authorization': 'BrowserID %s' % self._getassertion()}
        self.app.get('/1.0/sync/1.5', headers=headers, status=503)

    def test_discovery(self):
        res = self.app.get('/')
        self.assertEqual(
            res.json, {
                'auth': 'http://localhost',
                'services': {
                    'sync': ['1.1', '1.5'],
                },
                'browserid': {
                    'allowed_issuers': None,
                    'trusted_issuers': None,
                },
                'oauth': {
                    'default_issuer': 'api.accounts.firefox.com',
                    'scope': 'https://identity.mozilla.com/apps/oldsync',
                    'server_url': 'https://oauth.accounts.firefox.com/v1',
                }
            })

    def test_version_returns_404_by_default(self):
        # clear cache
        try:
            del tokenserver.views.version_view.__json__
        except AttributeError:
            pass
        with mock.patch('os.path.exists', return_value=False):
            self.app.get('/__version__', status=404)

    def test_version_returns_file_in_current_folder_if_present(self):
        # clear cache
        try:
            del tokenserver.views.version_view.__json__
        except AttributeError:
            pass
        content = {'version': '0.8.1'}
        fake_file = mock.mock_open(read_data=json.dumps(content))
        with mock.patch('os.path.exists'):
            with mock.patch('tokenserver.views.open', fake_file):
                response = self.app.get('/__version__')
                self.assertEquals(response.json, content)

    def test_lbheartbeat(self):
        res = self.app.get('/__lbheartbeat__')
        self.assertEqual(res.json, {})

    def test_unauthorized_error_status(self):
        # Totally busted auth -> generic error.
        headers = {'Authorization': 'Unsupported-Auth-Scheme IHACKYOU'}
        res = self.app.get('/1.0/sync/1.1', headers=headers, status=401)
        self.assertEqual(res.json['status'], 'error')

        # BrowserID verifier errors
        assertion = self._getassertion()
        headers = {'Authorization': 'BrowserID %s' % assertion}
        # Bad signature -> "invalid-credentials"
        errs = browserid.errors
        with self.mock_browserid_verifier(exc=errs.InvalidSignatureError):
            res = self.app.get('/1.0/sync/1.1', headers=headers, status=401)
        self.assertEqual(res.json['status'], 'invalid-credentials')
        # Bad audience -> "invalid-credentials"
        with self.mock_browserid_verifier(exc=errs.AudienceMismatchError):
            res = self.app.get('/1.0/sync/1.1', headers=headers, status=401)
        self.assertEqual(res.json['status'], 'invalid-credentials')
        self.assertMetricWasLogged('token.assertion.verify_failure')
        self.assertMetricWasLogged('token.assertion.audience_mismatch_error')
        self.clearLogs()
        # Expired timestamp -> "invalid-timestamp"
        with self.mock_browserid_verifier(exc=errs.ExpiredSignatureError):
            res = self.app.get('/1.0/sync/1.1', headers=headers, status=401)
        self.assertEqual(res.json['status'], 'invalid-timestamp')
        self.assertTrue('X-Timestamp' in res.headers)
        self.assertMetricWasLogged('token.assertion.verify_failure')
        self.assertMetricWasLogged('token.assertion.expired_signature_error')
        self.clearLogs()
        # Connection error -> 503
        with self.mock_browserid_verifier(exc=errs.ConnectionError):
            res = self.app.get('/1.0/sync/1.1', headers=headers, status=503)
        self.assertMetricWasLogged('token.assertion.verify_failure')
        self.assertMetricWasLogged('token.assertion.connection_error')
        self.assertExceptionWasLogged('Unexpected verification error')
        self.clearLogs()
        # Some other wacky error -> not captured
        with self.mock_browserid_verifier(exc=ValueError):
            with self.assertRaises(ValueError):
                res = self.app.get('/1.0/sync/1.1', headers=headers)

        # OAuth verifier errors
        token = self._gettoken()
        headers = {'Authorization': 'Bearer %s' % token}
        # Bad token -> "invalid-credentials"
        err = fxa.errors.ClientError({"code": 400, "errno": 108})
        with self.mock_oauth_verifier(exc=err):
            res = self.app.get('/1.0/sync/1.1', headers=headers, status=401)
        self.assertEqual(res.json['status'], 'invalid-credentials')
        self.assertMetricWasLogged('token.oauth.errno.108')
        self.assertMessageWasNotLogged('Unexpected verification error')
        # Untrusted scopes -> "invalid-credentials"
        err = fxa.errors.TrustError({"code": 400, "errno": 999})
        with self.mock_oauth_verifier(exc=err):
            res = self.app.get('/1.0/sync/1.1', headers=headers, status=401)
        self.assertEqual(res.json['status'], 'invalid-credentials')
        self.assertMessageWasNotLogged('Unexpected verification error')
        # Connection error -> 503
        with self.mock_oauth_verifier(exc=errs.ConnectionError):
            res = self.app.get('/1.0/sync/1.1', headers=headers, status=503)
        self.assertMetricWasLogged('token.oauth.verify_failure')
        self.assertMetricWasLogged('token.oauth.connection_error')
        self.assertExceptionWasLogged('Unexpected verification error')
        self.clearLogs()
        # Some other wacky error -> not captured
        with self.mock_oauth_verifier(exc=ValueError):
            with self.assertRaises(ValueError):
                res = self.app.get('/1.0/sync/1.1', headers=headers)

    def test_unverified_token(self):
        headers = {'Authorization': 'BrowserID %s' % self._getassertion()}
        # Assertion should not be rejected if fxa-tokenVerified is unset
        mock_response = {
            "status": "okay",
            "email": "*****@*****.**",
            "idpClaims": {}
        }
        with self.mock_browserid_verifier(response=mock_response):
            self.app.get("/1.0/sync/1.1", headers=headers, status=200)
        # Assertion should not be rejected if fxa-tokenVerified is True
        mock_response['idpClaims']['fxa-tokenVerified'] = True
        with self.mock_browserid_verifier(response=mock_response):
            self.app.get("/1.0/sync/1.1", headers=headers, status=200)
        # Assertion should be rejected if fxa-tokenVerified is False
        mock_response['idpClaims']['fxa-tokenVerified'] = False
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get("/1.0/sync/1.1", headers=headers, status=401)
        self.assertEqual(res.json['status'], 'invalid-credentials')

    def test_generation_number_change(self):
        headers = {"Authorization": "BrowserID %s" % self._getassertion()}
        # Start with no generation number.
        mock_response = {"status": "okay", "email": "*****@*****.**"}
        with self.mock_browserid_verifier(response=mock_response):
            res1 = self.app.get("/1.0/sync/1.1", headers=headers)
        # Now send an explicit generation number.
        # The node assignment should not change.
        mock_response["idpClaims"] = {"fxa-generation": 12}
        with self.mock_browserid_verifier(response=mock_response):
            res2 = self.app.get("/1.0/sync/1.1", headers=headers)
        self.assertEqual(res1.json["uid"], res2.json["uid"])
        self.assertEqual(res1.json["api_endpoint"], res2.json["api_endpoint"])
        # Clients that don't report generation number are still allowed.
        del mock_response["idpClaims"]
        with self.mock_browserid_verifier(response=mock_response):
            res2 = self.app.get("/1.0/sync/1.1", headers=headers)
        self.assertEqual(res1.json["uid"], res2.json["uid"])
        mock_response["idpClaims"] = {"some-nonsense": "lolwut"}
        with self.mock_browserid_verifier(response=mock_response):
            res2 = self.app.get("/1.0/sync/1.1", headers=headers)
        self.assertEqual(res1.json["uid"], res2.json["uid"])
        # But previous generation numbers get an invalid-generation response.
        mock_response["idpClaims"] = {"fxa-generation": 10}
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get("/1.0/sync/1.1", headers=headers, status=401)
        self.assertEqual(res.json["status"], "invalid-generation")
        # Equal generation numbers are accepted.
        mock_response["idpClaims"] = {"fxa-generation": 12}
        with self.mock_browserid_verifier(response=mock_response):
            res2 = self.app.get("/1.0/sync/1.1", headers=headers)
        self.assertEqual(res1.json["uid"], res2.json["uid"])
        self.assertEqual(res1.json["api_endpoint"], res2.json["api_endpoint"])
        # Later generation numbers are accepted.
        # Again, the node assignment should not change.
        mock_response["idpClaims"] = {"fxa-generation": 13}
        with self.mock_browserid_verifier(response=mock_response):
            res2 = self.app.get("/1.0/sync/1.1", headers=headers)
        self.assertEqual(res1.json["uid"], res2.json["uid"])
        self.assertEqual(res1.json["api_endpoint"], res2.json["api_endpoint"])
        # And that should lock out the previous generation number
        mock_response["idpClaims"] = {"fxa-generation": 12}
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get("/1.0/sync/1.1", headers=headers, status=401)
        self.assertEqual(res.json["status"], "invalid-generation")
        # Various nonsense generation numbers should give errors.
        mock_response["idpClaims"] = {"fxa-generation": "whatswrongwithyour"}
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get("/1.0/sync/1.1", headers=headers, status=401)
        self.assertEqual(res.json["status"], "invalid-generation")
        mock_response["idpClaims"] = {"fxa-generation": None}
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get("/1.0/sync/1.1", headers=headers, status=401)
        self.assertEqual(res.json["status"], "invalid-generation")
        mock_response["idpClaims"] = {"fxa-generation": "42"}
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get("/1.0/sync/1.1", headers=headers, status=401)
        self.assertEqual(res.json["status"], "invalid-generation")
        mock_response["idpClaims"] = {"fxa-generation": ["I", "HACK", "YOU"]}
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get("/1.0/sync/1.1", headers=headers, status=401)
        self.assertEqual(res.json["status"], "invalid-generation")

    def test_client_state_change(self):
        mock_response = {
            "status": "okay",
            "email": "*****@*****.**",
            "idpClaims": {
                "fxa-generation": 1234,
                "fxa-keysChangedAt": 1234
            },
        }
        # Start with no client-state header.
        headers = {'Authorization': 'BrowserID %s' % self._getassertion()}
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get('/1.0/sync/1.1', headers=headers)
        uid0 = res.json['uid']
        # No change == same uid.
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get('/1.0/sync/1.1', headers=headers)
        self.assertEqual(res.json['uid'], uid0)
        # Changing client-state header requires changing generation.
        headers['X-Client-State'] = 'aaaa'
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get('/1.0/sync/1.1', headers=headers, status=401)
        self.assertEqual(res.json['status'], 'invalid-client-state')
        desc = res.json['errors'][0]['description']
        self.assertTrue(desc.endswith('new value with no generation change'))
        # Changing client-state header requires changing keys_changed_at.
        mock_response["idpClaims"]["fxa-generation"] += 1
        headers['X-Client-State'] = 'aaaa'
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get('/1.0/sync/1.1', headers=headers, status=401)
        self.assertEqual(res.json['status'], 'invalid-client-state')
        desc = res.json['errors'][0]['description']
        self.assertTrue(desc.endswith('with no keys_changed_at change'))
        # Change the client-state header, get a new uid.
        mock_response["idpClaims"]["fxa-keysChangedAt"] += 1
        headers['X-Client-State'] = 'aaaa'
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get('/1.0/sync/1.1', headers=headers)
        uid1 = res.json['uid']
        self.assertNotEqual(uid1, uid0)
        # No change == same uid.
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get('/1.0/sync/1.1', headers=headers)
        self.assertEqual(res.json['uid'], uid1)
        # Send a client-state header, get a new uid.
        headers['X-Client-State'] = 'bbbb'
        mock_response["idpClaims"]["fxa-generation"] += 1
        mock_response["idpClaims"]["fxa-keysChangedAt"] += 1
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get('/1.0/sync/1.1', headers=headers)
        uid2 = res.json['uid']
        self.assertNotEqual(uid2, uid0)
        self.assertNotEqual(uid2, uid1)
        # No change == same uid.
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get('/1.0/sync/1.1', headers=headers)
        self.assertEqual(res.json['uid'], uid2)
        # Use a previous client-state, get an auth error.
        headers['X-Client-State'] = 'aaaa'
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get('/1.0/sync/1.1', headers=headers, status=401)
        self.assertEqual(res.json['status'], 'invalid-client-state')
        desc = res.json['errors'][0]['description']
        self.assertTrue(desc.endswith('stale value'))
        del headers['X-Client-State']
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get('/1.0/sync/1.1', headers=headers, status=401)
        self.assertEqual(res.json['status'], 'invalid-client-state')
        headers['X-Client-State'] = 'aaaa'
        mock_response["idpClaims"]["fxa-generation"] += 1
        mock_response["idpClaims"]["fxa-keysChangedAt"] += 1
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get('/1.0/sync/1.1', headers=headers, status=401)
        self.assertEqual(res.json['status'], 'invalid-client-state')

    def test_fxa_kid_change(self):
        # Starting off not reporting keys_changed_at.
        # We don't expect to encounter this in production, but it might
        # happen to self-hosters who update tokenserver without updating
        # their FxA stack.
        headers = {
            "Authorization": "BrowserID %s" % self._getassertion(),
            "X-Client-State": "616161",
        }
        mock_response = {
            "status": "okay",
            "email": "*****@*****.**",
            "idpClaims": {
                "fxa-generation": 1234
            },
        }
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get('/1.0/sync/1.1', headers=headers)
        token = self.unsafelyParseToken(res.json["id"])
        self.assertEqual(token["fxa_kid"], "0000000001234-YWFh")
        # Now pretend we updated FxA and it started sending keys_changed_at.
        mock_response["idpClaims"]["fxa-generation"] = 2345
        mock_response["idpClaims"]["fxa-keysChangedAt"] = 2345
        headers["X-Client-State"] = "626262"
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get('/1.0/sync/1.1', headers=headers)
        token = self.unsafelyParseToken(res.json["id"])
        self.assertEqual(token["fxa_kid"], "0000000002345-YmJi")
        # If we roll back the FxA stack so it stops reporting keys_changed_at,
        # users will get locked out because we can't produce `fxa_kid`.
        del mock_response["idpClaims"]["fxa-keysChangedAt"]
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get('/1.0/sync/1.1', headers=headers, status=401)
        self.assertEqual(res.json["status"], "invalid-keysChangedAt")
        # We will likewise reject values below the high-water mark.
        mock_response["idpClaims"]["fxa-keysChangedAt"] = 2340
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get('/1.0/sync/1.1', headers=headers, status=401)
        self.assertEqual(res.json["status"], "invalid-keysChangedAt")
        # But accept the correct value, even if generation number changes.
        mock_response["idpClaims"]["fxa-generation"] = 3456
        mock_response["idpClaims"]["fxa-keysChangedAt"] = 2345
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get('/1.0/sync/1.1', headers=headers)
        token = self.unsafelyParseToken(res.json["id"])
        self.assertEqual(token["fxa_kid"], "0000000002345-YmJi")
        # We should error out if keysChangedAt changes to be larger than
        # the corresponding generation number.
        mock_response["idpClaims"]["fxa-keysChangedAt"] = 4567
        headers["X-Client-State"] = "636363"
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get('/1.0/sync/1.1', headers=headers, status=401)
        self.assertEqual(res.json["status"], "invalid-keysChangedAt")
        # But accept further updates if both values change in unison.
        mock_response["idpClaims"]["fxa-generation"] = 4567
        mock_response["idpClaims"]["fxa-keysChangedAt"] = 4567
        headers["X-Client-State"] = "636363"
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get('/1.0/sync/1.1', headers=headers)
        token = self.unsafelyParseToken(res.json["id"])
        self.assertEqual(token["fxa_kid"], "0000000004567-Y2Nj")

    def test_fxa_kid_change_with_oauth(self):
        # Starting off not reporting keys_changed_at.
        # This uses BrowserID since OAuth always reports keys_changed_at.
        headers_browserid = {
            "Authorization": "BrowserID %s" % self._getassertion(),
            "X-Client-State": "616161",
        }
        mock_response = {
            "status": "okay",
            "email": "*****@*****.**",
            "idpClaims": {
                "fxa-generation": 1234
            },
        }
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get('/1.0/sync/1.1', headers=headers_browserid)
        token0 = self.unsafelyParseToken(res.json["id"])
        self.assertEqual(token0["fxa_kid"], "0000000001234-YWFh")
        # Now an OAuth client shows up, setting keys_changed_at.
        # (The value matches generation number above, beause in this scenario
        # FxA hasn't been updated to track and report keysChangedAt yet).
        headers_oauth = {
            "Authorization": "Bearer %s" % self._gettoken("*****@*****.**"),
            "X-KeyID": "1234-YWFh",
        }
        res = self.app.get('/1.0/sync/1.1', headers=headers_oauth)
        token = self.unsafelyParseToken(res.json["id"])
        self.assertEqual(token["fxa_kid"], "0000000001234-YWFh")
        self.assertEqual(token["uid"], token0["uid"])
        self.assertEqual(token["node"], token0["node"])
        # At this point, BrowserID clients are locked out until FxA is updated,
        # because we're now expecting to see keys_changed_at for that user.
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get('/1.0/sync/1.1',
                               headers=headers_browserid,
                               status=401)
        self.assertEqual(res.json["status"], "invalid-keysChangedAt")
        # We will likewise reject values below the high-water mark.
        mock_response["idpClaims"]["fxa-keysChangedAt"] = 1230
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get('/1.0/sync/1.1',
                               headers=headers_browserid,
                               status=401)
        self.assertEqual(res.json["status"], "invalid-keysChangedAt")
        headers_oauth["X-KeyID"] = "1230-YWFh"
        res = self.app.get('/1.0/sync/1.1', headers=headers_oauth, status=401)
        self.assertEqual(res.json["status"], "invalid-keysChangedAt")
        # We accept new values via OAuth.
        headers_oauth["X-KeyID"] = "2345-YmJi"
        res = self.app.get('/1.0/sync/1.1', headers=headers_oauth)
        token = self.unsafelyParseToken(res.json["id"])
        self.assertEqual(token["fxa_kid"], "0000000002345-YmJi")
        self.assertNotEqual(token["uid"], token0["uid"])
        self.assertEqual(token["node"], token0["node"])
        # And via BrowserID, as long as generation number increases as well.
        headers_browserid["X-Client-State"] = "636363"
        mock_response["idpClaims"]["fxa-generation"] = 3456
        mock_response["idpClaims"]["fxa-keysChangedAt"] = 3456
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get('/1.0/sync/1.1', headers=headers_browserid)
        token = self.unsafelyParseToken(res.json["id"])
        self.assertEqual(token["fxa_kid"], "0000000003456-Y2Nj")

    def test_kid_change_during_gradual_tokenserver_rollout(self):
        # Let's start with a user already in the db, with no keys_changed_at.
        user0 = self.backend.allocate_user("sync-1.1",
                                           "*****@*****.**",
                                           generation=1234,
                                           client_state="616161")
        # User hits updated tokenserver node, writing keys_changed_at to db.
        headers = {
            "Authorization": "BrowserID %s" % self._getassertion(),
            "X-Client-State": "616161",
        }
        mock_response = {
            "status": "okay",
            "email": "*****@*****.**",
            "idpClaims": {
                "fxa-generation": 1234,
                "fxa-keysChangedAt": 1200,
            },
        }
        with self.mock_browserid_verifier(response=mock_response):
            self.app.get('/1.0/sync/1.1', headers=headers)
        # That should not have triggered a node re-assignment.
        user1 = self.backend.get_user("sync-1.1", mock_response["email"])
        self.assertEqual(user1['uid'], user0['uid'])
        self.assertEqual(user1['node'], user0['node'])
        # That should have written keys_changed_at into the db.
        self.assertEqual(user1["generation"], 1234)
        self.assertEqual(user1["keys_changed_at"], 1200)
        # User does a password reset on their Firefox Account.
        mock_response["idpClaims"]["fxa-generation"] = 2345
        mock_response["idpClaims"]["fxa-keysChangedAt"] = 2345
        headers["X-Client-State"] = "626262"
        # They sync again, but hit a tokenserver node that isn't updated yet.
        # Simulate this by writing the updated data directly to the backend,
        # which should trigger a node re-assignment.
        self.backend.update_user("sync-1.1",
                                 user1,
                                 generation=2345,
                                 client_state="626262")
        self.assertNotEqual(user1['uid'], user0['uid'])
        self.assertEqual(user1['node'], user0['node'])
        # They sync again, hitting an updated tokenserver node.
        # This should succeed, despite keys_changed_at appearing to have
        # changed without any corresponding change in generation number.
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get('/1.0/sync/1.1', headers=headers)
        token = self.unsafelyParseToken(res.json["id"])
        self.assertEqual(token["fxa_kid"], "0000000002345-YmJi")
        # That should not have triggered a second node re-assignment.
        user2 = self.backend.get_user("sync-1.1", mock_response["email"])
        self.assertEqual(user2['uid'], user1['uid'])
        self.assertEqual(user2['node'], user1['node'])

    def test_client_state_cannot_revert_to_empty(self):
        # Start with a client-state header.
        headers = {
            'Authorization': 'BrowserID %s' % self._getassertion(),
            'X-Client-State': 'aaaa',
        }
        res = self.app.get('/1.0/sync/1.1', headers=headers)
        uid0 = res.json['uid']
        # Sending no client-state will fail.
        del headers['X-Client-State']
        res = self.app.get('/1.0/sync/1.1', headers=headers, status=401)
        self.assertEqual(res.json['status'], 'invalid-client-state')
        desc = res.json['errors'][0]['description']
        self.assertTrue(desc.endswith('empty string'))
        headers['X-Client-State'] = ''
        res = self.app.get('/1.0/sync/1.1', headers=headers, status=401)
        self.assertEqual(res.json['status'], 'invalid-client-state')
        desc = res.json['errors'][0]['description']
        self.assertTrue(desc.endswith('empty string'))
        # And the uid will be unchanged.
        headers['X-Client-State'] = 'aaaa'
        res = self.app.get('/1.0/sync/1.1', headers=headers)
        self.assertEqual(res.json['uid'], uid0)

    def test_credentials_from_oauth_and_browserid(self):
        # Send initial credentials via oauth.
        headers_oauth = {
            "Authorization": "Bearer %s" % self._gettoken(),
            "X-KeyID": "7-YWFh",
        }
        res1 = self.app.get("/1.0/sync/1.1", headers=headers_oauth)
        # Send the same credentials via BrowserID
        headers_browserid = {
            "Authorization": "BrowserID %s" % self._getassertion(),
            "X-Client-State": "616161",
        }
        mock_response = {
            "status": "okay",
            "email": "*****@*****.**",
            "idpClaims": {
                "fxa-generation": 12,
                "fxa-keysChangedAt": 7
            },
        }
        with self.mock_browserid_verifier(response=mock_response):
            res2 = self.app.get("/1.0/sync/1.1", headers=headers_browserid)
        # They should get the same node assignment.
        self.assertEqual(res1.json["uid"], res2.json["uid"])
        self.assertEqual(res1.json["api_endpoint"], res2.json["api_endpoint"])
        # Earlier generation number via BrowserID -> invalid-generation
        mock_response["idpClaims"]['fxa-generation'] = 11
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get("/1.0/sync/1.1",
                               headers=headers_browserid,
                               status=401)
        self.assertEqual(res.json["status"], "invalid-generation")
        # Earlier keys_changed_at via BrowserID is not accepted.
        mock_response["idpClaims"]['fxa-generation'] = 12
        mock_response["idpClaims"]['fxa-keysChangedAt'] = 6
        with self.mock_browserid_verifier(response=mock_response):
            res1 = self.app.get("/1.0/sync/1.1",
                                headers=headers_browserid,
                                status=401)
        self.assertEqual(res1.json['status'], 'invalid-keysChangedAt')
        # Earlier generation number via OAuth -> invalid-generation
        mock_response["idpClaims"]['fxa-generation'] = 11
        del mock_response["idpClaims"]["fxa-keysChangedAt"]
        with self.mock_oauth_verifier(response=mock_response):
            res = self.app.get("/1.0/sync/1.1",
                               headers=headers_oauth,
                               status=401)
        self.assertEqual(res.json["status"], "invalid-generation")
        # Earlier keys_changed_at via OAuth is not accepted.
        headers_oauth['X-KeyID'] = '6-YWFh'
        res1 = self.app.get("/1.0/sync/1.1", headers=headers_oauth, status=401)
        self.assertEqual(res1.json['status'], 'invalid-keysChangedAt')
        # Change client-state via BrowserID.
        headers_browserid['X-Client-State'] = '626262'
        mock_response["idpClaims"]['fxa-generation'] = 42
        mock_response["idpClaims"]['fxa-keysChangedAt'] = 42
        with self.mock_browserid_verifier(response=mock_response):
            res1 = self.app.get("/1.0/sync/1.1", headers=headers_browserid)
        # Previous OAuth creds are rejected due to keys_changed_at update.
        headers_oauth['X-KeyID'] = '7-YmJi'
        res2 = self.app.get("/1.0/sync/1.1", headers=headers_oauth, status=401)
        self.assertEqual(res2.json['status'], 'invalid-keysChangedAt')
        # Updated OAuth creds are accepted.
        headers_oauth['X-KeyID'] = '42-YmJi'
        res2 = self.app.get("/1.0/sync/1.1", headers=headers_oauth)
        # They should again get the same node assignment.
        self.assertEqual(res1.json["uid"], res2.json["uid"])
        self.assertEqual(res1.json["api_endpoint"], res2.json["api_endpoint"])

    def test_client_specified_duration(self):
        headers = {'Authorization': 'BrowserID %s' % self._getassertion()}
        # It's ok to request a shorter-duration token.
        res = self.app.get('/1.0/sync/1.1?duration=12', headers=headers)
        self.assertEquals(res.json['duration'], 12)
        # But you can't exceed the server's default value.
        res = self.app.get('/1.0/sync/1.1?duration=4000', headers=headers)
        self.assertEquals(res.json['duration'], 3600)
        # And nonsense values are ignored.
        res = self.app.get('/1.0/sync/1.1?duration=lolwut', headers=headers)
        self.assertEquals(res.json['duration'], 3600)
        res = self.app.get('/1.0/sync/1.1?duration=-1', headers=headers)
        self.assertEquals(res.json['duration'], 3600)

    def test_allow_new_users(self):
        # New users are allowed by default.
        settings = self.config.registry.settings
        self.assertEquals(settings.get('tokenserver.allow_new_users'), None)
        assertion = self._getassertion(email="*****@*****.**")
        headers = {'Authorization': 'BrowserID %s' % assertion}
        self.app.get('/1.0/sync/1.1', headers=headers, status=200)
        # They're allowed if we explicitly allow them.
        settings['tokenserver.allow_new_users'] = True
        assertion = self._getassertion(email="*****@*****.**")
        headers = {'Authorization': 'BrowserID %s' % assertion}
        self.app.get('/1.0/sync/1.1', headers=headers, status=200)
        # They're not allowed if we explicitly disable them.
        settings['tokenserver.allow_new_users'] = False
        assertion = self._getassertion(email="*****@*****.**")
        headers = {'Authorization': 'BrowserID %s' % assertion}
        res = self.app.get('/1.0/sync/1.1', headers=headers, status=401)
        self.assertEqual(res.json['status'], 'new-users-disabled')
        # But existing users are still allowed.
        assertion = self._getassertion(email="*****@*****.**")
        headers = {'Authorization': 'BrowserID %s' % assertion}
        self.app.get('/1.0/sync/1.1', headers=headers, status=200)
        assertion = self._getassertion(email="*****@*****.**")
        headers = {'Authorization': 'BrowserID %s' % assertion}
        self.app.get('/1.0/sync/1.1', headers=headers, status=200)

    def test_metrics_uid_logging(self):
        assert "fxa.metrics_uid_secret_key" in self.config.registry.settings
        assertion = self._getassertion(email="*****@*****.**")
        headers = {'Authorization': 'BrowserID %s' % assertion}
        self.app.get('/1.0/sync/1.1', headers=headers, status=200)
        self.assertMetricWasLogged('uid')
        self.assertMetricWasLogged('uid.first_seen_at')
        self.assertMetricWasLogged('metrics_uid')
        self.assertMetricWasLogged('metrics_device_id')

    def test_uid_and_kid_from_browserid_assertion(self):
        assertion = self._getassertion(email="*****@*****.**")
        headers_browserid = {
            "Authorization": "BrowserID %s" % (assertion, ),
            "X-Client-State": "616161",
        }
        mock_response = {
            "status": "okay",
            "email": "*****@*****.**",
            "idpClaims": {
                "fxa-generation": 13,
                'fxa-keysChangedAt': 12
            },
        }
        with self.mock_browserid_verifier(response=mock_response):
            res = self.app.get("/1.0/sync/1.1", headers=headers_browserid)
        token = self.unsafelyParseToken(res.json["id"])
        self.assertEqual(token["uid"], res.json["uid"])
        self.assertEqual(token["fxa_uid"], "testuser")
        self.assertEqual(token["fxa_kid"], "0000000000012-YWFh")
        self.assertNotEqual(token["hashed_fxa_uid"], token["fxa_uid"])
        self.assertEqual(token["hashed_fxa_uid"], res.json["hashed_fxa_uid"])
        self.assertIn("hashed_device_id", token)

    def test_uid_and_kid_from_oauth_token(self):
        oauth_token = self._gettoken(email="*****@*****.**")
        headers_oauth = {
            "Authorization": "Bearer %s" % (oauth_token, ),
            "X-KeyID": "12-YWFh",
        }
        res = self.app.get("/1.0/sync/1.1", headers=headers_oauth)
        token = self.unsafelyParseToken(res.json["id"])
        self.assertEqual(token["uid"], res.json["uid"])
        self.assertEqual(token["fxa_uid"], "testuser")
        self.assertEqual(token["fxa_kid"], "0000000000012-YWFh")
        self.assertNotEqual(token["hashed_fxa_uid"], token["fxa_uid"])
        self.assertEqual(token["hashed_fxa_uid"], res.json["hashed_fxa_uid"])
        self.assertIn("hashed_device_id", token)

    def test_metrics_uid_is_returned_in_response(self):
        assert "fxa.metrics_uid_secret_key" in self.config.registry.settings
        assertion = self._getassertion(email="*****@*****.**")
        headers = {'Authorization': 'BrowserID %s' % assertion}
        res = self.app.get('/1.0/sync/1.1', headers=headers, status=200)
        self.assertTrue('hashed_fxa_uid' in res.json)

    def test_node_type_is_returned_in_response(self):
        assertion = self._getassertion(email="*****@*****.**")
        headers = {'Authorization': 'BrowserID %s' % assertion}
        res = self.app.get('/1.0/sync/1.1', headers=headers, status=200)
        self.assertEqual(res.json['node_type'], 'example')
Example #55
0
class TestStandardLibraryTarget(TestCase):
    def setUp(self):
        self.capture = LogCapture(attributes=('name', 'levelname',
                                              'getMessage', 'shoehorn_event'))
        self.addCleanup(self.capture.uninstall)

    def test_minimal(self):
        logger.info(event='test')
        self.capture.check(
            ('root', 'INFO', '', Event(event='test', level='info')))

    def test_named_logger(self):
        logger = get_logger('foo')
        logger.info(event='test')
        self.capture.check(
            ('foo', 'INFO', '', Event(event='test', logger='foo',
                                      level='info')))

    def test_level(self):
        logger.warning(event='test')
        self.capture.check(
            ('root', 'WARNING', '', Event(event='test', level='warning')))

    def test_sub_args(self):
        logger.info('foo %s', 'bar')
        self.capture.check(('root', 'INFO', 'foo bar',
                            Event(message='foo %s',
                                  args=('bar', ),
                                  level='info')))

    def test_exc_info(self):
        bad = Exception('bad')
        try:
            raise bad
        except:
            logger.exception('foo')
        self.capture.check(('root', 'ERROR', 'foo',
                            Event(level='error', message='foo',
                                  exc_info=True)))
        compare(bad, actual=self.capture.records[-1].exc_info[1])

    def test_stack_info(self):
        if PY2:
            return
        logger.info('foo', stack_info=True)
        self.capture.check(('root', 'INFO', 'foo',
                            Event(message='foo', stack_info=True,
                                  level='info')))
        compare('Stack (most recent call last):',
                actual=self.capture.records[-1].stack_info.split('\n')[0])

    def test_default_logger(self):
        from shoehorn import logger
        logger.info('er hi')
        self.capture.check(
            ('root', 'INFO', 'er hi', Event(message='er hi', level='info')))
Example #56
0
class TestMetrics(unittest2.TestCase):
    def setUp(self):
        self.logs = LogCapture()

    def tearDown(self):
        self.logs.uninstall()

    def test_service_metrics(self):
        stub_service = Service(name="stub", path="/stub")

        @stub_service.get()
        @metrics_timer("view_time")
        def stub_view(request):
            request.metrics["stub"] = "stub-a-dub-dub"
            return {}

        with pyramid.testing.testConfig() as config:
            config.include("cornice")
            config.include("mozsvc")
            register_service_views(config, stub_service)
            app = TestApp(config.make_wsgi_app())
            res = app.get("/stub")
            self.assertEqual(res.body, "{}")

        self.assertTrue(len(self.logs.records), 1)
        r = self.logs.records[0]
        self.assertEqual(r.stub, "stub-a-dub-dub")
        self.assertTrue(0 < r.request_time < 0.1)
        self.assertTrue(0 < r.view_time <= r.request_time)

    def test_timing_decorator(self):
        @metrics_timer("timer1")
        def doit1():
            time.sleep(0.01)

        def viewit(request):
            doit1()

        request = Request.blank("/")
        initialize_request_metrics(request)
        with pyramid.testing.testConfig(request=request):
            viewit(request)

        ts = request.metrics["timer1"]
        self.assertTrue(0.01 < ts < 0.1)

    def test_timing_contextmanager(self):
        def viewit(request):
            with metrics_timer("timer1"):
                time.sleep(0.01)

        request = Request.blank("/")
        initialize_request_metrics(request)
        with pyramid.testing.testConfig(request=request):
            viewit(request)

        ts = request.metrics["timer1"]
        self.assertTrue(0.01 < ts < 0.1)

    def test_timing_contextmanager_with_explicit_request_object(self):
        def viewit(request):
            with metrics_timer("timer1", request):
                time.sleep(0.01)

        request = Request.blank("/")
        initialize_request_metrics(request)
        viewit(request)

        ts = request.metrics["timer1"]
        self.assertTrue(0.01 < ts < 0.1)

    def test_timing_contextmanager_doesnt_fail_if_no_metrics_dict(self):
        def viewit(request):
            with metrics_timer("timer1"):
                time.sleep(0.01)

        request = Request.blank("/")
        with pyramid.testing.testConfig(request=request):
            viewit(request)

        self.assertFalse(hasattr(request, "metrics"))

    def test_timing_contextmanager_doesnt_fail_if_no_reqest_object(self):
        with metrics_timer("timer1"):
            time.sleep(0.01)

    def test_that_service_metrics_include_correct_response_codes(self):
        stub_service = Service(name="stub", path="/{what}")

        @stub_service.get()
        def stub_view(request):
            what = request.matchdict["what"]
            if what == "ok":
                return Response(status=200)
            if what == "notfound":
                return Response(status=404)
            if what == "forbidden":
                return Response(status=403)
            if what == "exc_forbidden":
                raise HTTPForbidden
            if what == "impl_forbidden":
                request.response.status_code = 403
                return ""
            raise HTTPNotFound

        with pyramid.testing.testConfig() as config:
            config.include("cornice")
            config.include("mozsvc")
            register_service_views(config, stub_service)
            app = TestApp(config.make_wsgi_app())

            app.get("/ok", status=200)
            r = self.logs.records[-1]
            self.assertEqual(r.code, 200)

            app.get("/notfound", status=404)
            r = self.logs.records[-1]
            self.assertEqual(r.code, 404)
            app.get("/forbidden", status=403)
            r = self.logs.records[-1]
            self.assertEqual(r.code, 403)

            app.get("/exc_notfound", status=404)
            r = self.logs.records[-1]
            self.assertEqual(r.code, 404)
            app.get("/exc_forbidden", status=403)
            r = self.logs.records[-1]
            self.assertEqual(r.code, 403)

            app.get("/impl_forbidden", status=403)
            r = self.logs.records[-1]
            self.assertEqual(r.code, 403)
Example #57
0
class ShowBearsTest(unittest.TestCase):
    def setUp(self):
        self.console_printer = ConsolePrinter(print_colored=False)
        self.logs = LogCapture()
        self.logs.__enter__()

    deprecation_messages = [
        ('root', 'WARNING', 'show_description parameter is deprecated'),
        ('root', 'WARNING', 'show_params parameter is deprecated')
    ]

    def tearDown(self):
        self.logs.__exit__(None, None, None)

    def test_show_bear_minimal(self):
        with retrieve_stdout() as stdout:
            show_bear(SomelocalBear, False, False, self.console_printer)
            self.assertEqual(stdout.getvalue(), 'SomelocalBear\n')

        self.logs.check(*self.deprecation_messages)

    def test_show_bear_desc_only(self):
        with retrieve_stdout() as stdout:
            show_bear(SomelocalBear, True, False, self.console_printer)
            self.assertEqual(
                stdout.getvalue(),
                'SomelocalBear\n  Some local-bear Description.\n\n')

        self.logs.check(*self.deprecation_messages)

    def test_show_bear_details_only(self):
        with retrieve_stdout() as stdout:
            show_bear(SomelocalBear, False, True, self.console_printer)
            self.assertEqual(
                stdout.getvalue(), 'SomelocalBear\n'
                '  The bear does not provide information about '
                'which languages it can analyze.\n\n'
                '  No needed settings.\n\n'
                '  No optional settings.\n\n'
                '  This bear does not provide information about '
                'what categories it can detect.\n\n'
                '  This bear cannot fix issues or does not '
                'provide information about what categories it '
                'can fix.\n\n  Path:\n   ' +
                repr(SomelocalBear.source_location) + '\n\n')

        self.logs.check(*self.deprecation_messages)

    def test_show_bear_long_without_content(self):
        with retrieve_stdout() as stdout:
            show_bear(SomelocalBear, True, True, self.console_printer)
            self.assertEqual(
                stdout.getvalue(), 'SomelocalBear\n'
                '  Some local-bear Description.\n\n'
                '  The bear does not provide information about '
                'which languages it can analyze.\n\n'
                '  No needed settings.\n\n'
                '  No optional settings.\n\n'
                '  This bear does not provide information about '
                'what categories it can detect.\n\n'
                '  This bear cannot fix issues or does not '
                'provide information about what categories it '
                'can fix.\n\n  Path:\n   ' +
                repr(SomelocalBear.source_location) + '\n\n')

        self.logs.check(*self.deprecation_messages)

    def test_show_bear_with_content(self):
        with retrieve_stdout() as stdout:
            show_bear(TestBear, True, True, self.console_printer)
            self.assertEqual(
                stdout.getvalue(), 'TestBear\n'
                '  Test bear Description.\n\n'
                '  Supported languages:\n'
                '   * F#\n'
                '   * Shakespearean Programming Language\n\n'
                '  Needed Settings:\n'
                '   * setting1: Required Setting.\n\n'
                '  Optional Settings:\n'
                '   * setting2: Optional Setting. ('
                "Optional, defaults to 'None'."
                ')\n\n'
                '  Can detect:\n   * Formatting\n\n'
                '  Can fix:\n   * Formatting\n\n  Path:\n   ' +
                repr(TestBear.source_location) + '\n\n')

        self.logs.check(*self.deprecation_messages)

    def test_show_bear_settings_only(self):
        with retrieve_stdout() as stdout:
            args = default_arg_parser().parse_args(['--show-settings'])
            show_bear(TestBear, False, False, self.console_printer, args)
            self.assertEqual(
                stdout.getvalue(), 'TestBear\n'
                '  Needed Settings:\n'
                '   * setting1: Required Setting.\n\n'
                '  Optional Settings:\n'
                '   * setting2: Optional Setting. ('
                "Optional, defaults to 'None'.)\n\n")

        self.logs.check(*self.deprecation_messages)

    def test_show_bears_empty(self):
        with retrieve_stdout() as stdout:
            show_bears({}, {}, True, True, self.console_printer)
            self.assertIn('No bears to show.', stdout.getvalue())

        self.logs.check(*self.deprecation_messages)

    def test_show_bears_with_json(self):
        args = default_arg_parser().parse_args(['--json'])
        with retrieve_stdout() as stdout:
            show_bears({}, {}, True, True, self.console_printer, args)
            self.assertEqual('{\n  "bears": []\n}\n', stdout.getvalue())

        self.logs.check(*self.deprecation_messages)

    @patch('coalib.output.ConsoleInteraction.show_bear')
    def test_show_bears(self, show_bear):
        local_bears = OrderedDict([('default', [SomelocalBear]),
                                   ('test', [SomelocalBear])])
        show_bears(local_bears, {}, True, True, self.console_printer)
        show_bear.assert_called_once_with(SomelocalBear, True, True,
                                          self.console_printer, None)

        self.logs.check(*self.deprecation_messages)

    def test_show_bears_sorted(self):
        local_bears = OrderedDict([('default', [SomelocalBear]),
                                   ('test', [aSomelocalBear])])
        global_bears = OrderedDict([('default', [SomeglobalBear]),
                                    ('test', [BSomeglobalBear])])

        with retrieve_stdout() as stdout:
            show_bears(local_bears, global_bears, False, False,
                       self.console_printer)
            self.assertEqual(
                stdout.getvalue(), 'aSomelocalBear\n'
                'BSomeglobalBear\n'
                'SomeglobalBear\n'
                'SomelocalBear\n')

        self.logs.check(*(self.deprecation_messages * 5))

    def test_show_bears_capabilities(self):
        with retrieve_stdout() as stdout:
            show_language_bears_capabilities(
                {
                    'some_language':
                    ({'Formatting', 'Security'}, {'Formatting'})
                }, self.console_printer)
            self.assertIn(
                'coala can do the following for SOME_LANGUAGE\n'
                '    Can detect only: Formatting, Security\n'
                '    Can fix        : Formatting\n', stdout.getvalue())
            show_language_bears_capabilities({'some_language': (set(), set())},
                                             self.console_printer)
            self.assertIn('coala does not support some_language',
                          stdout.getvalue())
            show_language_bears_capabilities({}, self.console_printer)
            self.assertIn('There is no bear available for this language',
                          stdout.getvalue())
            show_language_bears_capabilities(
                {'some_language': ({'Formatting', 'Security'}, set())},
                self.console_printer)
            self.assertIn(
                'coala can do the following for SOME_LANGUAGE\n'
                '    Can detect only: Formatting, Security\n',
                stdout.getvalue())
Example #58
0
 def setUp(self):
     self.logs = LogCapture()
Example #59
0
 def test_clear_global_state(self):
     from logging import _handlers, _handlerList
     capture = LogCapture()
     capture.uninstall()
     self.assertFalse(capture in _handlers)
     self.assertFalse(capture in _handlerList)
Example #60
0
    def test_token_endpoint(self):
        authreq = AuthorizationRequest(state="state",
                                       redirect_uri="http://example.com/authz",
                                       client_id="client1")

        _sdb = self.provider.sdb
        sid = _sdb.access_token.key(user="******", areq=authreq)
        access_grant = _sdb.access_token(sid=sid)
        _sdb[sid] = {
            "oauth_state": "authz",
            "sub": "sub",
            "authzreq": "",
            "client_id": "client1",
            "code": access_grant,
            "code_used": False,
            "redirect_uri": "http://example.com/authz"
        }

        # Construct Access token request
        areq = AccessTokenRequest(code=access_grant,
                                  redirect_uri="http://example.com/authz",
                                  client_id="client1",
                                  client_secret="hemlighet",
                                  grant_type='authorization_code')
        with LogCapture(level=logging.DEBUG) as logcap:
            resp = self.provider.token_endpoint(request=areq.to_urlencoded())

        atr = AccessTokenResponse().deserialize(resp.message, "json")
        assert _eq(atr.keys(), ['access_token', 'token_type', 'refresh_token'])

        expected = (
            'body: code=<REDACTED>&client_secret=<REDACTED>&grant_type'
            '=authorization_code'
            '   &client_id=client1&redirect_uri=http%3A%2F%2Fexample.com'
            '%2Fauthz')
        assert _eq(parse_qs(logcap.records[1].msg[6:]), parse_qs(expected[6:]))
        expected = {u'code': '<REDACTED>', u'client_secret': '<REDACTED>',
                    u'redirect_uri': u'http://example.com/authz',
                    u'client_id': 'client1',
                    u'grant_type': 'authorization_code'}
        # Don't try this at home, kids!
        # We have to eval() to a dict here because otherwise the arbitrary
        # ordering of the string causes the test to fail intermittently.
        assert _eq(eval(logcap.records[2].msg[4:]), expected)
        assert _eq(logcap.records[3].msg, 'Verified Client ID: client1')
        expected = {'redirect_uri': u'http://example.com/authz',
                    'client_secret': '<REDACTED>',
                    'code': u'<REDACTED>', 'client_id': 'client1',
                    'grant_type': 'authorization_code'}
        assert eval(logcap.records[4].msg[20:]) == expected
        expected = {'code': '<REDACTED>', 'authzreq': '', 'sub': 'sub',
                    'access_token': '<REDACTED>',
                    'token_type': 'Bearer',
                    'redirect_uri': 'http://example.com/authz',
                    'code_used': True, 'client_id': 'client1',
                    'oauth_state': 'token',
                    'refresh_token': '<REDACTED>', 'access_token_scope': '?'}
        assert _eq(eval(logcap.records[5].msg[7:]), expected)
        expected = {'access_token': u'<REDACTED>', 'token_type': 'Bearer',
                    'refresh_token': '<REDACTED>'}
        assert _eq(eval(logcap.records[6].msg[21:]), expected)