forked from google/openhtf
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Squash commit for mfg-inspector output
- Loading branch information
1 parent
56bf44e
commit bee4aff
Showing
23 changed files
with
989 additions
and
100 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,19 +12,18 @@ | |
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
|
||
"""Example OpenHTF test logic. | ||
Run with (your virtualenv must be activated first): | ||
python ./hello_world.py --config ./hello_world.yaml | ||
""" | ||
|
||
|
||
import tempfile | ||
import time | ||
|
||
import example_plug | ||
import openhtf | ||
import openhtf.io.output as output | ||
|
||
from openhtf.names import * | ||
|
||
|
@@ -39,14 +38,17 @@ def example_monitor(example): | |
'widget_type').MatchesRegex(r'.*Widget$').Doc( | ||
'''This measurement tracks the type of widgets.'''), | ||
Measurement( | ||
'widget_color').Doc('Color of the widget')) | ||
'widget_color').Doc('Color of the widget'), | ||
Measurement( | ||
'widget_size').InRange(0, 10)) | ||
@plug(example=example_plug.Example) | ||
def hello_world(test, example): | ||
"""A hello world test phase.""" | ||
test.logger.info('Hello World!') | ||
test.measurements.widget_type = prompts.DisplayPrompt( | ||
'What\'s the widget type?', text_input=True) | ||
test.measurements.widget_color = 'Black' | ||
test.measurements.widget_size = 5 | ||
test.logger.info('Example says: %s', example.DoStuff()) | ||
|
||
|
||
|
@@ -69,7 +71,7 @@ def set_measurements(test): | |
@measures( | ||
Measurement('dimensions').WithDimensions(UOM['HERTZ']), | ||
Measurement('lots_of_dims').WithDimensions( | ||
UOM['HERTZ'], UOM['BYTE'], UOM['RADIAN'])) | ||
UOM['HERTZ'], UOM['SECOND'], UOM['RADIAN'])) | ||
def dimensions(test): | ||
for dim in range(5): | ||
test.measurements.dimensions[dim] = 1 << dim | ||
|
@@ -85,7 +87,18 @@ def attachments(test): | |
|
||
|
||
if __name__ == '__main__': | ||
test = openhtf.Test(hello_world, set_measurements, dimensions, attachments) | ||
test = openhtf.Test(hello_world, set_measurements, dimensions, attachments, | ||
# Some metadata fields, these in particular are used by mfg-inspector, | ||
# but you can include any metadata fields. | ||
test_name='MyTest', test_description='OpenHTF Example Test', | ||
test_version='1.0.0') | ||
test.AddOutputCallback(OutputToJSON( | ||
'./%(dut_id)s.%(start_time_millis)s', indent=4)) | ||
'./%(dut_id)s.%(start_time_millis)s.json', indent=4)) | ||
test.AddOutputCallback(output.OutputToTestRunProto( | ||
'./%(dut_id)s.%(start_time_millis)s.json')) | ||
# Example of how to upload to mfg-inspector. Replace user email and key, | ||
# these are dummy values. | ||
#test.AddOutputCallback(output.UploadToMfgInspector( | ||
# '[email protected]', | ||
# open('my-upload-key.p12', 'r').read())) | ||
test.Execute(test_start=triggers.PromptForTestStart()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
"""Output module for outputting to JSON.""" | ||
|
||
import logging | ||
import oauth2client.client | ||
import threading | ||
|
||
from openhtf import util | ||
from openhtf.io.output import json_factory | ||
from openhtf.io.output import mfg_inspector | ||
|
||
|
||
class OutputToTestRunProto(object): # pylint: disable=too-few-public-methods | ||
"""Return an output callback that writes mfg-inspector TestRun Protos. | ||
An example filename_pattern might be: | ||
'/data/test_records/%(dut_id)s.%(start_time_millis)s' | ||
To use this output mechanism: | ||
test = openhtf.Test(PhaseOne, PhaseTwo) | ||
test.AddOutputCallback(openhtf.OutputToTestRunProto( | ||
'/data/test_records/%(dut_id)s.%(start_time_millis)s')) | ||
Args: | ||
filename_pattern: A format string specifying the filename to write to, | ||
will be formatted with the Test Record as a dictionary. | ||
""" | ||
|
||
def __init__(self, filename_pattern): | ||
self.filename_pattern = filename_pattern | ||
|
||
def __call__(self, test_record): # pylint: disable=invalid-name | ||
as_dict = util.convert_to_dict(test_record) | ||
with open(self.filename_pattern % as_dict, 'w') as outfile: | ||
outfile.write(mfg_inspector.TestRunFromTestRecord( | ||
test_record).SerializeToString()) | ||
|
||
|
||
class UploadToMfgInspector(object): # pylint: disable=too-few-public-methods | ||
"""Generate a mfg-inspector TestRun proto and upload it. | ||
Create an output callback to upload to mfg-inspector.com using the given | ||
username and authentication key (which should be the key data itself, not a | ||
filename or file). | ||
""" | ||
|
||
TOKEN_URI = 'https://accounts.google.com/o/oauth2/token' | ||
SCOPE_CODE_URI = 'https://www.googleapis.com/auth/glass.infra.quantum_upload' | ||
DESTINATION_URL = ('https://clients2.google.com/factoryfactory/' | ||
'uploads/quantum_upload/') | ||
|
||
# pylint: disable=invalid-name,missing-docstring | ||
class _MemStorage(oauth2client.client.Storage): | ||
"""Helper Storage class that keeps credentials in memory.""" | ||
def __init__(self): | ||
self._lock = threading.Lock() | ||
self._credentials = None | ||
|
||
def acquire_lock(self): | ||
self._lock.acquire(True) | ||
|
||
def release_lock(self): | ||
self._lock.release() | ||
|
||
def locked_get(self): | ||
return self._credentials | ||
|
||
def locked_put(self, credentials): | ||
self._credentials = credentials | ||
# pylint: enable=invalid-name,missing-docstring | ||
|
||
def __init__(self, user, keydata): | ||
self.user = user | ||
self.keydata = keydata | ||
|
||
def __call__(self, test_record): # pylint: disable=invalid-name | ||
credentials = oauth2client.client.SignedJwtAssertionCredentials( | ||
service_account_name=self.user, | ||
private_key=self.keydata, | ||
scope=self.SCOPE_CODE_URI, | ||
user_agent='OpenHTF Guzzle Upload Client', | ||
token_uri=self.TOKEN_URI) | ||
credentials.set_store(self._MemStorage()) | ||
|
||
testrun = mfg_inspector.TestRunFromTestRecord(test_record) | ||
try: | ||
mfg_inspector.UploadTestRun(testrun, self.DESTINATION_URL, credentials) | ||
except mfg_inspector.UploadFailedError: | ||
# For now, just log the exception. Once output is a bit more robust, | ||
# we can propagate this up and handle it accordingly. | ||
logging.exception('Upload to mfg-inspector failed!') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
"""Module for outputting test record to JSON-formatted files.""" | ||
|
||
from json import JSONEncoder | ||
|
||
from openhtf import conf | ||
from openhtf import util | ||
from openhtf.exe import test_state | ||
|
||
|
||
class OutputToJSON(JSONEncoder): | ||
"""Return an output callback that writes JSON Test Records. | ||
An example filename_pattern might be: | ||
'/data/test_records/%(dut_id)s.%(start_time_millis)s' | ||
To use this output mechanism: | ||
test = openhtf.Test(PhaseOne, PhaseTwo) | ||
test.AddOutputCallback(openhtf.OutputToJson( | ||
'/data/test_records/%(dut_id)s.%(start_time_millis)s')) | ||
Args: | ||
filename_pattern: A format string specifying the filename to write to, | ||
will be formatted with the Test Record as a dictionary. | ||
inline_attachments: Whether attachments should be included inline in the | ||
output. Set to False if you expect to have large binary attachments. | ||
""" | ||
|
||
def __init__(self, filename_pattern=None, inline_attachments=True, **kwargs): | ||
super(OutputToJSON, self).__init__(**kwargs) | ||
self.filename_pattern = filename_pattern | ||
self.inline_attachments = inline_attachments | ||
|
||
def default(self, obj): | ||
# Handle a few custom objects that end up in our output. | ||
if isinstance(obj, BaseException): | ||
# Just repr exceptions. | ||
return repr(obj) | ||
if isinstance(obj, conf.Config): | ||
return obj.dictionary | ||
if obj in test_state.TestState.State: | ||
return str(obj) | ||
return super(OutputToJSON, self).default(obj) | ||
|
||
# pylint: disable=invalid-name | ||
def __call__(self, test_record): | ||
assert self.filename_pattern, 'filename_pattern required' | ||
if self.inline_attachments: | ||
as_dict = util.convert_to_dict(test_record) | ||
else: | ||
as_dict = util.convert_to_dict(test_record, ignore_keys='attachments') | ||
with open(self.filename_pattern % as_dict, 'w') as f: | ||
f.write(self.encode(as_dict)) | ||
# pylint: enable=invalid-name |
Oops, something went wrong.