def before(self):
     self.profiler = Profiler(
         profiling_group_name=DUMMY_TEST_PROFILING_GROUP_NAME,
         environment_override={
             'initial_sampling_interval': timedelta(),
             'agent_metadata': AgentMetadata(fleet_info=DefaultFleetInfo())
         })
     self.client_stubber = Stubber(
         self.profiler._profiler_runner.collector.reporter.
         codeguru_client_builder.codeguru_client)
     report_expected_params = {
         'agentProfile': ANY,
         'contentType': 'application/json',
         'profilingGroupName': DUMMY_TEST_PROFILING_GROUP_NAME
     }
     self.client_stubber.add_response(
         'configure_agent',
         {'configuration': {
             'shouldProfile': True,
             'periodInSeconds': 100
         }})
     self.client_stubber.add_response('post_agent_profile', {},
                                      report_expected_params)
     yield
     self.profiler.stop()
コード例 #2
0
 def test_exceptions_are_caught_and_do_not_propagate(self):
     Profiler(
         profiling_group_name="test-application",
         environment_override={
             "profiler_runner_factory": throw_exception
         },
     )
     Profiler(profiling_group_name=None)
    def test_report_via_invalid_reporting_mode(self):
        self.profiler = Profiler(
            profiling_group_name=DUMMY_TEST_PROFILING_GROUP_NAME,
            environment_override={
                "reporting_mode": "invalid_reporting_mode",
            })

        self.profiler.start()
        assert self.profiler.is_running() is False
コード例 #4
0
        class TestWhenAnotherInstanceAlreadyStarted:
            @pytest.fixture(autouse=True)
            def around(self):
                self.profiler_runner = Mock(spec_set=ProfilerRunner)
                self.profiler_runner.start = Mock(return_value=True)
                self.profiler_runner.is_running = Mock(return_value=False)
                self.first_profiler = Profiler(
                    profiling_group_name="pg_name",
                    environment_override={
                        "profiler_runner_factory":
                        mock_profiler_runner_factory(self.profiler_runner)
                    })
                self.first_profiler.start()
                self.second_profiler = Profiler(
                    profiling_group_name="test-application",
                    environment_override={
                        "profiler_runner_factory":
                        mock_profiler_runner_factory(self.profiler_runner)
                    })
                yield
                self.first_profiler.stop()
                self.second_profiler.stop()

            def test_stopping_first_instance_allows_next_profiler_to_start(
                    self):
                self.first_profiler.stop()
                assert self.second_profiler.start()
コード例 #5
0
 def around(self):
     self.profiler_runner = Mock(spec_set=ProfilerRunner)
     self.profiler_runner.pause = Mock()
     self.profiler = Profiler(profiling_group_name="test-application",
                              environment_override={
                                  "profiler_runner_factory":
                                  mock_profiler_runner_factory(
                                      self.profiler_runner)
                              })
     yield
     self.profiler.stop()
コード例 #6
0
 def around(self):
     self.profiler_runner = Mock(spec_set=ProfilerRunner)
     self.profiler_runner.is_running = Mock(return_value=False)
     self.profiler_runner.start = throw_exception
     self.profiler = Profiler(
         profiling_group_name="test-application",
         environment_override={
             "profiler_runner_factory":
             mock_profiler_runner_factory(self.profiler_runner)
         })
     yield
     self.profiler.stop()
        def test_profiler_does_not_start(self):
            with tempfile.NamedTemporaryFile() as killswitch_file:
                profiler = Profiler(
                    profiling_group_name=DUMMY_TEST_PROFILING_GROUP_NAME,
                    environment_override={
                        "killswitch_filepath": killswitch_file.name
                    })

                try:
                    assert profiler.start() is False
                finally:
                    profiler.stop()
