520 lines
20 KiB
Python
520 lines
20 KiB
Python
#!/usr/bin/env python
|
|
#
|
|
# Copyright 2018 The Android Open Source Project
|
|
#
|
|
# 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.
|
|
"""Unit tests for at_auth_unlock."""
|
|
|
|
import argparse
|
|
import filecmp
|
|
import os
|
|
import shutil
|
|
import subprocess
|
|
import unittest
|
|
|
|
from at_auth_unlock import *
|
|
from Crypto.PublicKey import RSA
|
|
from unittest.mock import patch
|
|
|
|
|
|
def dataPath(file):
|
|
return os.path.join(os.path.dirname(__file__), 'data', file)
|
|
|
|
|
|
DATA_FILE_PIK_CERTIFICATE = dataPath('atx_pik_certificate.bin')
|
|
DATA_FILE_PUK_CERTIFICATE = dataPath('atx_puk_certificate.bin')
|
|
DATA_FILE_PUK_KEY = dataPath('testkey_atx_puk.pem')
|
|
DATA_FILE_UNLOCK_CHALLENGE = dataPath('atx_unlock_challenge.bin')
|
|
DATA_FILE_UNLOCK_CREDENTIAL = dataPath('atx_unlock_credential.bin')
|
|
|
|
|
|
def createTempZip(contents):
|
|
tempzip = tempfile.NamedTemporaryFile()
|
|
with zipfile.ZipFile(tempzip, 'w') as zip:
|
|
for arcname in contents:
|
|
zip.write(contents[arcname], arcname)
|
|
return tempzip
|
|
|
|
|
|
def validUnlockCredsZip():
|
|
return createTempZip({
|
|
'pik_certificate_v1.bin': DATA_FILE_PIK_CERTIFICATE,
|
|
'puk_certificate_v1.bin': DATA_FILE_PUK_CERTIFICATE,
|
|
'puk_v1.pem': DATA_FILE_PUK_KEY
|
|
})
|
|
|
|
|
|
class UnlockCredentialsTest(unittest.TestCase):
|
|
|
|
def testFromValidZipArchive(self):
|
|
with validUnlockCredsZip() as zip:
|
|
creds = UnlockCredentials.from_credential_archive(zip)
|
|
self.assertIsNotNone(creds.intermediate_cert)
|
|
self.assertIsNotNone(creds.unlock_cert)
|
|
self.assertIsNotNone(creds.unlock_key)
|
|
|
|
def testFromInvalidZipArchive(self):
|
|
with self.assertRaises(zipfile.BadZipfile):
|
|
UnlockCredentials.from_credential_archive(DATA_FILE_PUK_KEY)
|
|
|
|
def testFromArchiveMissingPikCertificate(self):
|
|
with createTempZip({
|
|
'puk_certificate_v1.bin': DATA_FILE_PUK_CERTIFICATE,
|
|
'puk_v1.pem': DATA_FILE_PUK_KEY
|
|
}) as zip:
|
|
with self.assertRaises(ValueError):
|
|
UnlockCredentials.from_credential_archive(zip)
|
|
|
|
def testFromArchiveMissingPukCertificate(self):
|
|
with createTempZip({
|
|
'pik_certificate_v1.bin': DATA_FILE_PIK_CERTIFICATE,
|
|
'puk_v1.pem': DATA_FILE_PUK_KEY
|
|
}) as zip:
|
|
with self.assertRaises(ValueError):
|
|
UnlockCredentials.from_credential_archive(zip)
|
|
|
|
def testFromArchiveMissingPuk(self):
|
|
with createTempZip({
|
|
'pik_certificate_v1.bin': DATA_FILE_PIK_CERTIFICATE,
|
|
'puk_certificate_v1.bin': DATA_FILE_PUK_CERTIFICATE,
|
|
}) as zip:
|
|
with self.assertRaises(ValueError):
|
|
UnlockCredentials.from_credential_archive(zip)
|
|
|
|
def testFromArchiveMultiplePikCertificates(self):
|
|
with createTempZip({
|
|
'pik_certificate_v1.bin': DATA_FILE_PIK_CERTIFICATE,
|
|
'pik_certificate_v2.bin': DATA_FILE_PIK_CERTIFICATE,
|
|
'puk_certificate_v1.bin': DATA_FILE_PUK_CERTIFICATE,
|
|
'puk_v1.pem': DATA_FILE_PUK_KEY
|
|
}) as zip:
|
|
with self.assertRaises(ValueError):
|
|
UnlockCredentials.from_credential_archive(zip)
|
|
|
|
def testFromArchiveMultiplePukCertificates(self):
|
|
with createTempZip({
|
|
'pik_certificate_v1.bin': DATA_FILE_PIK_CERTIFICATE,
|
|
'puk_certificate_v1.bin': DATA_FILE_PUK_CERTIFICATE,
|
|
'puk_certificate_v2.bin': DATA_FILE_PUK_CERTIFICATE,
|
|
'puk_v1.pem': DATA_FILE_PUK_KEY
|
|
}) as zip:
|
|
with self.assertRaises(ValueError):
|
|
UnlockCredentials.from_credential_archive(zip)
|
|
|
|
def testFromArchiveMultiplePuks(self):
|
|
with createTempZip({
|
|
'pik_certificate_v1.bin': DATA_FILE_PIK_CERTIFICATE,
|
|
'puk_certificate_v1.bin': DATA_FILE_PUK_CERTIFICATE,
|
|
'puk_v1.pem': DATA_FILE_PUK_KEY,
|
|
'puk_v2.pem': DATA_FILE_PUK_KEY
|
|
}) as zip:
|
|
with self.assertRaises(ValueError):
|
|
UnlockCredentials.from_credential_archive(zip)
|
|
|
|
def testFromFiles(self):
|
|
creds = UnlockCredentials(
|
|
intermediate_cert_file=DATA_FILE_PIK_CERTIFICATE,
|
|
unlock_cert_file=DATA_FILE_PUK_CERTIFICATE,
|
|
unlock_key_file=DATA_FILE_PUK_KEY)
|
|
self.assertIsNotNone(creds.intermediate_cert)
|
|
self.assertIsNotNone(creds.unlock_cert)
|
|
self.assertIsNotNone(creds.unlock_key)
|
|
|
|
def testInvalidPuk(self):
|
|
with self.assertRaises(ValueError):
|
|
UnlockCredentials(
|
|
intermediate_cert_file=DATA_FILE_PIK_CERTIFICATE,
|
|
unlock_cert_file=DATA_FILE_PUK_CERTIFICATE,
|
|
unlock_key_file=DATA_FILE_PUK_CERTIFICATE)
|
|
|
|
def testPukNotPrivateKey(self):
|
|
tempdir = tempfile.mkdtemp()
|
|
try:
|
|
with open(DATA_FILE_PUK_KEY, 'rb') as f:
|
|
key = RSA.importKey(f.read())
|
|
pubkey = os.path.join(tempdir, 'pubkey.pub')
|
|
with open(pubkey, 'wb') as f:
|
|
f.write(key.publickey().exportKey())
|
|
with self.assertRaises(ValueError):
|
|
UnlockCredentials(
|
|
intermediate_cert_file=DATA_FILE_PIK_CERTIFICATE,
|
|
unlock_cert_file=DATA_FILE_PUK_CERTIFICATE,
|
|
unlock_key_file=pubkey)
|
|
finally:
|
|
shutil.rmtree(tempdir)
|
|
|
|
def testWrongSizeCerts(self):
|
|
pik_cert = DATA_FILE_PIK_CERTIFICATE
|
|
tempdir = tempfile.mkdtemp()
|
|
try:
|
|
# Copy a valid cert and truncate a single byte from the end to create a
|
|
# too-short cert.
|
|
shortfile = os.path.join(tempdir, 'shortfile.bin')
|
|
shutil.copy2(pik_cert, shortfile)
|
|
with open(shortfile, 'ab') as f:
|
|
f.seek(-1, os.SEEK_END)
|
|
f.truncate()
|
|
with self.assertRaises(ValueError):
|
|
creds = UnlockCredentials(
|
|
intermediate_cert_file=shortfile,
|
|
unlock_cert_file=DATA_FILE_PUK_CERTIFICATE,
|
|
unlock_key_file=DATA_FILE_PUK_KEY)
|
|
with self.assertRaises(ValueError):
|
|
creds = UnlockCredentials(
|
|
intermediate_cert_file=DATA_FILE_PIK_CERTIFICATE,
|
|
unlock_cert_file=shortfile,
|
|
unlock_key_file=DATA_FILE_PUK_KEY)
|
|
|
|
# Copy a valid cert and append an arbitrary byte on the end to create a
|
|
# too-long cert.
|
|
longfile = os.path.join(tempdir, 'longfile.bin')
|
|
shutil.copy2(pik_cert, longfile)
|
|
with open(longfile, 'ab') as f:
|
|
f.write(b'\0')
|
|
with self.assertRaises(ValueError):
|
|
creds = UnlockCredentials(
|
|
intermediate_cert_file=longfile,
|
|
unlock_cert_file=DATA_FILE_PUK_CERTIFICATE,
|
|
unlock_key_file=DATA_FILE_PUK_KEY)
|
|
with self.assertRaises(ValueError):
|
|
creds = UnlockCredentials(
|
|
intermediate_cert_file=DATA_FILE_PIK_CERTIFICATE,
|
|
unlock_cert_file=longfile,
|
|
unlock_key_file=DATA_FILE_PUK_KEY)
|
|
finally:
|
|
shutil.rmtree(tempdir)
|
|
|
|
|
|
def writeFullUnlockChallenge(out_file, product_id_hash=None):
|
|
"""Helper function to create a file with a full AvbAtxUnlockChallenge struct.
|
|
|
|
Arguments:
|
|
product_id_hash: [optional] 32 byte value to include in the challenge as the
|
|
SHA256 hash of the product ID. If not provided, will default to the
|
|
product ID hash from the subject of DATA_FILE_PUK_CERTIFICATE.
|
|
"""
|
|
if product_id_hash is None:
|
|
with open(DATA_FILE_PUK_CERTIFICATE, 'rb') as f:
|
|
product_id_hash = GetAtxCertificateSubject(f.read())
|
|
assert len(product_id_hash) == 32
|
|
|
|
with open(out_file, 'wb') as out:
|
|
out.write(struct.pack('<I', 1))
|
|
out.write(product_id_hash)
|
|
with open(DATA_FILE_UNLOCK_CHALLENGE, 'rb') as f:
|
|
out.write(f.read())
|
|
|
|
|
|
class MakeAtxUnlockCredentialTest(unittest.TestCase):
|
|
|
|
def testCredentialIsCorrect(self):
|
|
with validUnlockCredsZip() as zip:
|
|
creds = UnlockCredentials.from_credential_archive(zip)
|
|
|
|
tempdir = tempfile.mkdtemp()
|
|
try:
|
|
challenge_file = os.path.join(tempdir, 'challenge')
|
|
writeFullUnlockChallenge(challenge_file)
|
|
challenge = UnlockChallenge(challenge_file)
|
|
out_cred = os.path.join(tempdir, 'credential')
|
|
|
|
# Compare unlock credential generated by function with one generated
|
|
# using 'avbtool make_atx_unlock_credential', to check correctness.
|
|
MakeAtxUnlockCredential(creds, challenge, out_cred)
|
|
self.assertTrue(filecmp.cmp(out_cred, DATA_FILE_UNLOCK_CREDENTIAL))
|
|
finally:
|
|
shutil.rmtree(tempdir)
|
|
|
|
def testWrongChallengeSize(self):
|
|
with validUnlockCredsZip() as zip:
|
|
creds = UnlockCredentials.from_credential_archive(zip)
|
|
|
|
tempdir = tempfile.mkdtemp()
|
|
try:
|
|
out_cred = os.path.join(tempdir, 'credential')
|
|
|
|
# The bundled unlock challenge is just the 16 byte challenge, not the
|
|
# full AvbAtxUnlockChallenge like this expects.
|
|
with self.assertRaises(ValueError):
|
|
challenge = UnlockChallenge(DATA_FILE_UNLOCK_CHALLENGE)
|
|
MakeAtxUnlockCredential(creds, challenge, out_cred)
|
|
finally:
|
|
shutil.rmtree(tempdir)
|
|
|
|
|
|
def makeFastbootCommandFake(testcase,
|
|
expect_serial=None,
|
|
error_on_command_number=None,
|
|
product_id_hash=None,
|
|
stay_locked=False):
|
|
"""Construct a fake fastboot command handler, to be used with unitttest.mock.Mock.side_effect.
|
|
|
|
This can be used to create a callable that acts as a fake for a real device
|
|
responding to the fastboot commands involved in an authenticated unlock. The
|
|
returned callback is intended to be used with unittest.mock.Mock.side_effect.
|
|
There are a number of optional arguments here that can be used to customize
|
|
the behavior of the fake for a specific test.
|
|
|
|
Arguments:
|
|
testcase: unittest.TestCase object for the associated test
|
|
expect_serial: [optional] Expect (and assert) that the fastboot command
|
|
specifies a specific device serial to communicate with.
|
|
error_on_command_number: [optional] Return a fastboot error (non-zero exit
|
|
code) on the nth (0-based) command handled.
|
|
stay_locked: [optional] Make the fake report that the device is still locked
|
|
after an otherwise successful unlock attempt.
|
|
"""
|
|
|
|
def handler(args, *extraArgs, **kwargs):
|
|
if error_on_command_number is not None:
|
|
handler.command_counter += 1
|
|
if handler.command_counter - 1 == error_on_command_number:
|
|
raise subprocess.CalledProcessError(
|
|
returncode=1, cmd=args, output=b'Fake: ERROR')
|
|
|
|
testcase.assertEqual(args.pop(0), 'fastboot')
|
|
if expect_serial is not None:
|
|
# This is a bit fragile in that, in reality, fastboot allows '-s SERIAL'
|
|
# to not just be the first arguments, but it works for this use case.
|
|
testcase.assertEqual(args.pop(0), '-s')
|
|
testcase.assertEqual(args.pop(0), expect_serial)
|
|
|
|
if args[0:2] == ['oem', 'at-get-vboot-unlock-challenge']:
|
|
handler.challenge_staged = True
|
|
elif args[0] == 'get_staged':
|
|
if not handler.challenge_staged:
|
|
raise subprocess.CalledProcessError(
|
|
returncode=1, cmd=args, output=b'Fake: No data staged')
|
|
|
|
writeFullUnlockChallenge(args[1], product_id_hash=product_id_hash)
|
|
handler.challenge_staged = False
|
|
elif args[0] == 'stage':
|
|
handler.staged_file = args[1]
|
|
elif args[0:2] == ['oem', 'at-unlock-vboot']:
|
|
if handler.staged_file is None:
|
|
raise subprocess.CalledProcessError(
|
|
returncode=1, cmd=args, output=b'Fake: No unlock credential staged')
|
|
|
|
# Validate the unlock credential as if this were a test key locked device,
|
|
# which implies tests that want a successful unlock need to be set up to
|
|
# use DATA_FILE_PUK_KEY to sign the challenge. Credentials generated using
|
|
# other keys will be properly rejected.
|
|
if not filecmp.cmp(handler.staged_file, DATA_FILE_UNLOCK_CREDENTIAL):
|
|
raise subprocess.CalledProcessError(
|
|
returncode=1, cmd=args, output=b'Fake: Incorrect unlock credential')
|
|
|
|
handler.locked = True if stay_locked else False
|
|
elif args[0:2] == ['getvar', 'at-vboot-state']:
|
|
return b'avb-locked: ' + (b'1' if handler.locked else b'0')
|
|
return b'Fake: OK'
|
|
|
|
handler.command_counter = 0
|
|
handler.challenge_staged = False
|
|
handler.staged_file = None
|
|
handler.locked = True
|
|
return handler
|
|
|
|
|
|
class AuthenticatedUnlockTest(unittest.TestCase):
|
|
|
|
@patch('subprocess.check_output')
|
|
def testUnlockWithZipArchive(self, mock_subp_check_output):
|
|
with validUnlockCredsZip() as zip:
|
|
mock_subp_check_output.side_effect = makeFastbootCommandFake(self)
|
|
self.assertEqual(main([zip.name]), 0)
|
|
self.assertNotEqual(mock_subp_check_output.call_count, 0)
|
|
|
|
@patch('subprocess.check_output')
|
|
def testUnlockDeviceBySerial(self, mock_subp_check_output):
|
|
with validUnlockCredsZip() as zip:
|
|
SERIAL = 'abcde12345'
|
|
mock_subp_check_output.side_effect = makeFastbootCommandFake(
|
|
self, expect_serial=SERIAL)
|
|
self.assertEqual(main([zip.name, '-s', SERIAL]), 0)
|
|
self.assertNotEqual(mock_subp_check_output.call_count, 0)
|
|
|
|
@patch('subprocess.check_output')
|
|
def testUnlockWithIndividualFiles(self, mock_subp_check_output):
|
|
mock_subp_check_output.side_effect = makeFastbootCommandFake(self)
|
|
self.assertEqual(
|
|
main([
|
|
'--pik_cert', DATA_FILE_PIK_CERTIFICATE, '--puk_cert',
|
|
DATA_FILE_PUK_CERTIFICATE, '--puk', DATA_FILE_PUK_KEY
|
|
]), 0)
|
|
self.assertNotEqual(mock_subp_check_output.call_count, 0)
|
|
|
|
@patch('subprocess.check_output')
|
|
def testFastbootError(self, mock_subp_check_output):
|
|
"""Verify that errors are handled properly if fastboot commands error out."""
|
|
with validUnlockCredsZip() as zip:
|
|
for n in range(5):
|
|
mock_subp_check_output.reset_mock()
|
|
mock_subp_check_output.side_effect = makeFastbootCommandFake(
|
|
self, error_on_command_number=n)
|
|
self.assertNotEqual(main([zip.name]), 0)
|
|
self.assertNotEqual(mock_subp_check_output.call_count, 0)
|
|
|
|
@patch('subprocess.check_output')
|
|
def testDoesntActuallyUnlock(self, mock_subp_check_output):
|
|
"""Verify fails if fake set to not actually unlock."""
|
|
with validUnlockCredsZip() as zip:
|
|
mock_subp_check_output.side_effect = makeFastbootCommandFake(
|
|
self, stay_locked=True)
|
|
self.assertNotEqual(main([zip.name]), 0)
|
|
self.assertNotEqual(mock_subp_check_output.call_count, 0)
|
|
|
|
@patch('subprocess.check_output')
|
|
def testNoCredentialsMatchDeviceProductID(self, mock_subp_check_output):
|
|
"""Test two cases where fake responds with a challenge that has a product ID hash which doesn't match the credentials used."""
|
|
# Case 1: Change the product ID hash that the fake responds with.
|
|
with validUnlockCredsZip() as zip:
|
|
mock_subp_check_output.side_effect = makeFastbootCommandFake(
|
|
self, product_id_hash=b'\x00' * 32)
|
|
self.assertNotEqual(main([zip.name]), 0)
|
|
self.assertNotEqual(mock_subp_check_output.call_count, 0)
|
|
|
|
# Case 2: Use credentials with a different product ID.
|
|
with createTempZip({
|
|
'pik_certificate_v1.bin': DATA_FILE_PIK_CERTIFICATE,
|
|
# Note: PIK cert used as PUK cert so subject (i.e. product ID hash) is
|
|
# different
|
|
'puk_certificate_v1.bin': DATA_FILE_PIK_CERTIFICATE,
|
|
'puk_v1.pem': DATA_FILE_PUK_KEY
|
|
}) as zip:
|
|
mock_subp_check_output.side_effect = makeFastbootCommandFake(self)
|
|
self.assertNotEqual(main([zip.name]), 0)
|
|
self.assertNotEqual(mock_subp_check_output.call_count, 0)
|
|
|
|
@patch('subprocess.check_output')
|
|
def testMatchingCredentialSelectedFromZipArchives(self,
|
|
mock_subp_check_output):
|
|
"""Test correct credential based on product ID hash used if multiple provided directly through arguments."""
|
|
with validUnlockCredsZip() as correctCreds, createTempZip({
|
|
'pik_certificate_v1.bin': DATA_FILE_PIK_CERTIFICATE,
|
|
# Note: PIK cert used as PUK cert so subject (i.e. product ID hash)
|
|
# doesn't match
|
|
'puk_certificate_v1.bin': DATA_FILE_PIK_CERTIFICATE,
|
|
'puk_v1.pem': DATA_FILE_PUK_KEY
|
|
}) as wrongCreds:
|
|
mock_subp_check_output.side_effect = makeFastbootCommandFake(self)
|
|
self.assertEqual(main([wrongCreds.name, correctCreds.name]), 0)
|
|
self.assertNotEqual(mock_subp_check_output.call_count, 0)
|
|
|
|
@patch('subprocess.check_output')
|
|
def testMatchingCredentialSelectedFromDirectory(self, mock_subp_check_output):
|
|
"""Test correct credential based on product ID hash used if multiple provided indirectly through a directory argument."""
|
|
with validUnlockCredsZip() as correctCreds, createTempZip({
|
|
'pik_certificate_v1.bin': DATA_FILE_PIK_CERTIFICATE,
|
|
# Note: PIK cert used as PUK cert so subject (i.e. product ID hash)
|
|
# doesn't match
|
|
'puk_certificate_v1.bin': DATA_FILE_PIK_CERTIFICATE,
|
|
'puk_v1.pem': DATA_FILE_PUK_KEY
|
|
}) as wrongCreds:
|
|
tempdir = tempfile.mkdtemp()
|
|
try:
|
|
shutil.copy2(correctCreds.name, tempdir)
|
|
shutil.copy2(wrongCreds.name, tempdir)
|
|
|
|
mock_subp_check_output.side_effect = makeFastbootCommandFake(self)
|
|
self.assertEqual(main([tempdir]), 0)
|
|
self.assertNotEqual(mock_subp_check_output.call_count, 0)
|
|
finally:
|
|
shutil.rmtree(tempdir)
|
|
|
|
@patch('subprocess.check_output')
|
|
def testMatchingCredentialSelectedFromEither(self, mock_subp_check_output):
|
|
"""Test correct credential based on product ID hash used if arguments give some combination of file and directory arguments."""
|
|
with validUnlockCredsZip() as correctCreds, createTempZip({
|
|
'pik_certificate_v1.bin': DATA_FILE_PIK_CERTIFICATE,
|
|
# Note: PIK cert used as PUK cert so subject (i.e. product ID hash)
|
|
# doesn't match
|
|
'puk_certificate_v1.bin': DATA_FILE_PIK_CERTIFICATE,
|
|
'puk_v1.pem': DATA_FILE_PUK_KEY
|
|
}) as wrongCreds:
|
|
# Case 1: Correct creds in directory, wrong in file arg
|
|
tempdir = tempfile.mkdtemp()
|
|
try:
|
|
shutil.copy2(correctCreds.name, tempdir)
|
|
|
|
mock_subp_check_output.side_effect = makeFastbootCommandFake(self)
|
|
self.assertEqual(main([wrongCreds.name, tempdir]), 0)
|
|
self.assertNotEqual(mock_subp_check_output.call_count, 0)
|
|
|
|
finally:
|
|
shutil.rmtree(tempdir)
|
|
|
|
# Case 2: Correct creds in file arg, wrong in directory
|
|
tempdir = tempfile.mkdtemp()
|
|
try:
|
|
shutil.copy2(wrongCreds.name, tempdir)
|
|
|
|
mock_subp_check_output.side_effect = makeFastbootCommandFake(self)
|
|
self.assertEqual(main([tempdir, correctCreds.name]), 0)
|
|
self.assertNotEqual(mock_subp_check_output.call_count, 0)
|
|
|
|
# Case 2: Correct creds in file arg, wrong in directory
|
|
finally:
|
|
shutil.rmtree(tempdir)
|
|
|
|
@patch('argparse.ArgumentParser.error')
|
|
def testArgparseDirectoryWithNoCredentials(self, mock_parser_error):
|
|
"""Test """
|
|
tempdir = tempfile.mkdtemp()
|
|
try:
|
|
# Make sure random files are ignored.
|
|
with open(os.path.join(tempdir, 'so_random'), 'w') as f:
|
|
f.write("I'm a random file")
|
|
|
|
mock_parser_error.side_effect = ValueError('ArgumentParser.error')
|
|
with self.assertRaises(ValueError):
|
|
main([tempdir])
|
|
self.assertEqual(mock_parser_error.call_count, 1)
|
|
finally:
|
|
shutil.rmtree(tempdir)
|
|
|
|
@patch('argparse.ArgumentParser.error')
|
|
def testArgparseMutualExclusionArchiveAndFiles(self, mock_parser_error):
|
|
mock_parser_error.side_effect = ValueError('ArgumentParser.error')
|
|
with self.assertRaises(ValueError):
|
|
main(['dummy.zip', '--pik_cert', DATA_FILE_PIK_CERTIFICATE])
|
|
self.assertEqual(mock_parser_error.call_count, 1)
|
|
|
|
@patch('argparse.ArgumentParser.error')
|
|
def testArgparseMutualInclusionOfFileArgs(self, mock_parser_error):
|
|
mock_parser_error.side_effect = ValueError('ArgumentParser.error')
|
|
with self.assertRaises(ValueError):
|
|
main(['--pik_cert', 'pik_cert.bin', '--puk_cert', 'puk_cert.bin'])
|
|
self.assertEqual(mock_parser_error.call_count, 1)
|
|
|
|
mock_parser_error.reset_mock()
|
|
with self.assertRaises(ValueError):
|
|
main(['--pik_cert', 'pik_cert.bin', '--puk', 'puk.pem'])
|
|
self.assertEqual(mock_parser_error.call_count, 1)
|
|
|
|
mock_parser_error.reset_mock()
|
|
with self.assertRaises(ValueError):
|
|
main(['--puk_cert', 'puk_cert.bin', '--puk', 'puk.pem'])
|
|
self.assertEqual(mock_parser_error.call_count, 1)
|
|
|
|
@patch('argparse.ArgumentParser.error')
|
|
def testArgparseMissingBundleAndFiles(self, mock_parser_error):
|
|
mock_parser_error.side_effect = ValueError('ArgumentParser.error')
|
|
with self.assertRaises(ValueError):
|
|
main(['-s', '1234abcd'])
|
|
self.assertEqual(mock_parser_error.call_count, 1)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main(verbosity=3)
|