Bug 1899117 - Add file and input type telemetry for EXIF metadata stripper project. r=bvandersloot,anti-tracking-reviewers
Differential Revision: https://phabricator.services.mozilla.com/D226524
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
#include "mozilla/dom/ClipboardEvent.h"
|
||||
#include "mozilla/ContentEvents.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/ImageInputTelemetry.h"
|
||||
#include "mozilla/dom/DataTransfer.h"
|
||||
#include "nsIClipboard.h"
|
||||
|
||||
@@ -74,6 +75,17 @@ DataTransfer* ClipboardEvent::GetClipboardData() {
|
||||
}
|
||||
}
|
||||
|
||||
// Only collect image input telemetry on external paste events, unless in
|
||||
// automation. In tests we skip this check using the pref, since we cannot
|
||||
// synthesize external events.
|
||||
if ((!mEventIsInternal ||
|
||||
StaticPrefs::privacy_imageInputTelemetry_enableTestMode()) &&
|
||||
!mImageInputTelemetryCollected) {
|
||||
ImageInputTelemetry::MaybeRecordPasteImageInputTelemetry(
|
||||
event, GetParentObject()->PrincipalOrNull());
|
||||
mImageInputTelemetryCollected = true;
|
||||
}
|
||||
|
||||
return event->mClipboardData;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,9 @@ class ClipboardEvent : public Event {
|
||||
void InitClipboardEvent(const nsAString& aType, bool aCanBubble,
|
||||
bool aCancelable, DataTransfer* aClipboardData);
|
||||
|
||||
private:
|
||||
bool mImageInputTelemetryCollected = false;
|
||||
|
||||
protected:
|
||||
~ClipboardEvent() = default;
|
||||
};
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "mozilla/dom/DragEvent.h"
|
||||
#include "mozilla/dom/MouseEventBinding.h"
|
||||
#include "mozilla/ImageInputTelemetry.h"
|
||||
#include "mozilla/MouseEvents.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "prtime.h"
|
||||
@@ -64,6 +65,17 @@ DataTransfer* DragEvent::GetDataTransfer() {
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
}
|
||||
|
||||
// Only collect image input telemetry on external drop events, unless in
|
||||
// automation. In tests we skip this check using the pref, since we cannot
|
||||
// synthesize external events.
|
||||
if ((!mEventIsInternal ||
|
||||
StaticPrefs::privacy_imageInputTelemetry_enableTestMode()) &&
|
||||
!mImageInputTelemetryCollected) {
|
||||
ImageInputTelemetry::MaybeRecordDropImageInputTelemetry(
|
||||
dragEvent, GetParentObject()->PrincipalOrNull());
|
||||
mImageInputTelemetryCollected = true;
|
||||
}
|
||||
|
||||
return dragEvent->mDataTransfer;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,9 @@ class DragEvent : public MouseEvent {
|
||||
const nsAString& aType,
|
||||
const DragEventInit& aParam);
|
||||
|
||||
private:
|
||||
bool mImageInputTelemetryCollected = false;
|
||||
|
||||
protected:
|
||||
~DragEvent() = default;
|
||||
};
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "mozilla/dom/WheelEventBinding.h"
|
||||
#include "mozilla/dom/WindowGlobalChild.h"
|
||||
#include "mozilla/EventStateManager.h"
|
||||
#include "mozilla/ImageInputTelemetry.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/MouseEvents.h"
|
||||
#include "mozilla/PresShell.h"
|
||||
@@ -488,6 +489,8 @@ HTMLInputElement::nsFilePickerShownCallback::Done(
|
||||
|
||||
OwningFileOrDirectory* element = newFilesOrDirectories.AppendElement();
|
||||
element->SetAsFile() = domBlob->ToFile();
|
||||
|
||||
ImageInputTelemetry::MaybeRecordFilePickerImageInputTelemetry(domBlob);
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(mode == nsIFilePicker::modeOpen ||
|
||||
@@ -537,6 +540,8 @@ HTMLInputElement::nsFilePickerShownCallback::Done(
|
||||
|
||||
OwningFileOrDirectory* element = newFilesOrDirectories.AppendElement();
|
||||
element->SetAsFile() = file;
|
||||
|
||||
ImageInputTelemetry::MaybeRecordFilePickerImageInputTelemetry(blob);
|
||||
} else if (tmp) {
|
||||
RefPtr<Directory> directory = static_cast<Directory*>(tmp.get());
|
||||
OwningFileOrDirectory* element = newFilesOrDirectories.AppendElement();
|
||||
|
||||
@@ -15214,6 +15214,13 @@
|
||||
value: false
|
||||
mirror: always
|
||||
|
||||
# To be used in automated test environments to enable event telemetry
|
||||
# collection.
|
||||
- name: privacy.imageInputTelemetry.enableTestMode
|
||||
type: bool
|
||||
value: false
|
||||
mirror: always
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Prefs starting with "prompts."
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ImageInputTelemetry.h"
|
||||
|
||||
#include "mozilla/ContentEvents.h"
|
||||
#include "mozilla/MouseEvents.h"
|
||||
#include "mozilla/dom/Blob.h"
|
||||
#include "mozilla/dom/DataTransfer.h"
|
||||
#include "mozilla/dom/FileList.h"
|
||||
#include "mozilla/glean/GleanMetrics.h"
|
||||
#include "nsIPrincipal.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// Known MIME types as listed in nsMimeTypes.h + HEIC types
|
||||
static constexpr nsLiteralCString kKnownImageMIMETypes[] = {
|
||||
"image/gif"_ns,
|
||||
"image/jpeg"_ns,
|
||||
"image/jpg"_ns,
|
||||
"image/pjpeg"_ns,
|
||||
"image/png"_ns,
|
||||
"image/apng"_ns,
|
||||
"image/x-png"_ns,
|
||||
"image/x-portable-pixmap"_ns,
|
||||
"image/x-xbitmap"_ns,
|
||||
"image/x-xbm"_ns,
|
||||
"image/xbm"_ns,
|
||||
"image/x-jg"_ns,
|
||||
"image/tiff"_ns,
|
||||
"image/bmp"_ns,
|
||||
"image/x-ms-bmp"_ns,
|
||||
"image/x-ms-clipboard-bmp"_ns,
|
||||
"image/x-icon"_ns,
|
||||
"image/vnd.microsoft.icon"_ns,
|
||||
"image/icon"_ns, // "video/x-mng"_ns, - This is checked in
|
||||
// ImageInputTelemetry::IsKnownImageMIMEType()
|
||||
"image/x-jng"_ns,
|
||||
"image/svg+xml"_ns,
|
||||
"image/webp"_ns,
|
||||
"image/avif"_ns,
|
||||
"image/jxl"_ns,
|
||||
// Additionally added HEIC image formats due to mobile popularity
|
||||
"image/heic"_ns,
|
||||
"image/heif"_ns,
|
||||
};
|
||||
|
||||
/* private static */ bool ImageInputTelemetry::IsKnownImageMIMEType(
|
||||
const nsCString& aInputFileType) {
|
||||
if (aInputFileType.Find("video/x-mng"_ns) != kNotFound) {
|
||||
return true;
|
||||
}
|
||||
if (aInputFileType.Find("image/"_ns) != kNotFound) {
|
||||
for (const nsCString& knownImageMIMEType : kKnownImageMIMETypes) {
|
||||
if (aInputFileType.Equals(knownImageMIMEType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* private static */ bool ImageInputTelemetry::IsContentPrincipal(
|
||||
nsIPrincipal* aContentPrincipal) {
|
||||
bool isSystemPrincipal;
|
||||
aContentPrincipal->GetIsSystemPrincipal(&isSystemPrincipal);
|
||||
return !(isSystemPrincipal || aContentPrincipal->SchemeIs("about"));
|
||||
}
|
||||
|
||||
/* private static */ void ImageInputTelemetry::RecordImageInputTelemetry(
|
||||
const nsCString& aImageType, ImageInputType aInputType) {
|
||||
nsAutoCString inputType;
|
||||
switch (aInputType) {
|
||||
case ImageInputType::Drop:
|
||||
inputType = "Drop"_ns;
|
||||
break;
|
||||
case ImageInputType::Paste:
|
||||
inputType = "Paste"_ns;
|
||||
break;
|
||||
case ImageInputType::FilePicker:
|
||||
inputType = "FilePicker"_ns;
|
||||
break;
|
||||
}
|
||||
glean::image_input_telemetry::ImageInputExtra extra = {
|
||||
.imageType = Some(aImageType),
|
||||
.inputType = Some(inputType),
|
||||
};
|
||||
glean::image_input_telemetry::image_input.Record(Some(extra));
|
||||
}
|
||||
|
||||
/* private static */ void ImageInputTelemetry::MaybeRecordImageInputTelemetry(
|
||||
ImageInputType aInputType, dom::DataTransfer* aDataTransfer) {
|
||||
// Check if input datatransfers contains files.
|
||||
RefPtr<dom::FileList> files =
|
||||
aDataTransfer->GetFiles(*nsContentUtils::GetSystemPrincipal());
|
||||
if (!files) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoString fileType;
|
||||
nsCString fileTypeC;
|
||||
for (uint32_t i = 0; i < files->Length(); i++) {
|
||||
dom::File* file = files->Item(i);
|
||||
if (!file) {
|
||||
continue;
|
||||
}
|
||||
|
||||
file->GetType(fileType);
|
||||
fileTypeC = NS_ConvertUTF16toUTF8(fileType);
|
||||
if (IsKnownImageMIMEType(fileTypeC)) {
|
||||
ImageInputTelemetry::RecordImageInputTelemetry(fileTypeC, aInputType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ void ImageInputTelemetry::MaybeRecordDropImageInputTelemetry(
|
||||
WidgetDragEvent* aDragEvent, nsIPrincipal* aContentPrincipal) {
|
||||
MOZ_ASSERT(aDragEvent);
|
||||
MOZ_ASSERT(aContentPrincipal);
|
||||
|
||||
// Only collect telemetry when drag data is accessed on drop.
|
||||
if (aDragEvent->mMessage != eDrop || !aDragEvent->mDataTransfer) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only process events on content, not about pages, e.g. default drop
|
||||
// handler displays dropped file.
|
||||
if (!IsContentPrincipal(aContentPrincipal)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ImageInputTelemetry::MaybeRecordImageInputTelemetry(
|
||||
ImageInputType::Drop, aDragEvent->mDataTransfer);
|
||||
}
|
||||
|
||||
/* static */ void ImageInputTelemetry::MaybeRecordPasteImageInputTelemetry(
|
||||
InternalClipboardEvent* aClipboardEvent, nsIPrincipal* aContentPrincipal) {
|
||||
MOZ_ASSERT(aClipboardEvent);
|
||||
MOZ_ASSERT(aContentPrincipal);
|
||||
|
||||
// Only collect telemetry when clipboard data is accessed on paste.
|
||||
if (aClipboardEvent->mMessage != ePaste || !aClipboardEvent->mClipboardData) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only process events on content, neither system (e.g. URL bar) nor
|
||||
// about pages (e.g. searchbar in about:preferences).
|
||||
if (!IsContentPrincipal(aContentPrincipal)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ImageInputTelemetry::MaybeRecordImageInputTelemetry(
|
||||
ImageInputType::Paste, aClipboardEvent->mClipboardData);
|
||||
}
|
||||
|
||||
/* static */ void ImageInputTelemetry::MaybeRecordFilePickerImageInputTelemetry(
|
||||
dom::Blob* aFilePickerBlob) {
|
||||
MOZ_ASSERT(aFilePickerBlob);
|
||||
|
||||
nsAutoString fileType;
|
||||
nsCString fileTypeC;
|
||||
aFilePickerBlob->GetType(fileType);
|
||||
fileTypeC = NS_ConvertUTF16toUTF8(fileType);
|
||||
if (IsKnownImageMIMEType(fileTypeC)) {
|
||||
ImageInputTelemetry::RecordImageInputTelemetry(fileTypeC,
|
||||
ImageInputType::FilePicker);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
@@ -0,0 +1,71 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_imageinputtypetelemetry_h
|
||||
#define mozilla_imageinputtypetelemetry_h
|
||||
|
||||
#include "nsStringFwd.h"
|
||||
|
||||
class nsIPrincipal;
|
||||
|
||||
namespace mozilla {
|
||||
class InternalClipboardEvent;
|
||||
class WidgetDragEvent;
|
||||
namespace dom {
|
||||
class Blob;
|
||||
class DataTransfer;
|
||||
} // namespace dom
|
||||
|
||||
// Class for collection of image input file type and input type telemetry.
|
||||
class ImageInputTelemetry {
|
||||
public:
|
||||
enum ImageInputType {
|
||||
Drop,
|
||||
Paste,
|
||||
FilePicker,
|
||||
};
|
||||
|
||||
// Collect telemetry on drop of user image input to the browser. This is
|
||||
// collected in DragEvent:GetDataTransfer(). Telemetry is not collected
|
||||
// for about:* pages (e.g. newtab) and for system principals (e.g. drop on
|
||||
// about:preferences).
|
||||
static void MaybeRecordDropImageInputTelemetry(
|
||||
WidgetDragEvent* aDragEvent, nsIPrincipal* aContentPrincipal);
|
||||
// Collect telemetry on paste of user image input to the browser. This is
|
||||
// collected in ClipboardEvent:GetClipboardData(). Telemetry is not collected
|
||||
// for about:* pages (e.g. searchbar in about:preferences) and for system
|
||||
// principals (e.g. paste to urlbar).
|
||||
static void MaybeRecordPasteImageInputTelemetry(
|
||||
InternalClipboardEvent* aClipboardEvent, nsIPrincipal* aContentPrincipal);
|
||||
// Collect telemetry on user selection of image files through the FilePicker.
|
||||
// The telemetry is collected in
|
||||
// HTMLInputElement::nsFilePickerShownCallback::Done(), both for single and
|
||||
// multiple collected files.
|
||||
static void MaybeRecordFilePickerImageInputTelemetry(
|
||||
dom::Blob* aFilePickerBlob);
|
||||
|
||||
private:
|
||||
ImageInputTelemetry() = default;
|
||||
~ImageInputTelemetry() = default;
|
||||
|
||||
// This function returns true if kKnownImageMIMETypes contains aFileInputType.
|
||||
static bool IsKnownImageMIMEType(const nsCString& aInputFileType);
|
||||
// This function returns true if aContentPincipal is of any page possibly
|
||||
// collectiing user data (including local e.g. html pages).
|
||||
static bool IsContentPrincipal(nsIPrincipal* aContentPrincipal);
|
||||
// Iterate through input files from aDataTransfer and record a Glean event if
|
||||
// the file is an image of a type contained in kKnownImageMIMETypes.
|
||||
static void MaybeRecordImageInputTelemetry(ImageInputType aInputType,
|
||||
dom::DataTransfer* aDataTransfer);
|
||||
// Wrapper for recording an image_input Glean event containing the image_type
|
||||
// and the input_type (FilePicker, Paste, Drag).
|
||||
static void RecordImageInputTelemetry(const nsCString& aImageType,
|
||||
ImageInputType aInputType);
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_imageinputtypetelemetry_h
|
||||
@@ -0,0 +1,34 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
# Adding a new metric? We have docs for that!
|
||||
# https://firefox-source-docs.mozilla.org/toolkit/components/glean/user/new_definitions_file.html
|
||||
|
||||
---
|
||||
$schema: moz://mozilla.org/schemas/glean/metrics/2-0-0
|
||||
$tags:
|
||||
- 'Core :: Privacy: Anti-Tracking'
|
||||
|
||||
image.input.telemetry:
|
||||
image_input:
|
||||
type: event
|
||||
description: >
|
||||
Type of user image file(s) input and browser input type and platform.
|
||||
bugs:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1899117
|
||||
data_reviews:
|
||||
- https://phabricator.services.mozilla.com/D223316
|
||||
data_sensitivity:
|
||||
- interaction
|
||||
notification_emails:
|
||||
- lschwarz@mozilla.com
|
||||
- bvandersloot@mozilla.com
|
||||
expires: 139
|
||||
extra_keys:
|
||||
image_type:
|
||||
description: User input image file type(s).
|
||||
type: string
|
||||
input_type:
|
||||
description: User input type.
|
||||
type: string
|
||||
@@ -0,0 +1,24 @@
|
||||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
with Files("**"):
|
||||
BUG_COMPONENT = ("Core", "Privacy: Anti-Tracking")
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
"ImageInputTelemetry.h",
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
"ImageInputTelemetry.cpp",
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = "xul"
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += [
|
||||
"test/browser/browser.toml",
|
||||
]
|
||||
|
||||
MOCHITEST_MANIFESTS += ["test/mochitest/mochitest.toml"]
|
||||
@@ -0,0 +1,9 @@
|
||||
[DEFAULT]
|
||||
head = ["head.js"]
|
||||
prefs = ["privacy.imageInputTelemetry.enableTestMode=true", "browser.newtab.preload=false"]
|
||||
|
||||
["browser_dragimage_telemetry.js"]
|
||||
|
||||
["browser_filepicker_telemetry.js"]
|
||||
|
||||
["browser_pasteimage_telemetry.js"]
|
||||
@@ -0,0 +1,245 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use stric";
|
||||
|
||||
async function createDropEventAndSetFiles(browser, files, addListener = true) {
|
||||
await SpecialPowers.spawn(
|
||||
browser,
|
||||
[files, addListener],
|
||||
async (files, addListener) => {
|
||||
async function onDrop(event) {
|
||||
// Access DataTransfer so DragEvent::GetDataTransfer() is triggered.
|
||||
event.dataTransfer;
|
||||
}
|
||||
|
||||
const dataTransfer = new content.DataTransfer();
|
||||
dataTransfer.dropEffect = "copy";
|
||||
files.forEach(file => {
|
||||
dataTransfer.items.add(file);
|
||||
});
|
||||
|
||||
if (addListener) {
|
||||
content.document.addEventListener("drop", onDrop);
|
||||
}
|
||||
|
||||
let event = content.document.createEvent("DragEvent");
|
||||
event.initDragEvent(
|
||||
"drop",
|
||||
false,
|
||||
false,
|
||||
content.window,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
0,
|
||||
content.document.body,
|
||||
dataTransfer
|
||||
);
|
||||
content.document.dispatchEvent(event);
|
||||
|
||||
if (addListener) {
|
||||
content.document.removeEventListener("drop", onDrop);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
add_task(async function drag_single_image() {
|
||||
let snapshot = Glean.imageInputTelemetry.imageInput.testGetValue();
|
||||
is(snapshot, null, "Glean - Initially no event gathered!");
|
||||
|
||||
await BrowserTestUtils.withNewTab("example.com", async browser => {
|
||||
const files = new File(["some data"], "hello.jpg", { type: "image/jpg" });
|
||||
|
||||
await createDropEventAndSetFiles(browser, [files]);
|
||||
|
||||
await Services.fog.testFlushAllChildren();
|
||||
});
|
||||
|
||||
snapshot = Glean.imageInputTelemetry.imageInput.testGetValue();
|
||||
is(snapshot.length, 1, "Glean - One telemetry event gathered!");
|
||||
is(snapshot[0].name, "image_input", "Glean - Received correct event!");
|
||||
is(
|
||||
snapshot[0].extra.image_type,
|
||||
"image/jpg",
|
||||
"Glean - Event extra correct image type!"
|
||||
);
|
||||
is(
|
||||
snapshot[0].extra.input_type,
|
||||
"Drop",
|
||||
"Glean - Event extra correct input type!"
|
||||
);
|
||||
|
||||
// Cleanup
|
||||
Services.fog.testResetFOG();
|
||||
});
|
||||
|
||||
add_task(async function drag_single_image_about() {
|
||||
let snapshot = Glean.imageInputTelemetry.imageInput.testGetValue();
|
||||
is(snapshot, null, "Glean - Initially no event gathered!");
|
||||
|
||||
await BrowserTestUtils.withNewTab("about:newtab", async browser => {
|
||||
const files = new File(["some data"], "hello.jpg", { type: "image/jpg" });
|
||||
|
||||
await createDropEventAndSetFiles(browser, [files], false);
|
||||
|
||||
await Services.fog.testFlushAllChildren();
|
||||
});
|
||||
|
||||
snapshot = Glean.imageInputTelemetry.imageInput.testGetValue();
|
||||
is(
|
||||
snapshot,
|
||||
null,
|
||||
"Glean - No telemetry event gathered as expected on about:newtab!"
|
||||
);
|
||||
|
||||
// Cleanup
|
||||
Services.fog.testResetFOG();
|
||||
});
|
||||
|
||||
// Separate test since about:* pages use system principal
|
||||
add_task(async function drag_single_image_system() {
|
||||
let snapshot = Glean.imageInputTelemetry.imageInput.testGetValue();
|
||||
is(snapshot, null, "Glean - Initially no event gathered!");
|
||||
|
||||
await BrowserTestUtils.withNewTab("about:preferences", async browser => {
|
||||
const files = new File(["some data"], "hello.jpg", { type: "image/jpg" });
|
||||
|
||||
await createDropEventAndSetFiles(browser, [files]);
|
||||
|
||||
await Services.fog.testFlushAllChildren();
|
||||
});
|
||||
|
||||
snapshot = Glean.imageInputTelemetry.imageInput.testGetValue();
|
||||
is(
|
||||
snapshot,
|
||||
null,
|
||||
"Glean - No telemetry event gathered as expected on other about:* pages!"
|
||||
);
|
||||
|
||||
// Cleanup
|
||||
Services.fog.testResetFOG();
|
||||
});
|
||||
|
||||
add_task(async function drag_single_txt() {
|
||||
let snapshot = Glean.imageInputTelemetry.imageInput.testGetValue();
|
||||
is(snapshot, null, "Glean - Initially no event gathered!");
|
||||
|
||||
await BrowserTestUtils.withNewTab("example.com", async browser => {
|
||||
const files = new File(["some data"], "hello.txt", { type: "text/plain" });
|
||||
|
||||
await createDropEventAndSetFiles(browser, [files]);
|
||||
|
||||
await Services.fog.testFlushAllChildren();
|
||||
});
|
||||
|
||||
snapshot = Glean.imageInputTelemetry.imageInput.testGetValue();
|
||||
is(snapshot, null, "Glean - No telemetry collected for txt file!");
|
||||
|
||||
// Cleanup
|
||||
Services.fog.testResetFOG();
|
||||
});
|
||||
|
||||
add_task(async function drag_multiple_images() {
|
||||
let snapshot = Glean.imageInputTelemetry.imageInput.testGetValue();
|
||||
is(snapshot, null, "Glean - Initially no event gathered!");
|
||||
|
||||
await BrowserTestUtils.withNewTab("example.com", async browser => {
|
||||
let files = [];
|
||||
kKnownImageMIMETypes.forEach(mimeType => {
|
||||
const image = new File(["some data"], "hello", { type: mimeType });
|
||||
files.push(image);
|
||||
});
|
||||
|
||||
await createDropEventAndSetFiles(browser, files);
|
||||
|
||||
await Services.fog.testFlushAllChildren();
|
||||
});
|
||||
|
||||
snapshot = Glean.imageInputTelemetry.imageInput.testGetValue();
|
||||
is(
|
||||
snapshot.length,
|
||||
kKnownImageMIMETypes.length,
|
||||
"Glean - Collected telemetry for all known image types!"
|
||||
);
|
||||
|
||||
snapshot.forEach(function (event, i) {
|
||||
let eventMimeType = event.extra.image_type;
|
||||
is(
|
||||
kKnownImageMIMETypes[i],
|
||||
eventMimeType,
|
||||
"Glean - Correct MIME-Type: " + eventMimeType
|
||||
);
|
||||
is("Drop", event.extra.input_type, "Glean - Correct input type!");
|
||||
});
|
||||
|
||||
// Cleanup
|
||||
Services.fog.testResetFOG();
|
||||
});
|
||||
|
||||
add_task(async function drag_multiple_mixed() {
|
||||
let snapshot = Glean.imageInputTelemetry.imageInput.testGetValue();
|
||||
is(snapshot, null, "Glean - Initially no event gathered!");
|
||||
|
||||
await BrowserTestUtils.withNewTab("example.com", async browser => {
|
||||
const image1 = new File(["some data"], "A", { type: "plain/text" });
|
||||
const txt1 = new File(["some data"], "B", { type: "image/png" });
|
||||
const image2 = new File(["some data"], "C", { type: "plain/text" });
|
||||
const txt2 = new File(["some data"], "D", { type: "image/bmp" });
|
||||
|
||||
await createDropEventAndSetFiles(browser, [image1, txt1, image2, txt2]);
|
||||
|
||||
await Services.fog.testFlushAllChildren();
|
||||
});
|
||||
|
||||
snapshot = Glean.imageInputTelemetry.imageInput.testGetValue();
|
||||
is(snapshot.length, 2, "Glean - Correct number of events recorded!");
|
||||
is(
|
||||
snapshot[0].extra.image_type,
|
||||
"image/png",
|
||||
"Glean - Correct first image type!"
|
||||
);
|
||||
is(snapshot[0].extra.input_type, "Drop", "Glean - Correct first input type!");
|
||||
is(
|
||||
snapshot[1].extra.image_type,
|
||||
"image/bmp",
|
||||
"Glean - Correct second image type!"
|
||||
);
|
||||
is(
|
||||
snapshot[1].extra.input_type,
|
||||
"Drop",
|
||||
"Glean - Correct second input type!"
|
||||
);
|
||||
|
||||
// Cleanup
|
||||
Services.fog.testResetFOG();
|
||||
});
|
||||
|
||||
add_task(async function drag_multiple_txt() {
|
||||
let snapshot = Glean.imageInputTelemetry.imageInput.testGetValue();
|
||||
is(snapshot, null, "Glean - Initially no event gathered!");
|
||||
|
||||
await BrowserTestUtils.withNewTab("example.com", async browser => {
|
||||
const txt1 = new File(["some data"], "A", { type: "plain/text" });
|
||||
const txt2 = new File(["some data"], "B", { type: "plain/text" });
|
||||
const txt3 = new File(["some data"], "C", { type: "plain/text" });
|
||||
const txt4 = new File(["some data"], "D", { type: "plain/text" });
|
||||
|
||||
await createDropEventAndSetFiles(browser, [txt1, txt2, txt3, txt4]);
|
||||
|
||||
await Services.fog.testFlushAllChildren();
|
||||
});
|
||||
|
||||
snapshot = Glean.imageInputTelemetry.imageInput.testGetValue();
|
||||
is(snapshot, null, "Glean - No non-image input events collected!");
|
||||
|
||||
// Cleanup
|
||||
Services.fog.testResetFOG();
|
||||
});
|
||||
@@ -0,0 +1,192 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const PAGE = `
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<body>
|
||||
<input id="modeOpen" type=file></input>
|
||||
<input id="modeOpenMultiple" type=file multiple></input>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
const INPUT_URL = "data:text/html," + encodeURI(PAGE);
|
||||
|
||||
async function openFilePickerAndSetFiles(browser, files) {
|
||||
await SpecialPowers.spawn(browser, [files], async files => {
|
||||
let filePicker = content.SpecialPowers.MockFilePicker;
|
||||
filePicker.cleanup();
|
||||
filePicker.init(content.browsingContext);
|
||||
let filePickerShow = new Promise(resolve => {
|
||||
filePicker.showCallback = () => {
|
||||
filePicker.setFiles(files);
|
||||
filePicker.returnValue = filePicker.returnOk;
|
||||
info("MockFilePicker shown, files set!");
|
||||
resolve();
|
||||
};
|
||||
});
|
||||
|
||||
let input =
|
||||
files.length > 1
|
||||
? content.document.getElementById("modeOpenMultiple")
|
||||
: content.document.getElementById("modeOpen");
|
||||
content.document.notifyUserGestureActivation();
|
||||
input.click();
|
||||
|
||||
return filePickerShow;
|
||||
});
|
||||
}
|
||||
|
||||
add_task(async function filepicker_single_image() {
|
||||
let snapshot = Glean.imageInputTelemetry.imageInput.testGetValue();
|
||||
is(snapshot, null, "Glean - Initially no event gathered!");
|
||||
|
||||
await BrowserTestUtils.withNewTab(INPUT_URL, async browser => {
|
||||
const files = new File(["some data"], "hello.jpg", { type: "image/jpg" });
|
||||
|
||||
await openFilePickerAndSetFiles(browser, [files]);
|
||||
|
||||
await Services.fog.testFlushAllChildren();
|
||||
});
|
||||
|
||||
snapshot = Glean.imageInputTelemetry.imageInput.testGetValue();
|
||||
is(snapshot.length, 1, "Glean - One telemertry event gathered!");
|
||||
is(snapshot[0].name, "image_input", "Glean - Received correct event!");
|
||||
is(
|
||||
snapshot[0].extra.image_type,
|
||||
"image/jpg",
|
||||
"Glean - Event extra correct image type!"
|
||||
);
|
||||
is(
|
||||
snapshot[0].extra.input_type,
|
||||
"FilePicker",
|
||||
"Glean - Event extra correct input type!"
|
||||
);
|
||||
|
||||
// Cleanup
|
||||
Services.fog.testResetFOG();
|
||||
});
|
||||
|
||||
add_task(async function filepicker_single_txt() {
|
||||
let snapshot = Glean.imageInputTelemetry.imageInput.testGetValue();
|
||||
is(snapshot, null, "Glean - Initially no event gathered!");
|
||||
|
||||
await BrowserTestUtils.withNewTab(INPUT_URL, async browser => {
|
||||
const files = new File(["some data"], "hello.txt", {
|
||||
type: "plain/text",
|
||||
});
|
||||
|
||||
await openFilePickerAndSetFiles(browser, [files]);
|
||||
|
||||
await Services.fog.testFlushAllChildren();
|
||||
});
|
||||
|
||||
snapshot = Glean.imageInputTelemetry.imageInput.testGetValue();
|
||||
is(snapshot, null, "Glean - No telemetry collected for txt file!");
|
||||
|
||||
// Cleanup
|
||||
Services.fog.testResetFOG();
|
||||
});
|
||||
|
||||
add_task(async function filepicker_multiple_images() {
|
||||
let snapshot = Glean.imageInputTelemetry.imageInput.testGetValue();
|
||||
is(snapshot, null, "Glean - Initially no event gathered!");
|
||||
|
||||
await BrowserTestUtils.withNewTab(INPUT_URL, async browser => {
|
||||
let files = [];
|
||||
kKnownImageMIMETypes.forEach(mimeType => {
|
||||
const image = new File(["some data"], "hello", { type: mimeType });
|
||||
files.push(image);
|
||||
});
|
||||
|
||||
await openFilePickerAndSetFiles(browser, files);
|
||||
|
||||
await Services.fog.testFlushAllChildren();
|
||||
});
|
||||
|
||||
snapshot = Glean.imageInputTelemetry.imageInput.testGetValue();
|
||||
is(
|
||||
snapshot.length,
|
||||
kKnownImageMIMETypes.length,
|
||||
"Glean - Collected telemetry for all known image types!"
|
||||
);
|
||||
|
||||
snapshot.forEach(function (event, i) {
|
||||
let eventMimeType = event.extra.image_type;
|
||||
is(
|
||||
kKnownImageMIMETypes[i],
|
||||
eventMimeType,
|
||||
"Glean - Correct MIME-Type: " + eventMimeType
|
||||
);
|
||||
is("FilePicker", event.extra.input_type, "Glean - Correct input type!");
|
||||
});
|
||||
|
||||
// Cleanup
|
||||
Services.fog.testResetFOG();
|
||||
});
|
||||
|
||||
add_task(async function filepicker_multiple_mixed() {
|
||||
let snapshot = Glean.imageInputTelemetry.imageInput.testGetValue();
|
||||
is(snapshot, null, "Glean - Initially no event gathered!");
|
||||
|
||||
await BrowserTestUtils.withNewTab(INPUT_URL, async browser => {
|
||||
const image1 = new File(["some data"], "A", { type: "plain/text" });
|
||||
const txt1 = new File(["some data"], "B", { type: "image/png" });
|
||||
const image2 = new File(["some data"], "C", { type: "plain/text" });
|
||||
const txt2 = new File(["some data"], "D", { type: "image/bmp" });
|
||||
|
||||
await openFilePickerAndSetFiles(browser, [image1, txt1, image2, txt2]);
|
||||
|
||||
await Services.fog.testFlushAllChildren();
|
||||
});
|
||||
|
||||
snapshot = Glean.imageInputTelemetry.imageInput.testGetValue();
|
||||
is(snapshot.length, 2, "Glean - Correct number of events recorded!");
|
||||
is(
|
||||
snapshot[0].extra.image_type,
|
||||
"image/png",
|
||||
"Glean - Correct first image type!"
|
||||
);
|
||||
is(
|
||||
snapshot[0].extra.input_type,
|
||||
"FilePicker",
|
||||
"Glean - Correct first input type!"
|
||||
);
|
||||
is(
|
||||
snapshot[1].extra.image_type,
|
||||
"image/bmp",
|
||||
"Glean - Correct second image type!"
|
||||
);
|
||||
is(
|
||||
snapshot[1].extra.input_type,
|
||||
"FilePicker",
|
||||
"Glean - Correct second input type!"
|
||||
);
|
||||
|
||||
// Cleanup
|
||||
Services.fog.testResetFOG();
|
||||
});
|
||||
|
||||
add_task(async function filepicker_multiple_txt() {
|
||||
let snapshot = Glean.imageInputTelemetry.imageInput.testGetValue();
|
||||
is(snapshot, null, "Glean - Initially no event gathered!");
|
||||
|
||||
await BrowserTestUtils.withNewTab(INPUT_URL, async browser => {
|
||||
const txt1 = new File(["some data"], "A", { type: "plain/text" });
|
||||
const txt2 = new File(["some data"], "B", { type: "plain/text" });
|
||||
const txt3 = new File(["some data"], "C", { type: "plain/text" });
|
||||
const txt4 = new File(["some data"], "D", { type: "plain/text" });
|
||||
|
||||
await openFilePickerAndSetFiles(browser, [txt1, txt2, txt3, txt4]);
|
||||
|
||||
await Services.fog.testFlushAllChildren();
|
||||
});
|
||||
|
||||
snapshot = Glean.imageInputTelemetry.imageInput.testGetValue();
|
||||
is(snapshot, null, "Glean - No non-image input events collected!");
|
||||
|
||||
// Cleanup
|
||||
Services.fog.testResetFOG();
|
||||
});
|
||||
@@ -0,0 +1,182 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use stric";
|
||||
|
||||
async function setClipboard(file) {
|
||||
const tmp = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
||||
tmp.initWithPath(file);
|
||||
|
||||
const trans = Cc["@mozilla.org/widget/transferable;1"].createInstance(
|
||||
Ci.nsITransferable
|
||||
);
|
||||
trans.init(null);
|
||||
trans.addDataFlavor("application/x-moz-file");
|
||||
trans.setTransferData("application/x-moz-file", tmp);
|
||||
|
||||
// Write to clipboard.
|
||||
Services.clipboard.setData(trans, null, Ci.nsIClipboard.kGlobalClipboard);
|
||||
}
|
||||
|
||||
async function createPasteEvent(browser, addListener = true) {
|
||||
await SpecialPowers.spawn(browser, [addListener], async addListener => {
|
||||
function onPaste(event) {
|
||||
// Access DataTransfer so DragEvent::GetDataTransfer() is triggered.
|
||||
event.clipboardData;
|
||||
if (addListener) {
|
||||
content.document.removeEventListener("paste", onPaste);
|
||||
}
|
||||
}
|
||||
|
||||
if (addListener) {
|
||||
content.document.addEventListener("paste", onPaste);
|
||||
}
|
||||
});
|
||||
|
||||
await BrowserTestUtils.synthesizeKey("v", { accelKey: true }, browser);
|
||||
}
|
||||
|
||||
add_task(async function paste_single_image() {
|
||||
let snapshot = Glean.imageInputTelemetry.imageInput.testGetValue();
|
||||
is(snapshot, null, "Glean - Initially no event gathered!");
|
||||
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(
|
||||
gBrowser,
|
||||
"example.com"
|
||||
);
|
||||
let browser = tab.linkedBrowser;
|
||||
|
||||
const file = await IOUtils.createUniqueFile(
|
||||
PathUtils.tempDir,
|
||||
"test-file.jpg",
|
||||
0o600
|
||||
);
|
||||
|
||||
await setClipboard(file);
|
||||
|
||||
await createPasteEvent(browser);
|
||||
|
||||
await Services.fog.testFlushAllChildren();
|
||||
|
||||
snapshot = Glean.imageInputTelemetry.imageInput.testGetValue();
|
||||
is(snapshot.length, 1, "Glean - One telemetry event gathered!");
|
||||
is(snapshot[0].name, "image_input", "Glean - Received correct event!");
|
||||
is(
|
||||
snapshot[0].extra.image_type,
|
||||
"image/jpeg",
|
||||
"Glean - Event extra correct image type!"
|
||||
);
|
||||
is(
|
||||
snapshot[0].extra.input_type,
|
||||
"Paste",
|
||||
"Glean - Event extra correct input type!"
|
||||
);
|
||||
|
||||
// Cleanup
|
||||
await IOUtils.remove(file);
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
Services.fog.testResetFOG();
|
||||
});
|
||||
|
||||
add_task(async function paste_single_image_about() {
|
||||
let snapshot = Glean.imageInputTelemetry.imageInput.testGetValue();
|
||||
is(snapshot, null, "Glean - Initially no event gathered!");
|
||||
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(
|
||||
gBrowser,
|
||||
"about:newtab"
|
||||
);
|
||||
let browser = tab.linkedBrowser;
|
||||
|
||||
const file = await IOUtils.createUniqueFile(
|
||||
PathUtils.tempDir,
|
||||
"test-file.jpg",
|
||||
0o600
|
||||
);
|
||||
|
||||
await setClipboard(file);
|
||||
|
||||
await createPasteEvent(browser, false);
|
||||
|
||||
await Services.fog.testFlushAllChildren();
|
||||
|
||||
snapshot = Glean.imageInputTelemetry.imageInput.testGetValue();
|
||||
is(
|
||||
snapshot,
|
||||
null,
|
||||
"Glean - No telemetry event gathered as expected on about:newtab!"
|
||||
);
|
||||
|
||||
// Cleanup
|
||||
await IOUtils.remove(file);
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
Services.fog.testResetFOG();
|
||||
});
|
||||
|
||||
// Separate test since about:* pages use system principal
|
||||
add_task(async function paste_single_image_system() {
|
||||
let snapshot = Glean.imageInputTelemetry.imageInput.testGetValue();
|
||||
is(snapshot, null, "Glean - Initially no event gathered!");
|
||||
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(
|
||||
gBrowser,
|
||||
"about:preferences"
|
||||
);
|
||||
let browser = tab.linkedBrowser;
|
||||
|
||||
const file = await IOUtils.createUniqueFile(
|
||||
PathUtils.tempDir,
|
||||
"test-file.jpg",
|
||||
0o600
|
||||
);
|
||||
|
||||
await setClipboard(file);
|
||||
|
||||
await createPasteEvent(browser);
|
||||
|
||||
await Services.fog.testFlushAllChildren();
|
||||
|
||||
snapshot = Glean.imageInputTelemetry.imageInput.testGetValue();
|
||||
is(
|
||||
snapshot,
|
||||
null,
|
||||
"Glean - No telemetry event gathered as expected on other about:* pages!"
|
||||
);
|
||||
|
||||
// Cleanup
|
||||
await IOUtils.remove(file);
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
Services.fog.testResetFOG();
|
||||
});
|
||||
|
||||
add_task(async function paste_single_txt() {
|
||||
let snapshot = Glean.imageInputTelemetry.imageInput.testGetValue();
|
||||
is(snapshot, null, "Glean - Initially no event gathered!");
|
||||
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(
|
||||
gBrowser,
|
||||
"example.com"
|
||||
);
|
||||
let browser = tab.linkedBrowser;
|
||||
|
||||
const file = await IOUtils.createUniqueFile(
|
||||
PathUtils.tempDir,
|
||||
"test-file.txt",
|
||||
0o600
|
||||
);
|
||||
await IOUtils.writeUTF8(file, "Hello World!");
|
||||
|
||||
await setClipboard(file);
|
||||
|
||||
await createPasteEvent(browser);
|
||||
|
||||
await Services.fog.testFlushAllChildren();
|
||||
|
||||
snapshot = Glean.imageInputTelemetry.imageInput.testGetValue();
|
||||
is(snapshot, null, "Glean - No telemetry collected for txt file!");
|
||||
|
||||
// Cleanup
|
||||
await IOUtils.remove(file);
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
Services.fog.testResetFOG();
|
||||
});
|
||||
@@ -0,0 +1,34 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// Known MIME types as listed in nsMimeTypes.h
|
||||
const kKnownImageMIMETypes = [
|
||||
"image/gif",
|
||||
"image/jpeg",
|
||||
"image/jpg",
|
||||
"image/pjpeg",
|
||||
"image/png",
|
||||
"image/apng",
|
||||
"image/x-png",
|
||||
"image/x-portable-pixmap",
|
||||
"image/x-xbitmap",
|
||||
"image/x-xbm",
|
||||
"image/xbm",
|
||||
"image/x-jg",
|
||||
"image/tiff",
|
||||
"image/bmp",
|
||||
"image/x-ms-bmp",
|
||||
"image/x-ms-clipboard-bmp",
|
||||
"image/x-icon",
|
||||
"image/vnd.microsoft.icon",
|
||||
"image/icon",
|
||||
"video/x-mng",
|
||||
"image/x-jng",
|
||||
"image/svg+xml",
|
||||
"image/webp",
|
||||
"image/avif",
|
||||
"image/jxl",
|
||||
"image/heic",
|
||||
"image/heif",
|
||||
];
|
||||
@@ -0,0 +1,40 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Bug 1799977: Using workaround to test telemetry in plain mochitests
|
||||
const GleanTest = new Proxy(
|
||||
{},
|
||||
{
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
get(target, categoryName, receiver) {
|
||||
return new Proxy(
|
||||
{},
|
||||
{
|
||||
// eslint-disable-next-line no-shadow
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
get(target, metricName, receiver) {
|
||||
return {
|
||||
async testGetValue() {
|
||||
return SpecialPowers.spawnChrome(
|
||||
[categoryName, metricName],
|
||||
// eslint-disable-next-line no-shadow
|
||||
async (categoryName, metricName) => {
|
||||
await Services.fog.testFlushAllChildren();
|
||||
const window = this.browsingContext.topChromeWindow;
|
||||
let snapshot =
|
||||
window.Glean[categoryName][metricName].testGetValue();
|
||||
await Services.fog.testResetFOG();
|
||||
return snapshot;
|
||||
}
|
||||
);
|
||||
},
|
||||
};
|
||||
},
|
||||
}
|
||||
);
|
||||
},
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,5 @@
|
||||
[DEFAULT]
|
||||
support-files = ["head.js"]
|
||||
run-if = ["os == 'android'"]
|
||||
|
||||
["test_geckoview_filepicker_telemetry.html"]
|
||||
@@ -0,0 +1,56 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Tests for GeckoView Image Input Telemetry</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="head.js" type="application/javascript"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<input type="file"></input>
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
async function openFilePicker(window) {
|
||||
const image = new File(["some data"], "hello.jpg", { type: "image/jpg" });
|
||||
const txt = new File(["some data"], "hello.txt", { type: "plain/txt" });
|
||||
const files = [ image, txt]
|
||||
|
||||
await SpecialPowers.spawn(window, [files], async files => {
|
||||
let filePicker = content.SpecialPowers.MockFilePicker;
|
||||
filePicker.init(content.browsingContext);
|
||||
let filePickerShow = new Promise(resolve => {
|
||||
filePicker.showCallback = () => {
|
||||
filePicker.setFiles(files);
|
||||
filePicker.returnValue = filePicker.returnOk;
|
||||
info("MockFilePicker shown, files set!");
|
||||
resolve();
|
||||
};
|
||||
});
|
||||
|
||||
let input = content.document.querySelector("input[type=file]");
|
||||
content.document.notifyUserGestureActivation();
|
||||
input.click();
|
||||
|
||||
return filePickerShow;
|
||||
});
|
||||
}
|
||||
|
||||
add_task(async function test_imageinput_telemetry() {
|
||||
let snapshot = await GleanTest.imageInputTelemetry.imageInput.testGetValue();
|
||||
is(snapshot, null, "Glean - Initially no event gathered!");
|
||||
|
||||
await openFilePicker(window);
|
||||
|
||||
snapshot = await GleanTest.imageInputTelemetry.imageInput.testGetValue();
|
||||
is(snapshot.length, 1, "Glean - One telemetry event gathered!");
|
||||
is(snapshot[0].name, "image_input", "Glean - Received correct event!");
|
||||
is(snapshot[0].extra.image_type, "image/jpg", "Glean - Event extra correct image type!");
|
||||
is(snapshot[0].extra.input_type, "FilePicker", "Glean - Event extra correct input type!");
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -11,6 +11,7 @@ JAR_MANIFESTS += ["jar.mn"]
|
||||
|
||||
DIRS += [
|
||||
"bouncetrackingprotection",
|
||||
"imageinputmetadatastripper",
|
||||
]
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
|
||||
@@ -50,6 +50,7 @@ gecko_metrics = [
|
||||
"services/common/metrics.yaml",
|
||||
"services/sync/modules/metrics.yaml",
|
||||
"toolkit/components/antitracking/bouncetrackingprotection/metrics.yaml",
|
||||
"toolkit/components/antitracking/imageinputmetadatastripper/metrics.yaml",
|
||||
"toolkit/components/antitracking/metrics.yaml",
|
||||
"toolkit/components/cookiebanners/metrics.yaml",
|
||||
"toolkit/components/downloads/metrics.yaml",
|
||||
|
||||
Reference in New Issue
Block a user