Bug 1372051 - Remove external media test source. r=maja_zf

MozReview-Commit-ID: 1cGOuAusmUx

--HG--
extra : rebase_source : 0aa62bec8d2aca2ea55c26d6cc0efc4ceec5a761
This commit is contained in:
Bryce Van Dyk 2017-06-12 10:32:15 +12:00
Родитель 39d53ac121
Коммит 73ab403d2f
57 изменённых файлов: 0 добавлений и 3414 удалений

4
dom/media/test/external/MANIFEST.in поставляемый
Просмотреть файл

@ -1,4 +0,0 @@
exclude MANIFEST.in
include requirements.txt
recursive-include external_media_harness *
recursive-include external_media_tests *

5
dom/media/test/external/README.md поставляемый
Просмотреть файл

@ -1,5 +0,0 @@
external-media-tests
===================
Documentation for this library has moved to https://developer.mozilla.org/en-US/docs/Mozilla/QA/external-media-tests.

3
dom/media/test/external/docs/.hgignore поставляемый
Просмотреть файл

@ -1,3 +0,0 @@
_build
_static
_templates

216
dom/media/test/external/docs/Makefile поставляемый
Просмотреть файл

@ -1,216 +0,0 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
# User-friendly check for sphinx-build
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
endif
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " applehelp to make an Apple Help Book"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " xml to make Docutils-native XML files"
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
@echo " coverage to run coverage check of the documentation (if enabled)"
.PHONY: clean
clean:
rm -rf $(BUILDDIR)/*
.PHONY: html
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
.PHONY: dirhtml
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
.PHONY: singlehtml
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
.PHONY: pickle
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
.PHONY: json
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
.PHONY: htmlhelp
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
.PHONY: qthelp
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/ExternalMediaTests.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/ExternalMediaTests.qhc"
.PHONY: applehelp
applehelp:
$(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
@echo
@echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
@echo "N.B. You won't be able to view it unless you put it in" \
"~/Library/Documentation/Help or install it in your application" \
"bundle."
.PHONY: devhelp
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/ExternalMediaTests"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/ExternalMediaTests"
@echo "# devhelp"
.PHONY: epub
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
.PHONY: latex
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
.PHONY: latexpdf
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
.PHONY: latexpdfja
latexpdfja:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through platex and dvipdfmx..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
.PHONY: text
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
.PHONY: man
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
.PHONY: texinfo
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
.PHONY: info
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
.PHONY: gettext
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
.PHONY: changes
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
.PHONY: linkcheck
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
.PHONY: doctest
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."
.PHONY: coverage
coverage:
$(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
@echo "Testing of coverage in the sources finished, look at the " \
"results in $(BUILDDIR)/coverage/python.txt."
.PHONY: xml
xml:
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
@echo
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
.PHONY: pseudoxml
pseudoxml:
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
@echo
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."

297
dom/media/test/external/docs/conf.py поставляемый
Просмотреть файл

@ -1,297 +0,0 @@
# -*- coding: utf-8 -*-
#
# External Media Tests documentation build configuration file, created by
# sphinx-quickstart on Tue Mar 15 15:58:18 2016.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys
import os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.viewcode',
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'External Media Tests'
copyright = u'2015-2016, Mozilla, Inc.'
author = u'Syd Polk and Maja Frydrychowicz'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = u'0.1'
# The full version, including alpha/beta/rc tags.
release = u'0.1'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all
# documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents.
#keep_warnings = False
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'default'
on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
if not on_rtd:
try:
import sphinx_rtd_theme
html_theme = 'sphinx_rtd_theme'
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
except ImportError:
pass
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (relative to this directory) to use as a favicon of
# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
#html_extra_path = []
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Language to be used for generating the HTML full-text search index.
# Sphinx supports the following languages:
# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr'
#html_search_language = 'en'
# A dictionary with options for the search language support, empty by default.
# Now only 'ja' uses this config value
#html_search_options = {'type': 'default'}
# The name of a javascript file (relative to the configuration directory) that
# implements a search results scorer. If empty, the default will be used.
#html_search_scorer = 'scorer.js'
# Output file base name for HTML help builder.
htmlhelp_basename = 'ExternalMediaTestsdoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
# Latex figure (float) alignment
#'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'ExternalMediaTests.tex', u'External Media Tests Documentation',
u'Syd Polk and Maja Frydrychowicz', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'externalmediatests', u'External Media Tests Documentation',
[author], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'ExternalMediaTests', u'External Media Tests Documentation',
author, 'ExternalMediaTests', 'One line description of project.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False

Просмотреть файл

@ -1,19 +0,0 @@
external_media_harness package
==============================
Test case classes for use in video tests
external_media_harness.testcase module
--------------------------------------
.. autoclass:: external_media_harness.testcase.MediaTestCase
:members:
:show-inheritance:
.. autoclass:: external_media_harness.testcase.NetworkBandwidthTestCase
:members:
:show-inheritance:
.. autoclass:: external_media_harness.testcase.VideoPlaybackTestsMixin
:members:
:show-inheritance:

Просмотреть файл

@ -1,27 +0,0 @@
VideoPuppeteer
==============
video_puppeteer.VideoPuppeteer
------------------------------
.. autoclass:: external_media_tests.media_utils.video_puppeteer.VideoPuppeteer
:members:
:show-inheritance:
video_puppeteer.VideoException
------------------------------
.. autoexception:: external_media_tests.media_utils.video_puppeteer.VideoException
video_puppeteer.playback_started
--------------------------------
.. autofunction:: external_media_tests.media_utils.video_puppeteer.playback_started
video_puppeteer.playback_done
-----------------------------
.. autofunction:: external_media_tests.media_utils.video_puppeteer.playback_done

Просмотреть файл

@ -1,26 +0,0 @@
YoutubePuppeteer
================
youtube_puppeteer.YouTubePuppeteer
----------------------------------
.. autoclass:: external_media_tests.media_utils.youtube_puppeteer.YouTubePuppeteer
:members:
:show-inheritance:
youtube_puppeteer.playback_started
----------------------------------
.. autofunction:: external_media_tests.media_utils.youtube_puppeteer.playback_started
youtube_puppeteer.playback_done
-------------------------------
.. autofunction:: external_media_tests.media_utils.youtube_puppeteer.playback_done
youtbue_puppeteer.wait_for_almost_done
--------------------------------------
.. autofunction:: external_media_tests.media_utils.youtube_puppeteer.wait_for_almost_done

Просмотреть файл

@ -1,26 +0,0 @@
external_media_tests package
============================
This document highlights the utility classes for tests. In general, the indvidiual tests are not documented here.
Test pacakges
-------------
.. toctree::
external_media_tests.media_tests.video_puppeteer
external_media_tests.media_tests.youtube_puppeteer
external_media_tests.utils.verbose_until
----------------------------------------
.. autofunction:: external_media_tests.utils.verbose_until
external_media_tests.utils.save_memory_report
---------------------------------------------
.. autofunction:: external_media_tests.utils.save_memory_report

33
dom/media/test/external/docs/index.rst поставляемый
Просмотреть файл

@ -1,33 +0,0 @@
.. py:currentmodule:: external_media_tests
External Media Tests
====================
External Media Tests is a library built on top of `Firefox Puppeter`_ and the `Marionette python client`_. It is designed to test playback of video elements embedded in web pages, independent of vendor. Using this library, you can write tests which play, pause, and stop videos, as well as inspect properties such as currentTime().
.. _Marionette python client: http://marionette-client.readthedocs.org/en/latest
.. _Firefox Puppeter: http://firefox-puppeteer.readthedocs.org/en/latest/
Installation
------------
External Media Tests lives in `External Media Tests Source`_. Documentation for installation and usage lives on `External Media Tests`_; this documentation is API documentation for the various pieces of the test library.
.. _External Media Tests Source: https://hg.mozilla.org/dom/media/test/external
.. _External Media Tests: https://developer.mozilla.org/en-US/docs/Mozilla/QA/external-media-tests
Contents
--------
.. toctree::
external_media_harness
external_media_tests
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

263
dom/media/test/external/docs/make.bat поставляемый
Просмотреть файл

@ -1,263 +0,0 @@
@ECHO OFF
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set BUILDDIR=_build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
set I18NSPHINXOPTS=%SPHINXOPTS% .
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^<target^>` where ^<target^> is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. singlehtml to make a single large HTML file
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. devhelp to make HTML files and a Devhelp project
echo. epub to make an epub
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. text to make text files
echo. man to make manual pages
echo. texinfo to make Texinfo files
echo. gettext to make PO message catalogs
echo. changes to make an overview over all changed/added/deprecated items
echo. xml to make Docutils-native XML files
echo. pseudoxml to make pseudoxml-XML files for display purposes
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
echo. coverage to run coverage check of the documentation if enabled
goto end
)
if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\*
goto end
)
REM Check if sphinx-build is available and fallback to Python version if any
%SPHINXBUILD% 1>NUL 2>NUL
if errorlevel 9009 goto sphinx_python
goto sphinx_ok
:sphinx_python
set SPHINXBUILD=python -m sphinx.__init__
%SPHINXBUILD% 2> nul
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
:sphinx_ok
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "singlehtml" (
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\ExternalMediaTests.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\ExternalMediaTests.ghc
goto end
)
if "%1" == "devhelp" (
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished.
goto end
)
if "%1" == "epub" (
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The epub file is in %BUILDDIR%/epub.
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
if errorlevel 1 exit /b 1
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "latexpdf" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
cd %BUILDDIR%/latex
make all-pdf
cd %~dp0
echo.
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "latexpdfja" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
cd %BUILDDIR%/latex
make all-pdf-ja
cd %~dp0
echo.
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "text" (
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The text files are in %BUILDDIR%/text.
goto end
)
if "%1" == "man" (
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The manual pages are in %BUILDDIR%/man.
goto end
)
if "%1" == "texinfo" (
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
goto end
)
if "%1" == "gettext" (
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
if errorlevel 1 exit /b 1
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
if errorlevel 1 exit /b 1
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
if errorlevel 1 exit /b 1
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
if "%1" == "coverage" (
%SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage
if errorlevel 1 exit /b 1
echo.
echo.Testing of coverage in the sources finished, look at the ^
results in %BUILDDIR%/coverage/python.txt.
goto end
)
if "%1" == "xml" (
%SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The XML files are in %BUILDDIR%/xml.
goto end
)
if "%1" == "pseudoxml" (
%SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
goto end
)
:end

Просмотреть файл

@ -1,5 +0,0 @@
# 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/.
from runtests import cli

Просмотреть файл

@ -1,103 +0,0 @@
# 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/.
import os
import sys
import mozlog
from manifestparser import read_ini
from marionette_harness import (
BaseMarionetteTestRunner,
BaseMarionetteArguments,
BrowserMobProxyArguments,
)
from marionette_harness.runtests import MarionetteHarness, cli as mn_cli
import external_media_tests
from testcase import MediaTestCase
from external_media_tests.media_utils.video_puppeteer import debug_script
class MediaTestArgumentsBase(object):
name = 'Firefox Media Tests'
args = [
[['--urls'], {
'help': 'ini file of urls to make available to all tests',
'default': os.path.join(external_media_tests.urls, 'default.ini'),
}],
]
def verify_usage_handler(self, args):
if args.urls:
if not os.path.isfile(args.urls):
raise ValueError('--urls must provide a path to an ini file')
else:
path = os.path.abspath(args.urls)
args.video_urls = MediaTestArgumentsBase.get_urls(path)
if not args.video_urls:
raise ValueError('list of video URLs cannot be empty')
def parse_args_handler(self, args):
if not args.tests:
args.tests = [external_media_tests.manifest]
@staticmethod
def get_urls(manifest):
with open(manifest, 'r'):
return [line[0] for line in read_ini(manifest)]
class MediaTestArguments(BaseMarionetteArguments):
def __init__(self, **kwargs):
BaseMarionetteArguments.__init__(self, **kwargs)
self.register_argument_container(MediaTestArgumentsBase())
self.register_argument_container(BrowserMobProxyArguments())
class MediaTestRunner(BaseMarionetteTestRunner):
def __init__(self, **kwargs):
BaseMarionetteTestRunner.__init__(self, **kwargs)
if not self.server_root:
self.server_root = external_media_tests.resources
# pick up prefs from marionette_driver.geckoinstance.DesktopInstance
self.app = 'fxdesktop'
self.test_handlers = [MediaTestCase]
# Used in HTML report (--log-html)
def gather_media_debug(test, status):
rv = {}
marionette = test._marionette_weakref()
if marionette.session is not None:
try:
with marionette.using_context(marionette.CONTEXT_CHROME):
debug_lines = marionette.execute_script(debug_script)
if debug_lines:
name = 'mozMediaSourceObject.mozDebugReaderData'
rv[name] = '\n'.join(debug_lines)
else:
logger = mozlog.get_default_logger()
logger.info('No data available about '
'mozMediaSourceObject')
except:
logger = mozlog.get_default_logger()
logger.warning('Failed to gather test failure media debug',
exc_info=True)
return rv
self.result_callbacks.append(gather_media_debug)
class FirefoxMediaHarness(MarionetteHarness):
def parse_args(self, *args, **kwargs):
return MarionetteHarness.parse_args(self, {'mach': sys.stdout})
def cli():
mn_cli(MediaTestRunner, MediaTestArguments, FirefoxMediaHarness)
if __name__ == '__main__':
cli()

Просмотреть файл

@ -1,335 +0,0 @@
# 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/.
import re
import os
from marionette_driver import Wait
from marionette_driver.errors import TimeoutException
from marionette_harness import (
BrowserMobProxyTestCaseMixin,
MarionetteTestCase,
Marionette,
SkipTest,
)
from firefox_puppeteer import PuppeteerMixin
from external_media_tests.utils import (timestamp_now, verbose_until)
from external_media_tests.media_utils.video_puppeteer import (
VideoException,
VideoPuppeteer
)
class MediaTestCase(PuppeteerMixin, MarionetteTestCase):
"""
Necessary methods for MSE playback
:param video_urls: Urls you are going to play as part of the tests.
"""
def __init__(self, *args, **kwargs):
self.video_urls = kwargs.pop('video_urls', False)
super(MediaTestCase, self).__init__(*args, **kwargs)
def save_screenshot(self):
"""
Make a screenshot of the window that is currently playing the video
element.
"""
screenshot_dir = os.path.join(self.marionette.instance.workspace or '',
'screenshots')
filename = ''.join([self.id().replace(' ', '-'),
'_',
str(timestamp_now()),
'.png'])
path = os.path.join(screenshot_dir, filename)
if not os.path.exists(screenshot_dir):
os.makedirs(screenshot_dir)
with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
img_data = self.marionette.screenshot()
with open(path, 'wb') as f:
f.write(img_data.decode('base64'))
self.logger.info('Screenshot saved in {}'.format(os.path.abspath(path)))
def log_video_debug_lines(self, video):
"""
Log the debugging information that Firefox provides for video elements.
"""
with self.marionette.using_context(Marionette.CONTEXT_CHROME):
debug_lines = video.get_debug_lines()
if debug_lines:
self.logger.info('\n'.join(debug_lines))
def run_playback(self, video):
"""
Play the video all of the way through, or for the requested duration,
whichever comes first. Raises if the video stalls for too long.
:param video: VideoPuppeteer instance to play.
"""
with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
self.logger.info(video.test_url)
try:
verbose_until(Wait(video, interval=video.interval,
timeout=video.expected_duration * 1.3 +
video.stall_wait_time),
video, VideoPuppeteer.playback_done)
except VideoException as e:
raise self.failureException(e)
def check_playback_starts(self, video):
"""
Check to see if a given video will start. Raises if the video does not
start.
:param video: VideoPuppeteer instance to play.
"""
with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
self.logger.info(video.test_url)
try:
verbose_until(Wait(video, timeout=video.timeout),
video, VideoPuppeteer.playback_started)
except TimeoutException as e:
raise self.failureException(e)
def skipTest(self, reason):
"""
Skip this test.
Skip with marionette.marionette_test import SkipTest so that it
gets recognized a skip in marionette.marionette_test.CommonTestCase.run
"""
raise SkipTest(reason)
class NetworkBandwidthTestCase(MediaTestCase):
"""
Test MSE playback while network bandwidth is limited. Uses browsermobproxy
(https://bmp.lightbody.net/). Please see
https://developer.mozilla.org/en-US/docs/Mozilla/QA/external-media-tests
for more information on setting up browsermob_proxy.
"""
def __init__(self, *args, **kwargs):
super(NetworkBandwidthTestCase, self).__init__(*args, **kwargs)
BrowserMobProxyTestCaseMixin.__init__(self, *args, **kwargs)
self.proxy = None
def setUp(self):
super(NetworkBandwidthTestCase, self).setUp()
BrowserMobProxyTestCaseMixin.setUp(self)
self.proxy = self.create_browsermob_proxy()
def tearDown(self):
super(NetworkBandwidthTestCase, self).tearDown()
BrowserMobProxyTestCaseMixin.tearDown(self)
self.proxy = None
def run_videos(self, timeout=60):
"""
Run each of the videos in the video list. Raises if something goes
wrong in playback.
"""
with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
for url in self.video_urls:
video = VideoPuppeteer(self.marionette, url, stall_wait_time=60,
set_duration=60, timeout=timeout)
self.run_playback(video)
class VideoPlaybackTestsMixin(object):
"""
Test MSE playback in HTML5 video element.
These tests should pass on any site where a single video element plays
upon loading and is uninterrupted (by ads, for example).
This tests both starting videos and performing partial playback at one
minute each, and is the test that should be run frequently in automation.
"""
def test_playback_starts(self):
"""
Test to make sure that playback of the video element starts for each
video.
"""
with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
for url in self.video_urls:
try:
video = VideoPuppeteer(self.marionette, url, timeout=60)
# Second playback_started check in case video._start_time
# is not 0
self.check_playback_starts(video)
video.pause()
except TimeoutException as e:
raise self.failureException(e)
def test_video_playback_partial(self):
"""
Test to make sure that playback of 60 seconds works for each video.
"""
with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
for url in self.video_urls:
video = VideoPuppeteer(self.marionette, url,
stall_wait_time=10,
set_duration=60)
self.run_playback(video)
class NetworkBandwidthTestsMixin(object):
"""
Test video urls with various bandwidth settings.
"""
def test_playback_limiting_bandwidth_250(self):
self.proxy.limits({'downstream_kbps': 250})
self.run_videos(timeout=120)
def test_playback_limiting_bandwidth_500(self):
self.proxy.limits({'downstream_kbps': 500})
self.run_videos(timeout=120)
def test_playback_limiting_bandwidth_1000(self):
self.proxy.limits({'downstream_kbps': 1000})
self.run_videos(timeout=120)
reset_widevine_gmp_script = """
navigator.requestMediaKeySystemAccess('com.widevine.alpha',
[{initDataTypes: ['cenc']}]).then(
function(access) {
marionetteScriptFinished('success');
},
function(ex) {
marionetteScriptFinished(ex);
}
);
"""
class EMESetupMixin(object):
"""
An object that needs to use the Widevine GMP system must inherit
from this class, and then call check_eme_system() to insure that everything
is setup correctly.
"""
version_needs_reset = True
def check_eme_system(self):
"""
Download the most current version of the Widevine GMP
Plugins. Verify that all MSE and EME prefs are set correctly. Raises
if things are not OK.
"""
self.set_eme_prefs()
self.reset_GMP_version()
assert(self.check_eme_prefs())
def set_eme_prefs(self):
with self.marionette.using_context(Marionette.CONTEXT_CHROME):
# https://bugzilla.mozilla.org/show_bug.cgi?id=1187471#c28
# 2015-09-28 cpearce says this is no longer necessary, but in case
# we are working with older firefoxes...
self.marionette.set_pref('media.gmp.trial-create.enabled', False)
def reset_GMP_version(self):
if EMESetupMixin.version_needs_reset:
with self.marionette.using_context(Marionette.CONTEXT_CHROME):
if self.marionette.get_pref('media.gmp-widevinecdm.version'):
self.marionette.reset_pref('media.gmp-widevinecdm.version')
with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
widevine_result = self.marionette.execute_async_script(
reset_widevine_gmp_script,
script_timeout=60000)
if not widevine_result == 'success':
raise VideoException(
'ERROR: Resetting Widevine GMP failed {}'
.format(widevine_result))
EMESetupMixin.version_needs_reset = False
def check_and_log_boolean_pref(self, pref_name, expected_value):
with self.marionette.using_context(Marionette.CONTEXT_CHROME):
pref_value = self.marionette.get_pref(pref_name)
if pref_value is None:
self.logger.info('Pref {} has no value.'.format(pref_name))
return False
else:
self.logger.info('Pref {} = {}'.format(pref_name, pref_value))
if pref_value != expected_value:
self.logger.info('Pref {} has unexpected value.'
.format(pref_name))
return False
return True
def check_and_log_integer_pref(self, pref_name, minimum_value=0):
with self.marionette.using_context(Marionette.CONTEXT_CHROME):
pref_value = self.marionette.get_pref(pref_name)
if pref_value is None:
self.logger.info('Pref {} has no value.'.format(pref_name))
return False
else:
self.logger.info('Pref {} = {}'.format(pref_name, pref_value))
match = re.search('^\d+$', pref_value)
if not match:
self.logger.info('Pref {} is not an integer'
.format(pref_name))
return False
return pref_value >= minimum_value
def chceck_and_log_version_string_pref(self, pref_name, minimum_value='0'):
"""
Compare a pref made up of integers separated by stops .s, with a
version string of the same format. The number of integers in each
string does not need to match. The comparison is done by converting
each to an integer array and comparing those. Both version strings
must be made up of only integers, or this method will raise an
unhandled exception of type ValueError when the conversion to int
fails.
"""
with self.marionette.using_context(Marionette.CONTEXT_CHROME):
pref_value = self.marionette.get_pref(pref_name)
if pref_value is None:
self.logger.info('Pref {} has no value.'.format(pref_name))
return False
else:
self.logger.info('Pref {} = {}'.format(pref_name, pref_value))
match = re.search('^\d(.\d+)*$', pref_value)
if not match:
self.logger.info('Pref {} is not a version string'
.format(pref_name))
return False
pref_ints = [int(n) for n in pref_value.split('.')]
minumum_ints = [int(n) for n in minimum_value.split('.')]
return pref_ints >= minumum_ints
def check_eme_prefs(self):
with self.marionette.using_context(Marionette.CONTEXT_CHROME):
return all([
self.check_and_log_boolean_pref(
'media.mediasource.enabled', True),
self.check_and_log_boolean_pref(
'media.eme.enabled', True),
self.check_and_log_boolean_pref(
'media.mediasource.mp4.enabled', True),
self.check_and_log_boolean_pref(
'media.gmp-widevinecdm.enabled', True),
self.chceck_and_log_version_string_pref(
'media.gmp-widevinecdm.version', '1.0.0.0')
])

Просмотреть файл

@ -1,10 +0,0 @@
# 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/.
import os
root = os.path.abspath(os.path.dirname(__file__))
manifest = os.path.join(root, 'manifest.ini')
resources = os.path.join(root, 'resources')
urls = os.path.join(root, 'urls')

Просмотреть файл

@ -1 +0,0 @@
[include:playback/manifest.ini]

Просмотреть файл

Просмотреть файл

@ -1,192 +0,0 @@
# 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/.
from collections import namedtuple
from time import clock
from marionette_driver import By, expected, Wait
from marionette_harness import Marionette
from video_puppeteer import VideoPuppeteer, TimeRanges
from external_media_tests.utils import verbose_until
class TwitchPuppeteer(VideoPuppeteer):
"""
Wrapper around a Twitch .player element.
Note that the twitch stream needs to be playing for the puppeteer to work
correctly. Since twitch will load a player element for streams that are
not currently playing, the puppeteer will still detect a player element,
however the time ranges will not increase, and tests will fail.
Compared to video puppeteer, this class has the benefit of accessing the
twitch player element as well as the video element. The twitch player
element reports additional information to aid in testing -- such as if an
ad is playing. However, the attributes of this element do not appear to be
documented, which may leave them vulnerable to undocumented changes in
behaviour.
"""
_player_var_script = (
'var player_data_screen = '
'arguments[1].wrappedJSObject.getAttribute("data-screen");'
)
"""
A string containing JS that will assign player state to
variables. This is similar to `_video_var_script` from
`VideoPuppeteer`. See `_video_var_script` for more information on the
motivation for this method.
"""
def __init__(self, marionette, url, autostart=True,
set_duration=10.0, **kwargs):
self.player = None
self._last_seen_player_state = None
super(TwitchPuppeteer,
self).__init__(marionette, url, set_duration=set_duration,
autostart=False, **kwargs)
wait = Wait(self.marionette, timeout=30)
with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
verbose_until(wait, self,
expected.element_present(By.CLASS_NAME,
'player'))
self.player = self.marionette.find_element(By.CLASS_NAME,
'player')
self.marionette.execute_script("log('.player "
"element obtained');")
if autostart:
self.start()
def _update_expected_duration(self):
if 0 < self._set_duration:
self.expected_duration = self._set_duration
else:
# If we don't have a set duration we don't know how long is left
# in the stream.
self.expected_duration = float("inf")
def _calculate_remaining_time(self, played_ranges):
"""
Override of video_puppeteer's _calculate_remaining_time. See that
method for primary documentation.
This override is in place to adjust how remaining time is handled.
Twitch ads can cause small stutters which result in multiple played
ranges, despite no seeks being initiated by the tests. As such, when
calculating the remaining time, the start time is the min of all
played start times, and the end time is the max of played end times.
This being sensible behaviour relies on the tests not attempting seeks.
:param played_ranges: A TimeRanges object containing played ranges.
:return: The remaining time expected for this puppeteer.
"""
min_played_time = min(
[played_ranges.start(i) for i in range(0, played_ranges.length)])
max_played_time = max(
[played_ranges.end(i) for i in range(0, played_ranges.length)])
played_duration = max_played_time - min_played_time
return self.expected_duration - played_duration
def _execute_twitch_script(self, script):
"""
Execute JS script in content context with access to video element and
Twitch .player element.
:param script: script to be executed.
:return: value returned by script
"""
with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
return self.marionette.execute_script(script,
script_args=[self.video,
self.player])
@staticmethod
def _twitch_state_named_tuple():
"""
Create a named tuple class that can be used to store state snapshots
of the wrapped twitch player. The fields in the tuple should be used
as follows:
player_data_screen: the current displayed content, appears to be set
to nothing if no ad has been played, 'advertisement' during ad
playback, and 'content' following ad playback.
"""
return namedtuple('player_state_info',
['player_data_screen'])
def _create_player_state_info(self, **player_state_info_kwargs):
"""
Create an instance of the state info named tuple. This function
expects a dictionary containing the following keys:
player_data_screen.
For more information on the above keys and their values see
`_twitch_state_named_tuple`.
:return: A named tuple 'player_state_info', derived from arguments and
state information from the puppeteer.
"""
# Create player snapshot
state_info = self._twitch_state_named_tuple()
return state_info(**player_state_info_kwargs)
@property
def _fetch_state_script(self):
if not self._fetch_state_script_string:
self._fetch_state_script_string = (
self._video_var_script +
self._player_var_script +
'return ['
'baseURI,'
'currentTime,'
'duration,'
'[buffered.length, bufferedRanges],'
'[played.length, playedRanges],'
'totalFrames,'
'droppedFrames,'
'corruptedFrames,'
'player_data_screen];')
return self._fetch_state_script_string
def _refresh_state(self):
"""
Refresh the snapshot of the underlying video and player state. We do
this all in one so that the state doesn't change in between queries.
We also store information thouat can be derived from the snapshotted
information, such as lag. This is stored in the last seen state to
stress that it's based on the snapshot.
"""
values = self._execute_twitch_script(self._fetch_state_script)
video_keys = ['base_uri', 'current_time', 'duration',
'raw_buffered_ranges', 'raw_played_ranges',
'total_frames', 'dropped_frames', 'corrupted_frames']
player_keys = ['player_data_screen']
# Get video state
self._last_seen_video_state = (
self._create_video_state_info(**dict(
zip(video_keys, values[:len(video_keys)]))))
# Get player state
self._last_seen_player_state = (
self._create_player_state_info(**dict(
zip(player_keys, values[-len(player_keys):]))))
def __str__(self):
messages = [super(TwitchPuppeteer, self).__str__()]
if not self.player:
messages += ['\t.player: None']
return '\n'.join(messages)
if not self._last_seen_player_state:
messages += ['\t.player: No last seen state']
return '\n'.join(messages)
messages += ['.player: {']
for field in self._last_seen_player_state._fields:
# For compatibility with different test environments we force
# ascii
field_ascii = (
unicode(getattr(self._last_seen_player_state, field)).encode(
'ascii', 'replace'))
messages += [('\t{}: {}'.format(field, field_ascii))]
messages += '}'
return '\n'.join(messages)

Просмотреть файл

@ -1,459 +0,0 @@
# 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/.
from collections import namedtuple
from time import clock, sleep
from marionette_driver import By, expected, Wait
from marionette_harness import Marionette
from external_media_tests.utils import verbose_until
# Adapted from
# https://github.com/gavinsharp/aboutmedia/blob/master/chrome/content/aboutmedia.xhtml
debug_script = """
var mainWindow = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIWebNavigation)
.QueryInterface(Components.interfaces.nsIDocShellTreeItem)
.rootTreeItem
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindow);
var tabbrowser = mainWindow.gBrowser;
for (var i=0; i < tabbrowser.browsers.length; ++i) {
var b = tabbrowser.getBrowserAtIndex(i);
var media = b.contentDocumentAsCPOW.getElementsByTagName('video');
for (var j=0; j < media.length; ++j) {
var ms = media[j].mozMediaSourceObject;
if (ms) {
debugLines = ms.mozDebugReaderData.split(\"\\n\");
return debugLines;
}
}
}"""
class VideoPuppeteer(object):
"""
Wrapper to control and introspect HTML5 video elements.
A note about properties like current_time and duration:
These describe whatever stream is playing when the state is checked.
It is possible that many different streams are dynamically spliced
together, so the video stream that is currently playing might be the main
video or it might be something else, like an ad, for example.
:param marionette: The marionette instance this runs in.
:param url: the URL of the page containing the video element.
:param video_selector: the selector of the element that we want to watch.
This is set by default to 'video', which is what most sites use, but
others should work.
:param interval: The polling interval that is used to check progress.
:param set_duration: When set to >0, the polling and checking will stop at
the number of seconds specified. Otherwise, this will stop at the end
of the video.
:param stall_wait_time: The amount of time to wait to see if a stall has
cleared. If 0, do not check for stalls.
:param timeout: The amount of time to wait until the video starts.
"""
_video_var_script = (
'var video = arguments[0];'
'var baseURI = video.baseURI;'
'var currentTime = video.wrappedJSObject.currentTime;'
'var duration = video.wrappedJSObject.duration;'
'var buffered = video.wrappedJSObject.buffered;'
'var bufferedRanges = [];'
'for (var i = 0; i < buffered.length; i++) {'
'bufferedRanges.push([buffered.start(i), buffered.end(i)]);'
'}'
'var played = video.wrappedJSObject.played;'
'var playedRanges = [];'
'for (var i = 0; i < played.length; i++) {'
'playedRanges.push([played.start(i), played.end(i)]);'
'}'
'var totalFrames = '
'video.getVideoPlaybackQuality()["totalVideoFrames"];'
'var droppedFrames = '
'video.getVideoPlaybackQuality()["droppedVideoFrames"];'
'var corruptedFrames = '
'video.getVideoPlaybackQuality()["corruptedVideoFrames"];'
)
"""
A string containing JS that assigns video state to variables.
The purpose of this string script is to be appended to by this and
any inheriting classes to return these and other variables. In the case
of an inheriting class the script can be added to in order to fetch
further relevant variables -- keep in mind we only want one script
execution to prevent races, so it wouldn't do to have child classes
run this script then their own, as there is potential for lag in
between.
This script assigns a subset of the vars used later by the
`_video_state_named_tuple` function. Please see that function's
documentation for further information on these variables.
"""
def __init__(self, marionette, url, video_selector='video', interval=1,
set_duration=0, stall_wait_time=0, timeout=60,
autostart=True):
self.marionette = marionette
self.test_url = url
self.interval = interval
self.stall_wait_time = stall_wait_time
self.timeout = timeout
self._set_duration = set_duration
self.video = None
self.expected_duration = 0
self._first_seen_time = 0
self._first_seen_wall_time = 0
self._fetch_state_script_string = None
self._last_seen_video_state = None
wait = Wait(self.marionette, timeout=self.timeout)
with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
self.marionette.navigate(self.test_url)
print('URL: {}'.format(self.test_url))
verbose_until(wait, self,
expected.element_present(By.TAG_NAME, 'video'))
videos_found = self.marionette.find_elements(By.CSS_SELECTOR,
video_selector)
if len(videos_found) > 1:
print('{}: multiple video elements found. Using first.'.format(type(self).__name__))
if len(videos_found) <= 0:
print('{}: no video elements found.'.format(type(self).__name__))
return
self.video = videos_found[0]
print('video element obtained')
if autostart:
self.start()
def start(self):
# To get an accurate expected_duration, playback must have started
self._refresh_state()
wait = Wait(self, timeout=self.timeout)
verbose_until(wait, self, VideoPuppeteer.playback_started,
"Check if video has played some range")
self._first_seen_time = self._last_seen_video_state.current_time
self._first_seen_wall_time = clock()
self._update_expected_duration()
def get_debug_lines(self):
"""
Get Firefox internal debugging for the video element.
:return: A text string that has Firefox-internal debugging information.
"""
with self.marionette.using_context('chrome'):
debug_lines = self.marionette.execute_script(debug_script)
return debug_lines
def play(self):
"""
Tell the video element to Play.
"""
self._execute_video_script('arguments[0].wrappedJSObject.play();')
def pause(self):
"""
Tell the video element to Pause.
"""
self._execute_video_script('arguments[0].wrappedJSObject.pause();')
def playback_started(self):
"""
Determine if video has started
:param self: The VideoPuppeteer instance that we are interested in.
:return: True if is playing; False otherwise
"""
self._refresh_state()
try:
played_ranges = self._last_seen_video_state.played
return (
played_ranges.length > 0 and
played_ranges.start(0) < played_ranges.end(0) and
played_ranges.end(0) > 0.0
)
except Exception as e:
print ('Got exception {}'.format(e))
return False
def playback_done(self):
"""
If we are near the end and there is still a video element, then
we are essentially done. If this happens to be last time we are polled
before the video ends, we won't get another chance.
:param self: The VideoPuppeteer instance that we are interested in.
:return: True if we are close enough to the end of playback; False
otherwise.
"""
self._refresh_state()
if self._last_seen_video_state.remaining_time < self.interval:
return True
# Check to see if the video has stalled. Accumulate the amount of lag
# since the video started, and if it is too high, then raise.
if (self.stall_wait_time and
self._last_seen_video_state.lag > self.stall_wait_time):
raise VideoException('Video {} stalled.\n{}'
.format(self._last_seen_video_state.base_uri,
self))
# We are cruising, so we are not done.
return False
def _update_expected_duration(self):
"""
Update the duration of the target video at self.test_url (in seconds).
This is based on the last seen state, so the state should be,
refreshed at least once before this is called.
expected_duration represents the following: how long do we expect
playback to last before we consider the video to be 'complete'?
If we only want to play the first n seconds of the video,
expected_duration is set to n.
"""
# self._last_seen_video_state.duration is the duration of whatever was
# playing when the state was checked. In this case, we assume the video
# element always shows the same stream throughout playback (i.e. the
# are no ads spliced into the main video, for example), so
# self._last_seen_video_state.duration is the duration of the main
# video.
video_duration = self._last_seen_video_state.duration
# Do our best to figure out where the video started playing
played_ranges = self._last_seen_video_state.played
if played_ranges.length > 0:
# If we have a range we should only have on continuous range
assert played_ranges.length == 1
start_position = played_ranges.start(0)
else:
# If we don't have a range we should have a current time
start_position = self._first_seen_time
# In case video starts at t > 0, adjust target time partial playback
remaining_video = video_duration - start_position
if 0 < self._set_duration < remaining_video:
self.expected_duration = self._set_duration
else:
self.expected_duration = remaining_video
def _calculate_remaining_time(self, played_ranges):
"""
Calculate the remaining time expected for this puppeteer. Note that
this method accepts a played range rather than reading from the last
seen state. This is so when building a new state we are not forced to
read from the last one, and can use the played ranges associated with
that new state to calculate the remaining time.
:param played_ranges: A TimeRanges object containing played ranges.
For video_puppeteer we expect a single played range, but overrides may
expect different behaviour.
:return: The remaining time expected for this puppeteer.
"""
played_duration = played_ranges.end(0) - played_ranges.start(0)
return self.expected_duration - played_duration
@staticmethod
def _video_state_named_tuple():
"""
Create a named tuple class that can be used to store state snapshots
of the wrapped element. The fields in the tuple should be used as
follows:
base_uri: the baseURI attribute of the wrapped element.
current_time: the current time of the wrapped element.
duration: the duration of the wrapped element.
buffered: the buffered ranges of the wrapped element. In its raw form
this is as a list where the first element is the length and the second
element is a list of 2 item lists, where each two items are a buffered
range. Once assigned to the tuple this data should be wrapped in the
TimeRanges class.
played: the played ranges of the wrapped element. In its raw form this
is as a list where the first element is the length and the second
element is a list of 2 item lists, where each two items are a played
range. Once assigned to the tuple this data should be wrapped in the
TimeRanges class.
lag: the difference in real world time and wrapped element time.
Calculated as real world time passed - element time passed.
totalFrames: number of total frames for the wrapped element
droppedFrames: number of dropped frames for the wrapped element.
corruptedFrames: number of corrupted frames for the wrapped.
video_src: the src attribute of the wrapped element.
:return: A 'video_state_info' named tuple class.
"""
return namedtuple('video_state_info',
['base_uri',
'current_time',
'duration',
'remaining_time',
'buffered',
'played',
'lag',
'total_frames',
'dropped_frames',
'corrupted_frames',
'video_src'])
def _create_video_state_info(self, **video_state_info_kwargs):
"""
Create an instance of the video_state_info named tuple. This function
expects a dictionary populated with the following keys: current_time,
duration, raw_played_ranges, total_frames, dropped_frames, and
corrupted_frames.
Aside from raw_played_ranges, see `_video_state_named_tuple` for more
information on the above keys and values. For raw_played_ranges a
list is expected that can be consumed to make a TimeRanges object.
:return: A named tuple 'video_state_info' derived from arguments and
state information from the puppeteer.
"""
raw_buffered_ranges = video_state_info_kwargs['raw_buffered_ranges']
raw_played_ranges = video_state_info_kwargs['raw_played_ranges']
# Remove raw ranges from dict as they are not used in the final named
# tuple and will provide an unexpected kwarg if kept.
del video_state_info_kwargs['raw_buffered_ranges']
del video_state_info_kwargs['raw_played_ranges']
# Create buffered ranges
video_state_info_kwargs['buffered'] = (
TimeRanges(raw_buffered_ranges[0], raw_buffered_ranges[1]))
# Create played ranges
video_state_info_kwargs['played'] = (
TimeRanges(raw_played_ranges[0], raw_played_ranges[1]))
# Calculate elapsed times
elapsed_current_time = (video_state_info_kwargs['current_time'] -
self._first_seen_time)
elapsed_wall_time = clock() - self._first_seen_wall_time
# Calculate lag
video_state_info_kwargs['lag'] = (
elapsed_wall_time - elapsed_current_time)
# Calculate remaining time
played_ranages = video_state_info_kwargs['played']
if played_ranages.length > 0:
video_state_info_kwargs['remaining_time'] = (
self._calculate_remaining_time(played_ranages))
else:
# No playback has happened yet, remaining time is duration
video_state_info_kwargs['remaining_time'] = self.expected_duration
# Fetch non time critical source information
video_state_info_kwargs['video_src'] = self.video.get_attribute('src')
# Create video state snapshot
state_info = self._video_state_named_tuple()
return state_info(**video_state_info_kwargs)
@property
def _fetch_state_script(self):
if not self._fetch_state_script_string:
self._fetch_state_script_string = (
self._video_var_script +
'return ['
'baseURI,'
'currentTime,'
'duration,'
'[buffered.length, bufferedRanges],'
'[played.length, playedRanges],'
'totalFrames,'
'droppedFrames,'
'corruptedFrames];')
return self._fetch_state_script_string
def _refresh_state(self):
"""
Refresh the snapshot of the underlying video state. We do this all
in one so that the state doesn't change in between queries.
We also store information that can be derived from the snapshotted
information, such as lag. This is stored in the last seen state to
stress that it's based on the snapshot.
"""
keys = ['base_uri', 'current_time', 'duration', 'raw_buffered_ranges',
'raw_played_ranges', 'total_frames', 'dropped_frames',
'corrupted_frames']
values = self._execute_video_script(self._fetch_state_script)
self._last_seen_video_state = (
self._create_video_state_info(**dict(zip(keys, values))))
def _measure_progress(self):
self._refresh_state()
initial = self._last_seen_video_state.current_time
sleep(1)
self._refresh_state()
return self._last_seen_video_state.current_time - initial
def _execute_video_script(self, script):
"""
Execute JS script in content context with access to video element.
:param script: script to be executed
:return: value returned by script
"""
with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
return self.marionette.execute_script(script,
script_args=[self.video])
def __str__(self):
messages = ['{} - test url: {}: '
.format(type(self).__name__, self.test_url)]
if not self.video:
messages += ['\tvideo: None']
return '\n'.join(messages)
if not self._last_seen_video_state:
messages += ['\tvideo: No last seen state']
return '\n'.join(messages)
# Have video and state info
messages += [
'{',
'\t(video)'
]
messages += ['\tinterval: {}'.format(self.interval)]
messages += ['\texpected duration: {}'.format(self.expected_duration)]
messages += ['\tstall wait time: {}'.format(self.stall_wait_time)]
messages += ['\ttimeout: {}'.format(self.timeout)]
# Print each field on its own line
for field in self._last_seen_video_state._fields:
# For compatibility with different test environments we force ascii
field_ascii = (
unicode(getattr(self._last_seen_video_state, field))
.encode('ascii','replace'))
messages += [('\t{}: {}'.format(field, field_ascii))]
messages += '}'
return '\n'.join(messages)
class VideoException(Exception):
"""
Exception class to use for video-specific error processing.
"""
pass
class TimeRanges:
"""
Class to represent the TimeRanges data returned by played(). Exposes a
similar interface to the JavaScript TimeRanges object.
"""
def __init__(self, length, ranges):
# These should be the same,. Theoretically we don't need the length,
# but since this should be used to consume data coming back from
# JS exec, this is a valid sanity check.
assert length == len(ranges)
self.length = length
self.ranges = [(pair[0], pair[1]) for pair in ranges]
def __repr__(self):
return (
'TimeRanges: length: {}, ranges: {}'
.format(self.length, self.ranges)
)
def start(self, index):
return self.ranges[index][0]
def end(self, index):
return self.ranges[index][1]

Просмотреть файл

@ -1,490 +0,0 @@
# 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/.
import re
from collections import namedtuple
from json import loads
from time import sleep
from marionette_driver import By, expected, Wait
from marionette_driver.errors import TimeoutException, NoSuchElementException
from marionette_harness import Marionette
from video_puppeteer import VideoPuppeteer, VideoException
from external_media_tests.utils import verbose_until
class YouTubePuppeteer(VideoPuppeteer):
"""
Wrapper around a YouTube .html5-video-player element.
Can be used with youtube videos or youtube videos at embedded URLS. E.g.
both https://www.youtube.com/watch?v=AbAACm1IQE0 and
https://www.youtube.com/embed/AbAACm1IQE0 should work.
Using an embedded video has the advantage of not auto-playing more videos
while a test is running.
Compared to video puppeteer, this class has the benefit of accessing the
youtube player object as well as the video element. The YT player will
report information for the underlying video even if an add is playing (as
opposed to the video element behaviour, which will report on whatever
is play at the time of query), and can also report if an ad is playing.
Partial reference: https://developers.google.com/youtube/iframe_api_reference.
This reference is useful for site-specific features such as interacting
with ads, or accessing YouTube's debug data.
"""
_player_var_script = (
'var player_duration = arguments[1].wrappedJSObject.getDuration();'
'var player_current_time = '
'arguments[1].wrappedJSObject.getCurrentTime();'
'var player_playback_quality = '
'arguments[1].wrappedJSObject.getPlaybackQuality();'
'var player_movie_id = '
'arguments[1].wrappedJSObject.getVideoData()["video_id"];'
'var player_movie_title = '
'arguments[1].wrappedJSObject.getVideoData()["title"];'
'var player_url = '
'arguments[1].wrappedJSObject.getVideoUrl();'
'var player_state = '
'arguments[1].wrappedJSObject.getPlayerState();'
'var player_ad_state = arguments[1].wrappedJSObject.getAdState();'
'var player_breaks_count = '
'arguments[1].wrappedJSObject.getOption("ad", "breakscount");'
)
"""
A string containing JS that will assign player state to
variables. This is similar to `_video_var_script` from
`VideoPuppeteer`. See `_video_var_script` for more information on the
motivation for this method.
This script assigns a subset of the vars used later by the
`_yt_state_named_tuple` function. Please see that functions
documentation for further information on these variables.
"""
_yt_player_state = {
'UNSTARTED': -1,
'ENDED': 0,
'PLAYING': 1,
'PAUSED': 2,
'BUFFERING': 3,
'CUED': 5
}
_yt_player_state_name = {v: k for k, v in _yt_player_state.items()}
_time_pattern = re.compile('(?P<minute>\d+):(?P<second>\d+)')
def __init__(self, marionette, url, autostart=True, **kwargs):
self.player = None
self._last_seen_player_state = None
super(YouTubePuppeteer,
self).__init__(marionette, url,
video_selector='.html5-video-player video',
autostart=False,
**kwargs)
wait = Wait(self.marionette, timeout=30)
with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
verbose_until(wait, self,
expected.element_present(By.CLASS_NAME,
'html5-video-player'))
self.player = self.marionette.find_element(By.CLASS_NAME,
'html5-video-player')
print '.html5-video-player element obtained'
# When an ad is playing, self.player_duration indicates the duration
# of the spliced-in ad stream, not the duration of the main video, so
# we attempt to skip the ad first.
for attempt in range(5):
sleep(1)
self.process_ad()
if (self._last_seen_player_state.player_ad_inactive and
self._last_seen_video_state.duration and not
self._last_seen_player_state.player_buffering):
break
self._update_expected_duration()
if autostart:
self.start()
def player_play(self):
"""
Play via YouTube API.
"""
self._execute_yt_script('arguments[1].wrappedJSObject.playVideo();')
def player_pause(self):
"""
Pause via YouTube API.
"""
self._execute_yt_script('arguments[1].wrappedJSObject.pauseVideo();')
def _player_measure_progress(self):
"""
Determine player progress. Refreshes state.
:return: Playback progress in seconds via YouTube API with snapshots.
"""
self._refresh_state()
initial = self._last_seen_player_state.player_current_time
sleep(1)
self._refresh_state()
return self._last_seen_player_state.player_current_time - initial
def _get_player_debug_dict(self):
text = self._execute_yt_script('return arguments[1].'
'wrappedJSObject.getDebugText();')
if text:
try:
return loads(text)
except ValueError:
print 'Error loading JSON: DebugText'
def _execute_yt_script(self, script):
"""
Execute JS script in content context with access to video element and
YouTube .html5-video-player element.
:param script: script to be executed.
:return: value returned by script
"""
with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
return self.marionette.execute_script(script,
script_args=[self.video,
self.player])
def _check_if_ad_ended(self):
self._refresh_state()
return self._last_seen_player_state.player_ad_ended
def process_ad(self):
"""
Wait for this ad to finish. Refreshes state.
"""
self._refresh_state()
if self._last_seen_player_state.player_ad_inactive:
return
ad_timeout = (self._search_ad_duration() or 30) + 5
wait = Wait(self, timeout=ad_timeout, interval=1)
try:
print('process_ad: waiting {}s for ad'.format(ad_timeout))
verbose_until(wait,
self,
YouTubePuppeteer._check_if_ad_ended,
"Check if ad ended")
except TimeoutException:
print('Waiting for ad to end timed out')
def _search_ad_duration(self):
"""
Try and determine ad duration. Refreshes state.
:return: ad duration in seconds, if currently displayed in player
"""
self._refresh_state()
if not (self._last_seen_player_state.player_ad_playing or
self._player_measure_progress() == 0):
return None
if (self._last_seen_player_state.player_ad_playing and
self._last_seen_video_state.duration):
return self._last_seen_video_state.duration
selector = '.html5-video-player .videoAdUiAttribution'
wait = Wait(self.marionette, timeout=5)
try:
with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
wait.until(expected.element_present(By.CSS_SELECTOR,
selector))
countdown = self.marionette.find_element(By.CSS_SELECTOR,
selector)
ad_time = self._time_pattern.search(countdown.text)
if ad_time:
ad_minutes = int(ad_time.group('minute'))
ad_seconds = int(ad_time.group('second'))
return 60 * ad_minutes + ad_seconds
except (TimeoutException, NoSuchElementException):
print('Could not obtain element {}'.format(selector))
return None
def _player_stalled(self):
"""
Checks if the player has stalled. Refreshes state.
:return: True if playback is not making progress for 4-9 seconds. This
excludes ad breaks. Note that the player might just be busy with
buffering due to a slow network.
"""
# `current_time` stands still while ad is playing
def condition():
# no ad is playing and current_time stands still
return (not self._last_seen_player_state.player_ad_playing and
self._measure_progress() < 0.1 and
self._player_measure_progress() < 0.1 and
(self._last_seen_player_state.player_playing or
self._last_seen_player_state.player_buffering))
if condition():
sleep(2)
self._refresh_state()
if self._last_seen_player_state.player_buffering:
sleep(5)
self._refresh_state()
return condition()
else:
return False
@staticmethod
def _yt_state_named_tuple():
"""
Create a named tuple class that can be used to store state snapshots
of the wrapped youtube player. The fields in the tuple should be used
as follows:
player_duration: the duration as fetched from the wrapped player.
player_current_time: the current playback time as fetched from the
wrapped player.
player_remaining_time: the remaining time as calculated based on the
puppeteers expected time and the players current time.
player_playback_quality: the playback quality as fetched from the
wrapped player. See:
https://developers.google.com/youtube/js_api_reference#Playback_quality
player_movie_id: the movie id fetched from the wrapped player.
player_movie_title: the title fetched from the wrapped player.
player_url: the self reported url fetched from the wrapped player.
player_state: the current state of playback as fetch from the wrapped
player. See:
https://developers.google.com/youtube/js_api_reference#Playback_status
player_unstarted, player_ended, player_playing, player_paused,
player_buffering, and player_cued: these are all shortcuts to the
player state, only one should be true at any time.
player_ad_state: as player_state, but reports for the current ad.
player_ad_state, player_ad_inactive, player_ad_playing, and
player_ad_ended: these are all shortcuts to the ad state, only one
should be true at any time.
player_breaks_count: the number of ads as fetched from the wrapped
player. This includes both played and unplayed ads, and includes
streaming ads as well as pop up ads.
:return: A 'player_state_info' named tuple class.
"""
return namedtuple('player_state_info',
['player_duration',
'player_current_time',
'player_remaining_time',
'player_playback_quality',
'player_movie_id',
'player_movie_title',
'player_url',
'player_state',
'player_unstarted',
'player_ended',
'player_playing',
'player_paused',
'player_buffering',
'player_cued',
'player_ad_state',
'player_ad_inactive',
'player_ad_playing',
'player_ad_ended',
'player_breaks_count'
])
def _create_player_state_info(self, **player_state_info_kwargs):
"""
Create an instance of the state info named tuple. This function
expects a dictionary containing the following keys:
player_duration, player_current_time, player_playback_quality,
player_movie_id, player_movie_title, player_url, player_state,
player_ad_state, and player_breaks_count.
For more information on the above keys and their values see
`_yt_state_named_tuple`.
:return: A named tuple 'player_state_info', derived from arguments and
state information from the puppeteer.
"""
player_state_info_kwargs['player_remaining_time'] = (
self.expected_duration -
player_state_info_kwargs['player_current_time'])
# Calculate player state convenience info
player_state = player_state_info_kwargs['player_state']
player_state_info_kwargs['player_unstarted'] = (
player_state == self._yt_player_state['UNSTARTED'])
player_state_info_kwargs['player_ended'] = (
player_state == self._yt_player_state['ENDED'])
player_state_info_kwargs['player_playing'] = (
player_state == self._yt_player_state['PLAYING'])
player_state_info_kwargs['player_paused'] = (
player_state == self._yt_player_state['PAUSED'])
player_state_info_kwargs['player_buffering'] = (
player_state == self._yt_player_state['BUFFERING'])
player_state_info_kwargs['player_cued'] = (
player_state == self._yt_player_state['CUED'])
# Calculate ad state convenience info
player_ad_state = player_state_info_kwargs['player_ad_state']
player_state_info_kwargs['player_ad_inactive'] = (
player_ad_state == self._yt_player_state['UNSTARTED'])
player_state_info_kwargs['player_ad_playing'] = (
player_ad_state == self._yt_player_state['PLAYING'])
player_state_info_kwargs['player_ad_ended'] = (
player_ad_state == self._yt_player_state['ENDED'])
# Create player snapshot
state_info = self._yt_state_named_tuple()
return state_info(**player_state_info_kwargs)
@property
def _fetch_state_script(self):
if not self._fetch_state_script_string:
self._fetch_state_script_string = (
self._video_var_script +
self._player_var_script +
'return ['
'baseURI,'
'currentTime,'
'duration,'
'[buffered.length, bufferedRanges],'
'[played.length, playedRanges],'
'totalFrames,'
'droppedFrames,'
'corruptedFrames,'
'player_duration,'
'player_current_time,'
'player_playback_quality,'
'player_movie_id,'
'player_movie_title,'
'player_url,'
'player_state,'
'player_ad_state,'
'player_breaks_count];')
return self._fetch_state_script_string
def _refresh_state(self):
"""
Refresh the snapshot of the underlying video and player state. We do
this all in one so that the state doesn't change in between queries.
We also store information that can be derived from the snapshotted
information, such as lag. This is stored in the last seen state to
stress that it's based on the snapshot.
"""
values = self._execute_yt_script(self._fetch_state_script)
video_keys = ['base_uri', 'current_time', 'duration',
'raw_buffered_ranges', 'raw_played_ranges',
'total_frames', 'dropped_frames', 'corrupted_frames']
player_keys = ['player_duration', 'player_current_time',
'player_playback_quality', 'player_movie_id',
'player_movie_title', 'player_url', 'player_state',
'player_ad_state', 'player_breaks_count']
# Get video state
self._last_seen_video_state = (
self._create_video_state_info(**dict(
zip(video_keys, values[:len(video_keys)]))))
# Get player state
self._last_seen_player_state = (
self._create_player_state_info(**dict(
zip(player_keys, values[-len(player_keys):]))))
def mse_enabled(self):
"""
Check if the video source indicates mse usage for current video.
Refreshes state.
:return: True if MSE is being used, False if not.
"""
self._refresh_state()
return self._last_seen_video_state.video_src.startswith('blob')
def playback_started(self):
"""
Check whether playback has started. Refreshes state.
:return: True if play back has started, False if not.
"""
self._refresh_state()
# usually, ad is playing during initial buffering
if (self._last_seen_player_state.player_playing or
self._last_seen_player_state.player_buffering):
return True
if (self._last_seen_video_state.current_time > 0 or
self._last_seen_player_state.player_current_time > 0):
return True
return False
def playback_done(self):
"""
Check whether playback is done. Refreshes state.
:return: True if play back has ended, False if not.
"""
# in case ad plays at end of video
self._refresh_state()
if self._last_seen_player_state.player_ad_playing:
return False
return (self._last_seen_player_state.player_ended or
self._last_seen_player_state.player_remaining_time < 1)
def wait_for_almost_done(self, final_piece=120):
"""
Allow the given video to play until only `final_piece` seconds remain,
skipping ads mid-way as much as possible.
`final_piece` should be short enough to not be interrupted by an ad.
Depending on the length of the video, check the ad status every 10-30
seconds, skip an active ad if possible.
This call refreshes state.
:param final_piece: The length in seconds of the desired remaining time
to wait until.
"""
self._refresh_state()
rest = 10
duration = remaining_time = self.expected_duration
if duration < final_piece:
# video is short so don't attempt to skip more ads
return duration
elif duration > 600:
# for videos that are longer than 10 minutes
# wait longer between checks
rest = duration / 50
while remaining_time > final_piece:
if self._player_stalled():
if self._last_seen_player_state.player_buffering:
# fall back on timeout in 'wait' call that comes after this
# in test function
print('Buffering and no playback progress')
break
else:
message = '\n'.join(['Playback stalled', str(self)])
raise VideoException(message)
if self._last_seen_player_state.player_breaks_count > 0:
self.process_ad()
if remaining_time > 1.5 * rest:
sleep(rest)
else:
sleep(rest / 2)
# TODO during an ad, remaining_time will be based on ad's
# current_time rather than current_time of target video
remaining_time = self._last_seen_player_state.player_remaining_time
return remaining_time
def __str__(self):
messages = [super(YouTubePuppeteer, self).__str__()]
if not self.player:
messages += ['\t.html5-media-player: None']
return '\n'.join(messages)
if not self._last_seen_player_state:
messages += ['\t.html5-media-player: No last seen state']
return '\n'.join(messages)
messages += ['.html5-media-player: {']
for field in self._last_seen_player_state._fields:
# For compatibility with different test environments we force ascii
field_ascii = (
unicode(getattr(self._last_seen_player_state, field)).encode(
'ascii', 'replace'))
messages += [('\t{}: {}'.format(field, field_ascii))]
messages += '}'
return '\n'.join(messages)

Просмотреть файл

@ -1 +0,0 @@
[test_eme_playback.py]

Просмотреть файл

@ -1,2 +0,0 @@
[test_playback_limiting_bandwidth.py]
[test_ultra_low_bandwidth.py]

Просмотреть файл

@ -1 +0,0 @@
[test_video_playback.py]

Просмотреть файл

@ -1 +0,0 @@
[test_eme_playback_limiting_bandwidth.py]

Просмотреть файл

@ -1,18 +0,0 @@
# 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/.
from external_media_harness.testcase import (
MediaTestCase,
VideoPlaybackTestsMixin,
EMESetupMixin
)
class TestEMEPlayback(MediaTestCase, VideoPlaybackTestsMixin, EMESetupMixin):
def setUp(self):
super(TestEMEPlayback, self).setUp()
self.check_eme_system()
# Tests are implemented in VideoPlaybackTestsMixin

Просмотреть файл

@ -1,24 +0,0 @@
# 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/.
from marionette_harness import BrowserMobProxyTestCaseMixin
from external_media_harness.testcase import (
EMESetupMixin,
NetworkBandwidthTestCase,
NetworkBandwidthTestsMixin,
)
class TestEMEPlaybackLimitingBandwidth(NetworkBandwidthTestCase,
BrowserMobProxyTestCaseMixin,
NetworkBandwidthTestsMixin,
EMESetupMixin):
def setUp(self):
super(TestEMEPlaybackLimitingBandwidth, self).setUp()
self.check_eme_system()
# Tests in NetworkBandwidthTestsMixin

Просмотреть файл

@ -1,25 +0,0 @@
# 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/.
from marionette_harness import Marionette
from external_media_harness.testcase import MediaTestCase
from external_media_tests.media_utils.video_puppeteer import VideoPuppeteer
class TestFullPlayback(MediaTestCase):
""" Test MSE playback in HTML5 video element.
These tests should pass on any site where a single video element plays
upon loading and is uninterrupted (by ads, for example). This will play
the full videos, so it could take a while depending on the videos playing.
It should be run much less frequently in automated systems.
"""
def test_video_playback_full(self):
with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
for url in self.video_urls:
video = VideoPuppeteer(self.marionette, url,
stall_wait_time=10)
self.run_playback(video)

Просмотреть файл

@ -1,17 +0,0 @@
# 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/.
from marionette_harness import BrowserMobProxyTestCaseMixin
from external_media_harness.testcase import (
NetworkBandwidthTestCase, NetworkBandwidthTestsMixin
)
class TestPlaybackLimitingBandwidth(NetworkBandwidthTestCase,
NetworkBandwidthTestsMixin,
BrowserMobProxyTestCaseMixin):
# Tests are in NetworkBandwidthTestsMixin
pass

Просмотреть файл

@ -1,42 +0,0 @@
# 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/.
from marionette_harness import Marionette
from external_media_harness.testcase import MediaTestCase
from external_media_tests.media_utils.video_puppeteer import VideoPuppeteer
class TestShakaPlayback(MediaTestCase):
""" Test Widevine playback in shaka-player
This test takes manifest URLs rather than URLs for pages with videos. These
manifests are loaded with shaka-player
"""
def test_video_playback_partial(self):
""" Plays 60 seconds of the video from the manifest URLs given
"""
shakaUrl = "http://shaka-player-demo.appspot.com"
self.marionette.set_pref('media.mediasource.webm.enabled', True)
with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
for manifestUrl in self.video_urls:
vp = VideoPuppeteer(self.marionette,
shakaUrl,
stall_wait_time=10,
set_duration=60,
video_selector="video#video",
autostart=False)
manifestInput = self.marionette.find_element("id",
"manifestUrlInput")
manifestInput.clear()
manifestInput.send_keys(manifestUrl)
loadButton = self.marionette.find_element("id", "loadButton")
loadButton.click()
vp.start()
self.run_playback(vp)

Просмотреть файл

@ -1,15 +0,0 @@
# 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/.
from marionette_harness import BrowserMobProxyTestCaseMixin
from external_media_harness.testcase import NetworkBandwidthTestCase
class TestUltraLowBandwidth(NetworkBandwidthTestCase,
BrowserMobProxyTestCaseMixin):
def test_playback_limiting_bandwidth_160(self):
self.proxy.limits({'downstream_kbps': 160})
self.run_videos(timeout=120)

Просмотреть файл

@ -1,15 +0,0 @@
# 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/.
from external_media_harness.testcase import (
MediaTestCase,
VideoPlaybackTestsMixin
)
class TestVideoPlayback(MediaTestCase, VideoPlaybackTestsMixin):
# Tests are actually implemented in VideoPlaybackTestsMixin.
pass

Просмотреть файл

@ -1 +0,0 @@
[test_basic_stream_playback.py]

Просмотреть файл

@ -1,30 +0,0 @@
# 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/.
from marionette_driver.errors import TimeoutException
from marionette_harness import Marionette
from external_media_harness.testcase import MediaTestCase
from external_media_tests.media_utils.twitch_puppeteer import TwitchPuppeteer
class TestBasicStreamPlayback(MediaTestCase):
def test_video_playback_partial(self):
"""
Test to make sure that playback of 60 seconds works for each video.
"""
with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
for url in self.video_urls:
stream = TwitchPuppeteer(self.marionette, url,
stall_wait_time=10,
set_duration=60)
self.run_playback(stream)
def test_playback_starts(self):
with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
for url in self.video_urls:
try:
TwitchPuppeteer(self.marionette, url, timeout=60)
except TimeoutException as e:
raise self.failureException(e)

Просмотреть файл

@ -1 +0,0 @@
[test_basic_playback.py ]

Просмотреть файл

@ -1,72 +0,0 @@
# 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/.
from marionette_driver import Wait
from marionette_driver.errors import TimeoutException
from marionette_harness import Marionette
from external_media_tests.utils import verbose_until
from external_media_harness.testcase import MediaTestCase
from external_media_tests.media_utils.video_puppeteer import VideoException
from external_media_tests.media_utils.youtube_puppeteer import YouTubePuppeteer
class TestBasicYouTubePlayback(MediaTestCase):
def test_mse_is_enabled_by_default(self):
with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
youtube = YouTubePuppeteer(self.marionette, self.video_urls[0],
timeout=60)
wait = Wait(youtube,
timeout=min(300, youtube.expected_duration * 1.3),
interval=1)
try:
verbose_until(wait, youtube,
YouTubePuppeteer.mse_enabled,
"Failed to find 'blob' in video src url.")
except TimeoutException as e:
raise self.failureException(e)
def test_video_playing_in_one_tab(self):
with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
for url in self.video_urls:
self.logger.info(url)
youtube = YouTubePuppeteer(self.marionette, url)
self.logger.info('Expected duration: {}'
.format(youtube.expected_duration))
final_piece = 60
try:
time_left = youtube.wait_for_almost_done(
final_piece=final_piece)
except VideoException as e:
raise self.failureException(e)
duration = abs(youtube.expected_duration) + 1
if duration > 1:
self.logger.info('Almost done: {} - {} seconds left.'
.format(url, time_left))
if time_left > final_piece:
self.logger.warn('time_left greater than '
'final_piece - {}'
.format(time_left))
self.save_screenshot()
else:
self.logger.warn('Duration close to 0 - {}'
.format(youtube))
self.save_screenshot()
try:
verbose_until(Wait(youtube,
timeout=max(100, time_left) * 1.3,
interval=1),
youtube,
YouTubePuppeteer.playback_done)
except TimeoutException as e:
raise self.failureException(e)
def test_playback_starts(self):
with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
for url in self.video_urls:
try:
YouTubePuppeteer(self.marionette, url, timeout=60)
except TimeoutException as e:
raise self.failureException(e)

Просмотреть файл

@ -1,46 +0,0 @@
# 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/.
from external_media_harness.testcase import MediaTestCase
from marionette_driver import Wait
from external_media_tests.utils import verbose_until
from external_media_tests.media_utils.youtube_puppeteer import YouTubePuppeteer
class TestMediaSourcePrefs(MediaTestCase):
def setUp(self):
MediaTestCase.setUp(self)
self.test_urls = self.video_urls[:2]
self.max_timeout = 60
def tearDown(self):
MediaTestCase.tearDown(self)
def test_mse_prefs(self):
""" mediasource should only be used if MSE prefs are enabled."""
self.set_mse_enabled_prefs(False)
self.check_mse_src(False, self.test_urls[0])
self.set_mse_enabled_prefs(True)
self.check_mse_src(True, self.test_urls[0])
def set_mse_enabled_prefs(self, value):
with self.marionette.using_context('chrome'):
self.marionette.set_pref('media.mediasource.enabled', value)
self.marionette.set_pref('media.mediasource.mp4.enabled', value)
self.marionette.set_pref('media.mediasource.webm.enabled', value)
def check_mse_src(self, mse_expected, url):
with self.marionette.using_context('content'):
youtube = YouTubePuppeteer(self.marionette, url)
wait = Wait(youtube,
timeout=min(self.max_timeout,
youtube.expected_duration * 1.3),
interval=1)
def cond(y):
return y.mse_enabled == mse_expected
verbose_until(wait, youtube, cond)

Просмотреть файл

@ -1,45 +0,0 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<title>Mozilla</title>
<link rel="shortcut icon" type="image/ico" href="../images/mozilla_favicon.ico" />
</head>
<body>
<a href="mozilla.html">
<img id="mozilla_logo" src="../images/mozilla_logo.jpg" />
</a>
<a href="#community">RARARARARARA</a> |
<a href="#project">Project</a> |
<a href="#organization">Organization</a>
<div id="content">
<h1 id="page-title">
<strong>RARARARARARA</strong> that the internet should be public,
open and accessible.
</h1>
<h2><a name="community">RARARARARARA</a></h2>
<p id="community">
We're a global community of thousands who believe in the power
of technology to enrich people's lives.
<a href="mozilla_community.html">More</a>
</p>
<h2><a name="project">Project</a></h2>
<p id="project">
We're an open source project whose code is used for some of the
Internet's most innovative applications.
<a href="mozilla_projects.html">More</a>
</p>
<h2><a name="organization">Organization</a></h2>
<p id="organization">
We're a public benefit organization dedicated to making the
Internet better for everyone.
<a href="mozilla_mission.html">More</a>
</p>
</div>
</body>
</html>

Просмотреть файл

@ -1,21 +0,0 @@
from marionette_harness import Marionette
from external_media_harness.testcase import MediaTestCase
class TestSomethingElse(MediaTestCase):
def setUp(self):
MediaTestCase.setUp(self)
self.test_urls = [
'mozilla.html',
]
self.test_urls = [self.marionette.absolute_url(t)
for t in self.test_urls]
def tearDown(self):
MediaTestCase.tearDown(self)
def test_foo(self):
self.logger.info('foo!')
with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
self.marionette.navigate(self.test_urls[0])

Просмотреть файл

@ -1,9 +0,0 @@
# short videos; no ads; embedded; max 5 minutes
# 0:12
[https://youtube.com/embed/AbAACm1IQE0?autoplay=1]
# 2:18
[https://youtube.com/embed/yOQQCoxs8-k?autoplay=1]
# 0:08
[https://youtube.com/embed/1visYpIREUM?autoplay=1]
# 2:09
[https://youtube.com/embed/rjmuKV9BTkE?autoplay=1]

Просмотреть файл

@ -1,8 +0,0 @@
# YouTube test
#[https://www.youtube.com/watch?v=AbAACm1IQE0]
# ClearKey - 11:07
[http://www.netflix.com/watch/70136810]
# NoDRM - 2:24:xx
[http://www.netflix.com/watch/70304192]
# DRM - 24:47
[http://www.netflix.com/watch/80015538]

Просмотреть файл

@ -1,30 +0,0 @@
# The Shaka-player tests take manifest URLs rather than URLs for a page that
# plays a video (since shaka-player is the page that plays the video)
# This file contains the manifest URLs that shaka-player provides in it's
# dropdown
# "Angel One" (TNG clip) - multilingual, subtitles, VP8
[http://shaka-player-demo.appspot.com/assets/angel_one.mpd]
# "Car" (YT DASH test) - MP4
[http://shaka-player-demo.appspot.com/assets/car-20120827-manifest.mpd]
# "Car/CENC" (YT DASH EME test) - MP4, ClearKey
[http://shaka-player-demo.appspot.com/assets/car_cenc-20120827-manifest.mpd]
# "Feelings" (YT DASH test) - VP9
[http://shaka-player-demo.appspot.com/assets/feelings_vp9-20130806-manifest.mpd]
# "Feelings" (YT DASH test) - Audio only
[http://shaka-player-demo.appspot.com/assets/feelings_audio_only-20130806-manifest.mpd]
# "Car/SegmentTemplate" (Chromecast test) - MP4 (no SIDX, video only), Widevine
[http://shaka-player-demo.appspot.com/assets/car_segmenttemplate.mpd]
# "GPAC/SegmentList" (conformance test)
[http://download.tsi.telecom-paristech.fr/gpac/DASH_CONFORMANCE/TelecomParisTech/mp4-main-multi/mp4-main-multi-mpd-AV-NBS.mpd]
# "Oops" (modified YT DASH EME test) - MP4, multi-DRM
[http://shaka-player-demo.appspot.com/assets/oops_cenc-20121114-signedlicenseurl-manifest.mpd]
# "Oops" (modified YT DASH EME test) - MP4, Widevine, PSSH in MPD
# This stream currently does not load
#[http://shaka-player-demo.appspot.com/assets/oops_cenc_pssh.mpd]
# "Sintel" (1080p high bitrate test) - MP4
[http://storage.googleapis.com/widevine-demo-media/sintel-1080p/dash.mpd]
# "Sintel" (4k) - MP4, VP8, VP9
[http://storage.googleapis.com/widevine-demo-media/sintel-multicodec-4k/dash.mpd]
# "Sintel" (4k) - MP4, Widevine
[http://storage.googleapis.com/widevine-demo-media/sintel-4k-widevine/sintel.mpd]

Просмотреть файл

@ -1 +0,0 @@
[https://www.twitch.tv/food]

Просмотреть файл

@ -1,25 +0,0 @@
[https://www.youtube.com/watch?v=2GfaRuIMdos]
[https://www.youtube.com/watch?v=9vKvcCNt40g]
[https://www.youtube.com/watch?v=SHLLHya2pNo]
[https://www.youtube.com/watch?v=isMEMDE2enU]
[https://www.youtube.com/watch?v=H81M_MebLsk]
[https://www.youtube.com/watch?v=yopNkcDzQQw]
[https://www.youtube.com/watch?v=r_bG5beSqw0]
[https://www.youtube.com/watch?v=Ki9sSZKClO0]
[https://www.youtube.com/watch?v=gNS04P8djk4]
[https://www.youtube.com/watch?v=DwC_6fIBW0w]
[https://www.youtube.com/watch?v=g1D3A14o0NA]
[https://www.youtube.com/watch?v=cs-XZ_dN4Hc]
[https://www.youtube.com/watch?v=ZEWZ3AAH98c]
[https://www.youtube.com/watch?v=hwbVGE4GBJI]
[https://www.youtube.com/watch?v=cvcMnbkasIs]
[https://www.youtube.com/watch?v=cHaBuoHwQ0Y]
[https://www.youtube.com/watch?v=VKIYoAG9MZ0]
[https://www.youtube.com/watch?v=WWDb2_unEJc]
[https://www.youtube.com/watch?v=ybw5zonQffE]
[https://www.youtube.com/watch?v=hS6ps2Xph_o]
[https://www.youtube.com/watch?v=Bjb3xhgIqv4]
[https://www.youtube.com/watch?v=fOzvEhX4Kvk]
[https://www.youtube.com/watch?v=_TNsUxp_BxM]
[https://www.youtube.com/watch?v=QRdwCSHF3oo]
[https://www.youtube.com/watch?v=VwaHFcKJSYA]

Просмотреть файл

@ -1,19 +0,0 @@
# backlog of videos
[http://youtu.be/2iVAvSnofy8]
# 300s <= duration <= 1200s (5-20min)
[http://youtu.be/9bZkp7q19f0]
[http://youtu.be/KQ6zr6kCPj8]
# duration > 1200s (>20min)
[http://youtu.be/wZZ7oFKsKzY]
[http://youtu.be/eHUrC_UiZwY]
[http://youtu.be/FLX64H5FYa8]
[http://youtu.be/Fu2DcHzokew]
#no_ad_tests_youtube
#[http://youtu.be/pWI8RB2dmfU]
#[http://youtu.be/6GBtEmtVObw]
#playlist_tests_youtube
#[http://youtu.be/R6KJjPqlPz4?list=PL75_HhpYGJQ1Fzv9a46FlHfiy-fJusKBZ]

Просмотреть файл

@ -1,21 +0,0 @@
# duration < 300s (5min)
[http://youtu.be/065dlrJoHcw]
[http://youtu.be/1visYpIREUM]
[http://youtu.be/mDf7CR5QKcE]
[http://youtu.be/Aebs62bX0dA]
[http://youtu.be/6SFp1z7uA6g]
[http://youtu.be/tDDVAErOI5U]
# ad testing
[https://www.youtube.com/watch?v=l5ODwR6FPRQ]
[https://www.youtube.com/watch?v=7RMQksXpQSk]
# duration > 5 min
# video with ad in the middle
[https://www.youtube.com/watch?v=cht9Xq9suGg]
# long video (>30 min), no ads
[https://www.youtube.com/watch?v=-qXxNPvqHtQ]
# bug 1144172, duration ~ 1hr
#[https://www.youtube.com/watch?v=AYYDshv8C4g]

Просмотреть файл

@ -1,38 +0,0 @@
# < 1 no ads
[https://youtu.be/AbAACm1IQE0]
[https://www.youtube.com/watch?v=KdHZwWQWNyM]
[https://www.youtube.com/watch?v=-hVmkA_I9EE]
[https://www.youtube.com/watch?v=1visYpIREUM]
# 1 < t <= 5 no ads
[https://www.youtube.com/watch?v=rpYRAs6ePY8]
[https://www.youtube.com/watch?v=xcgUKzwg0Mo]
[https://youtu.be/sEAT2EFIJow]
[https://www.youtube.com/watch?v=SSgnbQ5UC48]
[https://youtu.be/4oQu26IhiaA]
[https://youtu.be/IbND63HOb0M]
[https://youtu.be/-9sJp9wrdAk]
[https://www.youtube.com/watch?v=yIQGH4aQWI0]
# 1 < t <= 5
[https://www.youtube.com/watch?v=-hVmkA_I9EE]
[https://www.youtube.com/watch?v=l5ODwR6FPRQ]
[https://www.youtube.com/watch?v=7RMQksXpQSk]
[https://www.youtube.com/watch?v=TsXMe8H6iyc]
[https://www.youtube.com/watch?v=tDDVAErOI5U]
# 5 < t <= 10
[https://youtu.be/Tl-hI2IsCo0] # no ad
[https://www.youtube.com/watch?v=IX_d_vMKswE] #no ad
[https://www.youtube.com/watch?v=YVQeTY-Ayko] #no ad
[https://www.youtube.com/watch?v=rE3j_RHkqJc]
[https://www.youtube.com/watch?v=l4bmZ1gRqCc]
# 10 < t <= 30
[https://www.youtube.com/watch?v=RvymAHt3nPc] # no ads
[https://www.youtube.com/watch?v=8XQ1onjXJK0]
[https://www.youtube.com/watch?v=6Lm9EHhbJAY]
[https://www.youtube.com/watch?v=cht9Xq9suGg]
# long video (>30 min), no ads
[https://www.youtube.com/watch?v=-qXxNPvqHtQ]

Просмотреть файл

@ -1,5 +0,0 @@
# a couple of very long videos, < 12 hours total
# 6:00:00 - can't embed due to copyright
[https://www.youtube.com/watch?v=5N8sUccRiTA]
# 2:09:00
[https://www.youtube.com/embed/b6q5N16dje4?autoplay=1]

Просмотреть файл

@ -1,39 +0,0 @@
# It appears these are not currently used by tests. They are left here as they
# reference failure scenarios. If tese are fixed that can be removed.
# videos from crashes, < 12 hours
# hang | NtUserMessageCall | SendMessageW
# 1:10:00
[https://www.youtube.com/watch?v=Ztie4DqeOak]
# nsPluginInstanceOwner::GetDocument(nsIDocument**)
# 22:40
[https://www.youtube.com/watch?v=D4cLM_JRrAU]
# 16:47
[https://www.youtube.com/watch?v=3C2r05Lxsrk]
# F1398665248_____________________________
# 1:06:00
[https://www.youtube.com/watch?v=59gTMBss8o0]
# 50:58
[https://www.youtube.com/watch?v=_7VFIZhR744]
# 44:54
[https://www.youtube.com/watch?v=d6ro4Oq5msA]
# hang | WaitForMultipleObjectsEx | RealMsgWaitForMultipleObjectsEx | MsgWaitForMultipleObjects | F_1152915508___________________________________
#1:07:12
[https://www.youtube.com/watch?v=Ffkf3tosmKw]
# 1:02:00
[https://www.youtube.com/watch?v=dC3AHEao2MI]
# hang | BaseGetNamedObjectDirectory | RealMsgWaitForMultipleObjectsEx | MsgWaitForMultipleObjects | F_1152915508___________________________________
# 10:00
[https://www.youtube.com/watch?v=fn3Qb56ujNQ]
# 5:00
[https://www.youtube.com/watch?v=gBsh1bT8ltI]
# 03:50:12
[https://www.youtube.com/watch?v=TdW4S8zbmJQ]

Просмотреть файл

@ -1,86 +0,0 @@
# It appears these are not currently used by tests. They are left here as they
# reference failure scenarios. If tese are fixed that can be removed.
# Total time: about 12-13 hours + unskippable ads
#Request url: https://crash-stats.mozilla.com/api/SuperSearchUnredacted/?product=Firefox&url=%24https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D&url=%21~list&url=%21~index&_results_number=50&platform=Windows&version=37.0&date=%3E2015-03-26
#Request url: https://crash-stats.mozilla.com/api/SuperSearchUnredacted/?product=Firefox&url=%24https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D&url=%21~list&url=%21~index&_results_number=5&platform=Windows&version=37.0&signature=%3Dhang+%7C+NtUserMessageCall+%7C+SendMessageW&date=%3E2015-03-26
#Request url: https://crash-stats.mozilla.com/api/SuperSearchUnredacted/?product=Firefox&url=%24https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D&url=%21~list&url=%21~index&_results_number=5&platform=Windows&version=37.0&signature=%3DOOM+%7C+small&date=%3E2015-03-26
#Request url: https://crash-stats.mozilla.com/api/SuperSearchUnredacted/?product=Firefox&url=%24https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D&url=%21~list&url=%21~index&_results_number=5&platform=Windows&version=37.0&signature=%3Dmozilla%3A%3Alayers%3A%3ACompositorD3D11%3A%3AHandleError%28long%2C+mozilla%3A%3Alayers%3A%3ACompositorD3D11%3A%3ASeverity%29+%7C+mozilla%3A%3Alayers%3A%3ACompositorD3D11%3A%3AFailed%28long%2C+mozilla%3A%3Alayers%3A%3ACompositorD3D11%3A%3ASeverity%29+%7C+mozilla%3A%3Alayers%3A%3ACompositorD3D11%3A%3AUpdateRenderTarget%28%29&date=%3E2015-03-26
#Request url: https://crash-stats.mozilla.com/api/SuperSearchUnredacted/?product=Firefox&url=%24https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D&url=%21~list&url=%21~index&_results_number=5&platform=Windows&version=37.0&signature=%3DOOM+%7C+large+%7C+mozalloc_abort%28char+const%2A+const%29+%7C+mozalloc_handle_oom%28unsigned+int%29+%7C+moz_xmalloc+%7C+nsTArray_base%3CnsTArrayInfallibleAllocator%2C+nsTArray_CopyWithMemutils%3E%3A%3AEnsureCapacity%28unsigned+int%2C+unsigned+int%29+%7C+nsTArray_base%3CnsTArrayInfallibleAllo...&date=%3E2015-03-26
#Request url: https://crash-stats.mozilla.com/api/SuperSearchUnredacted/?product=Firefox&url=%24https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D&url=%21~list&url=%21~index&_results_number=5&platform=Windows&version=37.0&signature=%3Dshutdownhang+%7C+WaitForSingleObjectEx+%7C+WaitForSingleObject+%7C+PR_Wait+%7C+nsThread%3A%3AProcessNextEvent%28bool%2C+bool%2A%29+%7C+NS_ProcessNextEvent%28nsIThread%2A%2C+bool%29+%7C+mozilla%3A%3AMediaShutdownManager%3A%3AShutdown%28%29&date=%3E2015-03-26
#Request url: https://crash-stats.mozilla.com/api/SuperSearchUnredacted/?product=Firefox&url=%24https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D&url=%21~list&url=%21~index&_results_number=5&platform=Windows&version=37.0&signature=%3Dmozilla%3A%3Alayers%3A%3ACompositorD3D11%3A%3AUpdateConstantBuffers%28%29&date=%3E2015-03-26
#Request url: https://crash-stats.mozilla.com/api/SuperSearchUnredacted/?product=Firefox&url=%24https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D&url=%21~list&url=%21~index&_results_number=5&platform=Windows&version=37.0&signature=%3Dmsvcr120.dll%400xf20c&date=%3E2015-03-26
#Request url: https://crash-stats.mozilla.com/api/SuperSearchUnredacted/?product=Firefox&url=%24https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D&url=%21~list&url=%21~index&_results_number=5&platform=Windows&version=37.0&signature=%3Djs%3A%3AGCMarker%3A%3AprocessMarkStackTop%28js%3A%3ASliceBudget%26%29&date=%3E2015-03-26
#Request url: https://crash-stats.mozilla.com/api/SuperSearchUnredacted/?product=Firefox&url=%24https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D&url=%21~list&url=%21~index&_results_number=5&platform=Windows&version=37.0&signature=%3Dshutdownhang+%7C+WaitForSingleObjectEx+%7C+WaitForSingleObject+%7C+PR_Wait+%7C+nsThread%3A%3AProcessNextEvent%28bool%2C+bool%2A%29+%7C+NS_ProcessNextEvent%28nsIThread%2A%2C+bool%29+%7C+mozilla%3A%3Alayers%3A%3ACompositorParent%3A%3AShutDown%28%29&date=%3E2015-03-26
#Request url: https://crash-stats.mozilla.com/api/SuperSearchUnredacted/?product=Firefox&url=%24https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D&url=%21~list&url=%21~index&_results_number=5&platform=Windows&version=37.0&signature=%3Dshutdownhang+%7C+WaitForSingleObjectEx+%7C+WaitForSingleObject+%7C+PR_Wait+%7C+mozilla%3A%3AReentrantMonitor%3A%3AWait%28unsigned+int%29+%7C+mozilla%3A%3Alayers%3A%3AImageBridgeChild%3A%3AShutDown%28%29&date=%3E2015-03-26
# shutdownhang | WaitForSingleObjectEx | WaitForSingleObject | PR_Wait | nsThread::ProcessNextEvent(bool, bool*) | NS_ProcessNextEvent(nsIThread*, bool) | mozilla::MediaShutdownManager::Shutdown()
[https://www.youtube.com/watch?v=PnwS01Yu9bs]
[https://www.youtube.com/watch?v=6hNOMhEqI9g]
[https://www.youtube.com/watch?v=gK9eCjYEwH4]
#[https://www.youtube.com/watch?v=E9DFupLEV7c] Geographic restriction
[https://www.youtube.com/watch?v=sLEVm0OGImU]
# hang | NtUserMessageCall | SendMessageW
[https://www.youtube.com/watch?v=kt0g4dWxEBo]
[https://www.youtube.com/watch?v=cvwMS6UmesQ]
[https://www.youtube.com/watch?v=Bj3YSTu3jUs]
[https://www.youtube.com/watch?v=J9bgaoXLbFI]
[https://www.youtube.com/watch?v=d5GUd6IElIw]
# shutdownhang | WaitForSingleObjectEx | WaitForSingleObject | PR_Wait | mozilla::ReentrantMonitor::Wait(unsigned int) | mozilla::layers::ImageBridgeChild::ShutDown()
[https://www.youtube.com/watch?v=6FMNFvKEy4c]
[https://www.youtube.com/watch?v=w4RNIyJw9RI]
#[https://www.youtube.com/watch?v=tKB5S1yp5MA] Account terminated
[https://www.youtube.com/watch?v=Tct2Iv1QRUU]
[https://www.youtube.com/watch?v=zDHOW9PdQYE]
# shutdownhang | WaitForSingleObjectEx | WaitForSingleObject | PR_Wait | nsThread::ProcessNextEvent(bool, bool*) | NS_ProcessNextEvent(nsIThread*, bool) | mozilla::layers::CompositorParent::ShutDown()
[https://www.youtube.com/watch?v=AGo24nC3_HU]
[https://www.youtube.com/watch?v=GsVaCnud57U]
[https://www.youtube.com/watch?v=zFg55zva7ok]
#[https://www.youtube.com/watch?v=5VSk7bwPPOM] Policy violation
[https://www.youtube.com/watch?v=2OYa5kR5EQ4]
# OOM | large | mozalloc_abort(char const* const) | mozalloc_handle_oom(unsigned int) | moz_xmalloc | nsTArray_base<nsTArrayInfallibleAllocator, nsTArray_CopyWithMemutils>::EnsureCapacity(unsigned int, unsigned int) | nsTArray_base<nsTArrayInfallibleAllo...
#[https://www.youtube.com/watch?v=1g91CAubt1c] Policy violation
[https://www.youtube.com/watch?v=HE_7UFHPfQ0]
# [https://www.youtube.com/watch?v=vhrM1JXG8-k] Live stream, Flash only
[https://www.youtube.com/watch?v=ERWFf0JS94E]
#[https://www.youtube.com/watch?v=8tmiawwVreE] Age restriction
# mozilla::layers::CompositorD3D11::UpdateConstantBuffers()
[https://www.youtube.com/watch?v=7azYa518LvE]
[https://www.youtube.com/watch?v=Zg5JvdXHUqg]
[https://www.youtube.com/watch?v=Q_kcoEY2wNw]
[https://www.youtube.com/watch?v=eNzUJa0WjfU]
[https://www.youtube.com/watch?v=B5V12xYb7hE]
# OOM | small
[https://www.youtube.com/watch?v=TS9Z8dN4OPo]
[https://www.youtube.com/watch?v=EpngdStzhmQ]
[https://www.youtube.com/watch?v=dUiDCX3BnM0]
[https://www.youtube.com/watch?v=Ii4Su6Z8pCw]
[https://www.youtube.com/watch?v=vviBJS6WQno]
# msvcr120.dll@0xf20c
[https://www.youtube.com/watch?v=hRE2VO9oa_g]
[https://www.youtube.com/watch?v=qLL8VanC3zI]
[https://www.youtube.com/watch?v=YX2LIztg2EI]
[https://www.youtube.com/watch?v=-7Eh28eatBo]
[https://www.youtube.com/watch?v=a32AMX55sZM]
# js::GCMarker::processMarkStackTop(js::SliceBudget&)
[https://www.youtube.com/watch?v=f0L2RzygE5k]
[https://www.youtube.com/watch?v=-1RGIDgwHgM]
[https://www.youtube.com/watch?v=iL1CEn7SQfQ]
[https://www.youtube.com/watch?v=450p7goxZqg]
[https://www.youtube.com/watch?v=Eo8c2sZ2eOY]
# mozilla::layers::CompositorD3D11::HandleError(long, mozilla::layers::CompositorD3D11::Severity) | mozilla::layers::CompositorD3D11::Failed(long, mozilla::layers::CompositorD3D11::Severity) | mozilla::layers::CompositorD3D11::UpdateRenderTarget()
[https://www.youtube.com/watch?v=a79R7bPhVhw]
[https://www.youtube.com/watch?v=JRNCgvZs5v4]
[https://www.youtube.com/watch?v=q8y58dWKfY8]
[https://www.youtube.com/watch?v=Ns9M6sUvqxs]
[https://www.youtube.com/watch?v=Ii-PCeTgR-A]

Просмотреть файл

@ -1,18 +0,0 @@
# mix of shorter/longer videos with/without ads, < 60 min
# 4:59 - can't embed
[https://www.youtube.com/watch?v=pWI8RB2dmfU]
# 0:46 ad at start
[https://www.youtube.com/embed/6SFp1z7uA6g?autoplay=1]
# 0:58 ad at start
[https://www.youtube.com/embed/Aebs62bX0dA?autoplay=1]
# 1:43 ad
[https://www.youtube.com/embed/l5ODwR6FPRQ?autoplay=1]
# 8:00 ad - can't embed
[https://www.youtube.com/watch?v=KlyXNRrsk4A]
# video with ad in beginning and in the middle 20:00
# https://bugzilla.mozilla.org/show_bug.cgi?id=1176815
[https://www.youtube.com/embed/cht9Xq9suGg?autoplay=1]
# 1:35 ad
[https://www.youtube.com/embed/orybDrUj4vA?autoplay=1]
# 3:02 ad
[https://www.youtube.com/embed/tDDVAErOI5U?autoplay=1]

Просмотреть файл

@ -1,13 +0,0 @@
# short videos; no ads; max 10 minutes
# 0:12
[https://youtu.be/AbAACm1IQE0]
# 0:30
[https://www.youtube.com/watch?v=KdHZwWQWNyM]
# 0:08
[https://www.youtube.com/watch?v=1visYpIREUM]
# 3:27
[https://www.youtube.com/watch?v=xcgUKzwg0Mo]
# 1:21
[https://youtu.be/sEAT2EFIJow]
# 1:23
[https://www.youtube.com/watch?v=SSgnbQ5UC48]

Просмотреть файл

@ -1,17 +0,0 @@
# It appears these are not currently used by tests. They are left here as they
# reference failure scenarios. If tese are fixed that can be removed.
# crash-data videos, < 15 minutes total
# hang | NtUserMessageCall | SendMessageW
# 5:40
[https://www.youtube.com/watch?v=UIobdRNLNek]
# F1398665248_____________________________
# 3:59
[https://www.youtube.com/watch?v=XGotQYd-X6o]
# hang | WaitForMultipleObjectsEx | RealMsgWaitForMultipleObjectsEx | MsgWaitForMultipleObjects | F_1152915508___________________________________
# 4:07
[https://www.youtube.com/watch?v=wQgppPHXJSs]

Просмотреть файл

@ -1,68 +0,0 @@
# 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/.
import datetime
import time
import types
from marionette_driver.errors import TimeoutException
def timestamp_now():
return int(time.mktime(datetime.datetime.now().timetuple()))
def verbose_until(wait, target, condition, message=""):
"""
Performs a `wait`.until(condition)` and adds information about the state of
`target` to any resulting `TimeoutException`.
:param wait: a `marionette.Wait` instance
:param target: the object you want verbose output about if a
`TimeoutException` is raised
This is usually the input value provided to the `condition` used by
`wait`. Ideally, `target` should implement `__str__`
:param condition: callable function used by `wait.until()`
:param message: optional message to log when exception occurs
:return: the result of `wait.until(condition)`
"""
if isinstance(condition, types.FunctionType):
name = condition.__name__
else:
name = str(condition)
err_message = '\n'.join([message,
'condition: ' + name,
str(target)])
return wait.until(condition, message=err_message)
def save_memory_report(marionette):
"""
Saves memory report (like about:memory) to current working directory.
:param marionette: Marionette instance to use for executing.
"""
with marionette.using_context('chrome'):
marionette.execute_async_script("""
Components.utils.import("resource://gre/modules/Services.jsm");
let Cc = Components.classes;
let Ci = Components.interfaces;
let dumper = Cc["@mozilla.org/memory-info-dumper;1"].
getService(Ci.nsIMemoryInfoDumper);
// Examples of dirs: "CurProcD" usually 'browser' dir in
// current FF dir; "DfltDwnld" default download dir
let file = Services.dirsvc.get("CurProcD", Ci.nsIFile);
file.append("media-memory-report");
file.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0777);
file.append("media-memory-report.json.gz");
dumper.dumpMemoryReportsToNamedFile(file.path, null, null, false);
log('Saved memory report to ' + file.path);
// for dmd-enabled build
dumper.dumpMemoryInfoToTempDir("media", false, false);
marionetteScriptFinished(true);
return;
""", script_timeout=30000)

74
dom/media/test/external/mach_commands.py поставляемый
Просмотреть файл

@ -1,74 +0,0 @@
# 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/.
from __future__ import absolute_import, unicode_literals
import os
import sys
from mozbuild.base import (
MachCommandBase,
MachCommandConditions as conditions,
)
from mach.decorators import (
CommandProvider,
Command,
)
def setup_argument_parser():
from external_media_harness.runtests import MediaTestArguments
from mozlog.structured import commandline
parser = MediaTestArguments()
commandline.add_logging_group(parser)
return parser
def run_external_media_test(tests, testtype=None, topsrcdir=None, **kwargs):
from external_media_harness.runtests import (
FirefoxMediaHarness,
MediaTestArguments,
MediaTestRunner,
mn_cli,
)
from mozlog.structured import commandline
from argparse import Namespace
parser = setup_argument_parser()
if not tests:
tests = [os.path.join(topsrcdir,
'dom/media/test/external/external_media_tests/manifest.ini')]
args = Namespace(tests=tests)
for k, v in kwargs.iteritems():
setattr(args, k, v)
parser.verify_usage(args)
args.logger = commandline.setup_logging("Firefox External Media Tests",
args,
{"mach": sys.stdout})
failed = mn_cli(MediaTestRunner, MediaTestArguments, FirefoxMediaHarness,
args=vars(args))
if failed > 0:
return 1
else:
return 0
@CommandProvider
class MachCommands(MachCommandBase):
@Command('external-media-tests', category='testing',
description='Run Firefox external media tests.',
conditions=[conditions.is_firefox],
parser=setup_argument_parser,
)
def run_external_media_test(self, tests, **kwargs):
kwargs['binary'] = kwargs['binary'] or self.get_binary_path('app')
return run_external_media_test(tests, topsrcdir=self.topsrcdir, **kwargs)

Просмотреть файл

@ -1,5 +0,0 @@
sphinx
sphinx-rtd-theme
-e dom/media/test/external

5
dom/media/test/external/requirements.txt поставляемый
Просмотреть файл

@ -1,5 +0,0 @@
firefox-puppeteer >= 52.1.0, <53.0.0
manifestparser==1.1
marionette-driver==2.2.0
marionette-harness==4.0.0
mozlog==3.3

42
dom/media/test/external/setup.py поставляемый
Просмотреть файл

@ -1,42 +0,0 @@
# 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/.
import os
from setuptools import setup, find_packages
PACKAGE_VERSION = '2.1'
THIS_DIR = os.path.dirname(os.path.realpath(__name__))
def read(*parts):
with open(os.path.join(THIS_DIR, *parts)) as f:
return f.read()
setup(name='external-media-tests',
version=PACKAGE_VERSION,
description=('A collection of Mozilla Firefox media playback tests run '
'with Marionette'),
classifiers=[
'Environment :: Console',
'Intended Audience :: Developers',
'License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)',
'Natural Language :: English',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Topic :: Software Development :: Libraries :: Python Modules',
],
keywords='mozilla',
author='Mozilla Automation and Tools Team',
author_email='tools@lists.mozilla.org',
url='https://hg.mozilla.org/mozilla-central/dom/media/test/external/',
license='MPL 2.0',
packages=find_packages(),
zip_safe=False,
install_requires=read('requirements.txt').splitlines(),
include_package_data=True,
entry_points="""
[console_scripts]
external-media-tests = external_media_harness:cli
""")