def test_queued_recorded_metrics_correctly_during_init(): Glean._reset() # Enable queueing Dispatcher.set_task_queueing(True) counter_metric = CounterMetricType( disabled=False, category="telemetry", lifetime=Lifetime.APPLICATION, name="counter_metric", send_in_pings=["store1"], ) for i in range(2): counter_metric.add() Glean.initialize( application_id=GLEAN_APP_ID, application_version=glean_version, upload_enabled=True, ) assert counter_metric.test_has_value() assert 2 == counter_metric.test_get_value()
def test_no_sending_deletion_ping_if_unchanged_outside_of_run(safe_httpserver, tmpdir): safe_httpserver.serve_content(b"", code=200) Glean._reset() config = Configuration(server_endpoint=safe_httpserver.url) Glean.initialize( application_id=GLEAN_APP_ID, application_version=glean_version, upload_enabled=False, data_dir=Path(str(tmpdir)), configuration=config, ) assert 0 == len(safe_httpserver.requests) Glean._reset() Glean.initialize( application_id=GLEAN_APP_ID, application_version=glean_version, upload_enabled=False, data_dir=Path(str(tmpdir)), configuration=config, ) assert 0 == len(safe_httpserver.requests)
def test_tempdir_is_cleared_multiprocess(safe_httpserver): safe_httpserver.serve_content(b"", code=200) Glean._configuration.server_endpoint = safe_httpserver.url # This test requires us to write a few files in the pending pings # directory, to which language bindings have theoretically no access. # Manually create the path to that directory, at the risk of breaking # the test in the future, if that changes in the Rust code. pings_dir = Glean._data_dir / "pending_pings" pings_dir.mkdir() for _ in range(10): with (pings_dir / str(uuid.uuid4())).open("wb") as fd: fd.write(b"/data/path/\n") fd.write(b"{}\n") # Make sure that resetting while the PingUploadWorker is running doesn't # delete the directory out from under the PingUploadWorker. p1 = PingUploadWorker._process() Glean._reset() p1.wait() assert p1.returncode == 0 assert 10 == len(safe_httpserver.requests)
def reset_glean(*, application_id: str, application_version: str, configuration: Optional[Configuration] = None, clear_stores: bool = True): """ Resets the Glean singleton. Args: application_id (str): The application id to use when sending pings. application_version (str): The version of the application sending Glean data. configuration (glean.config.Configuration): (optional) An object with global settings. """ from glean import Glean from glean._dispatcher import Dispatcher Dispatcher._testing_mode = True data_dir = None # type: Optional[Path] if not clear_stores: Glean._destroy_data_dir = False data_dir = Glean._data_dir Glean._reset() Glean.initialize( application_id=application_id, application_version=application_version, upload_enabled=True, configuration=configuration, data_dir=data_dir, )
def test_set_application_id_and_version(safe_httpserver): safe_httpserver.serve_content(b"", code=200) Glean._reset() Glean._initialize_with_tempdir_for_testing( application_id="my-id", application_version="my-version", upload_enabled=True, configuration=Configuration(server_endpoint=safe_httpserver.url), ) assert ( "my-version" == _builtins.metrics.glean.internal.metrics.app_display_version.test_get_value() ) Glean._configuration.server_endpoint = safe_httpserver.url _builtins.pings.baseline.submit() assert 1 == len(safe_httpserver.requests) request = safe_httpserver.requests[0] assert "baseline" in request.url assert "my-id" in request.url
def test_other_label_without_predefined_labels_before_glean_init(): labeled_counter_metric = metrics.LabeledCounterMetricType( disabled=False, category="telemetry", lifetime=Lifetime.APPLICATION, name="labeled_counter_metric", send_in_pings=["metrics"], ) Glean._reset() Dispatcher.set_task_queueing(True) for i in range(21): labeled_counter_metric["label_{}".format(i)].add(1) labeled_counter_metric["label_0"].add(1) Glean.initialize( application_id="glean-python-test", application_version=glean_version, upload_enabled=True, ) assert 2 == labeled_counter_metric["label_0"].test_get_value() for i in range(1, 16): assert 1 == labeled_counter_metric["label_{}".format( i)].test_get_value() assert 5 == labeled_counter_metric["__other__"].test_get_value()
def test_setting_upload_enabled_before_initialization_should_not_crash(): Glean._reset() Glean.set_upload_enabled(True) Glean.initialize( application_id=GLEAN_APP_ID, application_version=glean_version, upload_enabled=True, )
def test_data_dir_is_required(): Glean._reset() with pytest.raises(TypeError): Glean.initialize( application_id=GLEAN_APP_ID, application_version=glean_version, upload_enabled=True, configuration=Glean._configuration, )
def test_the_app_channel_must_be_correctly_set(): Glean._reset() Glean._initialize_with_tempdir_for_testing( application_id=GLEAN_APP_ID, application_version=glean_version, upload_enabled=True, configuration=Configuration(channel="my-test-channel"), ) assert ("my-test-channel" == _builtins.metrics.glean.internal.metrics. app_channel.test_get_value())
def test_set_application_id_and_version(): Glean._reset() Glean.initialize(application_id="my-id", application_version="my-version", upload_enabled=True) assert ("my-id" == _builtins.metrics.glean.internal.metrics.app_build. test_get_value()) assert ("my-version" == _builtins.metrics.glean.internal.metrics. app_display_version.test_get_value())
def test_app_display_version_unknown(): from glean import _builtins Glean._reset() Glean._initialize_with_tempdir_for_testing( application_id=GLEAN_APP_ID, application_version=None, upload_enabled=True, ) assert ("Unknown" == _builtins.metrics.glean.internal.metrics. app_display_version.test_get_value())
def test_set_application_build_id(): Glean._reset() Glean._initialize_with_tempdir_for_testing( application_id="my-id", application_version="my-version", application_build_id="123ABC", upload_enabled=True, ) assert ("123ABC" == _builtins.metrics.glean.internal.metrics.app_build. test_get_value())
def test_recording_upload_errors_doesnt_clobber_database( tmpdir, safe_httpserver, monkeypatch): """ Test that running the ping uploader subprocess doesn't clobber the database. If, under some bug, the subprocess had "upload_enabled" set to True, it could record upload errors in the database, clobbering any metrics that might have meanwhile been recorded in the main process. This test is known to fail if "upload_enabled" is set to `True` in the subprocess. """ tmpdir = Path(tmpdir) Glean._reset() Glean.initialize( application_id=GLEAN_APP_ID, application_version=glean_version, upload_enabled=True, data_dir=tmpdir, ) counter_metric = CounterMetricType( disabled=False, category="telemetry", lifetime=Lifetime.PING, name="counter_metric", send_in_pings=["baseline"], ) counter_metric.add(10) safe_httpserver.serve_content(b"", code=400) # Force the ping upload worker into a separate process monkeypatch.setattr(PingUploadWorker, "process", PingUploadWorker._process) Glean._configuration._server_endpoint = safe_httpserver.url Glean._submit_ping_by_name("baseline") ProcessDispatcher._wait_for_last_process() assert 1 == len(safe_httpserver.requests) # Force a reload of the database from disk Glean._reset() Glean.initialize( application_id=GLEAN_APP_ID, application_version=glean_version, upload_enabled=True, data_dir=tmpdir, ) metric = get_upload_failure_metric() assert not metric["status_code_4xx"].test_has_value()
def test_presubmit_makes_a_valid_ping(tmpdir, ping_schema_url, monkeypatch): # Bug 1648140: Submitting a ping prior to initialize meant that the core # metrics wouldn't yet be set. info_path = Path(str(tmpdir)) / "info.txt" Glean._reset() ping_name = "preinit_ping" ping = PingType(name=ping_name, include_client_id=True, send_if_empty=True, reason_codes=[]) # This test relies on testing mode to be disabled, since we need to prove the # real-world async behaviour of this. Dispatcher._testing_mode = False Dispatcher._queue_initial_tasks = True # Submit a ping prior to calling initialize ping.submit() Glean._initialize_with_tempdir_for_testing( application_id=GLEAN_APP_ID, application_version=glean_version, upload_enabled=True, configuration=Glean._configuration, ) monkeypatch.setattr(Glean._configuration, "ping_uploader", _RecordingUploader(info_path)) # Wait until the work is complete Dispatcher._task_worker._queue.join() while not info_path.exists(): time.sleep(0.1) with info_path.open("r") as fd: url_path = fd.readline() serialized_ping = fd.readline() print(url_path) assert ping_name == url_path.split("/")[3] assert 0 == validate_ping.validate_ping( io.StringIO(serialized_ping), sys.stdout, schema_url=ping_schema_url, )
def reset_glean( *, application_id: str, application_version: str, configuration: Optional[Configuration] = None, clear_stores: bool = True ) -> None: """ Resets the Glean singleton. Args: application_id (str): The application id to use when sending pings. application_version (str): The version of the application sending Glean data. configuration (glean.config.Configuration): (optional) An object with global settings. """ from glean import Glean from glean._dispatcher import Dispatcher data_dir: Optional[Path] = None if not clear_stores: Glean._destroy_data_dir = False data_dir = Glean._data_dir Glean._reset() # `_testing_mode` should be changed *after* `Glean._reset()` is run, so # that `Glean` properly joins on the worker thread when `_testing_mode` is # False. Dispatcher._testing_mode = True if data_dir is None: Glean._initialize_with_tempdir_for_testing( application_id=application_id, application_version=application_version, upload_enabled=True, configuration=configuration, ) else: Glean.initialize( application_id=application_id, application_version=application_version, upload_enabled=True, data_dir=data_dir, configuration=configuration, )
def test_sending_deletion_ping_if_disabled_outside_of_run( tmpdir, ping_schema_url): info_path = Path(str(tmpdir)) / "info.txt" data_dir = Path(str(tmpdir)) / "glean" Glean._reset() Glean.initialize( application_id=GLEAN_APP_ID, application_version=glean_version, upload_enabled=True, data_dir=data_dir, configuration=Configuration( ping_uploader=_RecordingUploader(info_path)), ) Glean._reset() Glean.initialize( application_id=GLEAN_APP_ID, application_version=glean_version, upload_enabled=False, data_dir=data_dir, configuration=Configuration( ping_uploader=_RecordingUploader(info_path)), ) while not info_path.exists(): time.sleep(0.1) with info_path.open("r") as fd: url_path = fd.readline() serialized_ping = fd.readline() assert "deletion-request" == url_path.split("/")[3] json_content = json.loads(serialized_ping) assert 0 == validate_ping.validate_ping( io.StringIO(serialized_ping), sys.stdout, schema_url=ping_schema_url, ) assert not json_content["client_info"]["client_id"].startswith("c0ffee")
def test_flipping_upload_enabled_respects_order_of_events(tmpdir, monkeypatch): Glean._reset() info_path = Path(str(tmpdir)) / "info.txt" # We create a ping and a metric before we initialize Glean ping = PingType( name="sample_ping_1", include_client_id=True, send_if_empty=True, reason_codes=[], ) # This test relies on testing mode to be disabled, since we need to prove the # real-world async behaviour of this. Dispatcher._testing_mode = False Dispatcher._queue_initial_tasks = True configuration = Glean._configuration configuration.ping_uploader = _RecordingUploader(info_path) Glean._initialize_with_tempdir_for_testing( application_id=GLEAN_APP_ID, application_version=glean_version, upload_enabled=True, configuration=Glean._configuration, ) # Glean might still be initializing. Disable upload. Glean.set_upload_enabled(False) # Submit a custom ping. ping.submit() # Wait until the work is complete Dispatcher._task_worker._queue.join() while not info_path.exists(): time.sleep(0.1) with info_path.open("r") as fd: url_path = fd.readline() # Validate we got the deletion-request ping assert "deletion-request" == url_path.split("/")[3]
def test_experiments_recording_before_glean_inits(): # This test relies on Glean not being initialized and task # queuing to be on. Glean._reset() Glean.set_experiment_active("experiment_set_preinit", "branch_a") Glean.set_experiment_active("experiment_preinit_disabled", "branch_a") Glean.set_experiment_inactive("experiment_preinit_disabled") # This will init Glean and flush the dispatcher's queue. Glean.initialize( application_id=GLEAN_APP_ID, application_version=glean_version, upload_enabled=True, ) assert Glean.test_is_experiment_active("experiment_set_preinit") assert not Glean.test_is_experiment_active("experiment_preinit_disabled")
def test_client_activity_api(tmpdir, monkeypatch): Glean._reset() info_path = Path(str(tmpdir)) / "info.txt" # This test relies on testing mode to be disabled, since we need to prove the # real-world async behaviour of this. configuration = Glean._configuration configuration.ping_uploader = _RecordingUploader(info_path) Glean._initialize_with_tempdir_for_testing( application_id=GLEAN_APP_ID, application_version=glean_version, upload_enabled=True, configuration=Glean._configuration, ) # Wait until the work is complete Dispatcher._task_worker._queue.join() # Making it active Glean.handle_client_active() url_path, payload = wait_for_ping(info_path) assert "baseline" == url_path.split("/")[3] assert payload["ping_info"]["reason"] == "active" assert "timespan" not in payload["metrics"] # Making it inactive Glean.handle_client_inactive() url_path, payload = wait_for_ping(info_path) assert "baseline" == url_path.split("/")[3] assert payload["ping_info"]["reason"] == "inactive" assert "glean.baseline.duration" in payload["metrics"]["timespan"] # Once more active Glean.handle_client_active() url_path, payload = wait_for_ping(info_path) assert "baseline" == url_path.split("/")[3] assert payload["ping_info"]["reason"] == "active" assert "timespan" not in payload["metrics"]
def test_clear_application_lifetime_metrics(tmpdir): Glean._reset() Glean.initialize( application_id=GLEAN_APP_ID, application_version=glean_version, upload_enabled=True, data_dir=Path(str(tmpdir)), ) counter_metric = CounterMetricType( disabled=False, category="test.telemetry", lifetime=Lifetime.APPLICATION, name="lifetime_reset", send_in_pings=["store1"], ) # Additionally get metrics using the loader. metrics = load_metrics(ROOT / "data" / "core.yaml", config={"allow_reserved": True}) counter_metric.add(10) metrics.core_ping.seq.add(10) assert counter_metric.test_has_value() assert counter_metric.test_get_value() == 10 assert metrics.core_ping.seq.test_has_value() assert metrics.core_ping.seq.test_get_value() == 10 Glean._reset() Glean.initialize( application_id=GLEAN_APP_ID, application_version=glean_version, upload_enabled=True, data_dir=Path(str(tmpdir)), ) assert not counter_metric.test_has_value() assert not metrics.core_ping.seq.test_has_value()
def test_tempdir_is_cleared_multiprocess(safe_httpserver): safe_httpserver.serve_content(b"", code=200) Glean._configuration.server_endpoint = safe_httpserver.url pings_dir = PingUploadWorker.storage_directory() pings_dir.mkdir() for i in range(100): with (pings_dir / str(uuid.uuid4())).open("wb") as fd: fd.write(b"/data/path/\n") fd.write(b"{}\n") # Make sure that resetting while the PingUploadWorker is running doesn't # delete the directory out from under the PingUploadWorker. p1 = PingUploadWorker._process() Glean._reset() p1.wait() assert p1.returncode == 0 assert 100 == len(safe_httpserver.requests)
def test_initialize_must_not_crash_if_data_dir_is_messed_up(tmpdir): filename = tmpdir / "dummy_file" # Create a file in a temporary directory with filename.open("w") as fd: fd.write("Contents\n") Glean._reset() assert False is Glean.is_initialized() # Pass in the filename as the data_dir Glean.initialize( application_id=GLEAN_APP_ID, application_version=glean_version, upload_enabled=True, data_dir=filename, ) # This should cause initialization to fail assert False is Glean.is_initialized() shutil.rmtree(str(tmpdir))
def test_that_thread_joins_before_directory_is_deleted_in_reset(): Dispatcher._testing_mode = False Dispatcher._queue_initial_tasks = False thread_canary = [0] boolean_metric = metrics.BooleanMetricType( disabled=False, category="telemetry", lifetime=Lifetime.APPLICATION, name="boolean_metric", send_in_pings=["store1"], ) def slow_task(): time.sleep(1) # This will cause a Rust panic if the data directory was deleted in # Glean._reset() before this has a chance to run. boolean_metric.set(True) thread_canary[0] = 1 Dispatcher.launch(slow_task) Glean._reset() assert thread_canary[0] == 1
def test_tempdir_is_cleared(): tempdir = Glean._data_dir Glean._reset() assert not tempdir.exists()