rdb_wrapper_test.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. #!/usr/bin/env vpython3
  2. # Copyright (c) 2020 The Chromium Authors. All rights reserved.
  3. # Use of this source code is governed by a BSD-style license that can be
  4. # found in the LICENSE file.
  5. """Unit tests for rdb_wrapper.py"""
  6. import contextlib
  7. import json
  8. import logging
  9. import os
  10. import sys
  11. import tempfile
  12. import unittest
  13. from unittest import mock
  14. sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
  15. import rdb_wrapper
  16. @contextlib.contextmanager
  17. def lucictx(ctx):
  18. try:
  19. orig = os.environ.get('LUCI_CONTEXT')
  20. if ctx is None:
  21. os.environ.pop('LUCI_CONTEXT', '')
  22. yield
  23. else:
  24. # windows doesn't allow a file to be opened twice at the same time.
  25. # therefore, this closes the temp file before yield, so that
  26. # rdb_wrapper.client() can open the LUCI_CONTEXT file.
  27. f = tempfile.NamedTemporaryFile(delete=False)
  28. f.write(json.dumps(ctx).encode('utf-8'))
  29. f.close()
  30. os.environ['LUCI_CONTEXT'] = f.name
  31. yield
  32. os.unlink(f.name)
  33. finally:
  34. if orig is None:
  35. os.environ.pop('LUCI_CONTEXT', '')
  36. else:
  37. os.environ['LUCI_CONTEXT'] = orig
  38. @mock.patch.dict(os.environ, {})
  39. class TestClient(unittest.TestCase):
  40. def test_without_lucictx(self):
  41. with lucictx(None):
  42. with rdb_wrapper.client("prefix") as s:
  43. self.assertIsNone(s)
  44. with lucictx({'something else': {'key': 'value'}}):
  45. with rdb_wrapper.client("prefix") as s:
  46. self.assertIsNone(s)
  47. def test_with_lucictx(self):
  48. with lucictx(
  49. {'result_sink': {
  50. 'address': '127',
  51. 'auth_token': 'secret'
  52. }}):
  53. with rdb_wrapper.client("prefix") as s:
  54. self.assertIsNotNone(s)
  55. self.assertEqual(
  56. s._url,
  57. 'http://127/prpc/luci.resultsink.v1.Sink/ReportTestResults',
  58. )
  59. self.assertDictEqual(
  60. s._session.headers, {
  61. 'Accept': 'application/json',
  62. 'Authorization': 'ResultSink secret',
  63. 'Content-Type': 'application/json',
  64. })
  65. class TestResultSink(unittest.TestCase):
  66. def test_report(self):
  67. session = mock.MagicMock()
  68. sink = rdb_wrapper.ResultSink(session, 'http://host', 'test_id_prefix/')
  69. sink.report("function_foo", rdb_wrapper.STATUS_PASS, 123)
  70. expected = {
  71. 'testId': 'test_id_prefix/function_foo',
  72. 'status': rdb_wrapper.STATUS_PASS,
  73. 'expected': True,
  74. 'duration': '123.000000000s',
  75. }
  76. session.post.assert_called_once_with(
  77. 'http://host',
  78. json={'testResults': [expected]},
  79. )
  80. def test_report_failure_reason(self):
  81. session = mock.MagicMock()
  82. sink = rdb_wrapper.ResultSink(session, 'http://host', 'test_id_prefix/')
  83. sink.report("function_foo", rdb_wrapper.STATUS_PASS, 123, 'Bad CL.')
  84. expected = {
  85. 'testId': 'test_id_prefix/function_foo',
  86. 'status': rdb_wrapper.STATUS_PASS,
  87. 'expected': True,
  88. 'duration': '123.000000000s',
  89. 'failureReason': {
  90. 'primaryErrorMessage': 'Bad CL.',
  91. },
  92. }
  93. session.post.assert_called_once_with(
  94. 'http://host',
  95. json={'testResults': [expected]},
  96. )
  97. def test_report_failure_reason_truncated(self):
  98. session = mock.MagicMock()
  99. sink = rdb_wrapper.ResultSink(session, 'http://host', 'test_id_prefix/')
  100. sink.report("function_foo", rdb_wrapper.STATUS_PASS, 123, 'X' * 1025)
  101. trunc_text = rdb_wrapper._FAILURE_REASON_TRUNCATE_TEXT
  102. limit = rdb_wrapper._FAILURE_REASON_LENGTH_LIMIT
  103. expected_truncated_error = 'X' * (limit - len(trunc_text)) + trunc_text
  104. expected = {
  105. 'testId': 'test_id_prefix/function_foo',
  106. 'status': rdb_wrapper.STATUS_PASS,
  107. 'expected': True,
  108. 'duration': '123.000000000s',
  109. 'failureReason': {
  110. 'primaryErrorMessage': expected_truncated_error,
  111. },
  112. }
  113. session.post.assert_called_once_with(
  114. 'http://host',
  115. json={'testResults': [expected]},
  116. )
  117. if __name__ == '__main__':
  118. logging.basicConfig(
  119. level=logging.DEBUG if '-v' in sys.argv else logging.ERROR)
  120. unittest.main()