Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: User-callback #1658

Merged
merged 15 commits into from
Mar 9, 2024
Merged

test: User-callback #1658

merged 15 commits into from
Mar 9, 2024

Conversation

buhtz
Copy link
Member

@buhtz buhtz commented Feb 24, 2024

Try to close #1648 creating a system test checking the output produced by a user callback while running a backup.

This PR might not be ready to merge but is read to review.

Do run the test via:

$ cd common
$ pytest test/test_plugin_usercallback.py::SystemTest -vs

@buhtz buhtz marked this pull request as draft February 24, 2024 22:38
@aryoda
Copy link
Contributor

aryoda commented Feb 25, 2024

A backup was created one time. But each next run of that test gave me a Nothing changed, no new snapshot necessary messages. But that test do create a temporary folder and delete it after every run. I am pretty sure about that. So how can there be a no snapshot needed message?

IMHO the takeSnapshot() function is quite complicated for historical reasons (a lot of branches and the core logic "hidden" in an else block). Above observations can be explained by this:

The INFO: Take a new snapshot. Profile: 1 Main profile log output is created first:

# take snapshot process begin
self.setTakeSnapshotMessage(0, '...')
self.snapshotLog.new(now)
profile_id = self.config.currentProfile()
profile_name = self.config.profileName()
logger.info("Take a new snapshot. Profile: %s %s"
%(profile_id, profile_name), self)

Then the takeSnapshot() function is called which really tries to create a snapshot:

ret_val, ret_error = self.takeSnapshot(sid, now, include_folders)

If no changes were reported by rsync and the config (profile) does not enforce taking a snapshot even if nothing has changed then you see the INFO: Nothing changed, no new snapshot necessary log output:

The 2nd element of params is never set to True:

backintime/common/snapshots.py

Lines 1284 to 1286 in 5cbffdf

if not params[1] and not self.config.takeSnapshotRegardlessOfChanges():
self.remove(new_snapshot)
logger.info("Nothing changed, no new snapshot necessary", self)

But that test does create a temporary folder and delete it after every run

Yes, this is the only way for BiT's takeSnapshot to check if anything has changed:

  1. Create a temp folder as snapshot target (well hidden in an if):

    backintime/common/snapshots.py

    Lines 1185 to 1186 in 5cbffdf

    if not new_snapshot.saveToContinue and not new_snapshot.makeDirs():
    return [False, True]

  2. Execute rsync

    backintime/common/snapshots.py

    Lines 1225 to 1229 in 5cbffdf

    proc = tools.Execute(cmd,
    callback = self.rsyncCallback, # TODO interprets the user_data in params as: list of two bool [error, changes] but params is reused as return value of this function with [changes, error]. Use a separate variable to avoid confusion!
    user_data = params,
    filters = (self.filterRsyncProgress,),
    parent = self)

    The user_data argument contains the well-known params variable which stores the rsync result finally (error flag + changes flag).

  3. If an error occurred during rsyncing or nothing has changed then the temp snapshot target folder is deleted again (self.remove(new_snapshot)):

    backintime/common/snapshots.py

    Lines 1274 to 1286 in 5cbffdf

    # params[0] -> error?
    if params[0]:
    if not self.config.continueOnErrors():
    self.remove(new_snapshot)
    return [False, True]
    has_errors = True
    new_snapshot.failed = True
    # params[1] -> changes?
    if not params[1] and not self.config.takeSnapshotRegardlessOfChanges():
    self.remove(new_snapshot)
    logger.info("Nothing changed, no new snapshot necessary", self)

@buhtz
Copy link
Member Author

buhtz commented Feb 26, 2024

I updated my initial comment. Read to review.

@buhtz buhtz marked this pull request as ready for review February 26, 2024 10:03
common/config.py Show resolved Hide resolved
@buhtz
Copy link
Member Author

buhtz commented Feb 27, 2024

Regarding to your comment in PR #1269 the question is if this tests would make you sleep better? 😄
Currently it is only a "local snapshot" without ssh involved. But the (un)mount reason signals (7 & 8) are fired also.

@@ -77,6 +77,7 @@ def test_with_pylint(self):
'E1101', # no-member
'W1401', # anomalous-backslash-in-string (invalid escape sequence)
'E0401', # import-error
'I0021', # useless-suppression
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See pylint docu about I0021. It detects useless pylint-disable comments (e.g. # pylint: disable=E0401). I assume we will use such comments a lot in the next years. But they also become useless again very often because of heavy refactoring.

@buhtz buhtz merged commit c1a50a9 into bit-team:dev Mar 9, 2024
1 check passed
@buhtz buhtz deleted the test/1648usercallback branch March 9, 2024 20:48
buhtz added a commit that referenced this pull request Mar 15, 2024
The debug output now contains minimal diagnostic information about appliation name, version, if it runs as root and the operating system.

- Separated code from `collect_diagnostics()` into `collect_minimal_diagnostics()` which is then called in `common/backintime.py::startApp()` to build a debug message.
- Fixed an the user-callback unit tests introduced in #1658
- Minor refactoring and minor mods in README.md and CONTRIBUTING.md.

Fix #1664
Improve PR #1658
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Unit test: User callback
2 participants