コード例 #8
0
 def before(self):
     self.timer = Timer()
     self.profiler = Profiler(
         profiling_group_name=DUMMY_TEST_PROFILING_GROUP_NAME,
         environment_override={
             "timer": self.timer,
             "cpu_limit_percentage": 40,
             "sampling_interval": timedelta(seconds=0.01),
             'agent_metadata':
             AgentMetadata(fleet_info=DefaultFleetInfo())
         },
     )
     yield
     self.profiler.stop()
コード例 #9
0
class TestEndToEndProfiling:
    @before
    def before(self):
        self.profiler = Profiler(
            profiling_group_name=DUMMY_TEST_PROFILING_GROUP_NAME,
            environment_override={
                'initial_sampling_interval': timedelta(),
                'agent_metadata': AgentMetadata(fleet_info=DefaultFleetInfo())
            })
        self.client_stubber = Stubber(
            self.profiler._profiler_runner.collector.reporter.
            codeguru_client_builder.codeguru_client)
        report_expected_params = {
            'agentProfile': ANY,
            'contentType': 'application/json',
            'profilingGroupName': DUMMY_TEST_PROFILING_GROUP_NAME
        }
        self.client_stubber.add_response(
            'configure_agent',
            {'configuration': {
                'shouldProfile': True,
                'periodInSeconds': 100
            }})
        self.client_stubber.add_response('post_agent_profile', {},
                                         report_expected_params)
        yield
        self.profiler.stop()

    def test_report_when_stopped(self):
        with \
                patch(
                    "codeguru_profiler_agent.reporter.agent_configuration.AgentConfiguration.is_under_min_reporting_time",
                    return_value=False), \
                patch(
                    "codeguru_profiler_agent.sdk_reporter.sdk_reporter.SdkReporter.check_create_pg_called_during_submit_profile",
                    return_value=False):
            with self.client_stubber:
                self.profiler.start()
                self.profiler.stop()  # stop will trigger the report

            # check that we have reported. assert_no_pending_responses will fail if post_agent_profile is not called
            # with the expected parameters.
            self.client_stubber.assert_no_pending_responses()

    def test_report_via_invalid_reporting_mode(self):
        self.profiler = Profiler(
            profiling_group_name=DUMMY_TEST_PROFILING_GROUP_NAME,
            environment_override={
                "reporting_mode": "invalid_reporting_mode",
            })

        self.profiler.start()
        assert self.profiler.is_running() is False
コード例 #10
0
        class TestExceptionHandling:
            @pytest.fixture(autouse=True)
            def around(self):
                self.profiler_runner = Mock(spec_set=ProfilerRunner)
                self.profiler_runner.is_running = Mock(return_value=False)
                self.profiler_runner.start = throw_exception
                self.profiler = Profiler(
                    profiling_group_name="test-application",
                    environment_override={
                        "profiler_runner_factory":
                        mock_profiler_runner_factory(self.profiler_runner)
                    })
                yield
                self.profiler.stop()

            def test_exceptions_are_caught_and_do_not_propagate(self):
                assert (not self.profiler.start())
コード例 #11
0
        class TestWhenStartWasNotCalled:
            @pytest.fixture(autouse=True)
            def around(self):
                self.profiler = Profiler(
                    profiling_group_name="test-application")
                yield

            def test_it_returns_true(self):
                assert self.profiler.stop()
コード例 #12
0
 def test_it_raises_a_value_error(self):
     with pytest.raises(ValueError):
         Profiler(
             profiling_group_name="unit-test",
             environment_override={
                 "allow_top_level_exceptions": True,
                 "reporting_mode": "wrong-reporting-mode"
             },
         )
        def before(self):
            temporary_directory = tempfile.mkdtemp()
            self.temp_filepath = str(
                Path(temporary_directory,
                     'test_profiler_stops_after_killswitch_was_detected'))

            self.profiler = Profiler(
                profiling_group_name="test-application",
                environment_override={
                    "cpu_limit_percentage": None,
                    "killswitch_filepath": self.temp_filepath,
                    "sampling_interval": timedelta(seconds=0.1),
                    'agent_metadata':
                    AgentMetadata(fleet_info=DefaultFleetInfo())
                })
            yield
            shutil.rmtree(temporary_directory)
            self.profiler.stop()
コード例 #14
0
 def around(self):
     self.profiler_runner = Mock(spec_set=ProfilerRunner)
     self.profiler_runner.start = Mock(return_value=True)
     self.profiler_runner.is_running = Mock(return_value=False)
     self.first_profiler = Profiler(
         profiling_group_name="pg_name",
         environment_override={
             "profiler_runner_factory":
             mock_profiler_runner_factory(self.profiler_runner)
         })
     self.first_profiler.start()
     self.second_profiler = Profiler(
         profiling_group_name="test-application",
         environment_override={
             "profiler_runner_factory":
             mock_profiler_runner_factory(self.profiler_runner)
         })
     yield
     self.first_profiler.stop()
     self.second_profiler.stop()
コード例 #15
0
        class TestWhenRunnerIsRunning:
            @pytest.fixture(autouse=True)
            def around(self):
                self.profiler_runner = Mock(spec_set=ProfilerRunner)
                self.profiler_runner.is_running = Mock(return_value=True)
                self.profiler_runner.resume = Mock()
                self.profiler = Profiler(
                    profiling_group_name="test-application",
                    environment_override={
                        "profiler_runner_factory":
                        mock_profiler_runner_factory(self.profiler_runner)
                    })
                yield
                self.profiler.stop()

            def test_it_returns_true(self):
                assert self.profiler.start()

            def test_it_calls_resume(self):
                self.profiler.start()
                assert self.profiler_runner.resume.called
コード例 #16
0
    class TestCPULimitReachedDuringProfiling:
        @before
        def before(self):
            self.timer = Timer()
            self.profiler = Profiler(
                profiling_group_name=DUMMY_TEST_PROFILING_GROUP_NAME,
                environment_override={
                    "timer": self.timer,
                    "cpu_limit_percentage": 40,
                    "sampling_interval": timedelta(seconds=0.01),
                    'agent_metadata':
                    AgentMetadata(fleet_info=DefaultFleetInfo())
                },
            )
            yield
            self.profiler.stop()

        def test_profiler_terminates(self):
            self.profiler.start()
            assert self.profiler.is_running()

            # With sampling_interval to be 0.01 seconds, having runProfiler as 0.5 seconds should breach
            # the cpu limit. We need to sample 20 times before we check the CPU limit
            for i in range(20):
                self.timer.record('sampleAndAggregate', 0.5)

            assert wait_for(lambda: not self.profiler.is_running(),
                            timeout_seconds=5)
    class TestKillSwitchActivatesDuringExecution:
        @before
        def before(self):
            temporary_directory = tempfile.mkdtemp()
            self.temp_filepath = str(
                Path(temporary_directory,
                     'test_profiler_stops_after_killswitch_was_detected'))

            self.profiler = Profiler(
                profiling_group_name="test-application",
                environment_override={
                    "cpu_limit_percentage": None,
                    "killswitch_filepath": self.temp_filepath,
                    "sampling_interval": timedelta(seconds=0.1),
                    'agent_metadata':
                    AgentMetadata(fleet_info=DefaultFleetInfo())
                })
            yield
            shutil.rmtree(temporary_directory)
            self.profiler.stop()

        def test_profiler_stops_after_killswitch_was_detected(self):
            self.profiler.start()
            assert self.profiler.is_running() is True

            Path(self.temp_filepath).touch()

            # Force the killswitch check happens immediately
            self.profiler._profiler_runner_instance.profiler_disabler.killswitch.last_check_for_file_time = None

            assert (wait_for(lambda: not self.profiler.is_running(),
                             timeout_seconds=5))
    def before(self):
        self.mock_reporter = MagicMock(name="reporter", spec=SdkReporter)
        self.mock_profile = MagicMock(name="profile", spec=Profile)
        self.mock_profile_factory = MagicMock(name="profile_factory",
                                              spec=Profile,
                                              return_value=self.mock_profile)
        self.timer = mock_timer()
        self.time_now = CURRENT_TIME_FOR_TESTING_SECOND
        self.clock = lambda: self.time_now
        self.reporting_interval = DEFAULT_REPORTING_INTERVAL

        self.environment = {
            "profiling_group_name": TEST_PROFILING_GROUP_NAME,
            "sampling_interval": timedelta(seconds=TEST_SAMPLING_INTERVAL),
            "host_weight": TEST_HOST_WEIGHT,
            "profile_factory": self.mock_profile_factory,
            "errors_metadata": ERRORS_METADATA,
            "memory_limit_bytes": DEFAULT_MEMORY_LIMIT_BYTES,
            "clock": self.clock,
            "timer": self.timer,
        }

        self.configuration = {
            "reporter": self.mock_reporter,
            "environment": self.environment,
        }

        AgentConfiguration.set(
            AgentConfiguration(
                should_profile=True,
                sampling_interval=timedelta(seconds=TEST_SAMPLING_INTERVAL),
                minimum_time_reporting=INITIAL_MINIMUM_REPORTING_INTERVAL,
                reporting_interval=self.reporting_interval,
                max_stack_depth=999,
                cpu_limit_percentage=10))

        assert len(self.environment.keys()) == 8
        self.profiler = Profiler(
            profiling_group_name=TEST_PROFILING_GROUP_NAME,
            environment_override=self.environment)
        assert len(self.environment.keys()) == 7

        self.subject = LocalAggregator(**self.configuration)
        self.mock_profile_factory.reset_mock()
        self.timer.reset_mock()

        def move_clock_to(duration_timedelta):
            self.time_now = \
                CURRENT_TIME_FOR_TESTING_SECOND + duration_timedelta.total_seconds()

        self.move_clock_to = move_clock_to
