Skip to content
This repository has been archived by the owner on Mar 27, 2023. It is now read-only.

Support Phantomas per metrics #22

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 7 additions & 8 deletions holmes/facters/phantomas.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
# -*- coding: utf-8 -*-

from holmes.facters import Facter
from holmes.facters.phantomas_info import phantomas_metrics
import json
import subprocess
import threading
import re

NOTICES_PATTERN = re.compile(r'Time spent on backend / frontend: (\d+)% / (\d+)%')
Expand All @@ -29,16 +29,15 @@ def __init__(self, *args, **kwargs):
@classmethod
def get_fact_definitions(cls):
definitions = {}
for metric in self.config['metrics']:
for metric in phantomas_metrics:
definitions['page.phantomas.%s' % metric] = {
'title': 'Phantomas metrics - %s',
'title': 'Phantomas metrics - %s' % metric,
'description': lambda value: '%d' % value
}
if self.config['notices']:
definitions['page.phantomas.notices'] = {
'title': 'Phantomas notices - Time spent on backend / frontend',
'description': lambda value: '%d / %d' % value
}
definitions['page.phantomas.notices'] = {
'title': 'Phantomas notices - Time spent on backend / frontend',
'description': lambda value: '%d / %d' % value
}
return definitions

def parse_metrics(self, proc):
Expand Down
100 changes: 100 additions & 0 deletions holmes/facters/phantomas_info.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
phantomas_version = '0.11.0'

phantomas_metrics = [
'ajaxRequests',
'assetsNotGzipped',
'assetsWithQueryString',
'base64Count',
'base64Size',
'biggestLatency',
'biggestResponse',
'bodyHTMLSize',
'bodySize',
'cacheHits',
'cacheMisses',
'cachePasses',
'cachingDisabled',
'cachingNotSpecified',
'cachingTooShort',
'commentsSize',
'consoleMessages',
'contentLength',
'cookiesRecv',
'cookiesSent',
'cssCount',
'cssSize',
'documentCookiesCount',
'documentCookiesLength',
'documentWriteCalls',
'domains',
'domainsWithCookies',
'DOMelementMaxDepth',
'DOMelementsCount',
'DOMinserts',
'DOMqueries',
'DOMqueriesByClassName',
'DOMqueriesById',
'DOMqueriesByQuerySelectorAll',
'DOMqueriesByTagName',
'DOMqueriesDuplicated',
'evalCalls',
'eventsBound',
'fastestResponse',
'globalVariables',
'gzipRequests',
'headersCount',
'headersRecvCount',
'headersRecvSize',
'headersSentCount',
'headersSentSize',
'headersSize',
'hiddenContentSize',
'htmlCount',
'htmlSize',
'httpsRequests',
'httpTrafficCompleted',
'iframesCount',
'imageCount',
'imageSize',
'imagesWithoutDimensions',
'jQueryOnDOMReadyFunctions',
'jQuerySizzleCalls',
'jQueryVersion',
'jsCount',
'jsErrors',
'jsonCount',
'jsonSize',
'jsSize',
'localStorageEntries',
'maxRequestsPerDomain',
'medianLatency',
'medianRequestsPerDomain',
'medianResponse',
'multipleRequests',
'nodesWithInlineCSS',
'notFound',
'onDOMReadyTime',
'onDOMReadyTimeEnd',
'otherCount',
'otherSize',
'postRequests',
'redirects',
'requests',
'slowestResponse',
'smallestLatency',
'smallestResponse',
'smallImages',
'timeToFirstByte',
'timeToFirstCss',
'timeToFirstImage',
'timeToFirstJs',
'timeToLastByte',
'webfontCount',
'webfontSize',
'whiteSpacesSize',
'windowAlerts',
'windowConfirms',
'windowOnLoadTime',
'windowOnLoadTimeEnd',
'windowPrompts'
]
86 changes: 57 additions & 29 deletions tests/unit/facters/test_phantomas.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,17 @@
from holmes.config import Config
from holmes.reviewer import Reviewer
from holmes.facters.phantomas import PhantomasFacter
from holmes.facters.phantomas_info import phantomas_metrics
from tests.unit.base import FacterTestCase
from tests.fixtures import PageFactory


