|
12 | 12 | import sys |
13 | 13 | import sysconfig |
14 | 14 | import platform |
| 15 | +import ssl |
15 | 16 | import zipfile |
16 | 17 |
|
17 | 18 | try: |
@@ -1619,3 +1620,60 @@ def test_install_npm_win_zip_extraction(self): |
1619 | 1620 |
|
1620 | 1621 | # Verify extraction |
1621 | 1622 | mock_zip.extractall.assert_called_once_with(src_dir) |
| 1623 | + |
| 1624 | + |
| 1625 | +class TestCertifi: |
| 1626 | + """Tests for the --with-certifi option""" |
| 1627 | + |
| 1628 | + def test_urlopen_without_certifi(self): |
| 1629 | + """No SSL context is passed when certifi is not in use""" |
| 1630 | + with mock.patch.object(nodeenv, 'ignore_ssl_certs', False), \ |
| 1631 | + mock.patch.object(nodeenv, 'certifi_context', None), \ |
| 1632 | + mock.patch.object(nodeenv.urllib2, 'urlopen') as m_urlopen: |
| 1633 | + nodeenv.urlopen('https://nodejs.org/dist/index.json') |
| 1634 | + |
| 1635 | + assert m_urlopen.call_args[1] == {} |
| 1636 | + |
| 1637 | + def test_urlopen_with_certifi(self): |
| 1638 | + """The context built by main() is reused for every download""" |
| 1639 | + with mock.patch.object(nodeenv, 'ignore_ssl_certs', False), \ |
| 1640 | + mock.patch.object(nodeenv, 'certifi_context', |
| 1641 | + mock.sentinel.certifi_context), \ |
| 1642 | + mock.patch.object(nodeenv.urllib2, 'urlopen') as m_urlopen: |
| 1643 | + nodeenv.urlopen('https://nodejs.org/dist/index.json') |
| 1644 | + |
| 1645 | + context = m_urlopen.call_args[1]['context'] |
| 1646 | + assert context is mock.sentinel.certifi_context |
| 1647 | + |
| 1648 | + def test_urlopen_ignore_ssl_certs_wins(self): |
| 1649 | + """--ignore_ssl_certs takes precedence over --with-certifi""" |
| 1650 | + with mock.patch.object(nodeenv, 'ignore_ssl_certs', True), \ |
| 1651 | + mock.patch.object(nodeenv, 'certifi_context', |
| 1652 | + mock.sentinel.certifi_context), \ |
| 1653 | + mock.patch.object(nodeenv.urllib2, 'urlopen') as m_urlopen: |
| 1654 | + nodeenv.urlopen('https://nodejs.org/dist/index.json') |
| 1655 | + |
| 1656 | + assert m_urlopen.call_args[1]['context'].verify_mode == ssl.CERT_NONE |
| 1657 | + |
| 1658 | + def test_make_certifi_context(self): |
| 1659 | + certifi = mock.Mock() |
| 1660 | + certifi.where.return_value = '/path/to/cacert.pem' |
| 1661 | + |
| 1662 | + with mock.patch.dict(sys.modules, {'certifi': certifi}), \ |
| 1663 | + mock.patch.object(nodeenv.ssl, |
| 1664 | + 'create_default_context') as m_context: |
| 1665 | + assert nodeenv.make_certifi_context() is m_context.return_value |
| 1666 | + |
| 1667 | + m_context.assert_called_once_with(cafile='/path/to/cacert.pem') |
| 1668 | + |
| 1669 | + def test_make_certifi_context_without_certifi(self): |
| 1670 | + """A missing certifi is reported instead of silently ignored""" |
| 1671 | + with mock.patch.dict(sys.modules, {'certifi': None}), \ |
| 1672 | + mock.patch.object(nodeenv.logger, 'warning') as m_warning: |
| 1673 | + assert nodeenv.make_certifi_context() is None |
| 1674 | + |
| 1675 | + assert 'certifi is not installed' in m_warning.call_args[0][0] |
| 1676 | + |
| 1677 | + def test_with_certifi_is_configurable(self): |
| 1678 | + """with_certifi can be set from the config file, like other options""" |
| 1679 | + assert 'with_certifi' in nodeenv.Config._default |
0 commit comments