コード例 #19
0
 def around(self):
     self.profiler_runner = Mock(spec_set=ProfilerRunner)
     self.session = Mock()
     self.session.__repr__ = \
         Mock(return_value="Session(region_name='eu-west-2', profile_name='alternate_credentials')")
     self.profiler = Profiler(profiling_group_name="test-application",
                              region_name="ap-southeast-1",
                              aws_session=self.session,
                              environment_override={
                                  "sampling_interval":
                                  timedelta(seconds=0.01),
                                  "profiler_runner_factory":
                                  mock_profiler_runner_factory(
                                      self.profiler_runner)
                              })
     yield
コード例 #20
0
 def test_checks_number_of_params(self):
     environment = {
         'reporting_mode': 'codeguru_service',
         'excluded_threads': set(),
         'should_profile': True,
         'sampling_interval': timedelta(seconds=1),
         'reporting_interval': timedelta(minutes=10),
         'minimum_time_reporting': timedelta(minutes=1),
         'max_stack_depth': 1000,
         'cpu_limit_percentage': 10,
         'memory_limit_bytes': 1024,
         'host_weight': 1.0,
         'max_threads': 100
     }
     assert len(environment.keys()) == 11
     Profiler(profiling_group_name="test-application",
              environment_override=environment)
     assert len(environment.keys()) == 5
    def test_it_samples_and_saves_a_profile_to_a_file(self):
        with \
                patch(
                    "codeguru_profiler_agent.reporter.agent_configuration.AgentConfiguration.is_under_min_reporting_time",
                    return_value=False):

            file_prefix = str(Path(self.temporary_directory, FILE_PREFIX))

            test_start_time = time_utils.current_milli_time()

            profiler = Profiler(
                profiling_group_name=DUMMY_TEST_PROFILING_GROUP_NAME,
                environment_override={
                    "initial_sampling_interval": timedelta(),
                    "reporting_mode": "file",
                    "file_prefix": file_prefix,
                    'agent_metadata':
                    AgentMetadata(fleet_info=DefaultFleetInfo())
                })

            try:
                profiler.start()
            finally:
                profiler.stop()

            test_end_time = time_utils.current_milli_time()

            resulting_profile_path = str(
                Path(self.temporary_directory,
                     os.listdir(self.temporary_directory)[0]))

            with (open(resulting_profile_path)) as profiling_result_file:
                resulting_json = json.loads(profiling_result_file.read())

            self.assert_valid_agent_metadata(resulting_json["agentMetadata"])
            assert test_start_time <= resulting_json[
                "start"] <= resulting_json["end"] <= test_end_time
            assert frames_in_callgraph_are_in_expected_order(
                resulting_json["callgraph"],
                "test.help_utils:HelperThreadRunner:dummy_parent_method",
                "test.help_utils:HelperThreadRunner:dummy_method")
