You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

237 lines
8.1 KiB

  1. # -*- coding: utf-8 -*-
  2. import nilmtools.copy_one
  3. import nilmtools.cleanup
  4. import nilmtools.copy_one
  5. import nilmtools.copy_wildcard
  6. import nilmtools.decimate_auto
  7. import nilmtools.decimate
  8. import nilmtools.insert
  9. import nilmtools.median
  10. import nilmtools.pipewatch
  11. import nilmtools.prep
  12. import nilmtools.sinefit
  13. import nilmtools.trainola
  14. from nose.tools import assert_raises
  15. import unittest
  16. from testutil.helpers import *
  17. from nilmtools.filter import ArgumentError
  18. class CommandTester():
  19. url = "http://localhost:32182/"
  20. @classmethod
  21. def setup_class(cls):
  22. path = "tests/testdb"
  23. recursive_unlink(path)
  24. cls.db = nilmdb.utils.serializer_proxy(nilmdb.server.NilmDB)(path)
  25. cls.server = nilmdb.server.Server(cls.db, host="127.0.0.1",
  26. port=32182, stoppable=True)
  27. cls.server.start(blocking=False)
  28. @classmethod
  29. def teardown_class(cls):
  30. cls.server.stop()
  31. cls.db.close()
  32. def run(self, arg_string, infile=None, outfile=None):
  33. """Run a cmdline client with the specified argument string,
  34. passing the given input. Save the output and exit code."""
  35. os.environ['NILMDB_URL'] = self.url
  36. class stdio_wrapper:
  37. def __init__(self, stdin, stdout, stderr):
  38. self.io = (stdin, stdout, stderr)
  39. def __enter__(self):
  40. self.saved = ( sys.stdin, sys.stdout, sys.stderr )
  41. ( sys.stdin, sys.stdout, sys.stderr ) = self.io
  42. def __exit__(self, type, value, traceback):
  43. ( sys.stdin, sys.stdout, sys.stderr ) = self.saved
  44. # Empty input if none provided
  45. if infile is None:
  46. infile = io.TextIOWrapper(io.BytesIO(b""))
  47. # Capture stderr
  48. errfile = io.TextIOWrapper(io.BytesIO())
  49. if outfile is None:
  50. # If no output file, capture stdout with stderr
  51. outfile = errfile
  52. with stdio_wrapper(infile, outfile, errfile) as s:
  53. try:
  54. args = shlex.split(arg_string)
  55. sys.argv[0] = "test_runner"
  56. self.main(args)
  57. sys.exit(0)
  58. except SystemExit as e:
  59. exitcode = e.code
  60. # Capture raw binary output, and also try to decode a Unicode
  61. # string copy.
  62. self.captured_binary = outfile.buffer.getvalue()
  63. try:
  64. outfile.seek(0)
  65. self.captured = outfile.read()
  66. except UnicodeDecodeError:
  67. self.captured = None
  68. self.exitcode = exitcode
  69. def ok(self, arg_string, infile = None):
  70. self.run(arg_string, infile)
  71. if self.exitcode != 0:
  72. self.dump()
  73. eq_(self.exitcode, 0)
  74. def raises(self, exception, arg_string, infile=None):
  75. try:
  76. self.run(arg_string, infile)
  77. except exception as e:
  78. self.captured = f"Got correct exception: {e!r}\n"
  79. self.captured_binary = b""
  80. return
  81. self.dump()
  82. raise AssertionError(f"Didn't raise exception {exception}")
  83. def fail(self, arg_string, infile=None,
  84. exitcode=None, require_error=True,
  85. exception=None):
  86. self.run(arg_string, infile)
  87. if exitcode is not None and self.exitcode != exitcode:
  88. # Wrong exit code
  89. self.dump()
  90. eq_(self.exitcode, exitcode)
  91. if self.exitcode == 0:
  92. # Success, when we wanted failure
  93. self.dump()
  94. ne_(self.exitcode, 0)
  95. # Make sure the output contains the word "error" at the
  96. # beginning of a line, if requested
  97. if require_error and not re.search("^(?:test_runner: )error",
  98. self.captured, re.MULTILINE):
  99. raise AssertionError("command failed, but output doesn't "
  100. "contain the string 'error'")
  101. def contain(self, checkstring):
  102. in_(checkstring, self.captured)
  103. def match(self, checkstring):
  104. eq_(checkstring, self.captured)
  105. def matchfile(self, file):
  106. # Captured data should match file contents exactly
  107. with open(file) as f:
  108. contents = f.read()
  109. if contents != self.captured:
  110. print("--- reference file (first 1000 bytes):\n")
  111. print(contents[0:1000] + "\n")
  112. print("--- captured data (first 1000 bytes):\n")
  113. print(self.captured[0:1000] + "\n")
  114. zipped = itertools.zip_longest(contents, self.captured)
  115. for (n, (a, b)) in enumerate(zipped):
  116. if a != b:
  117. print("--- first difference is at offset", n)
  118. print("--- reference:", repr(a))
  119. print("--- captured:", repr(b))
  120. break
  121. raise AssertionError("captured data doesn't match " + file)
  122. def matchfilecount(self, file):
  123. # Last line of captured data should match the number of
  124. # non-commented lines in file
  125. count = 0
  126. with open(file) as f:
  127. for line in f:
  128. if line[0] != '#':
  129. count += 1
  130. eq_(self.captured.splitlines()[-1], sprintf("%d", count))
  131. def dump(self):
  132. printf("-----dump start-----\n%s-----dump end-----\n", self.captured)
  133. class TestAllCommands(CommandTester):
  134. def load_data(self):
  135. client = nilmdb.client.Client(url=self.url)
  136. client.stream_create("/newton/prep", "float32_8")
  137. client.stream_set_metadata("/newton/prep",
  138. { "description": "newton" })
  139. for ts in ("20120323T1000", "20120323T1002", "20120323T1004"):
  140. start = nilmdb.utils.time.parse_time(ts)
  141. fn = f"tests/data/prep-{ts}"
  142. data = nilmdb.utils.timestamper.TimestamperRate(fn, start, 120)
  143. client.stream_insert("/newton/prep", data);
  144. def test_copy(self):
  145. self.main = nilmtools.copy_one.main
  146. client = nilmdb.client.Client(url=self.url)
  147. self.load_data()
  148. # basic arguments
  149. self.fail(f"")
  150. self.raises(ArgumentError, f"no-such-src no-such-dest")
  151. self.raises(ArgumentError, f"-u {self.url} no-such-src no-such-dest")
  152. # nonexistent dest
  153. self.fail(f"/newton/prep /newton/prep-copy", require_error=False)
  154. self.contain("Destination /newton/prep-copy doesn't exist")
  155. # wrong type
  156. client.stream_create("/newton/prep-copy-wrongtype", "uint16_6")
  157. self.raises(ValueError, f"/newton/prep /newton/prep-copy-wrongtype")
  158. # copy with metadata, and compare
  159. client.stream_create("/newton/prep-copy", "float32_8")
  160. self.ok(f"/newton/prep /newton/prep-copy")
  161. a = list(client.stream_extract("/newton/prep"))
  162. b = list(client.stream_extract("/newton/prep-copy"))
  163. eq_(a, b)
  164. a = client.stream_get_metadata("/newton/prep")
  165. b = client.stream_get_metadata("/newton/prep-copy")
  166. eq_(a, b)
  167. # copy with no metadata
  168. client.stream_create("/newton/prep-copy-nometa", "float32_8")
  169. self.ok(f"--nometa /newton/prep /newton/prep-copy-nometa")
  170. a = list(client.stream_extract("/newton/prep"))
  171. b = list(client.stream_extract("/newton/prep-copy-nometa"))
  172. eq_(a, b)
  173. a = client.stream_get_metadata("/newton/prep")
  174. b = client.stream_get_metadata("/newton/prep-copy-nometa")
  175. ne_(a, b)
  176. def test_copy_wildcard(self):
  177. self.main = nilmtools.copy_wildcard.main
  178. def test_decimate(self):
  179. self.main = nilmtools.decimate.main
  180. def test_decimate_auto(self):
  181. self.main = nilmtools.decimate_auto.main
  182. def test_insert(self):
  183. self.main = nilmtools.insert.main
  184. def test_sinefit(self):
  185. self.main = nilmtools.sinefit.main
  186. def test_cleanup(self):
  187. self.main = nilmtools.cleanup.main
  188. def test_median(self):
  189. self.main = nilmtools.median.main
  190. def test_trainola(self):
  191. self.main = nilmtools.trainola.main
  192. def test_pipewatch(self):
  193. self.main = nilmtools.pipewatch.main
  194. def test_prep(self):
  195. self.main = nilmtools.prep.main