Merge lp:~larryprice/libertine/libertine-service into lp:libertine

Proposed by Larry Price
Status: Merged
Approved by: Christopher Townsend
Approved revision: 372
Merged at revision: 334
Proposed branch: lp:~larryprice/libertine/libertine-service
Merge into: lp:libertine
Diff against target: 2873 lines (+2532/-14)
46 files modified
data/CMakeLists.txt (+1/-1)
data/com.canonical.libertine.ContainerManager.service (+3/-0)
debian/libertine-tools.install (+2/-0)
debian/python3-libertine.install (+1/-0)
python/libertine/ChrootContainer.py (+3/-1)
python/libertine/ContainersConfig.py (+7/-5)
python/libertine/HostInfo.py (+1/-1)
python/libertine/Libertine.py (+1/-1)
python/libertine/LxcContainer.py (+6/-3)
python/libertine/service/apt.py (+77/-0)
python/libertine/service/container.py (+139/-0)
python/libertine/service/manager.py (+115/-0)
python/libertine/service/progress.py (+83/-0)
python/libertine/service/task_dispatcher.py (+114/-0)
python/libertine/service/tasks/__init__.py (+39/-0)
python/libertine/service/tasks/app_info_task.py (+35/-0)
python/libertine/service/tasks/base_task.py (+94/-0)
python/libertine/service/tasks/container_info_task.py (+29/-0)
python/libertine/service/tasks/create_task.py (+72/-0)
python/libertine/service/tasks/destroy_task.py (+42/-0)
python/libertine/service/tasks/install_task.py (+49/-0)
python/libertine/service/tasks/list_apps_task.py (+30/-0)
python/libertine/service/tasks/list_task.py (+25/-0)
python/libertine/service/tasks/remove_task.py (+48/-0)
python/libertine/service/tasks/search_task.py (+27/-0)
python/libertine/service/tasks/update_task.py (+39/-0)
tests/unit/CMakeLists.txt (+1/-0)
tests/unit/pytest.ini (+2/-0)
tests/unit/service/CMakeLists.txt (+12/-0)
tests/unit/service/tasks/CMakeLists.txt (+10/-0)
tests/unit/service/tasks/test_app_info_task.py (+61/-0)
tests/unit/service/tasks/test_container_info_task.py (+44/-0)
tests/unit/service/tasks/test_create_task.py (+234/-0)
tests/unit/service/tasks/test_destroy_task.py (+80/-0)
tests/unit/service/tasks/test_install_task.py (+76/-0)
tests/unit/service/tasks/test_list_apps_task.py (+59/-0)
tests/unit/service/tasks/test_list_task.py (+45/-0)
tests/unit/service/tasks/test_remove_task.py (+76/-0)
tests/unit/service/tasks/test_search_task.py (+43/-0)
tests/unit/service/tasks/test_update_task.py (+80/-0)
tests/unit/service/test_apt.py (+134/-0)
tests/unit/service/test_container.py (+202/-0)
tests/unit/service/test_task_dispatcher.py (+148/-0)
tools/CMakeLists.txt (+1/-1)
tools/libertine-container-manager (+1/-1)
tools/libertined (+141/-0)
To merge this branch: bzr merge lp:~larryprice/libertine/libertine-service
Reviewer Review Type Date Requested Status
Christopher Townsend Approve
Libertine CI Bot continuous-integration Approve
Review via email: mp+309794@code.launchpad.net

Commit message

Initial implementation of a libertine d-bus service.

Description of the change

Initial implementation of a libertine d-bus service.

How do it work? Every command is asynchronous. After making a call to the service, you'll get an object path back. You can listen on that object path for incoming data or listen for the task to finish with finished (success) or error (failure). It currently emits a processing signal every .5 seconds to let things like the Scopes SDK know there is an ongoing process, but we might want to consider removing this if we don't plan to be used by a specific scope.

What's not implemented? All things configure, fix-integrity, exec, merge. There is currently no way to get output directly from the running command (such as install/remove/create information). It would probably be a good idea to create an integration test which demonstrates how to use the service.