class TestPhantomasFacter(FacterTestCase):

@patch('subprocess.Popen')
def test_get_facts(self, popen_mock):
@patch('subprocess.Popen') # patch decorator here creates a new Popen object and passes it to the function (http://docs.python.org/dev/library/unittest.mock#unittest.mock.patch)
def test_can_get_facts(self, popen_mock):
wait_mock = Mock()
popen_mock.return_value = Mock(wait=wait_mock, **{'stdout.read': Mock(return_value='{"metrics": {}, "notices": []}')})
popen_mock.wait = Mock()
page = PageFactory.create(url="http://g1.globo.com/1/")

reviewer = Reviewer(
Expand Down Expand Up @@ -55,39 +55,67 @@ def test_parse_metrics(self):
facter.add_fact = Mock()

json_dict = {
"metrics": {
"foo": 7
'metrics': {
'foo': 7
},
"notices": ["Time spent on backend / frontend: 7% / 7%"]
'notices': ['Time spent on backend / frontend: 7% / 7%']
}
proc_mock = Mock(**{'stdout.read': Mock(return_value=json.dumps(json_dict))})
facter.parse_metrics(proc_mock)
self.assertIn('page.phantomas', facter.review.data)
self.assertDictEqual(json_dict, facter.review.data['page.phantomas'])
facter.add_fact.assert_called_with(
key=u'page.phantomas.foo',
value=7
)
facter.add_fact.assert_called_with(
key='page.phantomas.notices',
value=(u'7', u'7')
)
facter.add_fact.assert_has_calls([
call(key='page.phantomas.foo', value=7),
call(key='page.phantomas.notices', value=('7', '7')),
], True)

facter._all_metrics = True
json_dict = {
'metrics': {
'foo': 7
},
'notices': ['Foo bar']
}
proc_mock = Mock(**{'stdout.read': Mock(return_value=json.dumps(json_dict))})
facter.parse_metrics(proc_mock)
self.assertIn('page.phantomas', facter.review.data)
self.assertDictEqual(json_dict, facter.review.data['page.phantomas'])
facter.add_fact.assert_has_calls([
call(key='page.phantomas.foo', value=7),
call(key='page.phantomas.notices', value=('7', '7')),
call(key='page.phantomas.foo', value=7),
], True)

json_dict = {
'metrics': {},
'notices': []
}
proc_mock = Mock(**{'stdout.read': Mock(return_value=json.dumps(json_dict))})
facter.parse_metrics(proc_mock)
self.assertIn('page.phantomas', facter.review.data)
self.assertDictEqual(json_dict, facter.review.data['page.phantomas'])
facter.add_fact.assert_has_calls([
call(key='page.phantomas.foo', value=7),
call(key='page.phantomas.notices', value=('7', '7')),
call(key='page.phantomas.foo', value=7),
], True)

def test_can_get_fact_definitions(self):
page = PageFactory.create(url="http://g1.globo.com/1/")

reviewer = Reviewer(
api_url='http://localhost:2368',
page_uuid=page.uuid,
page_url=page.url,
config=Config(),
validators=[]
)
facter = PhantomasFacter(reviewer)
definitions = facter.get_fact_definitions()

# facter._all_metrics = True
# return_value = '''{
# 'metrics': {
# 'foo': 7
# },
# 'notices': ['Foo bar']
# }'''
# proc_mock = Mock(**{'stdout.read': Mock(return_value=return_value)})
# facter.parse_metrics(proc_mock)
expect('page.phantomas.notices' in definitions).to_be_true()

# return_value = '''{
# 'metrics': {},
# 'notices': []
# }'''
# proc_mock = Mock(**{'stdout.read': Mock(return_value=return_value)})
# facter.parse_metrics(proc_mock)
expect(definitions).to_length(len(phantomas_metrics) + 1)

for metric in phantomas_metrics:
expect('page.phantomas.%s' % metric in definitions).to_be_true()