mirror of
https://github.com/munki/munki.git
synced 2026-02-09 08:40:40 -06:00
1759 lines
74 KiB
Python
Executable File
1759 lines
74 KiB
Python
Executable File
#!/usr/bin/python
|
|
# encoding: utf-8
|
|
"""
|
|
appleupdates_test.py
|
|
|
|
Unit tests for appleupdates.
|
|
|
|
"""
|
|
# Copyright 2011 Google.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
import appleupdates
|
|
try:
|
|
import mox
|
|
except ImportError:
|
|
import sys
|
|
print >>sys.stderr, "mox module is required. run: easy_install mox"
|
|
raise
|
|
from Foundation import NSDate
|
|
import os
|
|
import unittest
|
|
import stubout
|
|
|
|
|
|
class TestAppleUpdates(mox.MoxTestBase):
|
|
"""Test AppleUpdates class."""
|
|
|
|
def setUp(self):
|
|
mox.MoxTestBase.setUp(self)
|
|
self.stubs = stubout.StubOutForTesting()
|
|
self.au = appleupdates.AppleUpdates()
|
|
self.encoded_cache_dir = appleupdates.urllib2.quote(self.au.cache_dir)
|
|
|
|
def tearDown(self):
|
|
self.mox.UnsetStubs()
|
|
self.stubs.UnsetAll()
|
|
|
|
def _MockMunkiDisplay(self):
|
|
"""Mock out all munkicommon.display_* methods."""
|
|
for display in [
|
|
'percent_done', 'status_major', 'status_minor',
|
|
'info', 'detail', 'debug1', 'debug2', 'warning', 'error']:
|
|
self.mox.StubOutWithMock(
|
|
appleupdates.munkicommon, 'display_%s' % display)
|
|
|
|
def _MockMunkiStatus(self):
|
|
"""Mock out munkistatus.message/detail/percent methods."""
|
|
for method in ['message', 'detail', 'percent']:
|
|
self.mox.StubOutWithMock(appleupdates.munkistatus, method)
|
|
|
|
def _MockFoundationPlist(self):
|
|
"""Mock out all FoundationPlist functions."""
|
|
for func_name in [
|
|
'readPlist', 'readPlistFromString', 'writePlist',
|
|
'writePlistToString']:
|
|
self.mox.StubOutWithMock(appleupdates.FoundationPlist, func_name)
|
|
|
|
def _MockUpdateCheck(self):
|
|
"""Mock out all updatecheck functions."""
|
|
for func_name in [
|
|
'getPrimaryManifestCatalogs', 'getItemDetail']:
|
|
self.mox.StubOutWithMock(appleupdates.updatecheck, func_name)
|
|
|
|
def testResetMunkiStatusAndDisplayMessageMunkiStatusOutputTrue(self):
|
|
"""Tests _ResetMunkiStatusAndDisplayMessage(), GUI is present."""
|
|
self._MockMunkiStatus()
|
|
self._MockMunkiDisplay()
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'log')
|
|
|
|
msg = 'foo + bar == foobar'
|
|
|
|
appleupdates.munkicommon.munkistatusoutput = True
|
|
appleupdates.munkicommon.display_status_major(msg)
|
|
|
|
self.mox.ReplayAll()
|
|
self.au._ResetMunkiStatusAndDisplayMessage(msg)
|
|
self.mox.VerifyAll()
|
|
|
|
def testResetMunkiStatusAndDisplayMessageMunkiStatusOutputFalse(self):
|
|
"""Tests _ResetMunkiStatusAndDisplayMessage(), GUI not present."""
|
|
self._MockMunkiDisplay()
|
|
|
|
msg = 'asdf'
|
|
|
|
appleupdates.munkicommon.munkistatusoutput = False
|
|
appleupdates.munkicommon.display_status_major(msg)
|
|
|
|
self.mox.ReplayAll()
|
|
self.au._ResetMunkiStatusAndDisplayMessage(msg)
|
|
self.mox.VerifyAll()
|
|
|
|
def testGetURLPath(self):
|
|
"""Tests _GetURLPath()."""
|
|
path = '/foo/bar/index.html'
|
|
url = 'https://www.example.com' + path
|
|
output_path = self.au._GetURLPath(url)
|
|
self.assertEqual(output_path, path)
|
|
|
|
path = '/foo/bar/'
|
|
url = 'https://www.example.com' + path
|
|
output_path = self.au._GetURLPath(url)
|
|
self.assertEqual(output_path, path)
|
|
|
|
def testRewriteURL(self):
|
|
"""Tests RewriteURL()."""
|
|
self.mox.StubOutWithMock(self.au, '_GetURLPath')
|
|
managed_installs = appleupdates.urllib2.quote(self.au.cache_dir)
|
|
path = '/foo/bar/'
|
|
url = 'https://www.example.com' + path
|
|
self.au._GetURLPath(url).AndReturn(path)
|
|
expected_output_url = 'file://localhost' + self.encoded_cache_dir + path
|
|
self.mox.ReplayAll()
|
|
output_url = self.au.RewriteURL(url)
|
|
self.assertEqual(output_url, expected_output_url)
|
|
self.mox.VerifyAll()
|
|
|
|
def testRewriteURLWithFileURL(self):
|
|
"""Tests RewriteURL() with a file://localhost/Managed*... URL."""
|
|
url = 'file://localhost' + self.encoded_cache_dir + 'foo/bar'
|
|
self.mox.ReplayAll()
|
|
output_url = self.au.RewriteURL(url)
|
|
self.assertEqual(output_url, url)
|
|
self.mox.VerifyAll()
|
|
|
|
def testRewriteProductURLs(self):
|
|
"""Test RewriteProductURLs()."""
|
|
self.mox.StubOutWithMock(self.au, 'RewriteURL')
|
|
|
|
product = {
|
|
'ServerMetadataURL': 'urlin0',
|
|
'Packages': [
|
|
{
|
|
'URL': 'urlin1',
|
|
'MetadataURL': 'urlin2',
|
|
},
|
|
],
|
|
'Distributions': {'lang': 'urlin3'},
|
|
}
|
|
|
|
self.au.RewriteURL('urlin0').AndReturn('urlout0')
|
|
self.au.RewriteURL('urlin2').AndReturn('urlout2')
|
|
self.au.RewriteURL('urlin3').AndReturn('urlout3')
|
|
|
|
self.mox.ReplayAll()
|
|
self.au.RewriteProductURLs(product)
|
|
self.assertEqual(product['ServerMetadataURL'], 'urlout0')
|
|
self.assertEqual(product['Packages'][0]['MetadataURL'], 'urlout2')
|
|
self.assertEqual(product['Distributions']['lang'], 'urlout3')
|
|
self.mox.VerifyAll()
|
|
|
|
def testRewriteProductURLsWhenNoServerMetadataURL(self):
|
|
"""Test RewriteProductURLs() when no ServerMetadataURL in product."""
|
|
self.mox.StubOutWithMock(self.au, 'RewriteURL')
|
|
|
|
product = {
|
|
'Packages': [
|
|
{
|
|
'URL': 'urlin1',
|
|
'MetadataURL': 'urlin2',
|
|
},
|
|
],
|
|
'Distributions': {'lang': 'urlin3'},
|
|
}
|
|
|
|
self.au.RewriteURL('urlin2').AndReturn('urlout2')
|
|
self.au.RewriteURL('urlin3').AndReturn('urlout3')
|
|
|
|
self.mox.ReplayAll()
|
|
self.au.RewriteProductURLs(product)
|
|
self.assertFalse('ServerMetadataURL' in product)
|
|
self.assertEqual(product['Packages'][0]['MetadataURL'], 'urlout2')
|
|
self.assertEqual(product['Distributions']['lang'], 'urlout3')
|
|
self.mox.VerifyAll()
|
|
|
|
def testRewriteProductURLsWhenRewritePkgUrls(self):
|
|
"""Test RewriteProductURLs() when rewrite_pkg_urls=True."""
|
|
self.mox.StubOutWithMock(self.au, 'RewriteURL')
|
|
|
|
product = {
|
|
'ServerMetadataURL': 'urlin0',
|
|
'Packages': [
|
|
{
|
|
'URL': 'urlin1',
|
|
'MetadataURL': 'urlin2',
|
|
},
|
|
],
|
|
'Distributions': {'lang': 'urlin3'},
|
|
}
|
|
|
|
self.au.RewriteURL('urlin0').AndReturn('urlout0')
|
|
self.au.RewriteURL('urlin1').AndReturn('urlout1')
|
|
self.au.RewriteURL('urlin2').AndReturn('urlout2')
|
|
self.au.RewriteURL('urlin3').AndReturn('urlout3')
|
|
|
|
self.mox.ReplayAll()
|
|
self.au.RewriteProductURLs(product, rewrite_pkg_urls=True)
|
|
self.assertEqual(product['ServerMetadataURL'], 'urlout0')
|
|
self.assertEqual(product['Packages'][0]['URL'], 'urlout1')
|
|
self.assertEqual(product['Packages'][0]['MetadataURL'], 'urlout2')
|
|
self.assertEqual(product['Distributions']['lang'], 'urlout3')
|
|
self.mox.VerifyAll()
|
|
|
|
def testRewriteCatalogURLs(self):
|
|
"""Test RewriteCatalogURLs()."""
|
|
self.mox.StubOutWithMock(self.au, 'RewriteProductURLs')
|
|
catalog = {
|
|
'Products': {
|
|
'key0': 'data',
|
|
},
|
|
}
|
|
|
|
self.au.RewriteProductURLs(
|
|
catalog['Products']['key0'], rewrite_pkg_urls=1).AndReturn(None)
|
|
|
|
self.mox.ReplayAll()
|
|
self.au.RewriteCatalogURLs(catalog, rewrite_pkg_urls=1)
|
|
self.mox.VerifyAll()
|
|
|
|
def testRewriteCatalogURLsWhenNoProducts(self):
|
|
"""Test RewriteCatalogURLs() when no products in catalog."""
|
|
self.mox.StubOutWithMock(self.au, 'RewriteProductURLs')
|
|
catalog = {
|
|
'not Products': {
|
|
'key0': 'data',
|
|
},
|
|
}
|
|
|
|
self.mox.ReplayAll()
|
|
self.au.RewriteCatalogURLs(catalog)
|
|
self.mox.VerifyAll()
|
|
|
|
def testCacheUpdateMetadata(self):
|
|
"""Test CacheUpdateMetadata()."""
|
|
self._MockMunkiDisplay()
|
|
self._MockFoundationPlist()
|
|
self.mox.StubOutWithMock(self.au, 'RetrieveURLToCacheDir')
|
|
self.mox.StubOutWithMock(self.au, 'RewriteCatalogURLs')
|
|
self.mox.StubOutWithMock(appleupdates.os.path, 'exists')
|
|
self.mox.StubOutWithMock(appleupdates.os, 'makedirs')
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'stopRequested')
|
|
|
|
|
|
catalog = {
|
|
'Products': {
|
|
'key0': {
|
|
'ServerMetadataURL': 'url0',
|
|
'Packages': [
|
|
{'MetadataURL': 'url1'},
|
|
],
|
|
'Distributions': {
|
|
'lang': 'url2',
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
appleupdates.FoundationPlist.readPlist(
|
|
self.au.filtered_catalog_path).AndReturn(catalog)
|
|
|
|
appleupdates.munkicommon.stopRequested().AndReturn(False)
|
|
appleupdates.munkicommon.display_status_minor(
|
|
'Caching metadata for product ID %s', 'key0')
|
|
self.au.RetrieveURLToCacheDir(
|
|
'url0', copy_only_if_missing=True).AndReturn(None)
|
|
|
|
appleupdates.munkicommon.stopRequested().AndReturn(False)
|
|
appleupdates.munkicommon.display_status_minor(
|
|
'Caching package metadata for product ID %s', 'key0')
|
|
self.au.RetrieveURLToCacheDir(
|
|
'url1', copy_only_if_missing=True).AndReturn(None)
|
|
|
|
appleupdates.munkicommon.stopRequested().AndReturn(False)
|
|
appleupdates.munkicommon.display_status_minor(
|
|
'Caching %s distribution for product ID %s', 'lang',
|
|
'key0').AndReturn(None)
|
|
self.au.RetrieveURLToCacheDir(
|
|
'url2', copy_only_if_missing=True).AndReturn(None)
|
|
|
|
appleupdates.munkicommon.stopRequested().AndReturn(False)
|
|
|
|
self.au.RewriteCatalogURLs(
|
|
catalog, rewrite_pkg_urls=False).AndReturn(None)
|
|
appleupdates.os.path.exists(
|
|
self.au.local_catalog_dir).AndReturn(False)
|
|
appleupdates.os.makedirs(self.au.local_catalog_dir).AndReturn(None)
|
|
|
|
appleupdates.FoundationPlist.writePlist(
|
|
catalog, self.au.local_download_catalog_path)
|
|
|
|
self.au.RewriteCatalogURLs(catalog, rewrite_pkg_urls=True).AndReturn(
|
|
None)
|
|
|
|
appleupdates.FoundationPlist.writePlist(
|
|
catalog, self.au.local_catalog_path)
|
|
|
|
self.mox.ReplayAll()
|
|
self.assertEqual(None, self.au.CacheUpdateMetadata())
|
|
self.mox.VerifyAll()
|
|
|
|
def testCacheUpdateMetadataWhenMakedirsError(self):
|
|
"""Test CacheUpdateMetadata() when os.makedirs() errors."""
|
|
self._MockMunkiDisplay()
|
|
self._MockFoundationPlist()
|
|
self.mox.StubOutWithMock(self.au, 'RetrieveURLToCacheDir')
|
|
self.mox.StubOutWithMock(appleupdates.os.path, 'exists')
|
|
self.mox.StubOutWithMock(appleupdates.os, 'makedirs')
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'stopRequested')
|
|
|
|
catalog = {
|
|
'Products': {
|
|
'key0': {
|
|
'ServerMetadataURL': 'url0',
|
|
'Packages': [
|
|
{'MetadataURL': 'url1'},
|
|
],
|
|
'Distributions': {
|
|
'lang': 'url2',
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
appleupdates.FoundationPlist.readPlist(
|
|
self.au.filtered_catalog_path).AndReturn(catalog)
|
|
|
|
appleupdates.munkicommon.stopRequested().AndReturn(False)
|
|
appleupdates.munkicommon.display_status_minor(
|
|
'Caching metadata for product ID %s', 'key0')
|
|
self.au.RetrieveURLToCacheDir(
|
|
'url0', copy_only_if_missing=True).AndReturn(None)
|
|
|
|
appleupdates.munkicommon.stopRequested().AndReturn(False)
|
|
appleupdates.munkicommon.display_status_minor(
|
|
'Caching package metadata for product ID %s', 'key0')
|
|
self.au.RetrieveURLToCacheDir(
|
|
'url1', copy_only_if_missing=True).AndReturn(None)
|
|
|
|
appleupdates.munkicommon.stopRequested().AndReturn(False)
|
|
appleupdates.munkicommon.display_status_minor(
|
|
'Caching %s distribution for product ID %s', 'lang',
|
|
'key0').AndReturn(None)
|
|
self.au.RetrieveURLToCacheDir(
|
|
'url2', copy_only_if_missing=True).AndReturn(None)
|
|
|
|
appleupdates.munkicommon.stopRequested().AndReturn(False)
|
|
|
|
appleupdates.os.path.exists(
|
|
self.au.local_catalog_dir).AndReturn(False)
|
|
appleupdates.os.makedirs(self.au.local_catalog_dir).AndRaise(OSError)
|
|
|
|
self.mox.ReplayAll()
|
|
self.assertRaises(
|
|
appleupdates.ReplicationError, self.au.CacheUpdateMetadata)
|
|
self.mox.VerifyAll()
|
|
|
|
def testCacheUpdateMetadataWhenNoProducts(self):
|
|
"""Test CacheUpdateMetadata() when no products in catalog."""
|
|
self._MockMunkiDisplay()
|
|
self._MockFoundationPlist()
|
|
|
|
catalog = {}
|
|
|
|
appleupdates.FoundationPlist.readPlist(
|
|
self.au.filtered_catalog_path).AndReturn(catalog)
|
|
|
|
self.mox.ReplayAll()
|
|
self.assertEqual(None, self.au.CacheUpdateMetadata())
|
|
self.mox.VerifyAll()
|
|
|
|
def testRetrieveURLToCacheDir(self):
|
|
"""Tests RetrieveURLToCacheDir()."""
|
|
self.mox.StubOutWithMock(self.au, '_GetURLPath')
|
|
self.mox.StubOutWithMock(appleupdates.os, 'makedirs')
|
|
self.mox.StubOutWithMock(appleupdates.os.path, 'exists')
|
|
self.mox.StubOutWithMock(self.au, 'GetSoftwareUpdateResource')
|
|
|
|
path = '/foo/bar'
|
|
url = 'https://www.example.com' + path
|
|
local_file_path = os.path.join(self.au.cache_dir, path.lstrip('/'))
|
|
local_dir_path = os.path.dirname(local_file_path)
|
|
|
|
self.au._GetURLPath(url).AndReturn(path)
|
|
|
|
appleupdates.os.path.exists(local_dir_path).AndReturn(False)
|
|
appleupdates.os.makedirs(local_dir_path).AndReturn(None)
|
|
self.au.GetSoftwareUpdateResource(
|
|
url, local_file_path, resume=True).AndReturn(None)
|
|
|
|
self.mox.ReplayAll()
|
|
output = self.au.RetrieveURLToCacheDir(url)
|
|
self.assertEqual(output, local_file_path)
|
|
self.mox.VerifyAll()
|
|
|
|
def testRetrieveURLToCacheDirWithMunkiDownloadError(self):
|
|
"""Tests RetrieveURLToCacheDir() with MunkiDownloadError."""
|
|
self.mox.StubOutWithMock(self.au, '_GetURLPath')
|
|
self.mox.StubOutWithMock(appleupdates.os, 'makedirs')
|
|
self.mox.StubOutWithMock(appleupdates.os.path, 'exists')
|
|
self.mox.StubOutWithMock(self.au, 'GetSoftwareUpdateResource')
|
|
|
|
path = '/foo/bar'
|
|
url = 'https://www.example.com' + path
|
|
local_file_path = os.path.join(self.au.cache_dir, path.lstrip('/'))
|
|
local_dir_path = os.path.dirname(local_file_path)
|
|
|
|
self.au._GetURLPath(url).AndReturn(path)
|
|
|
|
appleupdates.os.path.exists(local_dir_path).AndReturn(False)
|
|
appleupdates.os.makedirs(local_dir_path).AndReturn(None)
|
|
self.au.GetSoftwareUpdateResource(
|
|
url, local_file_path, resume=True).AndRaise(
|
|
appleupdates.fetch.MunkiDownloadError)
|
|
|
|
self.mox.ReplayAll()
|
|
self.assertRaises(
|
|
appleupdates.Error, self.au.RetrieveURLToCacheDir, url)
|
|
self.mox.VerifyAll()
|
|
|
|
def testRetrieveURLToCacheDirMakedirsError(self):
|
|
"""Tests RetrieveURLToCacheDir() with os.makedirs() error."""
|
|
self.mox.StubOutWithMock(self.au, '_GetURLPath')
|
|
self.mox.StubOutWithMock(appleupdates.os, 'makedirs')
|
|
self.mox.StubOutWithMock(appleupdates.os.path, 'exists')
|
|
|
|
path = '/foo/bar'
|
|
url = 'https://www.example.com' + path
|
|
local_file_path = os.path.join(self.au.cache_dir, path.lstrip('/'))
|
|
local_dir_path = os.path.dirname(local_file_path)
|
|
|
|
self.au._GetURLPath(url).AndReturn(path)
|
|
|
|
appleupdates.os.path.exists(local_dir_path).AndReturn(False)
|
|
appleupdates.os.makedirs(local_dir_path).AndRaise(OSError)
|
|
|
|
self.mox.ReplayAll()
|
|
self.assertRaises(
|
|
appleupdates.Error, self.au.RetrieveURLToCacheDir, url)
|
|
self.mox.VerifyAll()
|
|
|
|
def testRetrieveURLToCacheDirCopyOnlyIfMissing(self):
|
|
"""Tests RetrieveURLToCacheDir() with copy_only_if_missing=True."""
|
|
self.mox.StubOutWithMock(self.au, '_GetURLPath')
|
|
self.mox.StubOutWithMock(appleupdates.os.path, 'exists')
|
|
|
|
path = '/foo/bar'
|
|
url = 'https://www.example.com' + path
|
|
local_file_path = os.path.join(self.au.cache_dir, path.lstrip('/'))
|
|
|
|
self.au._GetURLPath(url).AndReturn(path)
|
|
|
|
appleupdates.os.path.exists(local_file_path).AndReturn(True)
|
|
|
|
self.mox.ReplayAll()
|
|
output = self.au.RetrieveURLToCacheDir(url, copy_only_if_missing=True)
|
|
self.assertEqual(output, local_file_path)
|
|
self.mox.VerifyAll()
|
|
|
|
def testWriteFilteredCatalog(self):
|
|
"""Tests _WriteFilteredCatalog()."""
|
|
self._MockFoundationPlist()
|
|
|
|
catalog_path = 'foo/catalog.sucatalog'
|
|
product_ids = ['1', '3']
|
|
catalog = {'Products': {'1': 'foo', '2': 'bar', '3': None}}
|
|
# output catalog will be missing 2, since it's not in product_ids
|
|
output_catalog = {'Products': {'1': 'foo', '3': None}}
|
|
|
|
appleupdates.FoundationPlist.readPlist(
|
|
self.au.extracted_catalog_path).AndReturn(catalog)
|
|
appleupdates.FoundationPlist.writePlist(
|
|
output_catalog, catalog_path).AndReturn(None)
|
|
|
|
self.mox.ReplayAll()
|
|
self.au._WriteFilteredCatalog(product_ids, catalog_path)
|
|
self.mox.VerifyAll()
|
|
|
|
def testIsRestartNeededFalse(self):
|
|
"""Tests IsRestartNeeded() when restart is not needed."""
|
|
self._MockFoundationPlist()
|
|
|
|
apple_updates = {
|
|
'AppleUpdates': [
|
|
{'RestartAction': 'None'},
|
|
{'RestartAction': 'Nope'},
|
|
]
|
|
}
|
|
appleupdates.FoundationPlist.readPlist(
|
|
self.au.apple_updates_plist).AndReturn(apple_updates)
|
|
self.mox.ReplayAll()
|
|
self.assertFalse(self.au.IsRestartNeeded())
|
|
self.mox.VerifyAll()
|
|
|
|
def testIsRestartNeededTrue(self):
|
|
"""Tests IsRestartNeeded() when restart is needed."""
|
|
self._MockFoundationPlist()
|
|
|
|
apple_updates = {
|
|
'AppleUpdates': [
|
|
{'RestartAction': 'None'},
|
|
{'RestartAction': self.au.RESTART_ACTIONS[0]},
|
|
]
|
|
}
|
|
appleupdates.FoundationPlist.readPlist(
|
|
self.au.apple_updates_plist).AndReturn(apple_updates)
|
|
self.mox.ReplayAll()
|
|
self.assertTrue(self.au.IsRestartNeeded())
|
|
self.mox.VerifyAll()
|
|
|
|
def testIsRestartNeededFoundationPlistError(self):
|
|
"""Tests IsRestartNeeded() when FoundationPlist has a read error."""
|
|
self._MockFoundationPlist()
|
|
|
|
exc = appleupdates.FoundationPlist.NSPropertyListSerializationException
|
|
appleupdates.FoundationPlist.readPlist(
|
|
self.au.apple_updates_plist).AndRaise(exc)
|
|
|
|
self.mox.ReplayAll()
|
|
self.assertTrue(self.au.IsRestartNeeded())
|
|
self.mox.VerifyAll()
|
|
|
|
def testClearAppleUpdateInfo(self):
|
|
"""Tests ClearAppleUpdateInfo()."""
|
|
self.mox.StubOutWithMock(appleupdates.os, 'unlink')
|
|
|
|
appleupdates.os.unlink(self.au.apple_updates_plist).AndReturn(None)
|
|
appleupdates.os.unlink(self.au.applicable_updates_plist).AndReturn(None)
|
|
appleupdates.os.unlink(self.au.apple_updates_plist).AndReturn(None)
|
|
appleupdates.os.unlink(
|
|
self.au.applicable_updates_plist).AndRaise(OSError)
|
|
appleupdates.os.unlink(self.au.apple_updates_plist).AndReturn(None)
|
|
appleupdates.os.unlink(
|
|
self.au.applicable_updates_plist).AndRaise(IOError)
|
|
appleupdates.os.unlink(self.au.apple_updates_plist).AndRaise(OSError)
|
|
appleupdates.os.unlink(self.au.apple_updates_plist).AndRaise(IOError)
|
|
|
|
self.mox.ReplayAll()
|
|
self.au.ClearAppleUpdateInfo()
|
|
self.au.ClearAppleUpdateInfo()
|
|
self.au.ClearAppleUpdateInfo()
|
|
self.au.ClearAppleUpdateInfo()
|
|
self.au.ClearAppleUpdateInfo()
|
|
self.mox.VerifyAll()
|
|
|
|
def testDownloadAvailableUpdates(self):
|
|
"""Tests DownloadAvailableUpdates()."""
|
|
self._MockMunkiDisplay()
|
|
self.mox.StubOutWithMock(self.au, '_ResetMunkiStatusAndDisplayMessage')
|
|
self.mox.StubOutWithMock(self.au, '_RunSoftwareUpdate')
|
|
self.mox.StubOutWithMock(appleupdates.os.path, 'exists')
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'getOsVersion')
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'stopRequested')
|
|
|
|
msg = 'Downloading available Apple Software Updates...'
|
|
catalog_url = 'file://localhost' + appleupdates.urllib2.quote(
|
|
self.au.local_download_catalog_path)
|
|
|
|
self.au._ResetMunkiStatusAndDisplayMessage(msg).AndReturn(None)
|
|
|
|
appleupdates.os.path.exists(
|
|
self.au.local_download_catalog_path).AndReturn(True)
|
|
appleupdates.munkicommon.getOsVersion().AndReturn('10.7')
|
|
self.au._RunSoftwareUpdate(
|
|
['-d', '-a'],
|
|
catalog_url=catalog_url,
|
|
stop_allowed=True).AndReturn(0)
|
|
appleupdates.munkicommon.stopRequested().AndReturn(False)
|
|
|
|
self.mox.ReplayAll()
|
|
self.assertTrue(self.au.DownloadAvailableUpdates())
|
|
self.mox.VerifyAll()
|
|
|
|
def testDownloadAvailableUpdatesLeopard(self):
|
|
"""Tests DownloadAvailableUpdates() with Leopard."""
|
|
self._MockMunkiDisplay()
|
|
self.mox.StubOutWithMock(self.au, '_ResetMunkiStatusAndDisplayMessage')
|
|
self.mox.StubOutWithMock(self.au, '_LeopardDownloadAvailableUpdates')
|
|
self.mox.StubOutWithMock(appleupdates.os.path, 'exists')
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'getOsVersion')
|
|
|
|
catalog_url = 'file://localhost' + appleupdates.urllib2.quote(
|
|
self.au.local_download_catalog_path)
|
|
|
|
msg = 'Downloading available Apple Software Updates...'
|
|
self.au._ResetMunkiStatusAndDisplayMessage(msg).AndReturn(None)
|
|
appleupdates.os.path.exists(
|
|
self.au.local_download_catalog_path).AndReturn(True)
|
|
appleupdates.munkicommon.getOsVersion().AndReturn('10.5')
|
|
self.au._LeopardDownloadAvailableUpdates(catalog_url).AndReturn(2)
|
|
appleupdates.munkicommon.display_error('softwareupdate error: %s' % 2)
|
|
|
|
self.mox.ReplayAll()
|
|
self.assertFalse(self.au.DownloadAvailableUpdates())
|
|
self.mox.VerifyAll()
|
|
|
|
def testDownloadAvailableUpdatesMissingCatalog(self):
|
|
"""Tests DownloadAvailableUpdates() with a missing catalog."""
|
|
self._MockMunkiDisplay()
|
|
self.mox.StubOutWithMock(self.au, '_ResetMunkiStatusAndDisplayMessage')
|
|
self.mox.StubOutWithMock(appleupdates.os.path, 'exists')
|
|
|
|
msg = 'Downloading available Apple Software Updates...'
|
|
self.au._ResetMunkiStatusAndDisplayMessage(msg).AndReturn(None)
|
|
|
|
appleupdates.os.path.exists(
|
|
self.au.local_download_catalog_path).AndReturn(False)
|
|
appleupdates.munkicommon.display_error(
|
|
'Missing local Software Update catalog at %s',
|
|
self.au.local_download_catalog_path)
|
|
|
|
self.mox.ReplayAll()
|
|
self.assertFalse(self.au.DownloadAvailableUpdates())
|
|
self.mox.VerifyAll()
|
|
|
|
def testGetAvailableUpdateProductIDsFailedSoftwareUpdate(self):
|
|
"""Tests GetAvailableUpdateProductIDs() with failed softwareupdate."""
|
|
self._MockMunkiDisplay()
|
|
self.mox.StubOutWithMock(self.au, '_RunSoftwareUpdate')
|
|
self.mox.StubOutWithMock(self.au, '_ResetMunkiStatusAndDisplayMessage')
|
|
self.mox.StubOutWithMock(appleupdates.os, 'unlink')
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'getOsVersion')
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'stopRequested')
|
|
|
|
msg = 'Checking for available Apple Software Updates...'
|
|
self.au._ResetMunkiStatusAndDisplayMessage(msg)
|
|
appleupdates.os.unlink(self.au.applicable_updates_plist).AndRaise(
|
|
OSError)
|
|
|
|
catalog_url = 'file://localhost' + appleupdates.urllib2.quote(
|
|
self.au.extracted_catalog_path)
|
|
self.au._RunSoftwareUpdate(
|
|
['-l', '-f', self.au.applicable_updates_plist],
|
|
catalog_url=catalog_url,
|
|
stop_allowed=True).AndReturn(1)
|
|
|
|
appleupdates.munkicommon.getOsVersion().AndReturn('10.6')
|
|
appleupdates.munkicommon.display_error('softwareupdate error: %s' % 1)
|
|
appleupdates.munkicommon.stopRequested().AndReturn(False)
|
|
|
|
self.mox.ReplayAll()
|
|
output = self.au.GetAvailableUpdateProductIDs()
|
|
self.assertEqual(output, [])
|
|
self.mox.VerifyAll()
|
|
|
|
def testGetAvailableUpdateProductIDsFailureReadingApplicableUpdates(self):
|
|
"""Tests GetAvailableUpdateProductIDs() failed applicable updates."""
|
|
self._MockFoundationPlist()
|
|
self.mox.StubOutWithMock(self.au, '_RunSoftwareUpdate')
|
|
self.mox.StubOutWithMock(self.au, '_ResetMunkiStatusAndDisplayMessage')
|
|
self.mox.StubOutWithMock(appleupdates.os, 'unlink')
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'getOsVersion')
|
|
|
|
msg = 'Checking for available Apple Software Updates...'
|
|
self.au._ResetMunkiStatusAndDisplayMessage(msg)
|
|
appleupdates.os.unlink(self.au.applicable_updates_plist).AndRaise(
|
|
OSError)
|
|
|
|
catalog_url = 'file://localhost' + appleupdates.urllib2.quote(
|
|
self.au.extracted_catalog_path)
|
|
self.au._RunSoftwareUpdate(
|
|
['-l', '-f', self.au.applicable_updates_plist],
|
|
catalog_url=catalog_url,
|
|
stop_allowed=True).AndReturn(0)
|
|
|
|
exc = appleupdates.FoundationPlist.NSPropertyListSerializationException
|
|
appleupdates.FoundationPlist.readPlist(
|
|
self.au.applicable_updates_plist).AndRaise(exc)
|
|
|
|
self.mox.ReplayAll()
|
|
output = self.au.GetAvailableUpdateProductIDs()
|
|
self.assertEqual(output, [])
|
|
self.mox.VerifyAll()
|
|
|
|
def testGetAvailableUpdateProductIDsEmptyApplicableUpdates(self):
|
|
"""Tests GetAvailableUpdateProductIDs() empty applicable updates."""
|
|
self._MockFoundationPlist()
|
|
self.mox.StubOutWithMock(self.au, '_RunSoftwareUpdate')
|
|
self.mox.StubOutWithMock(self.au, '_ResetMunkiStatusAndDisplayMessage')
|
|
self.mox.StubOutWithMock(appleupdates.os, 'unlink')
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'getOsVersion')
|
|
|
|
msg = 'Checking for available Apple Software Updates...'
|
|
self.au._ResetMunkiStatusAndDisplayMessage(msg)
|
|
appleupdates.os.unlink(self.au.applicable_updates_plist).AndRaise(
|
|
OSError)
|
|
|
|
catalog_url = 'file://localhost' + appleupdates.urllib2.quote(
|
|
self.au.extracted_catalog_path)
|
|
self.au._RunSoftwareUpdate(
|
|
['-l', '-f', self.au.applicable_updates_plist],
|
|
catalog_url=catalog_url,
|
|
stop_allowed=True).AndReturn(0)
|
|
|
|
appleupdates.FoundationPlist.readPlist(
|
|
self.au.applicable_updates_plist).AndReturn({})
|
|
|
|
self.mox.ReplayAll()
|
|
output = self.au.GetAvailableUpdateProductIDs()
|
|
self.assertEqual(output, [])
|
|
self.mox.VerifyAll()
|
|
|
|
def testGetAvailableUpdateProductIDsSuccess(self):
|
|
"""Tests GetAvailableUpdateProductIDs()."""
|
|
self._MockFoundationPlist()
|
|
self.mox.StubOutWithMock(self.au, '_RunSoftwareUpdate')
|
|
self.mox.StubOutWithMock(self.au, '_ResetMunkiStatusAndDisplayMessage')
|
|
self.mox.StubOutWithMock(appleupdates.os, 'unlink')
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'getOsVersion')
|
|
|
|
updates_plist_dict = {
|
|
'phaseResultsArray': [
|
|
{'productKey': '4zzz'},
|
|
{'noProductKeyHere': True},
|
|
{'productKey': 'zzz5'},
|
|
]
|
|
}
|
|
|
|
msg = 'Checking for available Apple Software Updates...'
|
|
self.au._ResetMunkiStatusAndDisplayMessage(msg)
|
|
appleupdates.os.unlink(self.au.applicable_updates_plist).AndRaise(
|
|
OSError)
|
|
|
|
catalog_url = 'file://localhost' + appleupdates.urllib2.quote(
|
|
self.au.extracted_catalog_path)
|
|
self.au._RunSoftwareUpdate(
|
|
['-l', '-f', self.au.applicable_updates_plist],
|
|
catalog_url=catalog_url,
|
|
stop_allowed=True).AndReturn(0)
|
|
|
|
appleupdates.FoundationPlist.readPlist(
|
|
self.au.applicable_updates_plist).AndReturn(updates_plist_dict)
|
|
|
|
self.mox.ReplayAll()
|
|
output = self.au.GetAvailableUpdateProductIDs()
|
|
self.assertEqual(len(output), 2)
|
|
self.assertTrue('4zzz' in output)
|
|
self.assertTrue('zzz5' in output)
|
|
self.mox.VerifyAll()
|
|
|
|
def testExtractAndCopyDownloadedCatalogMakedirsError(self):
|
|
"""Tests ExtractAndCopyDownloadedCatalog() with os.makedirs error."""
|
|
self.mox.StubOutWithMock(appleupdates.os, 'makedirs')
|
|
self.mox.StubOutWithMock(appleupdates.os.path, 'exists')
|
|
|
|
appleupdates.os.path.exists(self.au.local_catalog_dir).AndReturn(False)
|
|
appleupdates.os.makedirs(self.au.local_catalog_dir).AndRaise(
|
|
OSError)
|
|
|
|
self.mox.ReplayAll()
|
|
self.assertRaises(
|
|
appleupdates.ReplicationError,
|
|
self.au.ExtractAndCopyDownloadedCatalog)
|
|
self.mox.VerifyAll()
|
|
|
|
def testExtractAndCopyDownloadedCatalogPlaintextCatalog(self):
|
|
"""Tests ExtractAndCopyDownloadedCatalog() with plain-text catalog."""
|
|
self.mox.StubOutWithMock(appleupdates.os.path, 'exists')
|
|
|
|
appleupdates.os.path.exists(self.au.local_catalog_dir).AndReturn(True)
|
|
local_apple_sus_catalog = appleupdates.os.path.join(
|
|
self.au.local_catalog_dir,
|
|
appleupdates.APPLE_EXTRACTED_CATALOG_NAME)
|
|
|
|
contents = 'non-gzipped text'
|
|
mock_open = self.mox.CreateMockAnything()
|
|
mock_file = self.mox.CreateMockAnything()
|
|
mock_open(self.au.apple_download_catalog_path, 'rb').AndReturn(
|
|
mock_file)
|
|
mock_file.read(2).AndReturn(contents)
|
|
mock_file.seek(0).AndReturn(None)
|
|
mock_file.read().AndReturn(contents)
|
|
mock_file.close().AndReturn(None)
|
|
mock_open(local_apple_sus_catalog, 'wb').AndReturn(mock_file)
|
|
mock_file.write(contents)
|
|
mock_file.close()
|
|
|
|
self.mox.ReplayAll()
|
|
self.au.ExtractAndCopyDownloadedCatalog(_open=mock_open)
|
|
self.mox.VerifyAll()
|
|
|
|
def testExtractAndCopyDownloadedCatalogGzippedCatalog(self):
|
|
"""Tests ExtractAndCopyDownloadedCatalog() with gzipped catalog."""
|
|
self.mox.StubOutWithMock(appleupdates.os.path, 'exists')
|
|
self.mox.StubOutWithMock(appleupdates.gzip, 'open')
|
|
|
|
appleupdates.os.path.exists(self.au.local_catalog_dir).AndReturn(True)
|
|
local_apple_sus_catalog = appleupdates.os.path.join(
|
|
self.au.local_catalog_dir,
|
|
appleupdates.APPLE_EXTRACTED_CATALOG_NAME)
|
|
|
|
contents = 'gzipped text'
|
|
mock_open = self.mox.CreateMockAnything()
|
|
mock_file = self.mox.CreateMockAnything()
|
|
mock_open(self.au.apple_download_catalog_path, 'rb').AndReturn(
|
|
mock_file)
|
|
mock_file.read(2).AndReturn('\x1f\x8b')
|
|
mock_file.close().AndReturn(None)
|
|
appleupdates.gzip.open(
|
|
self.au.apple_download_catalog_path, 'rb').AndReturn(mock_file)
|
|
mock_file.read().AndReturn(contents)
|
|
mock_file.close()
|
|
mock_open(local_apple_sus_catalog, 'wb').AndReturn(mock_file)
|
|
mock_file.write(contents)
|
|
mock_file.close()
|
|
|
|
self.mox.ReplayAll()
|
|
self.au.ExtractAndCopyDownloadedCatalog(_open=mock_open)
|
|
self.mox.VerifyAll()
|
|
|
|
def testGetAppleCatalogURLMunki(self):
|
|
"""Tests _GetAppleCatalogURL() with Munki's pref."""
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'pref')
|
|
|
|
appleupdates.munkicommon.pref('SoftwareUpdateServerURL').AndReturn(
|
|
'url')
|
|
|
|
self.mox.ReplayAll()
|
|
self.assertEqual('url', self.au._GetAppleCatalogURL())
|
|
self.mox.VerifyAll()
|
|
|
|
def testGetAppleCatalogURLSoftwareUpdateOrMCX(self):
|
|
"""Tests _GetAppleCatalogURL() with SoftwareUpdate.plist or MCX pref."""
|
|
self.mox.StubOutWithMock(self.au, 'GetSoftwareUpdatePref')
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'pref')
|
|
|
|
appleupdates.munkicommon.pref('SoftwareUpdateServerURL').AndReturn(None)
|
|
self.au.GetSoftwareUpdatePref('CatalogURL').AndReturn('url')
|
|
|
|
self.mox.ReplayAll()
|
|
self.assertEqual('url', self.au._GetAppleCatalogURL())
|
|
self.mox.VerifyAll()
|
|
|
|
def testGetAppleCatalogURLDefault(self):
|
|
"""Tests _GetAppleCatalogURL() with default URL."""
|
|
self.mox.StubOutWithMock(self.au, 'GetSoftwareUpdatePref')
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'pref')
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'getOsVersion')
|
|
|
|
# Grab the first os_version/url combo to use for this test.
|
|
os_version = appleupdates.DEFAULT_CATALOG_URLS.keys()[0]
|
|
url = appleupdates.DEFAULT_CATALOG_URLS[os_version]
|
|
|
|
appleupdates.munkicommon.pref('SoftwareUpdateServerURL').AndReturn(None)
|
|
self.au.GetSoftwareUpdatePref('CatalogURL').AndReturn(None)
|
|
appleupdates.munkicommon.getOsVersion().AndReturn(os_version)
|
|
|
|
self.mox.ReplayAll()
|
|
self.assertEqual(url, self.au._GetAppleCatalogURL())
|
|
self.mox.VerifyAll()
|
|
|
|
def testGetAppleCatalogURLNotFound(self):
|
|
"""Tests _GetAppleCatalogURL() when the catalog URL is not found."""
|
|
self.mox.StubOutWithMock(self.au, 'GetSoftwareUpdatePref')
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'pref')
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'getOsVersion')
|
|
|
|
appleupdates.munkicommon.pref('SoftwareUpdateServerURL').AndReturn(None)
|
|
self.au.GetSoftwareUpdatePref('CatalogURL').AndReturn(None)
|
|
appleupdates.munkicommon.getOsVersion().AndReturn('UKNOWN OS VERSION!')
|
|
|
|
self.mox.ReplayAll()
|
|
self.assertRaises(
|
|
appleupdates.CatalogNotFoundError, self.au._GetAppleCatalogURL)
|
|
self.mox.VerifyAll()
|
|
|
|
def testCacheAppleCatalog(self):
|
|
"""Tests CacheAppleCatalog()."""
|
|
self._MockMunkiDisplay()
|
|
self.mox.StubOutWithMock(self.au, '_GetAppleCatalogURL')
|
|
self.mox.StubOutWithMock(self.au, 'ExtractAndCopyDownloadedCatalog')
|
|
self.mox.StubOutWithMock(appleupdates.os, 'makedirs')
|
|
self.mox.StubOutWithMock(appleupdates.os.path, 'exists')
|
|
self.mox.StubOutWithMock(self.au, 'GetSoftwareUpdateResource')
|
|
|
|
url = 'url'
|
|
self.au._GetAppleCatalogURL().AndReturn(url)
|
|
appleupdates.os.path.exists(self.au.temp_cache_dir).AndReturn(False)
|
|
appleupdates.os.makedirs(self.au.temp_cache_dir).AndReturn(None)
|
|
|
|
appleupdates.munkicommon.display_status_major(
|
|
'Checking Apple Software Update catalog...')
|
|
appleupdates.munkicommon.display_detail(
|
|
'Caching CatalogURL %s', url)
|
|
self.au.GetSoftwareUpdateResource(
|
|
url, self.au.apple_download_catalog_path, resume=True).AndReturn(
|
|
0)
|
|
self.au.ExtractAndCopyDownloadedCatalog().AndReturn(None)
|
|
|
|
self.mox.ReplayAll()
|
|
self.au.CacheAppleCatalog()
|
|
self.mox.VerifyAll()
|
|
|
|
def testCacheAppleCatalogWithBadCatalogURL(self):
|
|
"""Tests CacheAppleCatalog() with a bad catalog URL."""
|
|
self._MockMunkiDisplay()
|
|
self.mox.StubOutWithMock(self.au, '_GetAppleCatalogURL')
|
|
|
|
exc = appleupdates.CatalogNotFoundError('foo error')
|
|
self.au._GetAppleCatalogURL().AndRaise(exc)
|
|
appleupdates.munkicommon.display_error('foo error')
|
|
|
|
self.mox.ReplayAll()
|
|
self.assertRaises(
|
|
appleupdates.CatalogNotFoundError, self.au.CacheAppleCatalog)
|
|
self.mox.VerifyAll()
|
|
|
|
def testCacheAppleCatalogMakedirsError(self):
|
|
"""Tests CacheAppleCatalog() with os.makedirs error."""
|
|
self._MockMunkiDisplay()
|
|
self.mox.StubOutWithMock(self.au, '_GetAppleCatalogURL')
|
|
self.mox.StubOutWithMock(appleupdates.os, 'makedirs')
|
|
self.mox.StubOutWithMock(appleupdates.os.path, 'exists')
|
|
|
|
self.au._GetAppleCatalogURL().AndReturn('url')
|
|
appleupdates.os.path.exists(self.au.temp_cache_dir).AndReturn(False)
|
|
appleupdates.os.makedirs(self.au.temp_cache_dir).AndRaise(OSError)
|
|
|
|
self.mox.ReplayAll()
|
|
self.assertRaises(
|
|
appleupdates.ReplicationError, self.au.CacheAppleCatalog)
|
|
self.mox.VerifyAll()
|
|
|
|
def testCacheAppleCatalogMunkiDownloadError(self):
|
|
"""Tests CacheAppleCatalog() with a MunkiDownloadError."""
|
|
self._MockMunkiDisplay()
|
|
self.mox.StubOutWithMock(self.au, '_GetAppleCatalogURL')
|
|
self.mox.StubOutWithMock(self.au, 'ExtractAndCopyDownloadedCatalog')
|
|
self.mox.StubOutWithMock(appleupdates.os, 'makedirs')
|
|
self.mox.StubOutWithMock(appleupdates.os.path, 'exists')
|
|
self.mox.StubOutWithMock(self.au, 'GetSoftwareUpdateResource')
|
|
|
|
url = 'url'
|
|
self.au._GetAppleCatalogURL().AndReturn(url)
|
|
appleupdates.os.path.exists(self.au.temp_cache_dir).AndReturn(False)
|
|
appleupdates.os.makedirs(self.au.temp_cache_dir).AndReturn(None)
|
|
|
|
appleupdates.munkicommon.display_status_major(
|
|
'Checking Apple Software Update catalog...')
|
|
appleupdates.munkicommon.display_detail(
|
|
'Caching CatalogURL %s', url)
|
|
self.au.GetSoftwareUpdateResource(
|
|
url, self.au.apple_download_catalog_path, resume=True).AndRaise(
|
|
appleupdates.fetch.MunkiDownloadError)
|
|
|
|
self.mox.ReplayAll()
|
|
self.assertRaises(
|
|
appleupdates.fetch.MunkiDownloadError,
|
|
self.au.CacheAppleCatalog)
|
|
self.mox.VerifyAll()
|
|
|
|
def _InstalledApplePackagesHaveChangedHelper(
|
|
self, old_checksum, new_checksum):
|
|
"""Helper method for InstalledApplePackagesHaveChanged() testing."""
|
|
self.mox.StubOutWithMock(appleupdates.subprocess, 'Popen')
|
|
self.mox.StubOutWithMock(appleupdates.hashlib, 'sha256')
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'pref')
|
|
|
|
cmd = ['/usr/sbin/pkgutil', '--regexp', '--pkg-info-plist',
|
|
'com\.apple\.*']
|
|
output = 'output!'
|
|
|
|
mock_proc = self.mox.CreateMockAnything()
|
|
appleupdates.subprocess.Popen(
|
|
cmd, shell=False, bufsize=1,
|
|
stdin=appleupdates.subprocess.PIPE,
|
|
stdout=appleupdates.subprocess.PIPE,
|
|
stderr=appleupdates.subprocess.PIPE).AndReturn(mock_proc)
|
|
mock_proc.communicate().AndReturn((output, 'unused foo'))
|
|
mock_hash = self.mox.CreateMockAnything()
|
|
appleupdates.hashlib.sha256(output).AndReturn(mock_hash)
|
|
mock_hash.hexdigest().AndReturn(new_checksum)
|
|
appleupdates.munkicommon.pref(
|
|
'InstalledApplePackagesChecksum').AndReturn(old_checksum)
|
|
if old_checksum != new_checksum:
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'set_pref')
|
|
appleupdates.munkicommon.set_pref(
|
|
'InstalledApplePackagesChecksum', new_checksum)
|
|
|
|
self.mox.ReplayAll()
|
|
if old_checksum == new_checksum:
|
|
self.assertFalse(self.au.InstalledApplePackagesHaveChanged())
|
|
else:
|
|
self.assertTrue(self.au.InstalledApplePackagesHaveChanged())
|
|
self.mox.VerifyAll()
|
|
|
|
def testInstalledApplePackagesHaveChangedWhenNoChange(self):
|
|
"""Tests InstalledApplePackagesHaveChanged() when haven't changed."""
|
|
self._InstalledApplePackagesHaveChangedHelper('zzzz', 'zzzz')
|
|
|
|
def testInstalledApplePackagesHaveChangedWhenChanged(self):
|
|
"""Tests InstalledApplePackagesHaveChanged() when they have changed."""
|
|
self._InstalledApplePackagesHaveChangedHelper('asdf', 'zzzz')
|
|
|
|
def testAvailableUpdatesAreDownloadedNoUpdateInfo(self):
|
|
"""Tests AvailableUpdatesAreDownloaded() when update info is empty."""
|
|
self.mox.StubOutWithMock(self.au, 'GetSoftwareUpdateInfo')
|
|
self.au.GetSoftwareUpdateInfo().AndReturn(None)
|
|
|
|
self.mox.ReplayAll()
|
|
self.assertTrue(self.au.AvailableUpdatesAreDownloaded())
|
|
self.mox.VerifyAll()
|
|
|
|
def testIsForceCheckNeccessaryWithChangedHash(self):
|
|
"""Tests _IsForceCheckNeccessary() when the hash has changed."""
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'getsha256hash')
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'log')
|
|
|
|
appleupdates.munkicommon.getsha256hash(
|
|
self.au.apple_download_catalog_path).AndReturn('omg changed hash')
|
|
appleupdates.munkicommon.log('Apple update catalog has changed.')
|
|
|
|
self.mox.ReplayAll()
|
|
self.assertTrue(self.au._IsForceCheckNeccessary('outdated hash'))
|
|
self.mox.VerifyAll()
|
|
|
|
def testIsForceCheckNeccessaryWhenInstalledPackagesHaveChanged(self):
|
|
"""Tests _IsForceCheckNeccessary() when installed pkgs have changed."""
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'getsha256hash')
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'log')
|
|
self.mox.StubOutWithMock(self.au, 'InstalledApplePackagesHaveChanged')
|
|
|
|
appleupdates.munkicommon.getsha256hash(
|
|
self.au.apple_download_catalog_path).AndReturn('hash')
|
|
self.au.InstalledApplePackagesHaveChanged().AndReturn(True)
|
|
appleupdates.munkicommon.log('Installed Apple packages have changed.')
|
|
|
|
self.mox.ReplayAll()
|
|
self.assertTrue(self.au._IsForceCheckNeccessary('hash'))
|
|
self.mox.VerifyAll()
|
|
|
|
def testIsForceCheckNeccessaryWhenAvailableUpdatesAreNotDownloaded(self):
|
|
"""Tests _IsForceCheckNeccessary(); new updates aren't downloaded."""
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'getsha256hash')
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'log')
|
|
self.mox.StubOutWithMock(self.au, 'InstalledApplePackagesHaveChanged')
|
|
self.mox.StubOutWithMock(self.au, 'AvailableUpdatesAreDownloaded')
|
|
|
|
appleupdates.munkicommon.getsha256hash(
|
|
self.au.apple_download_catalog_path).AndReturn('hash')
|
|
self.au.InstalledApplePackagesHaveChanged().AndReturn(False)
|
|
self.au.AvailableUpdatesAreDownloaded().AndReturn(False)
|
|
appleupdates.munkicommon.log(
|
|
'Downloaded updates do not match our list of available updates.')
|
|
|
|
self.mox.ReplayAll()
|
|
self.assertTrue(self.au._IsForceCheckNeccessary('hash'))
|
|
self.mox.VerifyAll()
|
|
|
|
def testIsForceCheckNeccessaryWhenForceIsNotNeeded(self):
|
|
"""Tests _IsForceCheckNeccessary() when force is not needed."""
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'getsha256hash')
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'log')
|
|
self.mox.StubOutWithMock(self.au, 'InstalledApplePackagesHaveChanged')
|
|
self.mox.StubOutWithMock(self.au, 'AvailableUpdatesAreDownloaded')
|
|
|
|
appleupdates.munkicommon.getsha256hash(
|
|
self.au.apple_download_catalog_path).AndReturn('hash')
|
|
self.au.InstalledApplePackagesHaveChanged().AndReturn(False)
|
|
self.au.AvailableUpdatesAreDownloaded().AndReturn(True)
|
|
|
|
self.mox.ReplayAll()
|
|
self.assertFalse(self.au._IsForceCheckNeccessary('hash'))
|
|
self.mox.VerifyAll()
|
|
|
|
def _CheckForSoftwareUpdatesCacheAppleCatalogExceptionHelper(
|
|
self, exc, s=''):
|
|
"""Helper method for CheckForSoftwareUpdates() exception handling."""
|
|
self._MockMunkiDisplay()
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'getsha256hash')
|
|
self.mox.StubOutWithMock(self.au, 'CacheAppleCatalog')
|
|
|
|
appleupdates.munkicommon.getsha256hash(
|
|
self.au.apple_download_catalog_path).AndReturn(None)
|
|
self.au.CacheAppleCatalog().AndRaise(exc(s))
|
|
if exc == appleupdates.ReplicationError or \
|
|
exc == appleupdates.fetch.MunkiDownloadError:
|
|
appleupdates.munkicommon.display_warning(
|
|
'Could not download Apple SUS catalog:')
|
|
appleupdates.munkicommon.display_warning('\t%s', s)
|
|
|
|
self.mox.ReplayAll()
|
|
self.assertFalse(self.au.CheckForSoftwareUpdates())
|
|
self.mox.VerifyAll()
|
|
|
|
def testCheckForSoftwareUpdatesCatalogNotFound(self):
|
|
"""Tests CheckForSoftwareUpdates() with CatalogNotFoundError."""
|
|
self._CheckForSoftwareUpdatesCacheAppleCatalogExceptionHelper(
|
|
appleupdates.CatalogNotFoundError)
|
|
|
|
def testCheckForSoftwareUpdatesReplicationError(self):
|
|
"""Tests CheckForSoftwareUpdates() with ReplicationError."""
|
|
self._CheckForSoftwareUpdatesCacheAppleCatalogExceptionHelper(
|
|
appleupdates.ReplicationError, s='foo error')
|
|
|
|
def testCheckForSoftwareUpdatesMunkiDownloadError(self):
|
|
"""Tests CheckForSoftwareUpdates() with MunkiDownloadError."""
|
|
self._CheckForSoftwareUpdatesCacheAppleCatalogExceptionHelper(
|
|
appleupdates.fetch.MunkiDownloadError)
|
|
|
|
def testCheckForSoftwareUpdatesWhenForceCheckNotNeeded(self):
|
|
"""Tests CheckForSoftwareUpdates() when a force check is not needed."""
|
|
self._MockMunkiDisplay()
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'getsha256hash')
|
|
self.mox.StubOutWithMock(self.au, 'CacheAppleCatalog')
|
|
self.mox.StubOutWithMock(self.au, '_IsForceCheckNeccessary')
|
|
self.mox.StubOutWithMock(self.au, 'GetSoftwareUpdateInfo')
|
|
|
|
appleupdates.munkicommon.getsha256hash(
|
|
self.au.apple_download_catalog_path).AndReturn('hash')
|
|
self.au.CacheAppleCatalog().AndReturn(None)
|
|
self.au._IsForceCheckNeccessary('hash').AndReturn(False)
|
|
appleupdates.munkicommon.display_info(
|
|
'Skipping Apple Software Update check because sucatalog is '
|
|
'unchanged, installed Apple packages are unchanged and we '
|
|
'recently did a full check.')
|
|
# mock out GetSoftwareUpdateInfo() because its return value
|
|
# depends on whether or not we have cached updates
|
|
# this implies we might need some tests that deal with
|
|
# cached updates...
|
|
self.au.GetSoftwareUpdateInfo().AndReturn(False)
|
|
|
|
self.mox.ReplayAll()
|
|
self.assertFalse(self.au.CheckForSoftwareUpdates(force_check=False))
|
|
self.mox.VerifyAll()
|
|
|
|
def testCheckForSoftwareUpdatesWhenUpdateListEmpty(self):
|
|
"""Tests CheckForSoftwareUpdates() when updatelist is empty."""
|
|
self.mox.StubOutWithMock(self.au, 'CacheAppleCatalog')
|
|
self.mox.StubOutWithMock(self.au, 'GetAvailableUpdateProductIDs')
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'getsha256hash')
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'set_pref')
|
|
# Cannot stub out the builtin date() method, so stub the entire module.
|
|
mock_nsdate_module = self.mox.CreateMockAnything()
|
|
self.mox.StubOutWithMock(appleupdates, 'NSDate', mock_nsdate_module)
|
|
mock_nsdate_module.date = self.mox.CreateMockAnything()
|
|
|
|
appleupdates.munkicommon.getsha256hash(
|
|
self.au.apple_download_catalog_path).AndReturn('hash')
|
|
self.au.CacheAppleCatalog().AndReturn(None)
|
|
self.au.GetAvailableUpdateProductIDs().AndReturn([])
|
|
appleupdates.NSDate.date().AndReturn('d')
|
|
appleupdates.munkicommon.set_pref('LastAppleSoftwareUpdateCheck', 'd')
|
|
|
|
self.mox.ReplayAll()
|
|
self.assertFalse(self.au.CheckForSoftwareUpdates())
|
|
self.mox.VerifyAll()
|
|
|
|
def testCheckForSoftwareUpdatesWhenCacheUpdateMetadataError(self):
|
|
"""Tests CheckForSoftwareUpdates() when CacheUpdateMetadata() fails."""
|
|
self._MockMunkiDisplay()
|
|
self.mox.StubOutWithMock(self.au, 'CacheAppleCatalog')
|
|
self.mox.StubOutWithMock(self.au, 'GetAvailableUpdateProductIDs')
|
|
self.mox.StubOutWithMock(self.au, '_WriteFilteredCatalog')
|
|
self.mox.StubOutWithMock(self.au, 'CacheUpdateMetadata')
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'getsha256hash')
|
|
|
|
update_list = ['non-empty list']
|
|
|
|
appleupdates.munkicommon.getsha256hash(
|
|
self.au.apple_download_catalog_path).AndReturn('hash')
|
|
self.au.CacheAppleCatalog().AndReturn(None)
|
|
self.au.GetAvailableUpdateProductIDs().AndReturn(update_list)
|
|
self.au._WriteFilteredCatalog(
|
|
update_list, self.au.filtered_catalog_path).AndReturn(None)
|
|
exc = appleupdates.ReplicationError('foo err')
|
|
self.au.CacheUpdateMetadata().AndRaise(exc)
|
|
appleupdates.munkicommon.display_warning(
|
|
'Could not replicate software update metadata:')
|
|
appleupdates.munkicommon.display_warning('\t%s', 'foo err')
|
|
|
|
self.mox.ReplayAll()
|
|
self.assertFalse(self.au.CheckForSoftwareUpdates())
|
|
self.mox.VerifyAll()
|
|
|
|
def testCheckForSoftwareUpdatesWhenDownloadAvailableUpdateFails(self):
|
|
"""Tests CheckForSoftwareUpdates() when DownloadAvailUpdates() fails."""
|
|
self._MockMunkiDisplay()
|
|
self.mox.StubOutWithMock(self.au, 'CacheAppleCatalog')
|
|
self.mox.StubOutWithMock(self.au, 'GetAvailableUpdateProductIDs')
|
|
self.mox.StubOutWithMock(self.au, '_WriteFilteredCatalog')
|
|
self.mox.StubOutWithMock(self.au, 'CacheUpdateMetadata')
|
|
self.mox.StubOutWithMock(self.au, 'DownloadAvailableUpdates')
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'getsha256hash')
|
|
|
|
update_list = ['non-empty list']
|
|
|
|
appleupdates.munkicommon.getsha256hash(
|
|
self.au.apple_download_catalog_path).AndReturn('hash')
|
|
self.au.CacheAppleCatalog().AndReturn(None)
|
|
self.au.GetAvailableUpdateProductIDs().AndReturn(update_list)
|
|
self.au._WriteFilteredCatalog(
|
|
update_list, self.au.filtered_catalog_path).AndReturn(None)
|
|
self.au.CacheUpdateMetadata().AndReturn(None)
|
|
self.au.DownloadAvailableUpdates().AndReturn(False)
|
|
|
|
self.mox.ReplayAll()
|
|
self.assertFalse(self.au.CheckForSoftwareUpdates())
|
|
self.mox.VerifyAll()
|
|
|
|
def testCheckForSoftwareUpdatesSuccess(self):
|
|
"""Tests CheckForSoftwareUpdates() success."""
|
|
self._MockMunkiDisplay()
|
|
self.mox.StubOutWithMock(self.au, 'CacheAppleCatalog')
|
|
self.mox.StubOutWithMock(self.au, 'GetAvailableUpdateProductIDs')
|
|
self.mox.StubOutWithMock(self.au, '_WriteFilteredCatalog')
|
|
self.mox.StubOutWithMock(self.au, 'CacheUpdateMetadata')
|
|
self.mox.StubOutWithMock(self.au, 'DownloadAvailableUpdates')
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'getsha256hash')
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'set_pref')
|
|
# Cannot stub out the builtin date() method, so stub the entire module.
|
|
mock_nsdate_module = self.mox.CreateMockAnything()
|
|
self.mox.StubOutWithMock(appleupdates, 'NSDate', mock_nsdate_module)
|
|
mock_nsdate_module.date = self.mox.CreateMockAnything()
|
|
|
|
update_list = ['non-empty list']
|
|
|
|
appleupdates.munkicommon.getsha256hash(
|
|
self.au.apple_download_catalog_path).AndReturn('hash')
|
|
self.au.CacheAppleCatalog().AndReturn(None)
|
|
self.au.GetAvailableUpdateProductIDs().AndReturn(update_list)
|
|
self.au._WriteFilteredCatalog(
|
|
update_list, self.au.filtered_catalog_path).AndReturn(None)
|
|
self.au.CacheUpdateMetadata().AndReturn(None)
|
|
self.au.DownloadAvailableUpdates().AndReturn(True)
|
|
appleupdates.NSDate.date().AndReturn('d')
|
|
appleupdates.munkicommon.set_pref('LastAppleSoftwareUpdateCheck', 'd')
|
|
|
|
self.mox.ReplayAll()
|
|
self.assertTrue(self.au.CheckForSoftwareUpdates())
|
|
self.mox.VerifyAll()
|
|
|
|
def testAvailableUpdatesAreDownloadedFoundationPlistError(self):
|
|
"""Tests AvailableUpdatesAreDownloaded() when invalid index_plist."""
|
|
self._MockFoundationPlist()
|
|
self.mox.StubOutWithMock(self.au, 'GetSoftwareUpdateInfo')
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'log')
|
|
|
|
index_plist = '/Library/Updates/index.plist'
|
|
self.au.GetSoftwareUpdateInfo().AndReturn(True)
|
|
exc = appleupdates.FoundationPlist.FoundationPlistException
|
|
appleupdates.FoundationPlist.readPlist(index_plist).AndRaise(exc)
|
|
appleupdates.munkicommon.log(
|
|
'Apple downloaded update index is invalid: %s' % index_plist)
|
|
|
|
self.mox.ReplayAll()
|
|
self.assertFalse(self.au.AvailableUpdatesAreDownloaded())
|
|
self.mox.VerifyAll()
|
|
|
|
def testAvailableUpdatesAreDownloadedWithProductIdNotDownloaded(self):
|
|
"""Tests AvailableUpdatesAreDownloaded(); product_id not downloaded."""
|
|
self._MockFoundationPlist()
|
|
self.mox.StubOutWithMock(self.au, 'GetSoftwareUpdateInfo')
|
|
self.mox.StubOutWithMock(appleupdates.os.path, 'isdir')
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'log')
|
|
|
|
index_plist = '/Library/Updates/index.plist'
|
|
apple_updates = [
|
|
{'productKey': '1', 'name': 'name1'},
|
|
{'productKey': '999', 'name': 'name999'},
|
|
{'NOTproductKey': 'boo', 'name': 'nameboo'},
|
|
]
|
|
download_index = {
|
|
'ProductPaths': {
|
|
'1': 'path1', '3': 'path3', '5': 'path5',
|
|
}
|
|
}
|
|
self.au.GetSoftwareUpdateInfo().AndReturn(apple_updates)
|
|
exc = appleupdates.FoundationPlist.FoundationPlistException
|
|
appleupdates.FoundationPlist.readPlist(index_plist).AndReturn(
|
|
download_index)
|
|
appleupdates.os.path.isdir(os.path.join(
|
|
'/Library/Updates', 'path1')).AndReturn(True)
|
|
appleupdates.os.path.isdir('/Library/Updates/').AndReturn(True)
|
|
appleupdates.munkicommon.log(
|
|
'Apple Update product is not downloaded: %s' % 'name999')
|
|
|
|
self.mox.ReplayAll()
|
|
self.assertFalse(self.au.AvailableUpdatesAreDownloaded())
|
|
self.mox.VerifyAll()
|
|
|
|
def testAvailableUpdatesAreDownloadedWithNonExistentProductDir(self):
|
|
"""Tests AvailableUpdatesAreDownloaded(); non-existent product dir."""
|
|
self._MockFoundationPlist()
|
|
self.mox.StubOutWithMock(self.au, 'GetSoftwareUpdateInfo')
|
|
self.mox.StubOutWithMock(appleupdates.os.path, 'isdir')
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'log')
|
|
|
|
index_plist = '/Library/Updates/index.plist'
|
|
apple_updates = [
|
|
{'productKey': '1', 'name': 'name1'},
|
|
{'productKey': '3', 'name': 'name3'},
|
|
{'NOTproductKey': 'boo', 'name': 'nameboo'},
|
|
]
|
|
download_index = {
|
|
'ProductPaths': {
|
|
'1': 'path1', '3': 'path3', '5': 'path5',
|
|
}
|
|
}
|
|
self.au.GetSoftwareUpdateInfo().AndReturn(apple_updates)
|
|
exc = appleupdates.FoundationPlist.FoundationPlistException
|
|
appleupdates.FoundationPlist.readPlist(index_plist).AndReturn(
|
|
download_index)
|
|
appleupdates.os.path.isdir(os.path.join(
|
|
'/Library/Updates', 'path1')).AndReturn(True)
|
|
appleupdates.os.path.isdir(os.path.join(
|
|
'/Library/Updates', 'path3')).AndReturn(False)
|
|
appleupdates.munkicommon.log(
|
|
'Apple Update product directory is missing: %s' % 'name3')
|
|
|
|
self.mox.ReplayAll()
|
|
self.assertFalse(self.au.AvailableUpdatesAreDownloaded())
|
|
self.mox.VerifyAll()
|
|
|
|
def testAvailableUpdatesAreDownloadedSuccess(self):
|
|
"""Tests AvailableUpdatesAreDownloaded() with success."""
|
|
self._MockFoundationPlist()
|
|
self.mox.StubOutWithMock(self.au, 'GetSoftwareUpdateInfo')
|
|
self.mox.StubOutWithMock(appleupdates.os.path, 'isdir')
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'log')
|
|
|
|
index_plist = '/Library/Updates/index.plist'
|
|
apple_updates = [
|
|
{'productKey': '1', 'name': 'name1'},
|
|
{'productKey': '3', 'name': 'name3'},
|
|
{'NOTproductKey': 'boo', 'name': 'nameboo'},
|
|
]
|
|
download_index = {
|
|
'ProductPaths': {
|
|
'1': 'path1', '3': 'path3', '5': 'path5',
|
|
}
|
|
}
|
|
self.au.GetSoftwareUpdateInfo().AndReturn(apple_updates)
|
|
exc = appleupdates.FoundationPlist.FoundationPlistException
|
|
appleupdates.FoundationPlist.readPlist(index_plist).AndReturn(
|
|
download_index)
|
|
appleupdates.os.path.isdir(os.path.join(
|
|
'/Library/Updates', 'path1')).AndReturn(True)
|
|
appleupdates.os.path.isdir(os.path.join(
|
|
'/Library/Updates', 'path3')).AndReturn(True)
|
|
|
|
self.mox.ReplayAll()
|
|
self.assertTrue(self.au.AvailableUpdatesAreDownloaded())
|
|
self.mox.VerifyAll()
|
|
|
|
def testGetSoftwareUpdateInfo(self):
|
|
"""Tests GetSoftwareUpdateInfo()."""
|
|
self._MockFoundationPlist()
|
|
self.mox.StubOutWithMock(appleupdates.os.path, 'exists')
|
|
self.mox.StubOutWithMock(self.au, 'GetBlockingApps')
|
|
self.mox.StubOutWithMock(self.au, 'GetFirmwareAlertText')
|
|
|
|
blocking_apps = ['blocking1', 'blocking2']
|
|
applicable_updates = {
|
|
'phaseResultsArray': [
|
|
{'description': 'desc1', 'ignoreKey': 'name1',
|
|
'version': 'ver1', 'name': 'display_name1', 'sizeInKB': 1000,
|
|
'productKey': 'prodid1'},
|
|
{'description': 'desc2', 'ignoreKey': 'name2',
|
|
'version': 'ver2', 'name': 'display_name2', 'sizeInKB': 2000,
|
|
'productKey': 'prodid2', 'restartRequired': 'YES'},
|
|
]
|
|
}
|
|
expected_output = [
|
|
{'apple_product_name': 'display_name1',
|
|
'blocking_applications': blocking_apps,
|
|
'description': 'desc1',
|
|
'name': 'name1',
|
|
'version_to_install': 'ver1',
|
|
'display_name': 'display_name1',
|
|
'installed_size': 1000,
|
|
'productKey': 'prodid1'},
|
|
{'apple_product_name': 'display_name2',
|
|
'description': 'desc2',
|
|
'firmware_alert_text': 'This is a firmware update',
|
|
'name': 'name2',
|
|
'version_to_install': 'ver2',
|
|
'display_name': 'display_name2',
|
|
'installed_size': 2000,
|
|
'productKey': 'prodid2',
|
|
'RestartAction': 'RequireRestart'},
|
|
]
|
|
|
|
appleupdates.os.path.exists(self.au.applicable_updates_plist).AndReturn(
|
|
True)
|
|
appleupdates.FoundationPlist.readPlist(
|
|
self.au.applicable_updates_plist).AndReturn(applicable_updates)
|
|
self.au.GetBlockingApps(
|
|
applicable_updates['phaseResultsArray'][0]['productKey']).AndReturn(
|
|
blocking_apps)
|
|
self.au.GetFirmwareAlertText(
|
|
applicable_updates['phaseResultsArray'][0]['productKey']).AndReturn(
|
|
'')
|
|
self.au.GetBlockingApps(
|
|
applicable_updates['phaseResultsArray'][1]['productKey']).AndReturn(
|
|
[])
|
|
self.au.GetFirmwareAlertText(
|
|
applicable_updates['phaseResultsArray'][1]['productKey']).AndReturn(
|
|
'This is a firmware update')
|
|
|
|
self.mox.ReplayAll()
|
|
self.assertEqual(expected_output, self.au.GetSoftwareUpdateInfo())
|
|
self.mox.VerifyAll()
|
|
|
|
def testGetSoftwareUpdateInfoWhenApplicableUpdatesDoesntExist(self):
|
|
"""Tests GetSoftwareUpdateInfo(); Applicable Updates does not exist."""
|
|
self.mox.StubOutWithMock(appleupdates.os.path, 'exists')
|
|
|
|
appleupdates.os.path.exists(self.au.applicable_updates_plist).AndReturn(
|
|
False)
|
|
self.mox.ReplayAll()
|
|
self.assertEqual([], self.au.GetSoftwareUpdateInfo())
|
|
self.mox.VerifyAll()
|
|
|
|
def testWriteAppleUpdatesFile(self):
|
|
"""Tests WriteAppleUpdatesFile()."""
|
|
self._MockFoundationPlist()
|
|
self._MockUpdateCheck()
|
|
self.mox.StubOutWithMock(self.au, 'GetSoftwareUpdateInfo')
|
|
self.au.GetSoftwareUpdateInfo().AndReturn('appleupdates')
|
|
appleupdates.updatecheck.getPrimaryManifestCatalogs(
|
|
'', force_refresh=False).AndReturn(None)
|
|
appleupdates.FoundationPlist.writePlist(
|
|
{'AppleUpdates': 'appleupdates'},
|
|
self.au.apple_updates_plist).AndReturn(None)
|
|
self.mox.ReplayAll()
|
|
self.assertTrue(self.au.WriteAppleUpdatesFile() == len('appleupdates'))
|
|
self.mox.VerifyAll()
|
|
|
|
def testWriteAppleUpdatesFileFailure(self):
|
|
"""Tests WriteAppleUpdatesFile() with failure."""
|
|
self._MockFoundationPlist()
|
|
self._MockUpdateCheck()
|
|
self.mox.StubOutWithMock(self.au, 'GetSoftwareUpdateInfo')
|
|
self.mox.StubOutWithMock(appleupdates.os, 'unlink')
|
|
self.au.GetSoftwareUpdateInfo().AndReturn(None)
|
|
appleupdates.os.unlink(self.au.apple_updates_plist).AndRaise(OSError)
|
|
|
|
self.mox.ReplayAll()
|
|
self.assertTrue(self.au.WriteAppleUpdatesFile() == 0)
|
|
self.mox.VerifyAll()
|
|
|
|
def testDisplayAppleUpdateInfo(self):
|
|
"""Tests DisplayAppleUpdateInfo()."""
|
|
self._MockFoundationPlist()
|
|
self._MockMunkiDisplay()
|
|
appleupdates.munkicommon.report = {}
|
|
|
|
apple_updates = {'AppleUpdates': [
|
|
{'display_name': 'name1', 'version_to_install': 'ver1',
|
|
'RestartAction': 'RequireRestart'},
|
|
{'display_name': 'name2', 'version_to_install': 'ver2',
|
|
'RestartAction': 'RequireLogout'},
|
|
{'display_name': 'name3', 'version_to_install': 'ver3'},
|
|
]}
|
|
|
|
appleupdates.FoundationPlist.readPlist(
|
|
self.au.apple_updates_plist).AndReturn(apple_updates)
|
|
appleupdates.munkicommon.display_info(
|
|
'The following Apple Software Updates are available to install:')
|
|
appleupdates.munkicommon.display_info(' + %s-%s' % ('name1', 'ver1'))
|
|
appleupdates.munkicommon.display_info(' *Restart required')
|
|
appleupdates.munkicommon.display_info(' + %s-%s' % ('name2', 'ver2'))
|
|
appleupdates.munkicommon.display_info(' *Logout required')
|
|
appleupdates.munkicommon.display_info(' + %s-%s' % ('name3', 'ver3'))
|
|
|
|
self.mox.ReplayAll()
|
|
self.assertTrue(
|
|
'RestartRequired' not in appleupdates.munkicommon.report)
|
|
self.assertTrue('LogoutRequired' not in appleupdates.munkicommon.report)
|
|
self.au.DisplayAppleUpdateInfo()
|
|
self.assertTrue(appleupdates.munkicommon.report['RestartRequired'])
|
|
self.assertTrue(appleupdates.munkicommon.report['LogoutRequired'])
|
|
self.mox.VerifyAll()
|
|
|
|
def testDisplayAppleUpdateInfoWhenReadPlistFailed(self):
|
|
"""Tests DisplayAppleUpdateInfo() when readPlist() fails."""
|
|
self._MockFoundationPlist()
|
|
self._MockMunkiDisplay()
|
|
|
|
exc = appleupdates.FoundationPlist.FoundationPlistException
|
|
appleupdates.FoundationPlist.readPlist(
|
|
self.au.apple_updates_plist).AndRaise(exc)
|
|
appleupdates.munkicommon.display_error(
|
|
'Error reading: %s', self.au.apple_updates_plist)
|
|
|
|
self.mox.ReplayAll()
|
|
self.au.DisplayAppleUpdateInfo()
|
|
self.mox.VerifyAll()
|
|
|
|
def testGetSoftwareUpdatePref(self):
|
|
"""Tests GetSoftwareUpdatePref()."""
|
|
self.mox.StubOutWithMock(appleupdates, 'CFPreferencesCopyAppValue')
|
|
pref_name = 'foo'
|
|
expected_return = 'bar'
|
|
appleupdates.CFPreferencesCopyAppValue(
|
|
pref_name,
|
|
appleupdates.APPLE_SOFTWARE_UPDATE_PREFS_DOMAIN
|
|
).AndReturn(expected_return)
|
|
|
|
self.mox.ReplayAll()
|
|
self.au.GetSoftwareUpdatePref(pref_name)
|
|
self.mox.VerifyAll()
|
|
|
|
def testLeopardSetupSoftwareUpdateCheck(self):
|
|
"""Tests _LeopardSetupSoftwareUpdateCheck()."""
|
|
self._MockMunkiDisplay()
|
|
self.mox.StubOutWithMock(appleupdates, 'CFPreferencesSetValue')
|
|
self.mox.StubOutWithMock(appleupdates, 'CFPreferencesAppSynchronize')
|
|
appleupdates.CFPreferencesSetValue(
|
|
'AgreedToLicenseAgreement', True,
|
|
appleupdates.APPLE_SOFTWARE_UPDATE_PREFS_DOMAIN,
|
|
appleupdates.kCFPreferencesCurrentUser,
|
|
appleupdates.kCFPreferencesCurrentHost).AndReturn(None)
|
|
appleupdates.CFPreferencesSetValue(
|
|
'AutomaticDownload', True,
|
|
appleupdates.APPLE_SOFTWARE_UPDATE_PREFS_DOMAIN,
|
|
appleupdates.kCFPreferencesCurrentUser,
|
|
appleupdates.kCFPreferencesCurrentHost).AndReturn(None)
|
|
appleupdates.CFPreferencesSetValue(
|
|
'LaunchAppInBackground', True,
|
|
appleupdates.APPLE_SOFTWARE_UPDATE_PREFS_DOMAIN,
|
|
appleupdates.kCFPreferencesCurrentUser,
|
|
appleupdates.kCFPreferencesCurrentHost).AndReturn(None)
|
|
appleupdates.CFPreferencesAppSynchronize(
|
|
appleupdates.APPLE_SOFTWARE_UPDATE_PREFS_DOMAIN).AndReturn(None)
|
|
appleupdates.munkicommon.display_error(
|
|
'Error setting com.apple.SoftwareUpdate ByHost preferences.')
|
|
|
|
self.mox.ReplayAll()
|
|
self.au._LeopardSetupSoftwareUpdateCheck()
|
|
self.mox.VerifyAll()
|
|
|
|
# TODO(ogle): _LeopardDownloadAvailableUpdates, _RunSoftwareUpdate, and
|
|
# InstallAppleUpdates tests are missing here.
|
|
|
|
def testAppleSoftwareUpdatesAvailableWhenCheckNeeded(self):
|
|
"""Tests AppleSoftwareUpdatesAvailable() when check needed."""
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'stopRequested')
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'pref')
|
|
self.mox.StubOutWithMock(self.au, 'CheckForSoftwareUpdates')
|
|
self.mox.StubOutWithMock(self.au, 'WriteAppleUpdatesFile')
|
|
#self.mox.StubOutWithMock(self.au, 'DisplayAppleUpdateInfo')
|
|
# Cannot stub out the builtin NSDate methods, so stub the entire module.
|
|
mock_nsdate_module = self.mox.CreateMockAnything()
|
|
self.mox.StubOutWithMock(appleupdates, 'NSDate', mock_nsdate_module)
|
|
mock_nsdate_new = self.mox.CreateMockAnything()
|
|
mock_nsdate_datewithstring = self.mox.CreateMockAnything()
|
|
mock_nsdate_module.new = mock_nsdate_new
|
|
mock_nsdate_module.dateWithString_ = mock_nsdate_datewithstring
|
|
|
|
now_nsdate = NSDate.dateWithString_('2011-08-22 18:00:00 -400')
|
|
appleupdates.NSDate.new().AndReturn(now_nsdate)
|
|
|
|
# use a date barely older than the 24 hour threshold.
|
|
recent_date_str = '2011-08-21 17:59:00 -0400'
|
|
recent_date_nsdate = NSDate.dateWithString_(recent_date_str)
|
|
appleupdates.munkicommon.pref('LastAppleSoftwareUpdateCheck').AndReturn(
|
|
recent_date_str)
|
|
appleupdates.NSDate.dateWithString_(recent_date_str).AndReturn(
|
|
recent_date_nsdate)
|
|
|
|
self.au.CheckForSoftwareUpdates(force_check=True).AndReturn(True)
|
|
appleupdates.munkicommon.stopRequested().AndReturn(False)
|
|
self.au.WriteAppleUpdatesFile().AndReturn(True)
|
|
#self.au.DisplayAppleUpdateInfo().AndReturn(None)
|
|
|
|
self.mox.ReplayAll()
|
|
out = self.au.AppleSoftwareUpdatesAvailable(
|
|
force_check=False, suppress_check=False)
|
|
self.assertTrue(out)
|
|
self.mox.VerifyAll()
|
|
|
|
def testAppleSoftwareUpdatesAvailableWhenRecentlyChecked(self):
|
|
"""Tests AppleSoftwareUpdatesAvailable() when recently check."""
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'stopRequested')
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'pref')
|
|
self.mox.StubOutWithMock(self.au, 'CheckForSoftwareUpdates')
|
|
self.mox.StubOutWithMock(self.au, 'WriteAppleUpdatesFile')
|
|
#self.mox.StubOutWithMock(self.au, 'DisplayAppleUpdateInfo')
|
|
# Cannot stub out the builtin NSDate methods, so stub the entire module.
|
|
mock_nsdate_module = self.mox.CreateMockAnything()
|
|
self.mox.StubOutWithMock(appleupdates, 'NSDate', mock_nsdate_module)
|
|
mock_nsdate_new = self.mox.CreateMockAnything()
|
|
mock_nsdate_datewithstring = self.mox.CreateMockAnything()
|
|
mock_nsdate_module.new = mock_nsdate_new
|
|
mock_nsdate_module.dateWithString_ = mock_nsdate_datewithstring
|
|
|
|
now_nsdate = NSDate.dateWithString_('2011-08-22 18:00:00 -400')
|
|
appleupdates.NSDate.new().AndReturn(now_nsdate)
|
|
|
|
# use a date barely newer than the 24 hour threshold.
|
|
recent_date_str = '2011-08-21 18:01:00 -0400'
|
|
recent_date_nsdate = NSDate.dateWithString_(recent_date_str)
|
|
appleupdates.munkicommon.pref('LastAppleSoftwareUpdateCheck').AndReturn(
|
|
recent_date_str)
|
|
appleupdates.NSDate.dateWithString_(recent_date_str).AndReturn(
|
|
recent_date_nsdate)
|
|
|
|
self.au.CheckForSoftwareUpdates(force_check=False).AndReturn(True)
|
|
appleupdates.munkicommon.stopRequested().AndReturn(False)
|
|
self.au.WriteAppleUpdatesFile().AndReturn(True)
|
|
#self.au.DisplayAppleUpdateInfo().AndReturn(None)
|
|
|
|
self.mox.ReplayAll()
|
|
out = self.au.AppleSoftwareUpdatesAvailable(
|
|
force_check=False, suppress_check=False)
|
|
self.assertTrue(out)
|
|
self.mox.VerifyAll()
|
|
|
|
def testAppleSoftwareUpdatesAvailableWhenNsDateValueError(self):
|
|
"""Tests AppleSoftwareUpdatesAvailable() when ValueError is raised."""
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'stopRequested')
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'pref')
|
|
self.mox.StubOutWithMock(self.au, 'CheckForSoftwareUpdates')
|
|
self.mox.StubOutWithMock(self.au, 'WriteAppleUpdatesFile')
|
|
#self.mox.StubOutWithMock(self.au, 'DisplayAppleUpdateInfo')
|
|
|
|
# use a date string that will not parse correctly.
|
|
appleupdates.munkicommon.pref('LastAppleSoftwareUpdateCheck').AndReturn(
|
|
'zomg this is not a date!!!!!')
|
|
|
|
self.au.CheckForSoftwareUpdates(force_check=True).AndReturn(True)
|
|
appleupdates.munkicommon.stopRequested().AndReturn(False)
|
|
self.au.WriteAppleUpdatesFile().AndReturn(True)
|
|
#self.au.DisplayAppleUpdateInfo().AndReturn(None)
|
|
|
|
self.mox.ReplayAll()
|
|
out = self.au.AppleSoftwareUpdatesAvailable(
|
|
force_check=False, suppress_check=False)
|
|
self.assertTrue(out)
|
|
self.mox.VerifyAll()
|
|
|
|
def testAppleSoftwareUpdatesAvailableForceCheck(self):
|
|
"""Tests AppleSoftwareUpdatesAvailable() with force_check=True."""
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'stopRequested')
|
|
self.mox.StubOutWithMock(self.au, 'CheckForSoftwareUpdates')
|
|
self.mox.StubOutWithMock(self.au, 'WriteAppleUpdatesFile')
|
|
#self.mox.StubOutWithMock(self.au, 'DisplayAppleUpdateInfo')
|
|
|
|
self.au.CheckForSoftwareUpdates(force_check=True).AndReturn(True)
|
|
appleupdates.munkicommon.stopRequested().AndReturn(False)
|
|
self.au.WriteAppleUpdatesFile().AndReturn(True)
|
|
#self.au.DisplayAppleUpdateInfo().AndReturn(None)
|
|
|
|
self.mox.ReplayAll()
|
|
out = self.au.AppleSoftwareUpdatesAvailable(
|
|
force_check=True, suppress_check=False)
|
|
self.assertTrue(out)
|
|
self.mox.VerifyAll()
|
|
|
|
def testAppleSoftwareUpdatesAvailableSuppressCheck(self):
|
|
"""Tests AppleSoftwareUpdatesAvailable() with suppress_check=True."""
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'stopRequested')
|
|
self.mox.StubOutWithMock(self.au, 'WriteAppleUpdatesFile')
|
|
#self.mox.StubOutWithMock(self.au, 'DisplayAppleUpdateInfo')
|
|
|
|
appleupdates.munkicommon.stopRequested().AndReturn(False)
|
|
self.au.WriteAppleUpdatesFile().AndReturn(True)
|
|
#self.au.DisplayAppleUpdateInfo().AndReturn(None)
|
|
|
|
self.mox.ReplayAll()
|
|
out = self.au.AppleSoftwareUpdatesAvailable(
|
|
force_check=False, suppress_check=True)
|
|
self.assertTrue(out)
|
|
self.mox.VerifyAll()
|
|
|
|
def testAppleSoftwareUpdatesAvailableSuppressCheckNoneAvailable(self):
|
|
"""Tests AppleSoftwareUpdatesAvailable() when no updates available."""
|
|
self.mox.StubOutWithMock(appleupdates.munkicommon, 'stopRequested')
|
|
self.mox.StubOutWithMock(self.au, 'WriteAppleUpdatesFile')
|
|
#self.mox.StubOutWithMock(self.au, 'DisplayAppleUpdateInfo')
|
|
|
|
appleupdates.munkicommon.stopRequested().AndReturn(False)
|
|
self.au.WriteAppleUpdatesFile().AndReturn(False)
|
|
|
|
self.mox.ReplayAll()
|
|
out = self.au.AppleSoftwareUpdatesAvailable(
|
|
force_check=False, suppress_check=True)
|
|
self.assertFalse(out)
|
|
self.mox.VerifyAll()
|
|
|
|
def testSoftwareUpdateListCached(self):
|
|
"""Tests SoftwareUpdateList() when update list is cached."""
|
|
self.au._update_list_cache = 'not none'
|
|
|
|
output = self.au.SoftwareUpdateList()
|
|
self.assertEqual(output, self.au._update_list_cache)
|
|
|
|
def testSoftwareUpdateList(self):
|
|
"""Tests SoftwareUpdateList() success."""
|
|
self._MockMunkiDisplay()
|
|
self.mox.StubOutWithMock(appleupdates.subprocess, 'Popen')
|
|
|
|
process_output = (
|
|
' * Foo Package 1\n'
|
|
' * Bar Update 2\n'
|
|
' ignore more, because I do not start with " * "\n'
|
|
' * Zoo Install 3\n'
|
|
' * Security Patch!\n'
|
|
)
|
|
expected_output = [
|
|
'Foo Package 1', 'Bar Update 2', 'Zoo Install 3', 'Security Patch!'
|
|
]
|
|
|
|
appleupdates.munkicommon.display_detail(
|
|
'Getting list of available Apple Software Updates')
|
|
mock_process = self.mox.CreateMockAnything()
|
|
appleupdates.subprocess.Popen(
|
|
['/usr/sbin/softwareupdate', '-l'], shell=False, bufsize=-1,
|
|
stdin=appleupdates.subprocess.PIPE,
|
|
stdout=appleupdates.subprocess.PIPE,
|
|
stderr=appleupdates.subprocess.PIPE).AndReturn(mock_process)
|
|
mock_process.communicate().AndReturn((process_output, 'unused'))
|
|
mock_process.returncode = 0
|
|
appleupdates.munkicommon.display_detail(
|
|
'softwareupdate returned %d updates.', 4)
|
|
|
|
self.mox.ReplayAll()
|
|
output = self.au.SoftwareUpdateList()
|
|
self.assertTrue(self.au._update_list_cache is not None)
|
|
self.assertEqual(output, expected_output)
|
|
self.mox.VerifyAll()
|
|
|
|
|
|
|
|
class TestAppleUpdatesModule(mox.MoxTestBase):
|
|
"""Test appleupdates module."""
|
|
|
|
def setUp(self):
|
|
mox.MoxTestBase.setUp(self)
|
|
self.stubs = stubout.StubOutForTesting()
|
|
|
|
def tearDown(self):
|
|
self.mox.UnsetStubs()
|
|
self.stubs.UnsetAll()
|
|
|
|
def testGlobals(self):
|
|
"""Test global variables."""
|
|
self.assertTrue(
|
|
type(getattr(appleupdates, 'DEFAULT_CATALOG_URLS', None)) is dict)
|
|
|
|
|
|
def main():
|
|
unittest.main()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|