To post a comment you must log in.
Revision history for this message
Libertine CI Bot (libertine-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
356. By Larry Price

Merge

357. By Larry Price

attempt to get this file in

358. By Larry Price

checkpoint

Revision history for this message
Libertine CI Bot (libertine-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
359. By Larry Price

trying to fix test_task_dispatcher

Revision history for this message
Libertine CI Bot (libertine-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
360. By Larry Price

Removed appstream (find it at lp:~larryprice/+junk/libertine-service-with-appstream)

Revision history for this message
Libertine CI Bot (libertine-ci-bot) wrote :

FAILED: Continuous integration, rev:360
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/202/
Executed test runs:
    FAILURE: https://jenkins.canonical.com/libertine/job/build/451/console
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-0-fetch/453
    FAILURE: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/433/console
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/433
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/433/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/433
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/433/artifact/output/*zip*/output.zip
    FAILURE: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/433/console
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/433
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/433/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/433
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/433/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/202/rebuild

review: Needs Fixing (continuous-integration)
361. By Larry Price

Restructure checking task equality for the sake of vivid

Revision history for this message
Libertine CI Bot (libertine-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
362. By Larry Price

use a real function instead of a magic function to test fuzzy equality

Revision history for this message
Libertine CI Bot (libertine-ci-bot) wrote :

PASSED: Continuous integration, rev:362
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/204/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/libertine/job/build/453
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=vivid+overlay,testname=default/356
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=default/356
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=zesty,testname=default/356
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=vivid+overlay,testname=default/356
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=xenial+overlay,testname=default/356
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=zesty,testname=default/356
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-0-fetch/455
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/435
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/435/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/435
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/435/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/435
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/435/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/435
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/435/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/435
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/435/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/435
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/435/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/204/rebuild

review: Approve (continuous-integration)
363. By Larry Price

Merge

Revision history for this message
Libertine CI Bot (libertine-ci-bot) wrote :

PASSED: Continuous integration, rev:363
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/205/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/libertine/job/build/454
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=vivid+overlay,testname=default/357
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=default/357
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=zesty,testname=default/357
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=vivid+overlay,testname=default/357
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=xenial+overlay,testname=default/357
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=zesty,testname=default/357
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-0-fetch/456
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/436
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/436/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/436
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/436/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/436
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/436/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/436
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/436/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/436
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/436/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/436
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/436/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/205/rebuild

review: Approve (continuous-integration)
364. By Larry Price

Update for status reporting and delayed callback

Revision history for this message
Libertine CI Bot (libertine-ci-bot) wrote :

PASSED: Continuous integration, rev:364
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/206/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/libertine/job/build/455
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=vivid+overlay,testname=default/358
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=default/358
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=zesty,testname=default/358
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=vivid+overlay,testname=default/358
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=xenial+overlay,testname=default/358
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=zesty,testname=default/358
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-0-fetch/457
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/437
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/437/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/437
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/437/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/437
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/437/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/437
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/437/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/437
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/437/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/437
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/437/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/206/rebuild

review: Approve (continuous-integration)
365. By Larry Price

address minor threading issues

Revision history for this message
Libertine CI Bot (libertine-ci-bot) wrote :

PASSED: Continuous integration, rev:365
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/207/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/libertine/job/build/456
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=vivid+overlay,testname=default/359
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=default/359
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=zesty,testname=default/359
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=vivid+overlay,testname=default/359
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=xenial+overlay,testname=default/359
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=zesty,testname=default/359
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-0-fetch/458
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/438
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/438/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/438
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/438/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/438
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/438/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/438
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/438/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/438
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/438/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/438
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/438/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/207/rebuild

review: Approve (continuous-integration)
366. By Larry Price

update task retrieval

Revision history for this message
Libertine CI Bot (libertine-ci-bot) wrote :

PASSED: Continuous integration, rev:366
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/208/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/libertine/job/build/457
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=vivid+overlay,testname=default/360
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=default/360
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=zesty,testname=default/360
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=vivid+overlay,testname=default/360
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=xenial+overlay,testname=default/360
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=zesty,testname=default/360
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-0-fetch/459
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/439
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/439/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/439
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/439/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/439
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/439/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/439
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/439/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/439
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/439/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/439
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/439/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/208/rebuild

review: Approve (continuous-integration)
367. By Larry Price

upstreaming changes from integration branch

368. By Larry Price

fixing all the things

369. By Larry Price

stop double-running tests

Revision history for this message
Libertine CI Bot (libertine-ci-bot) wrote :

PASSED: Continuous integration, rev:368
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/209/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/libertine/job/build/458
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=vivid+overlay,testname=default/361
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=default/361
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=zesty,testname=default/361
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=vivid+overlay,testname=default/361
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=xenial+overlay,testname=default/361
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=zesty,testname=default/361
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-0-fetch/460
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/440
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/440/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/440
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/440/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/440
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/440/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/440
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/440/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/440
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/440/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/440
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/440/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/209/rebuild

review: Approve (continuous-integration)
Revision history for this message
Libertine CI Bot (libertine-ci-bot) wrote :

PASSED: Continuous integration, rev:369
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/210/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/libertine/job/build/459
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=vivid+overlay,testname=default/362
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=default/362
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=zesty,testname=default/362
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=vivid+overlay,testname=default/362
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=xenial+overlay,testname=default/362
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=zesty,testname=default/362
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-0-fetch/461
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/441
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/441/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/441
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/441/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/441
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/441/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/441
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/441/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/441
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/441/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/441
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/441/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/210/rebuild

review: Approve (continuous-integration)
370. By Larry Price

upstreaming changes from integration tests

Revision history for this message
Libertine CI Bot (libertine-ci-bot) wrote :

PASSED: Continuous integration, rev:370
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/211/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/libertine/job/build/460
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=vivid+overlay,testname=default/363
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=default/363
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=zesty,testname=default/363
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=vivid+overlay,testname=default/363
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=xenial+overlay,testname=default/363
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=zesty,testname=default/363
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-0-fetch/462
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/442
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/442/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/442
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/442/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/442
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/442/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/442
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/442/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/442
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/442/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/442
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/442/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/211/rebuild

review: Approve (continuous-integration)
371. By Larry Price

remove unused appstream dep

Revision history for this message
Libertine CI Bot (libertine-ci-bot) wrote :

FAILED: Continuous integration, rev:371
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/227/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/libertine/job/build/480
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=vivid+overlay,testname=default/377
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=default/377
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=zesty,testname=default/377
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=vivid+overlay,testname=default/377
    FAILURE: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=xenial+overlay,testname=default/377/console
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=zesty,testname=default/377
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-0-fetch/482
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/462
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/462/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/462
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/462/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/462
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/462/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/462
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/462/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/462
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/462/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/462
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/462/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/227/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Libertine CI Bot (libertine-ci-bot) wrote :

PASSED: Continuous integration, rev:371
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/228/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/libertine/job/build/481
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=vivid+overlay,testname=default/378
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=default/378
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=zesty,testname=default/378
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=vivid+overlay,testname=default/378
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=xenial+overlay,testname=default/378
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=zesty,testname=default/378
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-0-fetch/483
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/463
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/463/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/463
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/463/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/463
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/463/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/463
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/463/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/463
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/463/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/463
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/463/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/228/rebuild

review: Approve (continuous-integration)
372. By Larry Price

merge

Revision history for this message
Libertine CI Bot (libertine-ci-bot) wrote :

PASSED: Continuous integration, rev:372
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/233/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/libertine/job/build/489
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=vivid+overlay,testname=default/385
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=default/385
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=zesty,testname=default/385
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=vivid+overlay,testname=default/385
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=xenial+overlay,testname=default/385
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=zesty,testname=default/385
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-0-fetch/491
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/471
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/471/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/471
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/471/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/471
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/471/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/471
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/471/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/471
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/471/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/471
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/471/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/233/rebuild

review: Approve (continuous-integration)
Revision history for this message
Christopher Townsend (townsend) wrote :

Ok, let's get this in:)

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'data/CMakeLists.txt'
--- data/CMakeLists.txt 2016-10-07 18:58:30 +0000
+++ data/CMakeLists.txt 2016-11-16 17:34:14 +0000
@@ -8,7 +8,7 @@
8 DESTINATION ${CMAKE_INSTALL_DATADIR}/upstart/sessions)8 DESTINATION ${CMAKE_INSTALL_DATADIR}/upstart/sessions)
9install(FILES libertine-lxc-sudo9install(FILES libertine-lxc-sudo
10 DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/sudoers.d)10 DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/sudoers.d)
11install(FILES com.canonical.libertine.LxcManager.service11install(FILES com.canonical.libertine.LxcManager.service com.canonical.libertine.ContainerManager.service
12 DESTINATION ${CMAKE_INSTALL_DATADIR}/dbus-1/services)12 DESTINATION ${CMAKE_INSTALL_DATADIR}/dbus-1/services)
1313
14configure_file("python3-libertine-chroot.click-hook.in"14configure_file("python3-libertine-chroot.click-hook.in"
1515
=== added file 'data/com.canonical.libertine.ContainerManager.service'
--- data/com.canonical.libertine.ContainerManager.service 1970-01-01 00:00:00 +0000
+++ data/com.canonical.libertine.ContainerManager.service 2016-11-16 17:34:14 +0000
@@ -0,0 +1,3 @@
1[D-BUS Service]
2Name=com.canonical.libertine.ContainerManager
3Exec=/usr/bin/libertined --cache-output
04
=== modified file 'debian/libertine-tools.install'
--- debian/libertine-tools.install 2016-10-26 20:48:08 +0000
+++ debian/libertine-tools.install 2016-11-16 17:34:14 +0000
@@ -1,4 +1,6 @@
1usr/bin/libertine-container-manager1usr/bin/libertine-container-manager
2usr/bin/libertine-launch2usr/bin/libertine-launch
3usr/bin/libertined
4usr/share/dbus-1/services/com.canonical.libertine.ContainerManager.service
3usr/share/bash-completion/completions/libertine-container-manager5usr/share/bash-completion/completions/libertine-container-manager
4usr/share/man6usr/share/man
57
=== modified file 'debian/python3-libertine.install'
--- debian/python3-libertine.install 2016-10-13 18:28:34 +0000
+++ debian/python3-libertine.install 2016-11-16 17:34:14 +0000
@@ -4,4 +4,5 @@
4usr/lib/python*/*/libertine/Libertine.py4usr/lib/python*/*/libertine/Libertine.py
5usr/lib/python*/*/libertine/__init__.py5usr/lib/python*/*/libertine/__init__.py
6usr/lib/python*/*/libertine/launcher6usr/lib/python*/*/libertine/launcher
7usr/lib/python*/*/libertine/service
7usr/lib/python*/*/libertine/utils.py8usr/lib/python*/*/libertine/utils.py
89
=== modified file 'python/libertine/ChrootContainer.py'
--- python/libertine/ChrootContainer.py 2016-11-16 16:38:16 +0000
+++ python/libertine/ChrootContainer.py 2016-11-16 17:34:14 +0000
@@ -64,8 +64,10 @@
64 container_root = os.path.join(utils.get_libertine_containers_dir_path(), self.container_id)64 container_root = os.path.join(utils.get_libertine_containers_dir_path(), self.container_id)
65 try:65 try:
66 shutil.rmtree(container_root)66 shutil.rmtree(container_root)
67 return True
67 except Exception as e:68 except Exception as e:
68 print("%s" % e)69 print("%s" % e)
70 return False
6971
70 def create_libertine_container(self, password=None, multiarch=False, verbosity=1):72 def create_libertine_container(self, password=None, multiarch=False, verbosity=1):
71 # Create the actual chroot73 # Create the actual chroot
@@ -147,7 +149,7 @@
147 def update_packages(self, verbosity=1):149 def update_packages(self, verbosity=1):
148 retcode = super().update_packages(verbosity)150 retcode = super().update_packages(verbosity)
149 self._run_ldconfig(verbosity)151 self._run_ldconfig(verbosity)
150 return retcode152 return retcode == 0
151153
152 def install_package(self, package_name, verbosity=1, no_dialog=False, update_cache=True):154 def install_package(self, package_name, verbosity=1, no_dialog=False, update_cache=True):
153 returncode = super().install_package(package_name, verbosity, no_dialog, update_cache)155 returncode = super().install_package(package_name, verbosity, no_dialog, update_cache)
154156
=== modified file 'python/libertine/ContainersConfig.py'
--- python/libertine/ContainersConfig.py 2016-11-09 18:25:33 +0000
+++ python/libertine/ContainersConfig.py 2016-11-16 17:34:14 +0000
@@ -28,6 +28,7 @@
28 if (os.path.exists(container_config_file) and28 if (os.path.exists(container_config_file) and
29 os.path.getsize(container_config_file) != 0):29 os.path.getsize(container_config_file) != 0):
30 with open(container_config_file, 'r') as fd:30 with open(container_config_file, 'r') as fd:
31 fcntl.flock(fd, fcntl.LOCK_EX)
31 container_list = json.load(fd)32 container_list = json.load(fd)
3233
33 return container_list34 return container_list
@@ -41,18 +42,18 @@
41 container_list["_warning"] = "This file is automatically generated by Libertine and should not be manually edited."42 container_list["_warning"] = "This file is automatically generated by Libertine and should not be manually edited."
4243
43 with open(container_config_file, 'w') as fd:44 with open(container_config_file, 'w') as fd:
44 fcntl.lockf(fd, fcntl.LOCK_EX)45 fcntl.flock(fd, fcntl.LOCK_EX)
45 json.dump(container_list, fd, sort_keys=True, indent=4)46 json.dump(container_list, fd, sort_keys=True, indent=4)
46 fd.write('\n')47 fd.write('\n')
47 fcntl.lockf(fd, fcntl.LOCK_UN)
4848
4949
50def container_config_hash():50def container_config_hash():
51 checksum = md5()51 checksum = md5()
52 container_config_file = libertine.utils.get_libertine_database_file_path()52 container_config_file = libertine.utils.get_libertine_database_file_path()
53 if (os.path.exists(container_config_file) and os.path.getsize(container_config_file) != 0):53 if (os.path.exists(container_config_file) and os.path.getsize(container_config_file) != 0):
54 with open(container_config_file, "rb") as f:54 with open(container_config_file, "rb") as fd:
55 for chunk in iter(lambda: f.read(128 * checksum.block_size), b""):55 fcntl.flock(fd, fcntl.LOCK_EX)
56 for chunk in iter(lambda: fd.read(128 * checksum.block_size), b""):
56 checksum.update(chunk)57 checksum.update(chunk)
57 return checksum.hexdigest()58 return checksum.hexdigest()
5859
@@ -90,7 +91,8 @@
90 return container[key]91 return container[key]
9192
92 def _get_array_object_value_by_key(self, container_id, array_key, object_key, matcher, key):93 def _get_array_object_value_by_key(self, container_id, array_key, object_key, matcher, key):
93 for item in self._get_value_by_key(container_id, array_key):94 items = self._get_value_by_key(container_id, array_key) or []
95 for item in items:
94 if item[object_key] == matcher:96 if item[object_key] == matcher:
95 return item[key]97 return item[key]
9698
9799
=== modified file 'python/libertine/HostInfo.py'
--- python/libertine/HostInfo.py 2016-07-07 20:00:10 +0000
+++ python/libertine/HostInfo.py 2016-11-16 17:34:14 +0000
@@ -36,7 +36,7 @@
3636
37 return distinfo.get('CODENAME', 'n/a')37 return distinfo.get('CODENAME', 'n/a')
3838
39 def is_distro_valid(self, distro, force):39 def is_distro_valid(self, distro, force=False):
40 if force:40 if force:
41 return UbuntuDistroInfo().valid(distro)41 return UbuntuDistroInfo().valid(distro)
4242
4343
=== modified file 'python/libertine/Libertine.py'
--- python/libertine/Libertine.py 2016-11-10 16:36:05 +0000
+++ python/libertine/Libertine.py 2016-11-16 17:34:14 +0000
@@ -166,7 +166,7 @@
166 :param verbosity: the chattiness of the output on a range from 0 to 2166 :param verbosity: the chattiness of the output on a range from 0 to 2
167 """167 """
168 self.update_apt_cache(verbosity)168 self.update_apt_cache(verbosity)
169 return self.run_in_container(apt_command_prefix(verbosity) + '--force-yes dist-upgrade')169 return self.run_in_container(apt_command_prefix(verbosity) + '--force-yes dist-upgrade') == 0
170170
171 def install_package(self, package_name, verbosity=1, no_dialog=False, update_cache=True):171 def install_package(self, package_name, verbosity=1, no_dialog=False, update_cache=True):
172 """172 """
173173
=== modified file 'python/libertine/LxcContainer.py'
--- python/libertine/LxcContainer.py 2016-11-10 20:43:40 +0000
+++ python/libertine/LxcContainer.py 2016-11-16 17:34:14 +0000
@@ -199,9 +199,12 @@
199 return super().update_packages(verbosity)199 return super().update_packages(verbosity)
200200
201 def destroy_libertine_container(self):201 def destroy_libertine_container(self):
202 if self.container.defined:202 if not self.container.defined:
203 self.container.stop()203 return False
204 self.container.destroy()204
205 self.container.stop()
206 self.container.destroy()
207 return True
205208
206 def create_libertine_container(self, password=None, multiarch=False, verbosity=1):209 def create_libertine_container(self, password=None, multiarch=False, verbosity=1):
207 if password is None:210 if password is None:
208211
=== added directory 'python/libertine/service'
=== added file 'python/libertine/service/__init__.py'
=== added file 'python/libertine/service/apt.py'
--- python/libertine/service/apt.py 1970-01-01 00:00:00 +0000
+++ python/libertine/service/apt.py 2016-11-16 17:34:14 +0000
@@ -0,0 +1,77 @@
1# Copyright 2016 Canonical Ltd.
2#
3# This program is free software: you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; version 3 of the License.
6#
7# This program is distributed in the hope that it will be useful,
8# but WITHOUT ANY WARRANTY; without even the implied warranty of
9# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10# GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License
13# along with this program. If not, see <http://www.gnu.org/licenses/>.
14
15import apt
16import re
17
18import gi
19gi.require_version('Libertine', '1')
20from gi.repository import Libertine
21
22from libertine import utils
23from os import path
24from threading import Lock
25
26
27class AptCache(object):
28 """
29 Class to find app information using apt-cache
30 """
31 def __init__(self, container_id):
32 super(AptCache, self).__init__()
33 self._container = container_id
34 self._cache = None
35 self._lock = Lock()
36
37 def search(self, query):
38 self._load()
39
40 pkg_keys = [key for key in self._cache.keys() if re.match(query, key)]
41 apps = []
42 for key in pkg_keys:
43 apps.append(self._app_to_dict(key))
44 return apps
45
46 def app_info(self, app_id):
47 self._load()
48 return self._app_to_dict(app_id)
49
50 def _app_to_dict(self, app_id):
51 app_data = {}
52 if app_id in self._cache.keys():
53 app = self._cache[app_id]
54 app_data["name"] = app.name
55 app_data["id"] = app.name
56 app_data["package"] = app.name
57 if len(app.versions) > 0:
58 app_data["summary"] = app.versions[0].summary
59 app_data["website"] = app.versions[0].homepage
60 app_data["description"] = app.versions[0].description
61 app_data["package"] = app.name
62
63 return app_data
64
65 def _load(self):
66 with self._lock:
67 if self._cache is None:
68 try:
69 utils.get_logger().debug("Trying aptcache for container %s" % self._container)
70 container_path = Libertine.container_path(self._container)
71 if not container_path or not path.exists(container_path):
72 raise PermissionError
73
74 self._cache = apt.Cache(rootdir=container_path)
75 except PermissionError:
76 utils.get_logger().debug("Trying system aptcache")
77 self._cache = apt.Cache()
078
=== added file 'python/libertine/service/container.py'
--- python/libertine/service/container.py 1970-01-01 00:00:00 +0000
+++ python/libertine/service/container.py 2016-11-16 17:34:14 +0000
@@ -0,0 +1,139 @@
1# Copyright 2016 Canonical Ltd.
2#
3# This program is free software: you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; version 3 of the License.
6#
7# This program is distributed in the hope that it will be useful,
8# but WITHOUT ANY WARRANTY; without even the implied warranty of
9# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10# GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License
13# along with this program. If not, see <http://www.gnu.org/licenses/>.
14
15from libertine.service.tasks import *
16from libertine import utils
17from libertine.service import apt
18
19
20class Container(object):
21 def __init__(self, container_id, config, lock, connection, callback):
22 self._id = container_id
23 self._connection = connection
24 self._callback = callback
25 self._config = config
26 self._lock = lock
27 self._tasks = []
28 self._cache = apt.AptCache(self.id)
29
30 def _cleanup_task(self, task):
31 utils.get_logger().debug("cleaning up tasks for container '%s'" % self.id)
32
33 if task in self._tasks:
34 self._tasks.remove(task)
35
36 if len(self._tasks) == 0:
37 self._callback(self)
38
39 @property
40 def id(self):
41 return self._id
42
43 @property
44 def tasks(self):
45 return [task.id for task in self._tasks if task.running]
46
47 def search(self, query):
48 utils.get_logger().debug("search container '%s' for package '%s'" % (self.id, query))
49
50 task = SearchTask(self.id, self._cache, query, self._connection, self._cleanup_task)
51 self._tasks.append(task)
52 task.start()
53
54 return task.id
55
56 def app_info(self, package_name):
57 utils.get_logger().debug("get info for package '%s' in container '%s'" % (package_name, self.id))
58
59 related_task_ids = [t.id for t in self._tasks if t.package == package_name and t.running]
60 task = AppInfoTask(self.id, self._cache, package_name, related_task_ids, self._config, self._connection, self._cleanup_task)
61
62 self._tasks.append(task)
63 task.start()
64 return task.id
65
66 def install(self, package_name):
67 utils.get_logger().debug("Install package '%s' from container '%s'" % (package_name, self.id))
68
69 tasks = [t for t in self._tasks if t.matches(package_name, InstallTask) and t.running]
70 if len(tasks) > 0:
71 utils.get_logger().debug("Install already in progress for '%s':'%s'" % (package_name, self.id))
72 return tasks[0].id
73
74 task = InstallTask(package_name, self.id, self._config, self._lock, self._connection, self._cleanup_task)
75 self._tasks.append(task)
76 task.start()
77 return task.id
78
79 def remove(self, package_name):
80 utils.get_logger().debug("Remove package '%s' from container '%s'" % (package_name, self.id))
81
82 tasks = [t for t in self._tasks if t.matches(package_name, RemoveTask) and t.running]
83 if len(tasks) > 0:
84 utils.get_logger().debug("Remove already in progress for '%s':'%s'" % (package_name, self.id))
85 return tasks[0].id
86
87 task = RemoveTask(package_name, self.id, self._config, self._lock, self._connection, self._cleanup_task)
88 self._tasks.append(task)
89 task.start()
90 return task.id
91
92 def create(self, container_name, distro, container_type, enable_multiarch):
93 utils.get_logger().debug("Create container with ID '%s'" % self.id)
94
95 tasks = [t for t in self._tasks if t.matches(self.id, CreateTask) and t.running]
96 if len(tasks) > 0:
97 utils.get_logger().debug("Create already in progress for '%s'" % self.id)
98 return tasks[0].id
99
100 task = CreateTask(self.id, container_name, distro, container_type, enable_multiarch,
101 self._config, self._lock, self._connection, self._cleanup_task)
102 self._tasks.append(task)
103 task.start()
104 return task.id
105
106 def destroy(self):
107 utils.get_logger().debug("Destroy container with ID '%s'" % self.id)
108
109 tasks = [t for t in self._tasks if t.matches(self.id, DestroyTask) and t.running]
110 if len(tasks) > 0:
111 utils.get_logger().debug("Destroy already in progress for '%s'" % self.id)
112 return tasks[0].id
113
114 task = DestroyTask(self.id, self._config, self._lock, self._connection, self._cleanup_task)
115 self._tasks.append(task)
116 task.start()
117 return task.id
118
119 def update(self):
120 utils.get_logger().debug("Update container with ID '%s'" % self.id)
121
122 tasks = [t for t in self._tasks if t.matches(self.id, UpdateTask) and t.running]
123 if len(tasks) > 0:
124 utils.get_logger().debug("Update already in progress for '%s'" % self.id)
125 return tasks[0].id
126
127 task = UpdateTask(self.id, self._config, self._lock, self._connection, self._cleanup_task)
128 self._tasks.append(task)
129 task.start()
130 return task.id
131
132 def list_apps(self):
133 utils.get_logger().debug("List all apps in container '%s'" % self.id)
134
135 task = ListAppsTask(self.id, self._config, self._connection, self._cleanup_task)
136
137 self._tasks.append(task)
138 task.start()
139 return task.id
0140
=== added file 'python/libertine/service/manager.py'
--- python/libertine/service/manager.py 1970-01-01 00:00:00 +0000
+++ python/libertine/service/manager.py 2016-11-16 17:34:14 +0000
@@ -0,0 +1,115 @@
1# Copyright 2016 Canonical Ltd.
2#
3# This program is free software: you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; version 3 of the License.
6#
7# This program is distributed in the hope that it will be useful,
8# but WITHOUT ANY WARRANTY; without even the implied warranty of
9# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10# GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License
13# along with this program. If not, see <http://www.gnu.org/licenses/>.
14
15import dbus
16import dbus.service
17import libertine.service.task_dispatcher
18from dbus.mainloop.glib import DBusGMainLoop
19from libertine.service import container
20from libertine import utils
21
22
23LIBERTINE_MANAGER_NAME = "com.canonical.libertine.Service"
24LIBERTINE_MANAGER_INTERFACE = LIBERTINE_MANAGER_NAME
25LIBERTINE_STORE_PATH = "/Manager"
26
27
28class Manager(dbus.service.Object):
29 def __init__(self):
30 utils.get_logger().debug("creating service")
31 DBusGMainLoop(set_as_default=True)
32 try:
33 bus_name = dbus.service.BusName(LIBERTINE_MANAGER_NAME,
34 bus=dbus.SessionBus(),
35 do_not_queue=True)
36 except dbus.exceptions.NameExistsException:
37 utils.get_logger().warning("service is already running")
38 raise
39
40 super().__init__(bus_name, LIBERTINE_STORE_PATH)
41
42 self._dispatcher = libertine.service.task_dispatcher.TaskDispatcher(self.connection)
43
44 # Information
45
46 @dbus.service.method(LIBERTINE_MANAGER_INTERFACE,
47 in_signature='ss',
48 out_signature='o')
49 def search(self, container_id, search_string):
50 utils.get_logger().debug("search('{}', '{}') called".format(container_id, search_string))
51 return self._dispatcher.search(container_id, search_string)
52
53 @dbus.service.method(LIBERTINE_MANAGER_INTERFACE,
54 in_signature='ss',
55 out_signature='o')
56 def app_info(self, container_id, app_id):
57 utils.get_logger().debug("app_info('{}', '{}') called".format(container_id, app_id))
58 return self._dispatcher.app_info(container_id, app_id)
59
60 @dbus.service.method(LIBERTINE_MANAGER_INTERFACE,
61 in_signature='s',
62 out_signature='o')
63 def container_info(self, container_id):
64 utils.get_logger().debug("container_info('{}')".format(container_id))
65 return self._dispatcher.container_info(container_id)
66
67 @dbus.service.method(LIBERTINE_MANAGER_INTERFACE,
68 in_signature='s',
69 out_signature='o')
70 def list_apps(self, container_id):
71 utils.get_logger().debug("list_apps('{}')".format(container_id))
72 return self._dispatcher.list_apps(container_id)
73
74 @dbus.service.method(LIBERTINE_MANAGER_INTERFACE,
75 out_signature='o')
76 def list(self):
77 utils.get_logger().debug("list()")
78 return self._dispatcher.list()
79
80 # Operations
81
82 @dbus.service.method(LIBERTINE_MANAGER_INTERFACE,
83 in_signature='ssssb',
84 out_signature='o')
85 def create(self, container_id, container_name='', distro='', container_type='', enable_multiarch=False):
86 utils.get_logger().debug("create('{}', '{}', '{}', '{}', '{}')".format(container_id, container_name, distro, container_type, enable_multiarch))
87 return self._dispatcher.create(container_id, container_name, distro, container_type, enable_multiarch)
88
89 @dbus.service.method(LIBERTINE_MANAGER_INTERFACE,
90 in_signature='s',
91 out_signature='o')
92 def destroy(self, container_id):
93 utils.get_logger().debug("destroy('{}')".format(container_id))
94 return self._dispatcher.destroy(container_id)
95
96 @dbus.service.method(LIBERTINE_MANAGER_INTERFACE,
97 in_signature='s',
98 out_signature='o')
99 def update(self, container_id):
100 utils.get_logger().debug("update('{}')".format(container_id))
101 return self._dispatcher.update(container_id)
102
103 @dbus.service.method(LIBERTINE_MANAGER_INTERFACE,
104 in_signature='ss',
105 out_signature='o')
106 def install(self, container_id, package_name):
107 utils.get_logger().debug("install('%s', '%s')" % (container_id, package_name))
108 return self._dispatcher.install(container_id, package_name)
109
110 @dbus.service.method(LIBERTINE_MANAGER_INTERFACE,
111 in_signature='ss',
112 out_signature='o')
113 def remove(self, container_id, package_name):
114 utils.get_logger().debug("remove('%s', '%s')" % (container_id, package_name))
115 return self._dispatcher.remove(container_id, package_name)
0116
=== added file 'python/libertine/service/progress.py'
--- python/libertine/service/progress.py 1970-01-01 00:00:00 +0000
+++ python/libertine/service/progress.py 2016-11-16 17:34:14 +0000
@@ -0,0 +1,83 @@
1# Copyright 2016 Canonical Ltd.
2#
3# This program is free software: you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; version 3 of the License.
6#
7# This program is distributed in the hope that it will be useful,
8# but WITHOUT ANY WARRANTY; without even the implied warranty of
9# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10# GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License
13# along with this program. If not, see <http://www.gnu.org/licenses/>.
14
15import dbus.service
16import threading
17from libertine import utils
18from time import time
19
20DOWNLOAD_INTERFACE = "com.canonical.applications.Download"
21PROGRESS_INTERFACE = "com.canonical.libertine.Progress"
22
23class Progress(dbus.service.Object):
24 def __init__(self, connection):
25 utils.get_logger().debug("creating a Progress object")
26 self._finished = False
27 self._result = []
28 self._error = ''
29 dbus.service.Object.__init__(self, conn=connection, object_path=("/Progress/%s" % hex(int(time()*10000000))[2:]))
30
31 self.emit_processing()
32
33 @property
34 def id(self):
35 return self._object_path
36
37 def emit_processing(self):
38 if not self.done:
39 self.processing(self.id)
40 threading.Timer(0.5, self.emit_processing).start()
41
42 @property
43 def done(self):
44 return self._finished
45
46 @dbus.service.signal(DOWNLOAD_INTERFACE)
47 def processing(self, path):
48 utils.get_logger().debug("emit processing('%s')" % path)
49
50 @dbus.service.signal(DOWNLOAD_INTERFACE)
51 def finished(self, path):
52 utils.get_logger().debug("emit finished('%s')" % path)
53 self._finished = True
54
55 @dbus.service.signal(DOWNLOAD_INTERFACE)
56 def progress(self, received, total):
57 utils.get_logger().debug("emit progress(%d, %d)" % (received, total))
58
59 @dbus.service.signal(DOWNLOAD_INTERFACE)
60 def error(self, message):
61 utils.get_logger().error("emit error(%s)" % message)
62 self._error = message
63 self._finished = True
64
65 @dbus.service.signal(PROGRESS_INTERFACE)
66 def data(self, message):
67 utils.get_logger().debug("emit data(%s)" % message)
68 self._result.append(message)
69
70 @dbus.service.method(PROGRESS_INTERFACE, out_signature='b')
71 def running(self):
72 utils.get_logger().debug("running()")
73 return not self.done
74
75 @dbus.service.method(PROGRESS_INTERFACE, out_signature='s')
76 def result(self):
77 utils.get_logger().debug("result()")
78 return "\n".join(self._result)
79
80 @dbus.service.method(PROGRESS_INTERFACE, out_signature='s')
81 def last_error(self):
82 utils.get_logger().debug("last_error()")
83 return self._error
084
=== added file 'python/libertine/service/task_dispatcher.py'
--- python/libertine/service/task_dispatcher.py 1970-01-01 00:00:00 +0000
+++ python/libertine/service/task_dispatcher.py 2016-11-16 17:34:14 +0000
@@ -0,0 +1,114 @@
1# Copyright 2016 Canonical Ltd.
2#
3# This program is free software: you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; version 3 of the License.
6#
7# This program is distributed in the hope that it will be useful,
8# but WITHOUT ANY WARRANTY; without even the implied warranty of
9# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10# GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License
13# along with this program. If not, see <http://www.gnu.org/licenses/>.
14
15
16import libertine.ContainersConfig
17from libertine.service.container import Container
18from libertine.service.tasks import *
19from threading import Lock
20from libertine import utils
21
22
23class TaskDispatcher(object):
24 def __init__(self, connection):
25 self._connection = connection
26 self._config = libertine.ContainersConfig.ContainersConfig()
27 self._lock = Lock()
28 self._containerless_tasks = []
29 self._tasks = []
30 self._containers = []
31
32 def _cleanup_task(self, task):
33 utils.get_logger().debug("cleaning up containerless task '%s'" % task.id)
34 if task in self._tasks:
35 self._tasks.remove(task)
36
37 def _cleanup_container(self, container):
38 utils.get_logger().debug("cleaning up container '%s'" % container)
39 if container in self._containers:
40 self._containers.remove(container)
41
42 def _find_or_create_container(self, container_id):
43 utils.get_logger().debug("finding or creating container '%s'" % container_id)
44 container = self._find_container(container_id)
45 if container is not None:
46 utils.get_logger().debug("using existing container '%s'" % container_id)
47 return container
48 container = Container(container_id, self._config, self._lock, self._connection, self._cleanup_container)
49 self._containers.append(container)
50
51 return container
52
53 def _find_container(self, container_id):
54 containers = [c for c in self._containers if c.id == container_id]
55 if len(containers) > 0:
56 return containers[0]
57
58 # Tasks (usually) run within a container
59
60 def search(self, container_id, query):
61 utils.get_logger().debug("dispatching search in container '%s' for package '%s'" % (container_id, query))
62 return self._find_or_create_container(container_id).search(query)
63
64 def app_info(self, container_id, app_id):
65 utils.get_logger().debug("dispatching app_info in container '%s' for package '%s'" % (container_id, app_id))
66 return self._find_or_create_container(container_id).app_info(app_id)
67
68 def install(self, container_id, package_name):
69 utils.get_logger().debug("dispatching install of package '%s' from container '%s'" % (package_name, container_id))
70 return self._find_or_create_container(container_id).install(package_name)
71
72 def remove(self, container_id, package_name):
73 utils.get_logger().debug("dispatching remove of package '%s' from container '%s'" % (package_name, container_id))
74 return self._find_or_create_container(container_id).remove(package_name)
75
76 def create(self, container_id, container_name, distro, container_type, enable_multiarch):
77 utils.get_logger().debug("dispatching create of container '%s'" % container_id)
78 return self._find_or_create_container(container_id).create(container_name, distro, container_type, enable_multiarch)
79
80 def destroy(self, container_id):
81 utils.get_logger().debug("dispatching destroy container '%s'" % container_id)
82 return self._find_or_create_container(container_id).destroy()
83
84 def update(self, container_id):
85 utils.get_logger().debug("dispatching update container '%s'" % container_id)
86 return self._find_or_create_container(container_id).update()
87
88 def list_apps(self, container_id):
89 utils.get_logger().debug("dispatching list all apps in container '%s'" % container_id)
90 return self._find_or_create_container(container_id).list_apps()
91
92 # Containerless Tasks
93
94 def container_info(self, container_id):
95 utils.get_logger().debug("dispatching get info for container '%s'" % container_id)
96
97 related_task_ids = []
98 container = self._find_container(container_id)
99 if container is not None:
100 related_task_ids = container.tasks
101 task = ContainerInfoTask(container_id, related_task_ids, self._config, self._connection, self._cleanup_task)
102 self._tasks.append(task)
103 task.start()
104
105 return task.id
106
107 def list(self):
108 utils.get_logger().debug("dispatching list all containers")
109
110 task = ListTask(self._connection, self._cleanup_task)
111 self._tasks.append(task)
112 task.start()
113
114 return task.id
0115
=== added directory 'python/libertine/service/tasks'
=== added file 'python/libertine/service/tasks/__init__.py'
--- python/libertine/service/tasks/__init__.py 1970-01-01 00:00:00 +0000
+++ python/libertine/service/tasks/__init__.py 2016-11-16 17:34:14 +0000
@@ -0,0 +1,39 @@
1# Copyright 2016 Canonical Ltd.
2#
3# This program is free software: you can redistribute it and/or modify it
4# under the terms of the GNU General Public License version 3, as published
5# by the Free Software Foundation.
6#
7# This program is distributed in the hope that it will be useful, but
8# WITHOUT ANY WARRANTY; without even the implied warranties of
9# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
10# PURPOSE. See the GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License along
13# with this program. If not, see <http://www.gnu.org/licenses/>.
14
15from .base_task import BaseTask
16from .app_info_task import AppInfoTask
17from .container_info_task import ContainerInfoTask
18from .create_task import CreateTask
19from .destroy_task import DestroyTask
20from .install_task import InstallTask
21from .remove_task import RemoveTask
22from .search_task import SearchTask
23from .update_task import UpdateTask
24from .list_task import ListTask
25from .list_apps_task import ListAppsTask
26
27__all__ = [
28 'AppInfoTask',
29 'BaseTask',
30 'ContainerInfoTask',
31 'CreateTask',
32 'DestroyTask',
33 'InstallTask',
34 'RemoveTask',
35 'SearchTask',
36 'UpdateTask',
37 'ListTask',
38 'ListAppsTask'
39 ]
040
=== added file 'python/libertine/service/tasks/app_info_task.py'
--- python/libertine/service/tasks/app_info_task.py 1970-01-01 00:00:00 +0000
+++ python/libertine/service/tasks/app_info_task.py 2016-11-16 17:34:14 +0000
@@ -0,0 +1,35 @@
1# Copyright 2016 Canonical Ltd.
2#
3# This program is free software: you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; version 3 of the License.
6#
7# This program is distributed in the hope that it will be useful,
8# but WITHOUT ANY WARRANTY; without even the implied warranty of
9# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10# GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License
13# along with this program. If not, see <http://www.gnu.org/licenses/>.
14
15
16from .base_task import BaseTask
17from libertine import utils
18
19
20class AppInfoTask(BaseTask):
21 def __init__(self, container_id, cache, app_id, tasks, config, connection, callback):
22 super().__init__(lock=None, container_id=container_id, config=config, connection=connection, callback=callback)
23 self._cache = cache
24 self._app_id = app_id
25 self._tasks = tasks
26
27 def _run(self):
28 app = self._cache.app_info(self._app_id)
29 if app == {}:
30 self._progress.error("Could not find app info for '%s' in container '%s'" % (self._app_id, self._container))
31 return
32
33 app['status'] = self._config.get_package_install_status(self._container, app['package']) or ''
34 app['task_ids'] = self._tasks
35 self._progress.data(str(app))
036
=== added file 'python/libertine/service/tasks/base_task.py'
--- python/libertine/service/tasks/base_task.py 1970-01-01 00:00:00 +0000
+++ python/libertine/service/tasks/base_task.py 2016-11-16 17:34:14 +0000
@@ -0,0 +1,94 @@
1# Copyright 2016 Canonical Ltd.
2#
3# This program is free software: you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; version 3 of the License.
6#
7# This program is distributed in the hope that it will be useful,
8# but WITHOUT ANY WARRANTY; without even the implied warranty of
9# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10# GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License
13# along with this program. If not, see <http://www.gnu.org/licenses/>.
14
15import libertine.service.progress
16import threading
17from abc import ABCMeta, abstractmethod
18from libertine import utils
19
20
21class BaseTask(metaclass=ABCMeta):
22 """
23 Abstract class for performing long-running, synchronous operations on a
24 Libertine container. Child classes must implement _run, which will execute
25 in a separate thread. Override _before to implement pre-execution actions
26 without locking; if _before returns False, _run will not be executed.
27 """
28 def __init__(self, lock, container_id, config, connection, callback):
29 self._lock = lock
30 self._container = container_id
31 self._config = config
32 self._callback = callback
33 self._connection = connection
34 self._progress = None
35 self._instant_callback = False
36
37 def matches(self, container, klass):
38 return self._container == container and self.__class__ == klass
39
40 @property
41 def id(self):
42 if self._progress is not None:
43 return self._progress.id
44 else:
45 return None
46
47 @property
48 def container(self):
49 return self._container or ''
50
51 @property
52 def package(self):
53 return ''
54
55 @property
56 def running(self):
57 return not self._progress.done
58
59 def _delayed_callback(self):
60 if self._instant_callback:
61 self._callback(self)
62 else:
63 threading.Timer(30, lambda: self._callback(self)).start()
64
65 def start(self):
66 self._progress = libertine.service.progress.Progress(self._connection)
67 thread = threading.Thread(target=self.run)
68 thread.start()
69 return thread
70
71 def run(self):
72 if not self._before():
73 self._progress.finished(self.container)
74 self._delayed_callback()
75 return
76
77 if self._lock is not None:
78 with self._lock:
79 self._run()
80 else:
81 self._run()
82
83 if self.running:
84 self._progress.finished(self.container)
85 utils.refresh_libertine_scope()
86
87 self._delayed_callback()
88
89 @abstractmethod
90 def _run(self):
91 pass
92
93 def _before(self):
94 return True
095
=== added file 'python/libertine/service/tasks/container_info_task.py'
--- python/libertine/service/tasks/container_info_task.py 1970-01-01 00:00:00 +0000
+++ python/libertine/service/tasks/container_info_task.py 2016-11-16 17:34:14 +0000
@@ -0,0 +1,29 @@
1# Copyright 2016 Canonical Ltd.
2#
3# This program is free software: you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; version 3 of the License.
6#
7# This program is distributed in the hope that it will be useful,
8# but WITHOUT ANY WARRANTY; without even the implied warranty of
9# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10# GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License
13# along with this program. If not, see <http://www.gnu.org/licenses/>.
14
15
16from .base_task import BaseTask
17from libertine import utils
18
19
20class ContainerInfoTask(BaseTask):
21 def __init__(self, container_id, tasks, config, connection, callback):
22 super().__init__(lock=None, container_id=container_id, config=config, connection=connection, callback=callback)
23 self._tasks = tasks
24
25 def _run(self):
26 container = {'id': str(self._container)}
27 container['status'] = self._config._get_value_by_key(self._container, 'installStatus') or ''
28 container['task_ids'] = self._tasks
29 self._progress.data(str(container))
030
=== added file 'python/libertine/service/tasks/create_task.py'
--- python/libertine/service/tasks/create_task.py 1970-01-01 00:00:00 +0000
+++ python/libertine/service/tasks/create_task.py 2016-11-16 17:34:14 +0000
@@ -0,0 +1,72 @@
1# Copyright 2016 Canonical Ltd.
2#
3# This program is free software: you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; version 3 of the License.
6#
7# This program is distributed in the hope that it will be useful,
8# but WITHOUT ANY WARRANTY; without even the implied warranty of
9# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10# GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License
13# along with this program. If not, see <http://www.gnu.org/licenses/>.
14
15
16from .base_task import BaseTask
17from libertine import LibertineContainer, utils
18from libertine.HostInfo import HostInfo
19
20
21class CreateTask(BaseTask):
22 def __init__(self, container_id, container_name, distro, container_type, enable_multiarch, config, lock, connection, callback):
23 super().__init__(lock=lock, container_id=container_id, config=config, connection=connection, callback=callback)
24 self._name = container_name
25 self._distro = distro
26 self._type = container_type
27 self._multiarch = enable_multiarch
28
29 def _run(self):
30 utils.get_logger().debug("Creating container '%s'" % self._container)
31
32 try:
33 container = LibertineContainer(self._container, self._config)
34
35 if not container.create_libertine_container(password='', multiarch=self._multiarch):
36 self._config.delete_container(self._container)
37 self._progress.error("Creating container '%s' failed" % self._container)
38 else:
39 self._config.update_container_install_status(self._container, "ready")
40 except RuntimeError as e:
41 self._progress.error(str(e))
42 self._config.delete_container(self._container)
43
44 def _before(self):
45 utils.get_logger().debug("CreateTask::_before")
46 if self._config.container_exists(self._container):
47 self._progress.error("Container '%s' already exists" % self._container)
48 return False
49
50 info = HostInfo()
51 if not self._distro:
52 self._distro = info.get_host_distro_release()
53 elif not info.is_distro_valid(self._distro):
54 self._progress.error("Invalid distro '%s'." % self._distro)
55 return False
56
57 if not self._type:
58 self._type = info.select_container_type_by_kernel()
59 elif self._type == 'lxc' and not info.has_lxc_support():
60 self._progress.error("System kernel does not support lxc type containers. Please either use chroot or leave empty.")
61 return False
62
63 if not self._name:
64 self._name = "Ubuntu \'" + info.get_distro_codename(self._distro) + "\'"
65
66 self._config.add_new_container(self._container, self._name, self._type, self._distro)
67
68 if self._multiarch:
69 self._config.update_container_multiarch_support(self._container, 'enabled')
70
71 self._config.update_container_install_status(self._container, 'installing')
72 return True
073
=== added file 'python/libertine/service/tasks/destroy_task.py'
--- python/libertine/service/tasks/destroy_task.py 1970-01-01 00:00:00 +0000
+++ python/libertine/service/tasks/destroy_task.py 2016-11-16 17:34:14 +0000
@@ -0,0 +1,42 @@
1# Copyright 2016 Canonical Ltd.
2#
3# This program is free software: you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; version 3 of the License.
6#
7# This program is distributed in the hope that it will be useful,
8# but WITHOUT ANY WARRANTY; without even the implied warranty of
9# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10# GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License
13# along with this program. If not, see <http://www.gnu.org/licenses/>.
14
15
16from .base_task import BaseTask
17from libertine import LibertineContainer, utils
18
19
20class DestroyTask(BaseTask):
21 def __init__(self, container_id, config, lock, connection, callback):
22 super().__init__(lock=lock, container_id=container_id, config=config, connection=connection, callback=callback)
23
24 def _run(self):
25 utils.get_logger().debug("Destroying container '%s'" % self._container)
26
27 container = LibertineContainer(self._container, self._config)
28 if not container.destroy_libertine_container():
29 self._progress.error("Destroying container '%s' failed" % self._container)
30 self._config.update_container_install_status(self._container, "ready")
31 return
32
33 self._config.delete_container(self._container)
34
35 def _before(self):
36 utils.get_logger().debug("CreateTask::_before")
37 if self._config._get_value_by_key(self._container, 'installStatus') != 'ready':
38 self._progress.error("Container '%s' does not exist" % self._container)
39 return False
40
41 self._config.update_container_install_status(self._container, 'removing')
42 return True
043
=== added file 'python/libertine/service/tasks/install_task.py'
--- python/libertine/service/tasks/install_task.py 1970-01-01 00:00:00 +0000
+++ python/libertine/service/tasks/install_task.py 2016-11-16 17:34:14 +0000
@@ -0,0 +1,49 @@
1# Copyright 2016 Canonical Ltd.
2#
3# This program is free software: you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; version 3 of the License.
6#
7# This program is distributed in the hope that it will be useful,
8# but WITHOUT ANY WARRANTY; without even the implied warranty of
9# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10# GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License
13# along with this program. If not, see <http://www.gnu.org/licenses/>.
14
15
16from .base_task import BaseTask
17from libertine import LibertineContainer, utils
18
19
20class InstallTask(BaseTask):
21 def __init__(self, package_name, container_id, config, lock, connection, callback):
22 super().__init__(lock=lock, container_id=container_id, config=config, connection=connection, callback=callback)
23 self._package = package_name
24
25 def matches(self, package, klass):
26 return self._package == package and self.__class__ == klass
27
28 @property
29 def package(self):
30 return self._package
31
32 def _run(self):
33 utils.get_logger().debug("Installing package '%s'" % self._package)
34 container = LibertineContainer(self._container, self._config)
35 if container.install_package(self._package):
36 self._config.update_package_install_status(self._container, self._package, "installed")
37 else:
38 self._config.delete_package(self._container, self._package)
39 self._progress.error("Package installation failed for '%s'" % self._package)
40
41 def _before(self):
42 utils.get_logger().debug("InstallTask::_before")
43 if self._config.package_exists(self._container, self._package):
44 self._progress.error("Package '%s' already exists, skipping install" % self._package)
45 return False
46 else:
47 self._config.add_new_package(self._container, self._package)
48 self._config.update_package_install_status(self._container, self._package, "installing")
49 return True
050
=== added file 'python/libertine/service/tasks/list_apps_task.py'
--- python/libertine/service/tasks/list_apps_task.py 1970-01-01 00:00:00 +0000
+++ python/libertine/service/tasks/list_apps_task.py 2016-11-16 17:34:14 +0000
@@ -0,0 +1,30 @@
1# Copyright 2016 Canonical Ltd.
2#
3# This program is free software: you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; version 3 of the License.
6#
7# This program is distributed in the hope that it will be useful,
8# but WITHOUT ANY WARRANTY; without even the implied warranty of
9# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10# GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License
13# along with this program. If not, see <http://www.gnu.org/licenses/>.
14
15
16from .base_task import BaseTask
17from libertine import LibertineContainer, utils
18
19
20class ListAppsTask(BaseTask):
21 def __init__(self, container_id, config, connection, callback):
22 super().__init__(lock=None, container_id=container_id, config=config, connection=connection, callback=callback)
23
24 def _run(self):
25 utils.get_logger().debug("Listing apps in container '%s'" % self._container)
26 if not self._config.container_exists(self._container):
27 self._progress.error("Container '%s' does not exist, skipping list" % self._container)
28 else:
29 container = LibertineContainer(self._container, self._config)
30 self._progress.data(str(container.list_app_launchers(use_json=True)))
031
=== added file 'python/libertine/service/tasks/list_task.py'
--- python/libertine/service/tasks/list_task.py 1970-01-01 00:00:00 +0000
+++ python/libertine/service/tasks/list_task.py 2016-11-16 17:34:14 +0000
@@ -0,0 +1,25 @@
1# Copyright 2016 Canonical Ltd.
2#
3# This program is free software: you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; version 3 of the License.
6#
7# This program is distributed in the hope that it will be useful,
8# but WITHOUT ANY WARRANTY; without even the implied warranty of
9# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10# GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License
13# along with this program. If not, see <http://www.gnu.org/licenses/>.
14
15
16from .base_task import BaseTask
17from libertine import utils
18
19
20class ListTask(BaseTask):
21 def __init__(self, connection, callback):
22 super().__init__(lock=None, container_id=None, config=None, connection=connection, callback=callback)
23
24 def _run(self):
25 self._progress.data(str(utils.Libertine.list_containers()))
026
=== added file 'python/libertine/service/tasks/remove_task.py'
--- python/libertine/service/tasks/remove_task.py 1970-01-01 00:00:00 +0000
+++ python/libertine/service/tasks/remove_task.py 2016-11-16 17:34:14 +0000
@@ -0,0 +1,48 @@
1# Copyright 2016 Canonical Ltd.
2#
3# This program is free software: you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; version 3 of the License.
6#
7# This program is distributed in the hope that it will be useful,
8# but WITHOUT ANY WARRANTY; without even the implied warranty of
9# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10# GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License
13# along with this program. If not, see <http://www.gnu.org/licenses/>.
14
15
16from .base_task import BaseTask
17from libertine import LibertineContainer, utils
18
19
20class RemoveTask(BaseTask):
21 def __init__(self, package_name, container_id, config, lock, connection, callback):
22 super().__init__(lock=lock, container_id=container_id, config=config, connection=connection, callback=callback)
23 self._package = package_name
24
25 def matches(self, package, klass):
26 return self._package == package and self.__class__ == klass
27
28 @property
29 def package(self):
30 return self._package
31
32 def _run(self):
33 utils.get_logger().debug("Removing package '%s'" % self._package)
34 container = LibertineContainer(self._container, self._config)
35 if container.remove_package(self._package):
36 self._config.delete_package(self._container, self._package)
37 else:
38 self._config.update_package_install_status(self._container, self._package, 'installed')
39 self._progress.error("Package removal failed for '%s'" % self._package)
40
41 def _before(self):
42 utils.get_logger().debug("RemoveTask::_before")
43 if self._config.get_package_install_status(self._container, self._package) == 'installed':
44 self._config.update_package_install_status(self._container, self._package, "removing")
45 return True
46 else:
47 self._progress.error("Package '%s' not installed, skipping remove" % self._package)
48 return False
049
=== added file 'python/libertine/service/tasks/search_task.py'
--- python/libertine/service/tasks/search_task.py 1970-01-01 00:00:00 +0000
+++ python/libertine/service/tasks/search_task.py 2016-11-16 17:34:14 +0000
@@ -0,0 +1,27 @@
1# Copyright 2016 Canonical Ltd.
2#
3# This program is free software: you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; version 3 of the License.
6#
7# This program is distributed in the hope that it will be useful,
8# but WITHOUT ANY WARRANTY; without even the implied warranty of
9# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10# GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License
13# along with this program. If not, see <http://www.gnu.org/licenses/>.
14
15
16from .base_task import BaseTask
17from libertine import utils
18
19
20class SearchTask(BaseTask):
21 def __init__(self, container_id, cache, query, connection, callback):
22 super().__init__(lock=None, container_id=container_id, config=None, connection=connection, callback=callback)
23 self._cache = cache
24 self._query = query
25
26 def _run(self):
27 self._progress.data(str(self._cache.search(self._query)))
028
=== added file 'python/libertine/service/tasks/update_task.py'
--- python/libertine/service/tasks/update_task.py 1970-01-01 00:00:00 +0000
+++ python/libertine/service/tasks/update_task.py 2016-11-16 17:34:14 +0000
@@ -0,0 +1,39 @@
1# Copyright 2016 Canonical Ltd.
2#
3# This program is free software: you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; version 3 of the License.
6#
7# This program is distributed in the hope that it will be useful,
8# but WITHOUT ANY WARRANTY; without even the implied warranty of
9# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10# GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License
13# along with this program. If not, see <http://www.gnu.org/licenses/>.
14
15
16from .base_task import BaseTask
17from libertine import LibertineContainer, utils
18
19
20class UpdateTask(BaseTask):
21 def __init__(self, container_id, config, lock, connection, callback):
22 super().__init__(lock=lock, container_id=container_id, config=config, connection=connection, callback=callback)
23
24 def _run(self):
25 utils.get_logger().debug("Updating container '%s'" % self._container)
26 container = LibertineContainer(self._container, self._config)
27 self._config.update_container_install_status(self._container, "updating")
28 if not container.update_libertine_container():
29 self._progress.error("Failed to update container '%s'" % self._container)
30
31 self._config.update_container_install_status(self._container, "ready")
32
33 def _before(self):
34 utils.get_logger().debug("UpdateTask::_before")
35 if not self._config.container_exists(self._container):
36 self._progress.error("Container '%s' does not exist, skipping update" % self._container)
37 return False
38 else:
39 return True
040
=== modified file 'tests/unit/CMakeLists.txt'
--- tests/unit/CMakeLists.txt 2016-09-27 00:55:28 +0000
+++ tests/unit/CMakeLists.txt 2016-11-16 17:34:14 +0000
@@ -30,3 +30,4 @@
30 ENVIRONMENT30 ENVIRONMENT
31 "GI_TYPELIB_PATH=${CMAKE_BINARY_DIR}/liblibertine;LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/liblibertine:${LD_LIBRARY_PATH};CMAKE_BINARY_DIR=${CMAKE_BINARY_DIR};PYTHONPATH=${CMAKE_SOURCE_DIR}/python;CMAKE_SOURCE_DIR=${CMAKE_SOURCE_DIR}")31 "GI_TYPELIB_PATH=${CMAKE_BINARY_DIR}/liblibertine;LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/liblibertine:${LD_LIBRARY_PATH};CMAKE_BINARY_DIR=${CMAKE_BINARY_DIR};PYTHONPATH=${CMAKE_SOURCE_DIR}/python;CMAKE_SOURCE_DIR=${CMAKE_SOURCE_DIR}")
3232
33add_subdirectory(service)
3334
=== added file 'tests/unit/pytest.ini'
--- tests/unit/pytest.ini 1970-01-01 00:00:00 +0000
+++ tests/unit/pytest.ini 2016-11-16 17:34:14 +0000
@@ -0,0 +1,2 @@
1[pytest]
2norecursedirs = service
03
=== added directory 'tests/unit/service'
=== added file 'tests/unit/service/CMakeLists.txt'
--- tests/unit/service/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ tests/unit/service/CMakeLists.txt 2016-11-16 17:34:14 +0000
@@ -0,0 +1,12 @@
1function(create_service_unit_test test_name)
2 add_test(${test_name} /usr/bin/python3 -m testtools.run ${test_name})
3 set_tests_properties(${test_name}
4 PROPERTIES ENVIRONMENT
5 "GI_TYPELIB_PATH=${CMAKE_BINARY_DIR}/liblibertine;LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/liblibertine:${LD_LIBRARY_PATH};PYTHONPATH=${CMAKE_CURRENT_SOURCE_DIR}:${CMAKE_SOURCE_DIR}/python;LIBERTINE_DATA_DIR=${CMAKE_CURRENT_SOURCE_DIR}")
6endfunction(create_service_unit_test)
7
8create_service_unit_test(test_container)
9create_service_unit_test(test_apt)
10create_service_unit_test(test_task_dispatcher)
11
12add_subdirectory(tasks)
013
=== added directory 'tests/unit/service/containerroot'
=== added directory 'tests/unit/service/containerroot/var'
=== added directory 'tests/unit/service/containerroot/var/cache'
=== added directory 'tests/unit/service/containerroot/var/cache/app-info'
=== added directory 'tests/unit/service/containerroot/var/cache/app-info/gv'
=== added file 'tests/unit/service/containerroot/var/cache/app-info/gv/en_US.gvz'
=== added directory 'tests/unit/service/tasks'
=== added file 'tests/unit/service/tasks/CMakeLists.txt'
--- tests/unit/service/tasks/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ tests/unit/service/tasks/CMakeLists.txt 2016-11-16 17:34:14 +0000
@@ -0,0 +1,10 @@
1create_service_unit_test(test_app_info_task)
2create_service_unit_test(test_container_info_task)
3create_service_unit_test(test_create_task)
4create_service_unit_test(test_destroy_task)
5create_service_unit_test(test_install_task)
6create_service_unit_test(test_list_task)
7create_service_unit_test(test_list_apps_task)
8create_service_unit_test(test_remove_task)
9create_service_unit_test(test_search_task)
10create_service_unit_test(test_update_task)
011
=== added file 'tests/unit/service/tasks/test_app_info_task.py'
--- tests/unit/service/tasks/test_app_info_task.py 1970-01-01 00:00:00 +0000
+++ tests/unit/service/tasks/test_app_info_task.py 2016-11-16 17:34:14 +0000
@@ -0,0 +1,61 @@
1# Copyright 2016 Canonical Ltd.
2#
3# This program is free software: you can redistribute it and/or modify it
4# under the terms of the GNU General Public License version 3, as published
5# by the Free Software Foundation.
6#
7# This program is distributed in the hope that it will be useful, but
8# WITHOUT ANY WARRANTY; without even the implied warranties of
9# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
10# PURPOSE. See the GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License along
13# with this program. If not, see <http://www.gnu.org/licenses/>.
14
15
16import unittest.mock
17from unittest import TestCase
18from libertine.service import tasks, apt
19from libertine.ContainersConfig import ContainersConfig
20
21
22class TestAppInfoTask(TestCase):
23 def setUp(self):
24 self.config = unittest.mock.create_autospec(ContainersConfig)
25 self.cache = unittest.mock.create_autospec(apt.AptCache)
26 self.connection = unittest.mock.Mock()
27
28 def test_app_not_found_causes_error(self):
29 self.called_with = None
30 def callback(t):
31 self.called_with = t
32
33 with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
34 progress = MockProgress.return_value
35 self.cache.app_info.return_value = {}
36 task = tasks.AppInfoTask('palpatine', self.cache, 'lightside', [1, 2], self.config, self.connection, callback)
37 task._instant_callback = True
38 task.start().join()
39
40 progress.error.assert_called_once_with('Could not find app info for \'lightside\' in container \'palpatine\'')
41
42 self.assertEqual(task, self.called_with)
43
44 def test_success_sends_data(self):
45 self.called_with = None
46 def callback(t):
47 self.called_with = t
48
49 with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
50 progress = MockProgress.return_value
51 progress.done = False
52
53 self.cache.app_info.return_value = {'package': 'darkside-common'}
54 self.config.get_package_install_status.return_value = 'installed'
55 task = tasks.AppInfoTask('palpatine', self.cache, 'darkside', [1, 2, 3], self.config, self.connection, callback)
56 task._instant_callback = True
57 task.start().join()
58
59 progress.data.assert_called_once_with(str({'package': 'darkside-common', 'status': 'installed', 'task_ids': [1, 2, 3]}))
60
61 self.assertEqual(task, self.called_with)
062
=== added file 'tests/unit/service/tasks/test_container_info_task.py'
--- tests/unit/service/tasks/test_container_info_task.py 1970-01-01 00:00:00 +0000
+++ tests/unit/service/tasks/test_container_info_task.py 2016-11-16 17:34:14 +0000
@@ -0,0 +1,44 @@
1# Copyright 2016 Canonical Ltd.
2#
3# This program is free software: you can redistribute it and/or modify it
4# under the terms of the GNU General Public License version 3, as published
5# by the Free Software Foundation.
6#
7# This program is distributed in the hope that it will be useful, but
8# WITHOUT ANY WARRANTY; without even the implied warranties of
9# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
10# PURPOSE. See the GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License along
13# with this program. If not, see <http://www.gnu.org/licenses/>.
14
15
16import unittest.mock
17from unittest import TestCase
18from libertine.service import tasks
19from libertine.ContainersConfig import ContainersConfig
20
21
22class TestContainerInfoTask(TestCase):
23 def setUp(self):
24 self.config = unittest.mock.create_autospec(ContainersConfig)
25 self.connection = unittest.mock.Mock()
26
27 def test_success_sends_data(self):
28 self.called_with = None
29 def callback(t):
30 self.called_with = t
31
32 with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
33 progress = MockProgress.return_value
34 progress.done = False
35
36 self.config._get_value_by_key.return_value = 'ready'
37 task = tasks.ContainerInfoTask('palpatine', [1, 2, 3], self.config, self.connection, callback)
38 task._instant_callback = True
39 task.start().join()
40
41 progress.data.assert_called_once_with(str({'id': 'palpatine', 'status': 'ready', 'task_ids': [1, 2, 3]}))
42 progress.finished.assert_called_once_with('palpatine')
43
44 self.assertEqual(task, self.called_with)
045
=== added file 'tests/unit/service/tasks/test_create_task.py'
--- tests/unit/service/tasks/test_create_task.py 1970-01-01 00:00:00 +0000
+++ tests/unit/service/tasks/test_create_task.py 2016-11-16 17:34:14 +0000
@@ -0,0 +1,234 @@
1# Copyright 2016 Canonical Ltd.
2#
3# This program is free software: you can redistribute it and/or modify it
4# under the terms of the GNU General Public License version 3, as published
5# by the Free Software Foundation.
6#
7# This program is distributed in the hope that it will be useful, but
8# WITHOUT ANY WARRANTY; without even the implied warranties of
9# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
10# PURPOSE. See the GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License along
13# with this program. If not, see <http://www.gnu.org/licenses/>.
14
15
16import unittest.mock
17from unittest import TestCase
18from libertine.service import tasks
19from libertine.ContainersConfig import ContainersConfig
20
21
22class TestCreateTask(TestCase):
23 def setUp(self):
24 self.config = unittest.mock.create_autospec(ContainersConfig)
25 self.connection = unittest.mock.Mock()
26 self.lock = unittest.mock.MagicMock()
27 self.called_with = None
28
29 def callback(self, task):
30 self.called_with = task
31
32 def test_success_creates_lxc_container(self):
33 self.config.container_exists.return_value = False
34 with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
35 progress = MockProgress.return_value
36 progress.done = False
37 task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', 'lxc', False, self.config, self.lock, self.connection, self.callback)
38 task._instant_callback = True
39
40 with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
41 MockHostInfo.return_value.is_distro_valid.return_value = True
42 MockHostInfo.return_value.has_lxc_support.return_value = True
43
44 with unittest.mock.patch('libertine.service.tasks.create_task.LibertineContainer') as MockContainer:
45 MockContainer.return_value.create_libertine_container.return_value = True
46 task.start().join()
47
48 progress.finished.assert_called_once_with('palpatine')
49 self.config.add_new_container.assert_called_once_with('palpatine', 'Emperor Palpatine', 'lxc', 'zesty')
50 self.config.update_container_install_status.assert_has_calls([
51 unittest.mock.call('palpatine', 'installing'),
52 unittest.mock.call('palpatine', 'ready')
53 ], any_order=True)
54 self.assertEqual(task, self.called_with)
55
56 def test_success_creates_chroot_container(self):
57 self.config.container_exists.return_value = False
58 with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
59 progress = MockProgress.return_value
60 progress.done = False
61 task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', 'chroot', False, self.config, self.lock, self.connection, self.callback)
62 task._instant_callback = True
63
64 with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
65 MockHostInfo.return_value.is_distro_valid.return_value = True
66
67 with unittest.mock.patch('libertine.service.tasks.create_task.LibertineContainer') as MockContainer:
68 MockContainer.return_value.create_libertine_container.return_value = True
69 task.start().join()
70
71 progress.finished.assert_called_once_with('palpatine')
72 self.config.add_new_container.assert_called_once_with('palpatine', 'Emperor Palpatine', 'chroot', 'zesty')
73 self.config.update_container_install_status.assert_has_calls([
74 unittest.mock.call('palpatine', 'installing'),
75 unittest.mock.call('palpatine', 'ready')
76 ], any_order=True)
77 self.assertEqual(task, self.called_with)
78
79 def test_container_runtime_error_sends_error(self):
80 self.config.container_exists.return_value = False
81 with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
82 progress = MockProgress.return_value
83 task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', 'lxc', False, self.config, self.lock, self.connection, self.callback)
84 task._instant_callback = True
85
86 with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
87 MockHostInfo.return_value.is_distro_valid.return_value = True
88 MockHostInfo.return_value.has_lxc_support.return_value = True
89
90 with unittest.mock.patch('libertine.service.tasks.create_task.LibertineContainer') as MockContainer:
91 MockContainer.return_value.create_libertine_container.side_effect = RuntimeError('a great disturbance')
92 task.start().join()
93
94 progress.error.assert_called_once_with('a great disturbance')
95
96 self.config.add_new_container.assert_called_once_with('palpatine', 'Emperor Palpatine', 'lxc', 'zesty')
97 self.config.update_container_install_status.assert_called_once_with('palpatine', 'installing')
98 self.config.delete_container.assert_called_once_with('palpatine')
99
100 self.assertEqual(task, self.called_with)
101
102 def test_failed_container_exists_sends_error(self):
103 self.config.container_exists.return_value = True
104 with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
105 progress = MockProgress.return_value
106 task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', 'lxc', False, self.config, self.lock, self.connection, self.callback)
107 task._instant_callback = True
108 task.start().join()
109
110 progress.error.assert_called_once_with('Container \'palpatine\' already exists')
111 self.assertEqual(task, self.called_with)
112
113 def test_container_invalid_distro_error_sends_error(self):
114 self.config.container_exists.return_value = False
115 with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
116 progress = MockProgress.return_value
117 with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
118 MockHostInfo.return_value.is_distro_valid.return_value = False
119 task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'vesty', 'lxc', False, self.config, self.lock, self.connection, self.callback)
120 task._instant_callback = True
121 task.start().join()
122
123 progress.error.assert_called_once_with('Invalid distro \'vesty\'.')
124 self.assertEqual(task, self.called_with)
125
126 def test_container_improper_lxc_error_sends_error(self):
127 self.config.container_exists.return_value = False
128 with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
129 progress = MockProgress.return_value
130 with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
131 MockHostInfo.return_value.is_distro_valid.return_value = True
132 MockHostInfo.return_value.has_lxc_support.return_value = False
133 task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', 'lxc', False, self.config, self.lock, self.connection, self.callback)
134 task._instant_callback = True
135 task.start().join()
136
137 progress.error.assert_called_once_with('System kernel does not support lxc type containers. Please either use chroot or leave empty.')
138 self.assertEqual(task, self.called_with)
139
140 def test_sets_generic_name_when_empty(self):
141 self.config.container_exists.return_value = False
142 with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
143 progress = MockProgress.return_value
144 progress.done = False
145 task = tasks.CreateTask('palpatine', None, 'zesty', 'chroot', False, self.config, self.lock, self.connection, self.callback)
146 task._instant_callback = True
147
148 with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
149 MockHostInfo.return_value.is_distro_valid.return_value = True
150 MockHostInfo.return_value.get_distro_codename.return_value = 'Zesty Zapus 17.04'
151
152 with unittest.mock.patch('libertine.service.tasks.create_task.LibertineContainer') as MockContainer:
153 MockContainer.return_value.create_libertine_container.return_value = True
154 task.start().join()
155
156 progress.finished.assert_called_once_with('palpatine')
157 self.config.add_new_container.assert_called_once_with('palpatine', 'Ubuntu \'Zesty Zapus 17.04\'', 'chroot', 'zesty')
158 self.config.update_container_install_status.assert_has_calls([
159 unittest.mock.call('palpatine', 'installing'),
160 unittest.mock.call('palpatine', 'ready')
161 ], any_order=True)
162 self.assertEqual(task, self.called_with)
163
164 def test_sets_multiarch(self):
165 self.config.container_exists.return_value = False
166 with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
167 progress = MockProgress.return_value
168 progress.done = False
169 task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', 'chroot', True, self.config, self.lock, self.connection, self.callback)
170 task._instant_callback = True
171
172 with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
173 MockHostInfo.return_value.is_distro_valid.return_value = True
174
175 with unittest.mock.patch('libertine.service.tasks.create_task.LibertineContainer') as MockContainer:
176 MockContainer.return_value.create_libertine_container.return_value = True
177 task.start().join()
178
179 progress.finished.assert_called_once_with('palpatine')
180 self.config.add_new_container.assert_called_once_with('palpatine', 'Emperor Palpatine', 'chroot', 'zesty')
181 self.config.update_container_multiarch_support.assert_called_once_with('palpatine', 'enabled')
182 self.config.update_container_install_status.assert_has_calls([
183 unittest.mock.call('palpatine', 'installing'),
184 unittest.mock.call('palpatine', 'ready')
185 ], any_order=True)
186 self.assertEqual(task, self.called_with)
187
188 def test_sets_default_type(self):
189 self.config.container_exists.return_value = False
190 with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
191 progress = MockProgress.return_value
192 progress.done = False
193 task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', None, False, self.config, self.lock, self.connection, self.callback)
194 task._instant_callback = True
195
196 with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
197 MockHostInfo.return_value.is_distro_valid.return_value = True
198 MockHostInfo.return_value.select_container_type_by_kernel.return_value = 'lxc'
199
200 with unittest.mock.patch('libertine.service.tasks.create_task.LibertineContainer') as MockContainer:
201 MockContainer.return_value.create_libertine_container.return_value = True
202 task.start().join()
203
204 progress.finished.assert_called_once_with('palpatine')
205 self.config.add_new_container.assert_called_once_with('palpatine', 'Emperor Palpatine', 'lxc', 'zesty')
206 self.config.update_container_install_status.assert_has_calls([
207 unittest.mock.call('palpatine', 'installing'),
208 unittest.mock.call('palpatine', 'ready')
209 ], any_order=True)
210 self.assertEqual(task, self.called_with)
211
212 def test_sets_default_distro(self):
213 self.config.container_exists.return_value = False
214 with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
215 progress = MockProgress.return_value
216 progress.done = False
217 task = tasks.CreateTask('palpatine', 'Emperor Palpatine', None, 'lxc', False, self.config, self.lock, self.connection, self.callback)
218 task._instant_callback = True
219
220 with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
221 MockHostInfo.return_value.has_lxc_support.return_value = True
222 MockHostInfo.return_value.get_host_distro_release.return_value = 'zesty'
223
224 with unittest.mock.patch('libertine.service.tasks.create_task.LibertineContainer') as MockContainer:
225 MockContainer.return_value.create_libertine_container.return_value = True
226 task.start().join()
227
228 progress.finished.assert_called_once_with('palpatine')
229 self.config.add_new_container.assert_called_once_with('palpatine', 'Emperor Palpatine', 'lxc', 'zesty')
230 self.config.update_container_install_status.assert_has_calls([
231 unittest.mock.call('palpatine', 'installing'),
232 unittest.mock.call('palpatine', 'ready')
233 ], any_order=True)
234 self.assertEqual(task, self.called_with)
0235
=== added file 'tests/unit/service/tasks/test_destroy_task.py'
--- tests/unit/service/tasks/test_destroy_task.py 1970-01-01 00:00:00 +0000
+++ tests/unit/service/tasks/test_destroy_task.py 2016-11-16 17:34:14 +0000
@@ -0,0 +1,80 @@
1# Copyright 2016 Canonical Ltd.
2#
3# This program is free software: you can redistribute it and/or modify it
4# under the terms of the GNU General Public License version 3, as published
5# by the Free Software Foundation.
6#
7# This program is distributed in the hope that it will be useful, but
8# WITHOUT ANY WARRANTY; without even the implied warranties of
9# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
10# PURPOSE. See the GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License along
13# with this program. If not, see <http://www.gnu.org/licenses/>.
14
15
16import unittest.mock
17from unittest import TestCase
18from libertine.service import tasks
19from libertine.ContainersConfig import ContainersConfig
20
21
22class TestDestroyTask(TestCase):
23 def setUp(self):
24 self.config = unittest.mock.create_autospec(ContainersConfig)
25 self.connection = unittest.mock.Mock()
26 self.lock = unittest.mock.MagicMock()
27 self.called_with = None
28
29 def callback(self, task):
30 self.called_with = task
31
32 def test_sends_error_on_non_ready_container(self):
33 self.config._get_value_by_key.return_value = ''
34 with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
35 progress = MockProgress.return_value
36 progress.done = False
37 task = tasks.DestroyTask('palpatine', self.config, self.lock, self.connection, self.callback)
38 task._instant_callback = True
39
40 with unittest.mock.patch('libertine.service.tasks.destroy_task.LibertineContainer') as MockContainer:
41 MockContainer.return_value.destroy_libertine_container.return_value = True
42 task.start().join()
43
44 progress.error.assert_called_once_with('Container \'palpatine\' does not exist')
45 self.assertEqual(task, self.called_with)
46
47 def test_sends_error_on_failed_destroy(self):
48 self.config._get_value_by_key.return_value = 'ready'
49 with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
50 progress = MockProgress.return_value
51 task = tasks.DestroyTask('palpatine', self.config, self.lock, self.connection, self.callback)
52 task._instant_callback = True
53
54 with unittest.mock.patch('libertine.service.tasks.destroy_task.LibertineContainer') as MockContainer:
55 MockContainer.return_value.destroy_libertine_container.return_value = False
56 task.start().join()
57
58 progress.error.assert_called_once_with('Destroying container \'palpatine\' failed')
59 self.config.update_container_install_status.assert_has_calls([
60 unittest.mock.call('palpatine', 'removing'),
61 unittest.mock.call('palpatine', 'ready')
62 ], any_order=True)
63 self.assertEqual(task, self.called_with)
64
65 def test_successfully_destroys(self):
66 self.config._get_value_by_key.return_value = 'ready'
67 with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
68 progress = MockProgress.return_value
69 progress.done = False
70 task = tasks.DestroyTask('palpatine', self.config, self.lock, self.connection, self.callback)
71 task._instant_callback = True
72
73 with unittest.mock.patch('libertine.service.tasks.destroy_task.LibertineContainer') as MockContainer:
74 MockContainer.return_value.destroy_libertine_container.return_value = True
75 task.start().join()
76
77 progress.finished.assert_called_once_with('palpatine')
78 self.config.update_container_install_status.assert_called_once_with('palpatine', 'removing')
79 self.config.delete_container.assert_called_once_with('palpatine')
80 self.assertEqual(task, self.called_with)
081
=== added file 'tests/unit/service/tasks/test_install_task.py'
--- tests/unit/service/tasks/test_install_task.py 1970-01-01 00:00:00 +0000
+++ tests/unit/service/tasks/test_install_task.py 2016-11-16 17:34:14 +0000
@@ -0,0 +1,76 @@
1# Copyright 2016 Canonical Ltd.
2#
3# This program is free software: you can redistribute it and/or modify it
4# under the terms of the GNU General Public License version 3, as published
5# by the Free Software Foundation.
6#
7# This program is distributed in the hope that it will be useful, but
8# WITHOUT ANY WARRANTY; without even the implied warranties of
9# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
10# PURPOSE. See the GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License along
13# with this program. If not, see <http://www.gnu.org/licenses/>.
14
15
16import unittest.mock
17from unittest import TestCase
18from libertine.service import tasks
19from libertine.ContainersConfig import ContainersConfig
20
21
22class TestInstallTask(TestCase):
23 def setUp(self):
24 self.config = unittest.mock.create_autospec(ContainersConfig)
25 self.connection = unittest.mock.Mock()
26 self.lock = unittest.mock.MagicMock()
27 self.called_with = None
28
29 def callback(self, task):
30 self.called_with = task
31
32 def test_sends_error_on_existing_package(self):
33 self.config.package_exists.return_value = True
34 with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
35 progress = MockProgress.return_value
36 task = tasks.InstallTask('darkside-common', 'palpatine', self.config, self.lock, self.connection, self.callback)
37 task._instant_callback = True
38 task.start().join()
39
40 progress.error.assert_called_once_with('Package \'darkside-common\' already exists, skipping install')
41 self.assertEqual(task, self.called_with)
42
43 def test_sends_error_on_failed_install(self):
44 self.config.package_exists.return_value = False
45 with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
46 progress = MockProgress.return_value
47 task = tasks.InstallTask('darkside-common', 'palpatine', self.config, self.lock, self.connection, self.callback)
48 task._instant_callback = True
49
50 with unittest.mock.patch('libertine.service.tasks.install_task.LibertineContainer') as MockContainer:
51 MockContainer.return_value.install_package.return_value = False
52 task.start().join()
53
54 progress.error.assert_called_once_with("Package installation failed for 'darkside-common'")
55 self.config.update_package_install_status.assert_called_once_with('palpatine', 'darkside-common', 'installing')
56 self.config.delete_package.assert_called_once_with('palpatine', 'darkside-common')
57 self.assertEqual(task, self.called_with)
58
59 def test_successfully_install(self):
60 self.config.package_exists.return_value = False
61 with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
62 progress = MockProgress.return_value
63 progress.done = False
64 task = tasks.InstallTask('darkside-common', 'palpatine', self.config, self.lock, self.connection, self.callback)
65 task._instant_callback = True
66
67 with unittest.mock.patch('libertine.service.tasks.install_task.LibertineContainer') as MockContainer:
68 MockContainer.return_value.install_package.return_value = True
69 task.start().join()
70
71 progress.finished.assert_called_once_with('palpatine')
72 self.config.update_package_install_status.assert_has_calls([
73 unittest.mock.call('palpatine', 'darkside-common', 'installing'),
74 unittest.mock.call('palpatine', 'darkside-common', 'installed')
75 ], any_order=True)
76 self.assertEqual(task, self.called_with)
077
=== added file 'tests/unit/service/tasks/test_list_apps_task.py'
--- tests/unit/service/tasks/test_list_apps_task.py 1970-01-01 00:00:00 +0000
+++ tests/unit/service/tasks/test_list_apps_task.py 2016-11-16 17:34:14 +0000
@@ -0,0 +1,59 @@
1# Copyright 2016 Canonical Ltd.
2#
3# This program is free software: you can redistribute it and/or modify it
4# under the terms of the GNU General Public License version 3, as published
5# by the Free Software Foundation.
6#
7# This program is distributed in the hope that it will be useful, but
8# WITHOUT ANY WARRANTY; without even the implied warranties of
9# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
10# PURPOSE. See the GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License along
13# with this program. If not, see <http://www.gnu.org/licenses/>.
14
15
16import unittest.mock
17from unittest import TestCase
18from libertine.service import tasks
19from libertine.ContainersConfig import ContainersConfig
20
21
22class TestListAppsTask(TestCase):
23 def setUp(self):
24 self.config = unittest.mock.create_autospec(ContainersConfig)
25 self.connection = unittest.mock.Mock()
26 self.lock = unittest.mock.MagicMock()
27 self.called_with = None
28
29 def callback(self, task):
30 self.called_with = task
31
32 def test_sends_error_on_non_existent_container(self):
33 self.config.container_exists.return_value = False
34 with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
35 progress = MockProgress.return_value
36 task = tasks.ListAppsTask('palpatine', self.config, self.connection, self.callback)
37 task._instant_callback = True
38
39 with unittest.mock.patch('libertine.service.tasks.list_apps_task.LibertineContainer') as MockContainer:
40 task.start().join()
41
42 progress.error.assert_called_once_with('Container \'palpatine\' does not exist, skipping list')
43 self.assertEqual(task, self.called_with)
44
45 def test_successfully_lists_apps(self):
46 self.config.container_exists.return_value = True
47 with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
48 progress = MockProgress.return_value
49 progress.done = False
50 task = tasks.ListAppsTask('palpatine', self.config, self.connection, self.callback)
51 task._instant_callback = True
52
53 with unittest.mock.patch('libertine.service.tasks.list_apps_task.LibertineContainer') as MockContainer:
54 MockContainer.return_value.list_app_launchers.return_value = 'jarjar\nsidius'
55 task.start().join()
56
57 progress.finished.assert_called_once_with('palpatine')
58 progress.data.assert_called_once_with('jarjar\nsidius')
59 self.assertEqual(task, self.called_with)
060
=== added file 'tests/unit/service/tasks/test_list_task.py'
--- tests/unit/service/tasks/test_list_task.py 1970-01-01 00:00:00 +0000
+++ tests/unit/service/tasks/test_list_task.py 2016-11-16 17:34:14 +0000
@@ -0,0 +1,45 @@
1# Copyright 2016 Canonical Ltd.
2#
3# This program is free software: you can redistribute it and/or modify it
4# under the terms of the GNU General Public License version 3, as published
5# by the Free Software Foundation.
6#
7# This program is distributed in the hope that it will be useful, but
8# WITHOUT ANY WARRANTY; without even the implied warranties of
9# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
10# PURPOSE. See the GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License along
13# with this program. If not, see <http://www.gnu.org/licenses/>.
14
15
16import unittest.mock
17from unittest import TestCase
18from libertine.service import tasks
19from libertine.ContainersConfig import ContainersConfig
20
21
22class TestListTask(TestCase):
23 def setUp(self):
24 self.config = unittest.mock.create_autospec(ContainersConfig)
25 self.connection = unittest.mock.Mock()
26
27 def test_success_sends_data(self):
28 self.called_with = None
29 def callback(t):
30 self.called_with = t
31
32 with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
33 progress = MockProgress.return_value
34 progress.done = False
35 task = tasks.ListTask(self.connection, callback)
36 task._instant_callback = True
37
38 with unittest.mock.patch('libertine.service.tasks.list_task.utils.Libertine') as MockLibertine:
39 MockLibertine.list_containers.return_value = 'palpatine\nvader\nmaul'
40 task.start().join()
41
42 progress.data.assert_called_once_with('palpatine\nvader\nmaul')
43 progress.finished.assert_called_once_with('')
44
45 self.assertEqual(task, self.called_with)
046
=== added file 'tests/unit/service/tasks/test_remove_task.py'
--- tests/unit/service/tasks/test_remove_task.py 1970-01-01 00:00:00 +0000
+++ tests/unit/service/tasks/test_remove_task.py 2016-11-16 17:34:14 +0000
@@ -0,0 +1,76 @@
1# Copyright 2016 Canonical Ltd.
2#
3# This program is free software: you can redistribute it and/or modify it
4# under the terms of the GNU General Public License version 3, as published
5# by the Free Software Foundation.
6#
7# This program is distributed in the hope that it will be useful, but
8# WITHOUT ANY WARRANTY; without even the implied warranties of
9# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
10# PURPOSE. See the GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License along
13# with this program. If not, see <http://www.gnu.org/licenses/>.
14
15
16import unittest.mock
17from unittest import TestCase
18from libertine.service import tasks
19from libertine.ContainersConfig import ContainersConfig
20
21
22class TestRemoveTask(TestCase):
23 def setUp(self):
24 self.config = unittest.mock.create_autospec(ContainersConfig)
25 self.connection = unittest.mock.Mock()
26 self.lock = unittest.mock.MagicMock()
27 self.called_with = None
28
29 def callback(self, task):
30 self.called_with = task
31
32 def test_sends_error_on_non_installed_package(self):
33 self.config.get_package_install_status.return_value = 'installing'
34 with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
35 progress = MockProgress.return_value
36 task = tasks.RemoveTask('darkside-common', 'palpatine', self.config, self.lock, self.connection, self.callback)
37 task._instant_callback = True
38 task.start().join()
39
40 progress.error.assert_called_once_with('Package \'darkside-common\' not installed, skipping remove')
41 self.assertEqual(task, self.called_with)
42
43 def test_sends_error_on_failed_install(self):
44 self.config.get_package_install_status.return_value = 'installed'
45 with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
46 progress = MockProgress.return_value
47 task = tasks.RemoveTask('darkside-common', 'palpatine', self.config, self.lock, self.connection, self.callback)
48 task._instant_callback = True
49
50 with unittest.mock.patch('libertine.service.tasks.remove_task.LibertineContainer') as MockContainer:
51 MockContainer.return_value.remove_package.return_value = False
52 task.start().join()
53
54 progress.error.assert_called_once_with("Package removal failed for 'darkside-common'")
55 self.config.update_package_install_status.assert_has_calls([
56 unittest.mock.call('palpatine', 'darkside-common', 'removing'),
57 unittest.mock.call('palpatine', 'darkside-common', 'installed')
58 ], any_order=True)
59 self.assertEqual(task, self.called_with)
60
61 def test_successfully_install(self):
62 self.config.get_package_install_status.return_value = 'installed'
63 with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
64 progress = MockProgress.return_value
65 progress.done = False
66 task = tasks.RemoveTask('darkside-common', 'palpatine', self.config, self.lock, self.connection, self.callback)
67 task._instant_callback = True
68
69 with unittest.mock.patch('libertine.service.tasks.remove_task.LibertineContainer') as MockContainer:
70 MockContainer.return_value.remove_package.return_value = True
71 task.start().join()
72
73 progress.finished.assert_called_once_with('palpatine')
74 self.config.update_package_install_status.assert_called_once_with('palpatine', 'darkside-common', 'removing')
75 self.config.delete_package.assert_called_once_with('palpatine', 'darkside-common')
76 self.assertEqual(task, self.called_with)
077
=== added file 'tests/unit/service/tasks/test_search_task.py'
--- tests/unit/service/tasks/test_search_task.py 1970-01-01 00:00:00 +0000
+++ tests/unit/service/tasks/test_search_task.py 2016-11-16 17:34:14 +0000
@@ -0,0 +1,43 @@
1# Copyright 2016 Canonical Ltd.
2#
3# This program is free software: you can redistribute it and/or modify it
4# under the terms of the GNU General Public License version 3, as published
5# by the Free Software Foundation.
6#
7# This program is distributed in the hope that it will be useful, but
8# WITHOUT ANY WARRANTY; without even the implied warranties of
9# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
10# PURPOSE. See the GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License along
13# with this program. If not, see <http://www.gnu.org/licenses/>.
14
15
16import unittest.mock
17from unittest import TestCase
18from libertine.service import tasks, apt
19
20
21class TestSearchTask(TestCase):
22 def setUp(self):
23 self.connection = unittest.mock.Mock()
24 self.lock = unittest.mock.MagicMock()
25 self.cache = unittest.mock.create_autospec(apt.AptCache)
26 self.called_with = None
27
28 def callback(self, task):
29 self.called_with = task
30
31 def test_successfully_lists_apps(self):
32 with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
33 progress = MockProgress.return_value
34 progress.done = False
35 task = tasks.SearchTask('palpatine', self.cache, 'jarjar', self.connection, self.callback)
36 task._instant_callback = True
37
38 self.cache.search.return_value = ['jarjar', 'sidius']
39 task.start().join()
40
41 progress.finished.assert_called_once_with('palpatine')
42 progress.data.assert_called_once_with(str(['jarjar', 'sidius']))
43 self.assertEqual(task, self.called_with)
044
=== added file 'tests/unit/service/tasks/test_update_task.py'
--- tests/unit/service/tasks/test_update_task.py 1970-01-01 00:00:00 +0000
+++ tests/unit/service/tasks/test_update_task.py 2016-11-16 17:34:14 +0000
@@ -0,0 +1,80 @@
1# Copyright 2016 Canonical Ltd.
2#
3# This program is free software: you can redistribute it and/or modify it
4# under the terms of the GNU General Public License version 3, as published
5# by the Free Software Foundation.
6#
7# This program is distributed in the hope that it will be useful, but
8# WITHOUT ANY WARRANTY; without even the implied warranties of
9# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
10# PURPOSE. See the GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License along
13# with this program. If not, see <http://www.gnu.org/licenses/>.
14
15
16import unittest.mock
17from unittest import TestCase
18from libertine.service import tasks
19from libertine.ContainersConfig import ContainersConfig
20
21
22class TestUpdateTask(TestCase):
23 def setUp(self):
24 self.config = unittest.mock.create_autospec(ContainersConfig)
25 self.connection = unittest.mock.Mock()
26 self.lock = unittest.mock.MagicMock()
27 self.called_with = None
28
29 def callback(self, task):
30 self.called_with = task
31
32 def test_sends_error_on_non_existent_container(self):
33 self.config.container_exists.return_value = False
34 with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
35 progress = MockProgress.return_value
36 task = tasks.UpdateTask('palpatine', self.config, self.lock, self.connection, self.callback)
37 task._instant_callback = True
38
39 with unittest.mock.patch('libertine.service.tasks.update_task.LibertineContainer') as MockContainer:
40 task.start().join()
41
42 progress.error.assert_called_once_with('Container \'palpatine\' does not exist, skipping update')
43 self.assertEqual(task, self.called_with)
44
45 def test_sends_error_on_failed_update(self):
46 self.config.container_exists.return_value = True
47 with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
48 progress = MockProgress.return_value
49 task = tasks.UpdateTask('palpatine', self.config, self.lock, self.connection, self.callback)
50 task._instant_callback = True
51
52 with unittest.mock.patch('libertine.service.tasks.update_task.LibertineContainer') as MockContainer:
53 MockContainer.return_value.update_libertine_container.return_value = False
54 task.start().join()
55
56 progress.error.assert_called_once_with('Failed to update container \'palpatine\'')
57 self.config.update_container_install_status.assert_has_calls([
58 unittest.mock.call('palpatine', 'updating'),
59 unittest.mock.call('palpatine', 'ready')
60 ], any_order=True)
61 self.assertEqual(task, self.called_with)
62
63 def test_successfully_updates(self):
64 self.config.container_exists.return_value = True
65 with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
66 progress = MockProgress.return_value
67 progress.done = False
68 task = tasks.UpdateTask('palpatine', self.config, self.lock, self.connection, self.callback)
69 task._instant_callback = True
70
71 with unittest.mock.patch('libertine.service.tasks.update_task.LibertineContainer') as MockContainer:
72 MockContainer.return_value.update_libertine_container.return_value = True
73 task.start().join()
74
75 progress.finished.assert_called_once_with('palpatine')
76 self.config.update_container_install_status.assert_has_calls([
77 unittest.mock.call('palpatine', 'updating'),
78 unittest.mock.call('palpatine', 'ready')
79 ], any_order=True)
80 self.assertEqual(task, self.called_with)
081
=== added file 'tests/unit/service/test_apt.py'
--- tests/unit/service/test_apt.py 1970-01-01 00:00:00 +0000
+++ tests/unit/service/test_apt.py 2016-11-16 17:34:14 +0000
@@ -0,0 +1,134 @@
1# Copyright 2016 Canonical Ltd.
2#
3# This program is free software: you can redistribute it and/or modify it
4# under the terms of the GNU General Public License version 3, as published
5# by the Free Software Foundation.
6#
7# This program is distributed in the hope that it will be useful, but
8# WITHOUT ANY WARRANTY; without even the implied warranties of
9# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
10# PURPOSE. See the GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License along
13# with this program. If not, see <http://www.gnu.org/licenses/>.
14
15import os
16import unittest.mock
17from unittest import TestCase
18from libertine.service import apt
19
20
21def build_mock_app(name, summary, website, description):
22 app = unittest.mock.Mock()
23 app.name = name
24 version = unittest.mock.Mock()
25 version.summary = summary
26 version.homepage = website
27 version.description = description
28 app.versions = [version]
29 return app
30
31
32class TestAptCache(TestCase):
33 def test_search_returns_empty_when_no_matching_results(self):
34 with unittest.mock.patch('libertine.service.apt.apt.Cache') as MockCache:
35 MockCache.return_value.keys.return_value = []
36
37 with unittest.mock.patch('libertine.service.apt.Libertine') as MockLibertine:
38 MockLibertine.container_path.return_value = '/some/junk'
39 self.assertEqual(apt.AptCache('palpatine').search('vim'), [])
40
41 def test_search_returns_matching_results(self):
42 with unittest.mock.patch('libertine.service.apt.apt.Cache') as MockCache:
43 MockCache.return_value = {
44 "vim": build_mock_app("vim", "vi improved", "vim.com", "who even uses raw vi"),
45 "gedit": build_mock_app("gedit", "text editor", "gedit.com", "visual text editor"),
46 "gimp": build_mock_app("gimp", "foss photoshop", "gimp.com", "edit bitmap images"),
47 "vim-common": build_mock_app("vim-common", "common vim stuff", "vim.common", "dependencies")
48 }
49
50 with unittest.mock.patch('libertine.service.apt.Libertine') as MockLibertine:
51 MockLibertine.container_path.return_value = '/some/junk'
52 results = apt.AptCache('palpatine').search('vim')
53
54 self.assertEqual(len(results), 2)
55 results = sorted(results, key=lambda xx: xx['id'])
56 self.assertEqual(results[0]['description'], 'who even uses raw vi')
57 self.assertEqual(results[0]['name'], 'vim')
58 self.assertEqual(results[0]['id'], 'vim')
59 self.assertEqual(results[0]['summary'], 'vi improved')
60 self.assertEqual(results[0]['website'], 'vim.com')
61 self.assertEqual(results[0]['package'], 'vim')
62
63 self.assertEqual(results[1]['description'], 'dependencies')
64 self.assertEqual(results[1]['name'], 'vim-common')
65 self.assertEqual(results[1]['id'], 'vim-common')
66 self.assertEqual(results[1]['summary'], 'common vim stuff')
67 self.assertEqual(results[1]['website'], 'vim.common')
68 self.assertEqual(results[1]['package'], 'vim-common')
69
70 MockCache.assert_called_once_with()
71
72 def test_app_info_returns_empty_dict_when_no_such_app_exists(self):
73 with unittest.mock.patch('libertine.service.apt.apt.Cache') as MockCache:
74 MockCache.return_value = {}
75 with unittest.mock.patch('libertine.service.apt.Libertine') as MockLibertine:
76 MockLibertine.container_path.return_value = '/some/junk'
77 self.assertEqual(apt.AptCache('palpatine').app_info("vim"), {})
78 MockCache.assert_called_once_with()
79
80 def test_app_info_returns_values_for_app(self):
81 with unittest.mock.patch('libertine.service.apt.apt.Cache') as MockCache:
82 MockCache.return_value = {
83 "vim": build_mock_app("vim", "vi improved", "vim.com", "who even uses raw vi"),
84 "gimp": build_mock_app("gimp", "foss photoshop", "gimp.com", "visual text editor"),
85 }
86 with unittest.mock.patch('libertine.service.apt.Libertine') as MockLibertine:
87 MockLibertine.container_path.return_value = '/some/junk'
88 self.assertEqual(apt.AptCache('palpatine').app_info("vim"), {
89 'name': 'vim',
90 'id': 'vim',
91 'package': 'vim',
92 'summary': 'vi improved',
93 'description': 'who even uses raw vi',
94 'website': 'vim.com'
95 })
96 MockCache.assert_called_once_with()
97
98 def test_loads_cache_from_container_directory(self):
99 with unittest.mock.patch('libertine.service.apt.apt.Cache') as MockCache:
100 MockCache.return_value = {
101 "vim": build_mock_app("vim", "vi improved", "vim.com", "who even uses raw vi"),
102 "gimp": build_mock_app("gimp", "foss photoshop", "gimp.com", "visual text editor"),
103 }
104 with unittest.mock.patch('libertine.service.apt.Libertine') as MockLibertine:
105 containerpath = "%s/containerroot" % os.path.dirname(os.path.realpath(__file__))
106 MockLibertine.container_path.return_value = containerpath
107 self.assertEqual(apt.AptCache('palpatine').app_info("vim"), {
108 'name': 'vim',
109 'id': 'vim',
110 'package': 'vim',
111 'summary': 'vi improved',
112 'description': 'who even uses raw vi',
113 'website': 'vim.com'
114 })
115
116 MockCache.assert_called_once_with(rootdir=containerpath)
117
118 def test_loads_cache_only_once(self):
119 with unittest.mock.patch('libertine.service.apt.apt.Cache') as MockCache:
120 MockCache.return_value = {
121 "vim": build_mock_app("vim", "vi improved", "vim.com", "who even uses raw vi"),
122 "gimp": build_mock_app("gimp", "foss photoshop", "gimp.com", "visual text editor"),
123 }
124 with unittest.mock.patch('libertine.service.apt.Libertine') as MockLibertine:
125 MockLibertine.container_path.return_value = '/some/junk'
126 cache = apt.AptCache('palpatine')
127 cache.app_info("vim")
128 cache.app_info("vim")
129
130 MockCache.assert_called_once_with()
131
132
133if __name__ == '__main__':
134 unittest.main()
0135
=== added file 'tests/unit/service/test_container.py'
--- tests/unit/service/test_container.py 1970-01-01 00:00:00 +0000
+++ tests/unit/service/test_container.py 2016-11-16 17:34:14 +0000
@@ -0,0 +1,202 @@
1# Copyright 2016 Canonical Ltd.
2#
3# This program is free software: you can redistribute it and/or modify it
4# under the terms of the GNU General Public License version 3, as published
5# by the Free Software Foundation.
6#
7# This program is distributed in the hope that it will be useful, but
8# WITHOUT ANY WARRANTY; without even the implied warranties of
9# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
10# PURPOSE. See the GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License along
13# with this program. If not, see <http://www.gnu.org/licenses/>.
14
15import unittest.mock
16from unittest import TestCase
17from libertine.service import container
18from libertine.service import tasks
19
20
21class TestContainer(TestCase):
22 def setUp(self):
23 self._connection = unittest.mock.Mock()
24 self._config = unittest.mock.Mock()
25 self._lock = unittest.mock.Mock()
26
27 def test_search_creates_search_task(self):
28 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
29 cache = MockCache.return_value
30 c = container.Container('palpatine', self._config, self._lock, self._connection, lambda task: task)
31 with unittest.mock.patch('libertine.service.container.SearchTask') as MockSearchTask:
32 c.search('darkseid')
33 MockSearchTask.assert_called_once_with('palpatine', cache, 'darkseid', self._connection, unittest.mock.ANY)
34 MockSearchTask.return_value.start.assert_called_once_with()
35
36 def test_app_info_creates_app_info_task(self):
37 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
38 cache = MockCache.return_value
39 c = container.Container('palpatine', self._config, self._lock, self._connection, lambda task: task)
40 with unittest.mock.patch('libertine.service.container.AppInfoTask') as MockAppInfoTask:
41 c.app_info('force')
42 MockAppInfoTask.assert_called_once_with('palpatine', cache, 'force', [], self._config, self._connection, unittest.mock.ANY)
43 MockAppInfoTask.return_value.start.assert_called_once_with()
44
45 def test_app_info_gets_related_task_info(self):
46 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
47 cache = MockCache.return_value
48 c = container.Container('palpatine', self._config, self._lock, self._connection, lambda task: task)
49 with unittest.mock.patch('libertine.service.container.InstallTask') as MockInstallTask:
50 MockInstallTask.return_value.package = 'darkside'
51 MockInstallTask.return_value.matches.return_value = False
52 install_task_id = c.install('darkside')
53 with unittest.mock.patch('libertine.service.container.RemoveTask') as MockRemoveTask:
54 MockRemoveTask.return_value.package = 'darkside'
55 remove_task_id = c.remove('darkside')
56 with unittest.mock.patch('libertine.service.container.AppInfoTask') as MockAppInfoTask:
57 c.app_info('darkside')
58 MockAppInfoTask.assert_called_once_with('palpatine', cache, 'darkside', [install_task_id, remove_task_id],
59 self._config, self._connection, unittest.mock.ANY)
60
61 def test_install_creates_install_task(self):
62 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
63 cache = MockCache.return_value
64 c = container.Container('palpatine', self._config, self._lock, self._connection, lambda task: task)
65 with unittest.mock.patch('libertine.service.container.InstallTask') as MockInstallTask:
66 c.install('force')
67 MockInstallTask.assert_called_once_with('force', 'palpatine', self._config, self._lock, self._connection, unittest.mock.ANY)
68 MockInstallTask.return_value.start.assert_called_once_with()
69
70 def test_install_only_calls_once_when_unfinished(self):
71 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
72 cache = MockCache.return_value
73 c = container.Container('palpatine', self._config, self._lock, self._connection, lambda task: task)
74 with unittest.mock.patch('libertine.service.container.InstallTask') as MockInstallTask:
75 c.install('darkside')
76 c.install('darkside')
77 c.install('darkside')
78 # MockInstallTask.assert_called_once_with('darkside', 'palpatine', self._config, self._lock, self._connection, unittest.mock.ANY)
79 MockInstallTask.return_value.start.assert_called_once_with()
80
81 def test_remove_creates_remove_task(self):
82 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
83 cache = MockCache.return_value
84 c = container.Container('palpatine', self._config, self._lock, self._connection, lambda task: task)
85 with unittest.mock.patch('libertine.service.container.RemoveTask') as MockRemoveTask:
86 c.remove('force')
87 MockRemoveTask.assert_called_once_with('force', 'palpatine', self._config, self._lock, self._connection, unittest.mock.ANY)
88 MockRemoveTask.return_value.start.assert_called_once_with()
89
90 def test_remove_only_calls_once_when_unfinished(self):
91 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
92 cache = MockCache.return_value
93 c = container.Container('palpatine', self._config, self._lock, self._connection, lambda task: task)
94 with unittest.mock.patch('libertine.service.container.RemoveTask') as MockRemoveTask:
95 c.remove('darkside')
96 c.remove('darkside')
97 c.remove('darkside')
98 # MockRemoveTask.assert_called_once_with('darkside', 'palpatine', self._config, self._lock, self._connection, unittest.mock.ANY)
99 MockRemoveTask.return_value.start.assert_called_once_with()
100
101 def test_create_creates_create_task(self):
102 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
103 cache = MockCache.return_value
104 c = container.Container('palpatine', self._config, self._lock, self._connection, lambda task: task)
105 with unittest.mock.patch('libertine.service.container.CreateTask') as MockCreateTask:
106 c.create('Emperor Palpatine', 'zesty', 'lxd', False)
107 MockCreateTask.assert_called_once_with('palpatine', 'Emperor Palpatine', 'zesty', 'lxd', False,
108 self._config, self._lock, self._connection, unittest.mock.ANY)
109 MockCreateTask.return_value.start.assert_called_once_with()
110
111 def test_create_only_calls_once_when_unfinished(self):
112 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
113 cache = MockCache.return_value
114 c = container.Container('palpatine', self._config, self._lock, self._connection, lambda task: task)
115 with unittest.mock.patch('libertine.service.container.CreateTask') as MockCreateTask:
116 c.create('Emperor Palpatine', 'zesty', 'lxd', False)
117 c.create('Emperor Palpatine', 'zesty', 'lxd', False)
118 c.create('Emperor Palpatine', 'zesty', 'lxd', False)
119 # MockCreateTask.assert_called_once_with('palpatine', 'Emperor Palpatine', 'zesty', 'lxd', False,
120 # self._config, self._lock, self._connection, unittest.mock.ANY)
121 MockCreateTask.return_value.start.assert_called_once_with()
122
123 def test_destroy_creates_destroy_task(self):
124 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
125 cache = MockCache.return_value
126 c = container.Container('palpatine', self._config, self._lock, self._connection, lambda task: task)
127 with unittest.mock.patch('libertine.service.container.DestroyTask') as MockDestroyTask:
128 c.destroy()
129 # MockDestroyTask.assert_called_once_with('palpatine', self._config, self._lock, self._connection, unittest.mock.ANY)
130 MockDestroyTask.return_value.start.assert_called_once_with()
131
132 def test_destroy_only_calls_once_when_unfinished(self):
133 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
134 cache = MockCache.return_value
135 c = container.Container('palpatine', self._config, self._lock, self._connection, lambda task: task)
136 with unittest.mock.patch('libertine.service.container.DestroyTask') as MockDestroyTask:
137 c.destroy()
138 c.destroy()
139 c.destroy()
140 # MockDestroyTask.assert_called_once_with('palpatine', self._config, self._lock, self._connection, unittest.mock.ANY)
141 MockDestroyTask.return_value.start.assert_called_once_with()
142
143 def test_update_creates_update_task(self):
144 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
145 cache = MockCache.return_value
146 c = container.Container('palpatine', self._config, self._lock, self._connection, lambda task: task)
147 with unittest.mock.patch('libertine.service.container.UpdateTask') as MockUpdateTask:
148 c.update()
149 MockUpdateTask.assert_called_once_with('palpatine', self._config, self._lock, self._connection, unittest.mock.ANY)
150 MockUpdateTask.return_value.start.assert_called_once_with()
151
152 def test_update_only_calls_once_when_unfinished(self):
153 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
154 cache = MockCache.return_value
155 c = container.Container('palpatine', self._config, self._lock, self._connection, lambda task: task)
156 with unittest.mock.patch('libertine.service.container.UpdateTask') as MockUpdateTask:
157 c.update()
158 c.update()
159 c.update()
160 # MockUpdateTask.assert_called_once_with('palpatine', self._config, self._lock, self._connection, unittest.mock.ANY)
161 MockUpdateTask.return_value.start.assert_called_once_with()
162
163 def test_list_apps_creates_list_apps_task(self):
164 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
165 cache = MockCache.return_value
166 c = container.Container('palpatine', self._config, self._lock, self._connection, lambda task: task)
167 with unittest.mock.patch('libertine.service.container.ListAppsTask') as MockListAppsTask:
168 c.list_apps()
169 MockListAppsTask.assert_called_once_with('palpatine', self._config, self._connection, unittest.mock.ANY)
170 MockListAppsTask.return_value.start.assert_called_once_with()
171
172 def test_removes_task_during_callback(self):
173 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
174 cache = MockCache.return_value
175 c = container.Container('palpatine', self._config, self._lock, self._connection, lambda task: task)
176 with unittest.mock.patch('libertine.service.container.InstallTask') as MockInstallTask:
177 MockInstallTask.return_value.package = 'force'
178 c.install('force')
179 self.assertEqual(1, len(MockInstallTask.return_value.start.mock_calls)) # ensure initial mocks were called
180 c.install('force')
181 self.assertEqual(1, len(MockInstallTask.return_value.start.mock_calls)) # ensure no more mocks were called
182 name, args, kwargs = MockInstallTask.mock_calls[0]
183 args[len(args)-1](MockInstallTask.return_value.start.return_value)
184 c.install('force')
185 self.assertEqual(2, len(MockInstallTask.return_value.start.mock_calls)) # ensure mocks were called again
186
187 def test_completing_all_tasks_fires_callback(self):
188 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
189 cache = MockCache.return_value
190 self._container_id = None
191 def callback(container):
192 self._container_id = container.id
193 c = container.Container('palpatine', self._config, self._lock, self._connection, callback)
194 with unittest.mock.patch('libertine.service.container.InstallTask') as MockInstallTask:
195 c.install('force')
196 name, args, kwargs = MockInstallTask.mock_calls[0]
197 args[len(args)-1](MockInstallTask.return_value)
198 self.assertEqual('palpatine', self._container_id)
199
200
201if __name__ == '__main__':
202 unittest.main()
0203
=== added file 'tests/unit/service/test_task_dispatcher.py'
--- tests/unit/service/test_task_dispatcher.py 1970-01-01 00:00:00 +0000
+++ tests/unit/service/test_task_dispatcher.py 2016-11-16 17:34:14 +0000
@@ -0,0 +1,148 @@
1# Copyright 2016 Canonical Ltd.
2#
3# This program is free software: you can redistribute it and/or modify it
4# under the terms of the GNU General Public License version 3, as published
5# by the Free Software Foundation.
6#
7# This program is distributed in the hope that it will be useful, but
8# WITHOUT ANY WARRANTY; without even the implied warranties of
9# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
10# PURPOSE. See the GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License along
13# with this program. If not, see <http://www.gnu.org/licenses/>.
14
15import unittest.mock
16from unittest import TestCase
17from libertine.service import task_dispatcher
18
19
20class TestTaskDispatcher(TestCase):
21 def setUp(self):
22 self._connection = unittest.mock.Mock()
23 self._config_patcher = unittest.mock.patch('libertine.service.task_dispatcher.libertine.ContainersConfig.ContainersConfig')
24 self._config_patcher.start()
25 self._dispatcher = task_dispatcher.TaskDispatcher(self._connection)
26
27 def tearDown(self):
28 self._config_patcher.stop()
29
30 def test_search_calls_search_on_container(self):
31 with unittest.mock.patch('libertine.service.task_dispatcher.Container') as MockContainer:
32 c = MockContainer.return_value
33 c.search.return_value = 123
34 self.assertEqual(123, self._dispatcher.search('palpatine', 'sith'))
35 c.search.assert_called_once_with('sith')
36
37 def test_app_info_calls_app_info_on_container(self):
38 with unittest.mock.patch('libertine.service.task_dispatcher.Container') as MockContainer:
39 c = MockContainer.return_value
40 c.app_info.return_value = 123
41 self.assertEqual(123, self._dispatcher.app_info('palpatine', 'deathstar'))
42 c.app_info.assert_called_once_with('deathstar')
43
44 def test_install_calls_install_on_container(self):
45 with unittest.mock.patch('libertine.service.task_dispatcher.Container') as MockContainer:
46 c = MockContainer.return_value
47 c.install.return_value = 123
48 self.assertEqual(123, self._dispatcher.install('palpatine', 'darkside'))
49 c.install.assert_called_once_with('darkside')
50
51 def test_remove_calls_remove_on_container(self):
52 with unittest.mock.patch('libertine.service.task_dispatcher.Container') as MockContainer:
53 c = MockContainer.return_value
54 c.remove.return_value = 123
55 self.assertEqual(123, self._dispatcher.remove('palpatine', 'lightside'))
56 c.remove.assert_called_once_with('lightside')
57
58 def test_create_calls_create_on_container(self):
59 with unittest.mock.patch('libertine.service.task_dispatcher.Container') as MockContainer:
60 c = MockContainer.return_value
61 c.create.return_value = 123
62 self.assertEqual(123, self._dispatcher.create('palpatine', 'Emperor Palpatine', 'zesty', 'lxd', False))
63 c.create.assert_called_once_with('Emperor Palpatine', 'zesty', 'lxd', False)
64
65 def test_destroy_calls_destroy_on_container(self):
66 with unittest.mock.patch('libertine.service.task_dispatcher.Container') as MockContainer:
67 c = MockContainer.return_value
68 c.destroy.return_value = 123
69 self.assertEqual(123, self._dispatcher.destroy('palpatine'))
70 c.destroy.assert_called_once_with()
71
72 def test_update_calls_update_on_container(self):
73 with unittest.mock.patch('libertine.service.task_dispatcher.Container') as MockContainer:
74 c = MockContainer.return_value
75 c.update.return_value = 123
76 self.assertEqual(123, self._dispatcher.update('palpatine'))
77 c.update.assert_called_once_with()
78
79 def test_list_apps_calls_list_apps_on_container(self):
80 with unittest.mock.patch('libertine.service.task_dispatcher.Container') as MockContainer:
81 c = MockContainer.return_value
82 c.list_apps.return_value = 123
83 self.assertEqual(123, self._dispatcher.list_apps('palpatine'))
84 c.list_apps.assert_called_once_with()
85
86 def test_containers_reused_on_subsequent_calls(self):
87 with unittest.mock.patch('libertine.service.task_dispatcher.Container') as MockContainer:
88 c = MockContainer.return_value
89 c.id = 'palpatine'
90 self._dispatcher.list_apps('palpatine')
91 self._dispatcher.list_apps('palpatine')
92 self._dispatcher.list_apps('palpatine')
93 MockContainer.assert_called_once_with('palpatine', unittest.mock.ANY, unittest.mock.ANY, self._connection, unittest.mock.ANY)
94
95 def test_container_callback_removes_container(self):
96 with unittest.mock.patch('libertine.service.task_dispatcher.Container') as MockContainer:
97 c = MockContainer.return_value
98 c.id = 'palpatine'
99 self._dispatcher.list_apps('palpatine')
100 MockContainer.assert_called_once_with('palpatine', unittest.mock.ANY, unittest.mock.ANY, self._connection, unittest.mock.ANY)
101 name, args, kwargs = MockContainer.mock_calls[0]
102 args[len(args)-1](MockContainer.return_value)
103 self._dispatcher.list_apps('palpatine')
104 MockContainer.assert_has_calls([ # verify container constructed twice
105 unittest.mock.call('palpatine', unittest.mock.ANY, unittest.mock.ANY, self._connection, unittest.mock.ANY),
106 unittest.mock.call('palpatine', unittest.mock.ANY, unittest.mock.ANY, self._connection, unittest.mock.ANY)
107 ], any_order=True)
108
109 def test_container_info_creates_container_info_task(self):
110 with unittest.mock.patch('libertine.service.task_dispatcher.ContainerInfoTask') as MockContainerInfoTask:
111 task = MockContainerInfoTask.return_value
112 task.id = 123
113 self.assertEqual(123, self._dispatcher.container_info('palpatine'))
114 MockContainerInfoTask.assert_called_once_with('palpatine', [], unittest.mock.ANY, self._connection, unittest.mock.ANY)
115 task.start.assert_called_once_with()
116
117 def test_container_info_forwards_container_task_ids(self):
118 with unittest.mock.patch('libertine.service.task_dispatcher.ContainerInfoTask') as MockContainerInfoTask:
119 task = MockContainerInfoTask.return_value
120 with unittest.mock.patch('libertine.service.task_dispatcher.Container') as MockContainer:
121 c = MockContainer.return_value
122 c.tasks = [1, 2, 3]
123 c.id = 'palpatine'
124 self._dispatcher.list_apps('palpatine') # creates container
125 self._dispatcher.container_info('palpatine')
126 MockContainerInfoTask.assert_called_once_with('palpatine', [1, 2, 3], unittest.mock.ANY, self._connection, unittest.mock.ANY)
127 task.start.assert_called_once_with()
128
129 def test_list_creates_list_task(self):
130 with unittest.mock.patch('libertine.service.task_dispatcher.ListTask') as MockListTask:
131 task = MockListTask.return_value
132 task.id = 123
133 self.assertEqual(123, self._dispatcher.list())
134 MockListTask.assert_called_once_with(self._connection, unittest.mock.ANY)
135 task.start.assert_called_once_with()
136
137 def test_containerless_tasks_are_cleaned_up(self):
138 with unittest.mock.patch('libertine.service.task_dispatcher.ListTask') as MockListTask:
139 self._dispatcher.list()
140 MockListTask.assert_called_once_with(self._connection, unittest.mock.ANY)
141 name, args, kwargs = MockListTask.mock_calls[0]
142 self.assertEqual(1, len(self._dispatcher._tasks))
143 args[len(args)-1](MockListTask.return_value)
144 self.assertEqual(0, len(self._dispatcher._tasks))
145
146
147if __name__ == '__main__':
148 unittest.main()
0149
=== modified file 'tools/CMakeLists.txt'
--- tools/CMakeLists.txt 2016-08-04 01:39:08 +0000
+++ tools/CMakeLists.txt 2016-11-16 17:34:14 +0000
@@ -1,4 +1,4 @@
1install(PROGRAMS libertine-container-manager libertine-launch libertine-lxc-manager libertine-xmir libertine-lxc-setup1install(PROGRAMS libertine-container-manager libertine-launch libertine-lxc-manager libertine-xmir libertine-lxc-setup libertined
2 DESTINATION ${CMAKE_INSTALL_BINDIR})2 DESTINATION ${CMAKE_INSTALL_BINDIR})
3install(FILES libertine-launch.1 libertine-container-manager.1 libertine-lxc-manager.1 libertine-xmir.13install(FILES libertine-launch.1 libertine-container-manager.1 libertine-lxc-manager.1 libertine-xmir.1
4 DESTINATION ${CMAKE_INSTALL_MANDIR}/man14 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1
55
=== modified file 'tools/libertine-container-manager'
--- tools/libertine-container-manager 2016-11-09 18:25:33 +0000
+++ tools/libertine-container-manager 2016-11-16 17:34:14 +0000
@@ -183,7 +183,7 @@
183 container = LibertineContainer(container_id)183 container = LibertineContainer(container_id)
184184
185 self.containers_config.update_container_install_status(container_id, "updating")185 self.containers_config.update_container_install_status(container_id, "updating")
186 if container.update_libertine_container(args.verbosity) is not 0:186 if not container.update_libertine_container(args.verbosity):
187 self.containers_config.update_container_install_status(container_id, "ready")187 self.containers_config.update_container_install_status(container_id, "ready")
188 sys.exit(1)188 sys.exit(1)
189189
190190
=== added file 'tools/libertined'
--- tools/libertined 1970-01-01 00:00:00 +0000
+++ tools/libertined 2016-11-16 17:34:14 +0000
@@ -0,0 +1,141 @@
1#!/usr/bin/python3
2# -*- coding: utf-8 -*-
3
4# Copyright 2016 Canonical Ltd.
5#
6# This program is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation; version 3 of the License.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18import argparse
19import signal
20import sys
21import os
22from gi.repository import GLib, GObject
23from libertine import utils
24from libertine.service import manager
25
26
27class OutputRedirector(object):
28 def __init__(self, config):
29 self.config = config
30 self.cache_path = '%s/.cache/libertined' % os.environ['HOME']
31 self.cache_file = '%s/libertined.log' % self.cache_path
32 self.output_file = None
33 self.copied_stdout = None
34 self.copied_stderr = None
35
36 def _fileno(self, file_or_fd):
37 return getattr(file_or_fd, 'fileno', lambda: file_or_fd)()
38
39 def _do_redirect(self, stream):
40 fd = self._fileno(stream)
41 copied_stream = os.fdopen(os.dup(fd), 'wb')
42 stream.flush()
43 os.dup2(self._fileno(self.output_file), fd)
44 return copied_stream, fd
45
46 def _undo_redirect(self, stream, stream_fd, copied_stream):
47 stream.flush()
48 os.dup2(copied_stream.fileno(), stream_fd)
49 copied_stream.close()
50
51 def _rotate_logs(self):
52 os.makedirs(self.cache_path, exist_ok=True)
53 num_backups = 3
54 for i in range(num_backups, 0, -1):
55 filename = '%s.%i' % (self.cache_file, i)
56 if os.path.exists(filename):
57 if i == num_backups:
58 os.remove(filename)
59 else:
60 os.rename(filename, '%s.%i' % (self.cache_file, i+1))
61 if os.path.exists(self.cache_file):
62 os.rename(self.cache_file, '%s.1' % self.cache_file)
63
64 def __enter__(self):
65 if self.config.debug:
66 os.environ['LIBERTINE_DEBUG'] = '1'
67 else:
68 if self.config.cache_output:
69 os.environ['LIBERTINE_DEBUG'] = '1'
70 self._rotate_logs()
71 self.output_file = open(self.cache_file, 'w')
72 else:
73 self.output_file = open(os.devnull, 'w')
74
75 self.copied_stdout, self.stdout_fd = self._do_redirect(sys.stdout)
76 self.copied_stderr, self.stderr_fd = self._do_redirect(sys.stderr)
77
78 def __exit__(self, type, value, tb):
79 if self.copied_stdout and self.stdout_fd:
80 self._undo_redirect(sys.stdout, self.stdout_fd, self.copied_stdout)
81 if self.copied_stderr and self.stderr_fd:
82 self._undo_redirect(sys.stderr, self.stderr_fd, self.copied_stderr)
83 if self.output_file:
84 self.output_file.close()
85
86
87class Config(object):
88 def __init__(self):
89 self._arg_parser = argparse.ArgumentParser(description=u'Libertine Store service')
90 self._arg_parser.add_argument(u'-l', u"--use-local-cache",
91 action='store_true',
92 default=False,
93 help=u"use local cache instead of system cache")
94 self._arg_parser.add_argument(u'-d', u"--debug",
95 action='store_true',
96 default=False,
97 help=u"allow all output on stdout")
98 self._arg_parser.add_argument(u'-c', u"--cache-output",
99 action='store_true',
100 default=False,
101 help=u"Log to $HOME/.cache/libertined/ instead of stdout")
102 args = self._arg_parser.parse_args(namespace=Config)
103
104
105class Loop(object):
106 def __init__(self):
107 GLib.unix_signal_add(GLib.PRIORITY_HIGH,
108 signal.SIGTERM,
109 self.sigterm,
110 None)
111 self.loop = GLib.MainLoop()
112
113 def sigterm(self, code):
114 utils.get_logger().info("terminate ('%s') signal received" % code)
115 self.shutdown()
116
117 def shutdown(self):
118 utils.get_logger().info("shutting service down")
119 self.loop.quit()
120
121 def run(self):
122 utils.get_logger().debug("entering main loop")
123 self.loop.run()
124
125
126def main():
127 config = Config()
128
129 with OutputRedirector(config):
130 utils.get_logger().info("Starting libertine service")
131 service = manager.Manager()
132 loop = Loop()
133 try:
134 loop.run()
135 except KeyboardInterrupt:
136 utils.get_logger().debug("keyboard interrupt received")
137 loop.shutdown()
138
139
140if __name__ == '__main__':
141 main()

Subscribers

People subscribed via source and target branches