~pjdc/mojo/sparkle-motion

« back to all changes in this revision

Viewing changes to mojo/tests/test_phase.py

  • Committer: mergebot at canonical
  • Author(s): "Daniel Manrique"
  • Date: 2019-04-19 01:25:24 UTC
  • mfrom: (494.2.5 parallel-nagios-check)
  • Revision ID: mergebot@juju-139df4-prod-is-toolbox-0.canonical.com-20190419012524-44wrayrluc0785rd
Verify nagios checks in parallel.

This uses Python's futures module for minimal-change parallel execution of nagios checks; one parallel "juju ssh" is dispatched for each  machine to check, and results are presented as they arrive. The logic and presentation stay the same otherwise.

I didn't declare futures as an explicit deb dependency (only in requirements.txt) because in the deb world, mojo depends on codetree which depends on futures, so they should always be there.

I added a couple of tests to verify the expected number of juju sshs is dispatched, and that the number of workers is properly calculated.

A possible refinement would be ability to specify a maximum number of workers; this could help if e.g. simultaneous juju ssh to a large number of units on a complex deployment causes any kind of trouble.

A couple of tweaks to the "juju ssh" command line were needed to avoid the display/pty getting borked when running several tasks in parallel, but I checked and they don't affect the visual output of things.

Reviewed-on: https://code.launchpad.net/~roadmr/mojo/parallel-nagios-check/+merge/366076
Reviewed-by: Stuart Bishop <stuart.bishop@canonical.com>

Show diffs side-by-side

added added

removed removed

Lines of Context:
573
573
        with self.assertRaises(NagiosCheckPhaseException):
574
574
            phase.run_nagios_checks('postgresql/0')
575
575
 
 
576
    @mock.patch('mojo.phase.NagiosCheckPhase.run_nagios_checks')
 
577
    @mock.patch('mojo.juju.Status')
 
578
    def test_all_checks_dispatched(self,  _juju_status, _run_nagios_checks):
 
579
        """Test that all expected checks are dispatched."""
 
580
        # Side effect that returns specific lists of machines for each service
 
581
        def smn_side_effect(service):
 
582
            machine_numbers = {'foo': [1, 2],
 
583
                               'bar':[4],
 
584
                               'baz':[5]}
 
585
            return machine_numbers[service]
 
586
 
 
587
        # Side effect that returns specific units for each service
 
588
        def su_side_effect(service):
 
589
            service_units = {'foo': ['foo/0', 'foo/1'],
 
590
                             'bar':['bar/2'],
 
591
                             'baz':['baz/1']}
 
592
            return service_units[service]
 
593
 
 
594
        # Set up all the mockery
 
595
        _juju_status().services_list.return_value = ['foo', 'bar', 'baz'] 
 
596
        _juju_status().service_machine_numbers.side_effect = smn_side_effect
 
597
        _juju_status().service_units.side_effect = su_side_effect
 
598
        _run_nagios_checks.return_value = "", "Everything OK"
 
599
        # Define a minimal, empty project and phase with 2 services to check
 
600
        self.empty_project = Project('unused', 'trusty', '/tmp')
 
601
        phase = NagiosCheckPhase()
 
602
        phase.options.update({'services': 'foo,bar'})
 
603
        workspace = self.create_workspace()
 
604
        self.create_spec(
 
605
                path=workspace.spec_dir,
 
606
                configs=['collect', 'services.cfg'], stage='staging')
 
607
        # Run the phase
 
608
        phase.run(self.empty_project, workspace, 'staging')
 
609
        # Check expected tests were all dispatched, as seen by calls to
 
610
        # run_nagios_checks
 
611
        all_skip = ['check_etc_bzr', 'check_log_archive_status']
 
612
        _run_nagios_checks.assert_has_calls([
 
613
            mock.call('foo/0', all_skip),
 
614
            mock.call('foo/1', all_skip),
 
615
            mock.call('bar/2', all_skip),
 
616
        ])
 
617
 
 
618
    @mock.patch('mojo.phase.ThreadPoolExecutor')
 
619
    @mock.patch('mojo.juju.Status')
 
620
    def test_max_worker_calculation(self,  _juju_status, _executor):
 
621
        """Test that max_workers is properly calculated."""
 
622
        # Side effect that returns specific lists of machines for each service
 
623
        def smn_side_effect(service):
 
624
            machine_numbers = {'foo': [1, 2],
 
625
                               'bar':[4],
 
626
                               'baz':[5]}
 
627
            return machine_numbers[service]
 
628
 
 
629
        # Set up all the mockery
 
630
        _juju_status().services_list.return_value = ['foo', 'bar', 'baz'] 
 
631
        _juju_status().service_machine_numbers.side_effect = smn_side_effect
 
632
        # Define a minimal, empty project and phase with 2 services to check
 
633
        self.empty_project = Project('unused', 'trusty', '/tmp')
 
634
        phase = NagiosCheckPhase()
 
635
        phase.options.update({'services': 'foo,bar'})
 
636
        workspace = self.create_workspace()
 
637
        self.create_spec(
 
638
                path=workspace.spec_dir,
 
639
                configs=['collect', 'services.cfg'], stage='staging')
 
640
        # Run the phase
 
641
        phase.run(self.empty_project, workspace, 'staging')
 
642
        # Check call to ThreadPoolExecutor for max_workers value
 
643
        # the value is "3", for the sum of machines in the "foo" and "bar"
 
644
        # services.
 
645
        _executor.assert_called_once_with(max_workers=3)
 
646
 
576
647
 
577
648
class CharmAuditPhaseTestCase(TestCase, utils.MojoTestCaseMixin):
578
649