コード例 #22
0
    class TestPause:
        @pytest.fixture(autouse=True)
        def around(self):
            self.profiler_runner = Mock(spec_set=ProfilerRunner)
            self.profiler_runner.pause = Mock()
            self.profiler = Profiler(profiling_group_name="test-application",
                                     environment_override={
                                         "profiler_runner_factory":
                                         mock_profiler_runner_factory(
                                             self.profiler_runner)
                                     })
            yield
            self.profiler.stop()

        def test_it_returns_true(self):
            assert self.profiler.pause()

        def test_it_calls_pause_on_runner(self):
            self.profiler.pause()
            assert self.profiler_runner.pause.called

        def test_exceptions_are_caught_and_do_not_propagate(self):
            self.profiler_runner.pause = throw_exception
            assert (not self.profiler.pause())
    def test_live_profiling(self):
        with \
                patch(
                    "codeguru_profiler_agent.reporter.agent_configuration.AgentConfiguration.is_under_min_reporting_time",
                    return_value=False), \
                patch(
                    "codeguru_profiler_agent.sdk_reporter.sdk_reporter.SdkReporter.check_create_pg_called_during_submit_profile",
                    return_value=False), \
                patch(
                    "codeguru_profiler_agent.reporter.agent_configuration.AgentConfiguration._is_reporting_interval_smaller_than_minimum_allowed",
                    return_value=False):

            profiler = Profiler(
                profiling_group_name=DUMMY_TEST_PROFILING_GROUP_NAME,
                region_name='eu-west-2',
                environment_override={
                    "initial_sampling_interval": timedelta(),
                    "sampling_interval": timedelta(seconds=1),
                    "reporting_interval": timedelta(seconds=2),
                    'agent_metadata':
                    AgentMetadata(fleet_info=DefaultFleetInfo())
                })

            client = profiler._profiler_runner.collector.reporter.codeguru_client_builder.codeguru_client
            aggregator = profiler._profiler_runner.collector

            assert AgentConfiguration.get().sampling_interval == timedelta(
                seconds=1)
            assert AgentConfiguration.get().reporting_interval == timedelta(
                seconds=2)

            with \
                    patch.object(client, "post_agent_profile",
                                 wraps=client.post_agent_profile) as wrapped_post_agent_profile, \
                    patch.object(client, "configure_agent",
                                 wraps=client.configure_agent) as wrapped_configure_agent, \
                    patch.object(aggregator, "add",
                                 wraps=aggregator.add) as wrapped_add, \
                    patch(
                        "codeguru_profiler_agent.reporter.agent_configuration.AgentConfiguration.is_under_min_reporting_time",
                        return_value=False), \
                    patch(
                        "codeguru_profiler_agent.reporter.agent_configuration.AgentConfiguration._is_reporting_interval_smaller_than_minimum_allowed",
                        return_value=False):

                wrapped_configure_agent.return_value = {
                    "configuration": {
                        "agentParameters": {
                            "SamplingIntervalInMilliseconds": "100",
                            "MinimumTimeForReportingInMilliseconds": "1000",
                            "MaxStackDepth": "1000",
                            "MemoryUsageLimitPercent": "29"
                        },
                        "periodInSeconds": 2,
                        "shouldProfile": True
                    }
                }

                try:
                    start_status = profiler.start()
                    assert start_status
                    assert profiler.is_running()
                    time.sleep(4)
                finally:
                    profiler.stop()

                # We should see at least 2 samples in 4 seconds as the sequence should happen in the order of
                # initial delay (1 second)
                # After 1 second, no flush -> sample
                # After 2 seconds, it attempt to flush (possibly succeed) -> sample/ no sample
                # After 3 seconds, it attempt to flush (must succeed if it did not flush before) -> no sample/ sample
                # After 4 seconds, no flush -> sample (if profiler has not stopped yet)
                assert wrapped_add.call_count >= 2
                assert wrapped_post_agent_profile.call_count >= 1
                assert wrapped_configure_agent.call_count >= 1
                assert AgentConfiguration.get().sampling_interval == timedelta(
                    seconds=1)
                assert AgentConfiguration.get(
                ).reporting_interval == timedelta(seconds=2)
    def test_live_profiling(self):
        with \
                patch(
                    "codeguru_profiler_agent.reporter.agent_configuration.AgentConfiguration.is_under_min_reporting_time",
                    return_value=False), \
                patch(
                    "codeguru_profiler_agent.reporter.agent_configuration.AgentConfiguration._is_reporting_interval_smaller_than_minimum_allowed",
                    return_value=False):

            profiler = Profiler(
                profiling_group_name=DUMMY_TEST_PROFILING_GROUP_NAME,
                region_name='eu-west-2',
                environment_override={
                    "initial_sampling_interval": timedelta(),
                    "sampling_interval": timedelta(seconds=1),
                    "reporting_interval": timedelta(seconds=2),
                    'agent_metadata':
                    AgentMetadata(fleet_info=DefaultFleetInfo())
                })

            client = profiler._profiler_runner.collector.reporter.codeguru_client_builder.codeguru_client
            aggregator = profiler._profiler_runner.collector

            assert AgentConfiguration.get().sampling_interval == timedelta(
                seconds=1)
            assert AgentConfiguration.get().reporting_interval == timedelta(
                seconds=2)

            with \
                    patch.object(client, "post_agent_profile",
                                 wraps=client.post_agent_profile) as wrapped_post_agent_profile, \
                    patch.object(client, "configure_agent",
                                 wraps=client.configure_agent) as wrapped_configure_agent, \
                    patch.object(aggregator, "add",
                                 wraps=aggregator.add) as wrapped_add, \
                    patch(
                        "codeguru_profiler_agent.reporter.agent_configuration.AgentConfiguration.is_under_min_reporting_time",
                        return_value=False), \
                    patch(
                        "codeguru_profiler_agent.reporter.agent_configuration.AgentConfiguration._is_reporting_interval_smaller_than_minimum_allowed",
                        return_value=False):

                wrapped_configure_agent.return_value = {
                    "configuration": {
                        "agentParameters": {
                            "SamplingIntervalInMilliseconds": "100",
                            "MinimumTimeForReportingInMilliseconds": "1000",
                            "MaxStackDepth": "1000",
                            "MemoryUsageLimitPercent": "29"
                        },
                        "periodInSeconds": 2,
                        "shouldProfile": True
                    }
                }

                try:
                    start_status = profiler.start()
                    assert start_status
                    assert profiler.is_running()
                    time.sleep(3)
                finally:
                    profiler.stop()

                assert wrapped_add.call_count >= 3
                assert wrapped_post_agent_profile.call_count >= 1
                assert wrapped_configure_agent.call_count >= 1
                assert AgentConfiguration.get().sampling_interval == timedelta(
                    seconds=1)
                assert AgentConfiguration.get(
                ).reporting_interval == timedelta(seconds=2)
コード例 #25
0
 def around(self):
     self.profiler = Profiler(
         profiling_group_name="test-application")
     yield
コード例 #26
0
 def test_it_does_propagate_a_value_error(self):
     environment = {"reporting_interval": timedelta(seconds=29)}
     Profiler(profiling_group_name="test-application",
              environment_override=environment)