Merge branch 'maintenance' into devel
Conflicts: CHANGELOG.md
This commit is contained in:
commit
e28ca60f21
13 changed files with 1244 additions and 567 deletions
|
|
@ -14,11 +14,11 @@ master
|
|||
HEAD
|
||||
\(detached.*
|
||||
|
||||
# maintenance is currently the branch for preparation of maintenance release 1.2.9
|
||||
# maintenance is currently the branch for preparation of maintenance release 1.2.10
|
||||
# so are any fix/... and improve/... branches
|
||||
maintenance 1.2.9 dedadbc9ac0305799e94ae279d3bca131629c4c5 pep440-dev
|
||||
fix/.* 1.2.9 dedadbc9ac0305799e94ae279d3bca131629c4c5 pep440-dev
|
||||
improve/.* 1.2.9 dedadbc9ac0305799e94ae279d3bca131629c4c5 pep440-dev
|
||||
maintenance 1.2.10 abe68adac8f465a31bf4f3f3933190c1fc242cda pep440-dev
|
||||
fix/.* 1.2.10 abe68adac8f465a31bf4f3f3933190c1fc242cda pep440-dev
|
||||
improve/.* 1.2.10 abe68adac8f465a31bf4f3f3933190c1fc242cda pep440-dev
|
||||
|
||||
# every other branch is a development branch and thus gets resolved to 1.3.0-dev for now
|
||||
.* 1.3.0 198d3450d94be1a2 pep440-dev
|
||||
|
|
|
|||
39
CHANGELOG.md
39
CHANGELOG.md
|
|
@ -69,6 +69,45 @@
|
|||
* [#1047](https://github.com/foosel/OctoPrint/issues/1047) - Fixed 90 degree
|
||||
webcam rotation for iOS Safari.
|
||||
|
||||
## 1.2.9 (2016-02-10)
|
||||
|
||||
### Improvements
|
||||
|
||||
* [#318](https://github.com/foosel/OctoPrint/issues/318) - Snapshots for timelapses are now named in a non-colliding, job-based way, allowing a new timelapse to start while the other is still being rendered (although printing with an active timelapse rendering job is not recommended and will be solved with a proper render job queue in a later version). Timelapses that were not successfully rendered are kept for 7 days (configurable, although not via the UI so far) and can be manually rendered or deleted through a new UI component within the timelapse tab that shows up if unrendered timelapses are detected.
|
||||
* [#485](https://github.com/foosel/OctoPrint/issues/485) - "Timelapse rendering" notification is now persistent, even across reloads/client switches. That should make it easier to see that a rendering job is currently in progress.
|
||||
* [#939](https://github.com/foosel/OctoPrint/issues/939) - Updated to Knockout 3.4.0
|
||||
* [#1204](https://github.com/foosel/OctoPrint/issues/1204) - Display total print time as estimated by GCODE viewer on GCODE viewer tab. That will allow access to an estimate even if the server hadn't yet calculated that when a print started. Note that due to slightly different implementation server and client side the resulting estimate might differ.
|
||||
* OctoPrint now serves an intermediary page upon start that informs the user about the server still starting up. Once the server is detected as running, the page automatically switches to the standard interface.
|
||||
* OctoPrint now displays a link to the release notes of an updated component in the update notification, the update confirmation and the version overview in the settings dialog. Please always make sure to at least skim over the release notes for new OctoPrint releases, they might contain important information that you need to know before updating.
|
||||
* Improved initial page loading speeds by introducing a preemptive cache. OctoPrint will now record how you access it and on server start pre-render the page so it's ideally available in the server-side cache when you try to access it.
|
||||
* Initialize login user name and password with an empty string and clear both on successful login (see [#1175](https://github.com/foosel/OctoPrint/pull/1175)).
|
||||
* Added a "Refresh" button to the file list for people who modify the stored files externally (doing this is not encouraged however due to reasons of book keeping, e.g. metadata tracking etc).
|
||||
* "Save" button on settings dialog is now disabled while background tasks (getting or receiving config data from the backend) are in progress.
|
||||
* Improved performance of terminal tab on lower powered clients. Adaptive rate limiting now ensures the server backs off with log updates if the client can't process them fast enough. If the client is really slow, log updates get disabled automatically during printing. This behaviour can be disabled with override buttons in the terminal tab's advanced options if necessary.
|
||||
* Added option to ignore any unhandled errors reported by the firmware and another option to only cancel ongoing prints on unhandled errors from the firmware (instead of instant disconnect that so far was the default).
|
||||
* Made version compatibility check PEP440 compliant (important for plugin authors).
|
||||
* Do not hiccup on manually sent `M28` commands.
|
||||
* Persist print recovery data on print failures (origin and name of printed file, position in file when print was aborted, time and date of print failure). Currently this data isn't used anywhere, but it [can be accessed from plugins in order to add recovery functionality](https://github.com/foosel/OctoPrint-PrintRecoveryPoc) to OctoPrint.
|
||||
* Small performance improvements in update checks.
|
||||
* The file upload dialog will now only display files having an extension that's supported for upload (if the browser supports it, also see [#1196](https://github.com/foosel/OctoPrint/issues/1196)).
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* [#1007](https://github.com/foosel/OctoPrint/issues/1007) - Don't enable the "Print" button if no print job is selected.
|
||||
* [#1181](https://github.com/foosel/OctoPrint/issues/1181) - Properly slugify UTF-8 only file names.
|
||||
* [#1196](https://github.com/foosel/OctoPrint/issues/1196) - Do not show drag-n-drop overlay if server is offline.
|
||||
* [#1208](https://github.com/foosel/OctoPrint/issues/1208) - Fixed `retraction_combing` profile setting being incorrectly used by bundled Cura plugin (see [#1209](https://github.com/foosel/OctoPrint/pull/1209))
|
||||
* Fixed OctoPrint compatibility check in the plugin manager, could report `False` for development versions against certain versions of Python's `setuptools` (thanks to @ignaworm who stumbled over this).
|
||||
* Fixed a missing parameter in `PluginSettings.remove` call (see [#1177](https://github.com/foosel/OctoPrint/pull/1177)).
|
||||
* Docs: Fixed the example for a custom `M114` control to also match negative coordinates.
|
||||
* Reset scroll position in settings dialog properly when re-opening it or switching tabs.
|
||||
* Fixed an issue that prevented system menu entries that were added to a so far empty system menu make the menu show up.
|
||||
* Fixed an issue that made requests to restricted resources fail even though the first run wizard had been completed successfully.
|
||||
* Fixed an issue where an unknown command or the suppression of a command could cause the communication to stall until a communication timeout was triggered.
|
||||
* Strip [unwanted ANSI characters](https://github.com/pypa/pip/issues/3418) from output produced by pip versions 8.0.0, 8.0.1 and 8.0.3 that prevents our plugin installation detection from working correctly.
|
||||
|
||||
([Commits](https://github.com/foosel/OctoPrint/compare/1.2.8...1.2.9))
|
||||
|
||||
## 1.2.8 (2015-12-07)
|
||||
|
||||
### Notes for Upgraders
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ or **[creating pull requests](#pull-requests)**.
|
|||
* [Where can I find those log files you keep talking about?](#where-can-i-find-those-log-files-you-keep-talking-about)
|
||||
* [Where can I find my browser's error console?](#where-can-i-find-my-browsers-error-console)
|
||||
* [Pull requests](#pull-requests)
|
||||
* [What do the branches mean?](#what-do-the-branches-mean)
|
||||
* [How OctoPrint is versioned](#how-octoprint-is-versioned)
|
||||
* [History](#history)
|
||||
* [Footnotes](#footnotes)
|
||||
|
||||
|
|
@ -225,12 +227,14 @@ See [How to open the Javascript Console in different browsers](https://webmaster
|
|||
make sure to backport it to the `maintenance` branch to also include it in
|
||||
the next release.
|
||||
4. Make sure you **follow the current coding style**. This means:
|
||||
|
||||
* Tabs instead of spaces in the Python files[2]
|
||||
* Spaces instead of tabs in the Javascript sources
|
||||
* English language (code, variables, comments, ...)
|
||||
* Comments where necessary: Tell why the code does something like it does
|
||||
* Comments where necessary: Tell *why* the code does something like it does
|
||||
it, structure your code
|
||||
* Following the general architecture
|
||||
|
||||
If your PR needs to make changes to the Stylesheets, change the ``.less`` files
|
||||
from which the CSS is compiled.
|
||||
5. **Test your changes thoroughly**. That also means testing with usage
|
||||
|
|
@ -240,13 +244,75 @@ See [How to open the Javascript Console in different browsers](https://webmaster
|
|||
your changes. Ideally **add unit tests** - OctoPrint severely lacks in that
|
||||
department, but we are trying to change that, so any new code already covered
|
||||
with a test suite helps a lot!
|
||||
6. In your pull request's description, **state what your pull request is doing**,
|
||||
6. In your pull request's description, **state what your pull request does**,
|
||||
as in, what feature does it implement, what bug does it fix. The more
|
||||
thoroughly you explain your intent behind the PR here, the higher the
|
||||
chances it will get merged fast.
|
||||
7. Important: Don't forget to **add yourself to the [AUTHORS](./AUTHORS.md)
|
||||
file** :)
|
||||
|
||||
## What do the branches mean?
|
||||
|
||||
There are three main branches in OctoPrint:
|
||||
|
||||
* `master`: The master branch always contains the current stable release. It
|
||||
is *only* updated on new releases. Will have a version number following
|
||||
the scheme `x.y.z` (e.g. `1.2.9`) or - if it's absolutely necessary to
|
||||
add a commit after release to this branch - `x.y.z.post<commits since x.y.z>`
|
||||
(e.g. `1.2.9.post1`).
|
||||
* `maintenance`: Improvements and fixes of the current release that make up
|
||||
the next release go here. More or less continously updated. You can consider
|
||||
this a preview of the next release version. It should be very stable at all
|
||||
times. Anything you spot in here helps tremendously with getting a rock solid
|
||||
next stable release, so if you want to help out development, running the
|
||||
`maintenance` branch and reporting back anything you find is a very good way
|
||||
to do that. Will usually have a version number following the scheme
|
||||
`x.y.z+1.dev.<commits since increase of z>` for an OctoPrint version of `x.y.z`
|
||||
(e.g. `1.2.10.dev12`).
|
||||
* `devel`: Ongoing development of new features that will go into the next bigger
|
||||
release (MINOR version number increases) will happen on this branch. Usually
|
||||
kept stable, sometimes stuff can break though or lose backwards compatibility
|
||||
temporarily. Can be considered the "bleeding edge". All PRs should target
|
||||
*this* branch. Important improvements and fixes from PRs here are backported to
|
||||
`maintenance` as needed. Will usually have a version number following the
|
||||
scheme `x.y+1.0.dev<commits since increase of y>` for an OctoPrint version
|
||||
of `x.y.z` (e.g. `1.3.0.dev123`).
|
||||
|
||||
Additionally, from time to time you might see other branches pop up in the repository.
|
||||
Those usually have one of the following prefixes:
|
||||
|
||||
* `fix/...`: Fixes under development that are to be merged into the `maintenance`
|
||||
and `devel` branches.
|
||||
* `improve/...`: Improvements under development that are to be merged into the
|
||||
`maintenance` and `devel` branches.
|
||||
* `dev/...` or `feature/...`: New functionality under development that is to be merged
|
||||
into the `devel` branch.
|
||||
|
||||
There is also the `gh-pages` branch, which holds OctoPrint's web page, and a couple of
|
||||
older development branches that are slowly being migrated or deleted.
|
||||
|
||||
## How OctoPrint is versioned
|
||||
|
||||
OctoPrint follows the [semantic versioning scheme](http://semver.org/) of **MAJOR.MINOR.PATCH**.
|
||||
|
||||
The **PATCH** version number is the one increasing most often due to OctoPrint's maintenance releases.
|
||||
Releases that only change the patch number indicate that they contain bug fixes and small improvements
|
||||
of existing functionality. Example: 1.2.8 to 1.2.9.
|
||||
|
||||
The **MINOR** version number increases with releases that add a lot of new functionality and
|
||||
large features. Example: 1.2.x to 1.3.0.
|
||||
|
||||
Finally, the **MAJOR** version number increases if there are breaking API changes that concern any of the
|
||||
documented interfaces (REST API, plugin interfaces, ...). So far this hasn't happened. Example: 1.x.y to 2.0.0.
|
||||
|
||||
OctoPrint's version numbers are automatically generated using [versioneer](https://github.com/warner/python-versioneer)
|
||||
and depend on the selected git branch, nearest git tag and commits. The generated version number
|
||||
should always be [PEP440](https://www.python.org/dev/peps/pep-0440/) compatible. Unless a git tag
|
||||
is used for version number determination, the version number will also contain the git hash within
|
||||
the local version identifier to allow for an exact determination of the active code base
|
||||
(e.g. `1.2.9.dev68+g46c7a9c`). Additionally, instances with active uncommitted changes will contain
|
||||
`.dirty` in the local version identifier.
|
||||
|
||||
## History
|
||||
|
||||
* 2015-01-23: More guidelines for creating pull requests, support/questions
|
||||
|
|
@ -255,6 +321,7 @@ See [How to open the Javascript Console in different browsers](https://webmaster
|
|||
* 2015-07-07: Added step to add yourself to AUTHORS when creating a PR :)
|
||||
* 2015-12-01: Heavily reworked to include examples, better structure and
|
||||
all information in one document.
|
||||
* 2016-02-10: Added information about branch structure and versioning.
|
||||
|
||||
## Footnotes
|
||||
* [1] - If you are wondering why, the problem is that anything that you add
|
||||
|
|
|
|||
|
|
@ -424,6 +424,7 @@ $(function() {
|
|||
} else {
|
||||
var output = [];
|
||||
output.push(gettext("Model size") + ": " + model.width.toFixed(2) + "mm × " + model.depth.toFixed(2) + "mm × " + model.height.toFixed(2) + "mm");
|
||||
output.push(gettext("Estimated total print time") + ": " + formatDuration(model.printTime));
|
||||
output.push(gettext("Estimated layer height") + ": " + model.layerHeight.toFixed(2) + gettext("mm"));
|
||||
output.push(gettext("Layer count") + ": " + model.layersPrinted.toFixed(0) + " " + gettext("printed") + ", " + model.layersTotal.toFixed(0) + " " + gettext("visited"));
|
||||
|
||||
|
|
|
|||
|
|
@ -57,6 +57,10 @@
|
|||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="muted">
|
||||
<small>{{ _('Note that the time estimates in this tab are calculated by the GCODE viewer in your browser and might differ from the values calculated by the server that are displayed in the "State" and "Files" panels in the sidebar due to slightly different implementations.') }}</small>
|
||||
</div>
|
||||
</div>
|
||||
<div data-bind="visible: waitForApproval">
|
||||
<h1>{{ _('Warning') }}</h1>
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ from octoprint.events import eventManager, Events
|
|||
import sarge
|
||||
import collections
|
||||
|
||||
import re
|
||||
|
||||
# currently configured timelapse
|
||||
current = None
|
||||
|
||||
|
|
@ -32,6 +34,10 @@ current_render_job = None
|
|||
_capture_format = "{prefix}-%d.jpg"
|
||||
_output_format = "{prefix}.mpg"
|
||||
|
||||
# old capture format, needed to delete old left-overs from
|
||||
# versions <1.2.9
|
||||
_old_capture_format_re = re.compile("^tmp_\d{5}.jpg$")
|
||||
|
||||
# valid timelapses
|
||||
_valid_timelapse_types = ["off", "timed", "zchange"]
|
||||
|
||||
|
|
@ -93,7 +99,7 @@ def get_unrendered_timelapses():
|
|||
del job["timestamp"]
|
||||
return job
|
||||
|
||||
return [util.dict_merge(dict(name=key), finalize_fields(value)) for key, value in jobs.items()]
|
||||
return sorted([util.dict_merge(dict(name=key), finalize_fields(value)) for key, value in jobs.items()], key=lambda x: x["name"])
|
||||
|
||||
|
||||
def delete_unrendered_timelapse(name):
|
||||
|
|
@ -129,14 +135,30 @@ def delete_old_unrendered_timelapses():
|
|||
clean_after_days = settings().getInt(["webcam", "cleanTmpAfterDays"])
|
||||
cutoff = time.time() - clean_after_days * 24 * 60 * 60
|
||||
|
||||
prefixes_to_clean = []
|
||||
for filename in os.listdir(basedir):
|
||||
try:
|
||||
path = os.path.join(basedir, filename)
|
||||
|
||||
prefix = _extract_prefix(filename)
|
||||
if prefix is None:
|
||||
# might be an old tmp_00000.jpg kinda frame. we can't
|
||||
# render those easily anymore, so delete that stuff
|
||||
if _old_capture_format_re.match(filename):
|
||||
os.remove(path)
|
||||
continue
|
||||
|
||||
if prefix in prefixes_to_clean:
|
||||
continue
|
||||
|
||||
if os.path.getmtime(path) < cutoff:
|
||||
os.remove(path)
|
||||
prefixes_to_clean.append(prefix)
|
||||
except:
|
||||
logging.getLogger(__name__).exception("Error while processing file {} during cleanup".format(filename))
|
||||
|
||||
for prefix in prefixes_to_clean:
|
||||
delete_unrendered_timelapse(prefix)
|
||||
|
||||
|
||||
def _create_render_start_handler(name, gcode=None):
|
||||
def f(movie):
|
||||
|
|
|
|||
Binary file not shown.
File diff suppressed because it is too large
Load diff
9
tests/timelapse/__init__.py
Normal file
9
tests/timelapse/__init__.py
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# coding=utf-8
|
||||
"""
|
||||
Unit tests for ``octoprint.timelapse``.
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
|
||||
__copyright__ = "Copyright (C) 2016 The OctoPrint Project - Released under terms of the AGPLv3 License"
|
||||
172
tests/timelapse/test_timelapse_helpers.py
Normal file
172
tests/timelapse/test_timelapse_helpers.py
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
# coding=utf-8
|
||||
from __future__ import absolute_import
|
||||
|
||||
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
|
||||
__copyright__ = "Copyright (C) 2016 The OctoPrint Project - Released under terms of the AGPLv3 License"
|
||||
|
||||
import unittest
|
||||
import mock
|
||||
|
||||
import os
|
||||
import time
|
||||
|
||||
from collections import namedtuple
|
||||
_stat = namedtuple("StatResult", "st_size, st_ctime, st_mtime")
|
||||
|
||||
import octoprint.settings
|
||||
import octoprint.timelapse
|
||||
|
||||
class TimelapseTest(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
# mock settings
|
||||
self.settings_patcher = mock.patch("octoprint.timelapse.settings")
|
||||
self.settings_getter = self.settings_patcher.start()
|
||||
|
||||
self.settings = mock.create_autospec(octoprint.settings.Settings)
|
||||
self.settings_getter.return_value = self.settings
|
||||
|
||||
self.now = time.time()
|
||||
|
||||
def cleanUp(self):
|
||||
self.settings_patcher.stop()
|
||||
|
||||
@mock.patch("os.remove")
|
||||
@mock.patch("os.listdir")
|
||||
def test_delete_unrendered_timelapse(self, mock_listdir, mock_remove):
|
||||
## prepare
|
||||
|
||||
mocked_path = "/path/to/timelapse/tmp"
|
||||
mocked_files = ["a-0.jpg",
|
||||
"a-1.jpg",
|
||||
"a-2.jpg",
|
||||
"b-0.jpg",
|
||||
"b-1.jpg",
|
||||
"tmp_00000.jpg",
|
||||
"tmp_00001.jpg"]
|
||||
|
||||
self.settings.getBaseFolder.return_value = mocked_path
|
||||
mock_listdir.return_value = mocked_files
|
||||
|
||||
## test
|
||||
octoprint.timelapse.delete_unrendered_timelapse("b")
|
||||
|
||||
## verify
|
||||
expected_deletions = map(lambda x: os.path.join(mocked_path, x), ["b-0.jpg",
|
||||
"b-1.jpg"])
|
||||
expected_deletion_calls = map(mock.call, expected_deletions)
|
||||
self.assertListEqual(mock_remove.mock_calls, expected_deletion_calls)
|
||||
|
||||
@mock.patch("time.time")
|
||||
@mock.patch("os.remove")
|
||||
@mock.patch("os.path.getmtime")
|
||||
@mock.patch("os.listdir")
|
||||
def test_delete_old_unrendered_timelapses(self, mock_listdir, mock_mtime, mock_remove, mock_time):
|
||||
## prepare
|
||||
|
||||
mocked_path = "/path/to/timelapse/tmp"
|
||||
mocked_files = ["old-0.jpg",
|
||||
"old-1.jpg",
|
||||
"old-2.jpg",
|
||||
"prefix-0.jpg",
|
||||
"prefix-1.jpg",
|
||||
"tmp_00000.jpg",
|
||||
"tmp_00001.jpg"]
|
||||
now = self.now
|
||||
days = 1
|
||||
|
||||
def mtime(p):
|
||||
if p.startswith(os.path.join(mocked_path, "old-0")):
|
||||
# old-0 is definitely older than cutoff
|
||||
return 0
|
||||
else:
|
||||
# all other files were just created
|
||||
return now
|
||||
|
||||
self.settings.getBaseFolder.return_value = mocked_path
|
||||
self.settings.getInt.return_value = days
|
||||
|
||||
mock_time.return_value = now
|
||||
|
||||
mock_listdir.return_value = mocked_files
|
||||
|
||||
mock_mtime.side_effect = mtime
|
||||
|
||||
## test
|
||||
octoprint.timelapse.delete_old_unrendered_timelapses()
|
||||
|
||||
## verify
|
||||
expected_deletions = map(lambda x: os.path.join(mocked_path, x), ["tmp_00000.jpg",
|
||||
"tmp_00001.jpg",
|
||||
"old-0.jpg",
|
||||
"old-1.jpg",
|
||||
"old-2.jpg"])
|
||||
expected_deletion_calls = map(mock.call, expected_deletions)
|
||||
self.assertListEqual(mock_remove.mock_calls, expected_deletion_calls)
|
||||
|
||||
@mock.patch("os.stat")
|
||||
@mock.patch("os.listdir")
|
||||
def test_get_finished_timelapses(self, mock_listdir, mock_stat):
|
||||
|
||||
## prepare
|
||||
|
||||
files = dict()
|
||||
files["one.mpg"] = _stat(st_size=1024, st_ctime=self.now, st_mtime=self.now)
|
||||
files["nope.jpg"] = _stat(st_size=100, st_ctime=self.now, st_mtime=self.now)
|
||||
files["two.mpg"] = _stat(st_size=2048, st_ctime=self.now, st_mtime=self.now)
|
||||
|
||||
mocked_path = "/path/to/timelapse"
|
||||
self.settings.getBaseFolder.return_value = mocked_path
|
||||
|
||||
mock_listdir.return_value = sorted(files.keys())
|
||||
|
||||
def stat(p):
|
||||
name = p[len(mocked_path) + 1:]
|
||||
return files[name]
|
||||
mock_stat.side_effect = stat
|
||||
|
||||
## test
|
||||
result = octoprint.timelapse.get_finished_timelapses()
|
||||
|
||||
## verify
|
||||
self.assertEqual(len(result), 2)
|
||||
self.assertEqual(result[0]["name"], "one.mpg")
|
||||
self.assertEqual(result[0]["bytes"], 1024)
|
||||
self.assertEqual(result[1]["name"], "two.mpg")
|
||||
self.assertEqual(result[1]["bytes"], 2048)
|
||||
|
||||
@mock.patch("os.stat")
|
||||
@mock.patch("os.listdir")
|
||||
def test_unrendered_timelapses(self, mock_listdir, mock_stat):
|
||||
## prepare
|
||||
files = dict()
|
||||
files["one-0.jpg"] = _stat(st_size=1, st_ctime=self.now - 1, st_mtime=self.now - 1)
|
||||
files["one-1.jpg"] = _stat(st_size=2, st_ctime=self.now, st_mtime=self.now)
|
||||
files["one-2.jpg"] = _stat(st_size=3, st_ctime=self.now, st_mtime=self.now)
|
||||
files["nope.mpg"] = _stat(st_size=2048, st_ctime=self.now, st_mtime=self.now)
|
||||
files["two-0.jpg"] = _stat(st_size=4, st_ctime=self.now, st_mtime=self.now)
|
||||
files["two-1.jpg"] = _stat(st_size=5, st_ctime=self.now, st_mtime=self.now)
|
||||
|
||||
mocked_path = "/path/to/timelapse/tmp"
|
||||
self.settings.getBaseFolder.return_value = mocked_path
|
||||
|
||||
mock_listdir.return_value = sorted(files.keys())
|
||||
|
||||
def stat(p):
|
||||
name = p[len(mocked_path) + 1:]
|
||||
return files[name]
|
||||
mock_stat.side_effect = stat
|
||||
|
||||
## test
|
||||
result = octoprint.timelapse.get_unrendered_timelapses()
|
||||
|
||||
## verify
|
||||
self.assertEqual(len(result), 2)
|
||||
|
||||
self.assertEqual(result[0]["name"], "one")
|
||||
self.assertEqual(result[0]["count"], 3)
|
||||
self.assertEqual(result[0]["bytes"], 6)
|
||||
|
||||
self.assertEqual(result[1]["name"], "two")
|
||||
self.assertEqual(result[1]["count"], 2)
|
||||
self.assertEqual(result[1]["bytes"], 9)
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue