dbryant4/furtive

View on GitHub
tests/test_cli.py

Summary

Maintainability
C
1 day
Test Coverage
""" Test cases for furtive script """
from future import standard_library
standard_library.install_aliases()

import os
import six
import sys
import imp
import yaml
import argparse
import unittest

if six.PY2:
    from io import BytesIO as StringIO
    from mock import MagicMock, patch
elif six.PY3:
    from io import StringIO
    from unittest.mock import MagicMock, patch

from furtive import cli

class TestScriptFurtive(unittest.TestCase):
    """ Test cases for furtive script which is the cli "binary" """

    def setUp(self):
        """ Common setup tasks for all tests in this test case """

        if os.path.exists('.test_manifest.yaml'):
            os.unlink('.test_manifest.yaml')
        if os.path.exists('tests/fixtures/test-data/test-file'):
            os.unlink('tests/fixtures/test-data/test-file')
        if os.path.exists('tests/fixtures/report.yml'):
            os.unlink('tests/fixtures/report.yml')

    def test_parse_args(self):
        """ Ensure parsing of proper arguments """

        args = '--basedir tests/fixtures/test-data --manifest .test_manifest.yaml create'
        parsed_args = cli.parse_args(args.split())

        self.assertEqual(parsed_args.basedir, 'tests/fixtures/test-data')
        self.assertEqual(parsed_args.manifest_path, '.test_manifest.yaml')
        self.assertEqual(parsed_args.action, 'create')
        self.assertEqual(parsed_args.log_level, 'info')

    def test_parse_args_omit_manifest(self):
        """ Ensure parsing of proper arguments when a manifest is not provided """

        args = '--basedir tests/fixtures/test-data create'
        parsed_args = cli.parse_args(args.split())

        self.assertEqual(parsed_args.manifest_path, 'tests/fixtures/test-data/.manifest.yaml')

    def test_parse_args_return_when_none(self):
        """ Ensure function returns parser object when None is passed """


        parsed_args = cli.parse_args(None)

        self.assertEqual(type(parsed_args), argparse.ArgumentParser)


    def test_create(self):
        """ Ensure a manifest can be created using the furtive cli """

        args = 'app.py --basedir tests/fixtures/test-data --manifest .test_manifest.yaml create'
        sys.argv = args.split()

        cli.main()

        self.assertTrue(os.path.exists('.test_manifest.yaml'))

    @patch('sys.stdout', new_callable=StringIO)
    def test_compare(self, mock_stdout):
        """ Ensure a manifest can be compared to current files """

        args = 'app.py --basedir tests/fixtures/test-data --manifest .test_manifest.yaml create'
        sys.argv = args.split()

        cli.main()

        with open('tests/fixtures/test-data/test-file', 'w') as text_file:
            text_file.write('This is a test file.')

        args = 'app.py --basedir tests/fixtures/test-data --manifest .test_manifest.yaml compare'
        sys.argv = args.split()
        cli.main()

        self.assertTrue('test-file' in mock_stdout.getvalue())
        self.assertTrue('!!python/unicode' not in mock_stdout.getvalue())

        args = 'app.py --basedir tests/fixtures/test-data --manifest .test_manifest.yaml create'
        sys.argv = args.split()
        cli.main()

        with open('tests/fixtures/test-data/test-file', 'w') as text_file:
            text_file.write('This is a test file with changed content.')

        args = 'app.py --basedir tests/fixtures/test-data --manifest .test_manifest.yaml compare'
        sys.argv = args.split()
        cli.main()

        self.assertTrue('test-file' in mock_stdout.getvalue())
        self.assertTrue('!!python' not in mock_stdout.getvalue())


    @patch('sys.stdout', new_callable=StringIO)
    def test_quiet(self, mock_stdout):
        """ Ensure nothing is printed to stdout if --quiet is provided.

            Basically re-running test_compare() but with the --quiet arg.
        """

        args = 'app.py --basedir tests/fixtures/test-data --manifest .test_manifest.yaml create --quiet'
        sys.argv = args.split()

        cli.main()

        with open('tests/fixtures/test-data/test-file', 'w') as text_file:
            text_file.write('This is a test file.')

        args = 'app.py --basedir tests/fixtures/test-data --manifest .test_manifest.yaml compare --quiet'
        sys.argv = args.split()
        cli.main()

        args = 'app.py --basedir tests/fixtures/test-data --manifest .test_manifest.yaml create --quiet'
        sys.argv = args.split()
        cli.main()

        with open('tests/fixtures/test-data/test-file', 'w') as text_file:
            text_file.write('This is a test file with changed content.')

        args = 'app.py --basedir tests/fixtures/test-data --manifest .test_manifest.yaml compare --quiet'
        sys.argv = args.split()
        cli.main()

        stdout = mock_stdout.getvalue()
        self.assertTrue(stdout == '', msg=stdout)

    def test_check(self):
        """ Ensure exit with 1 if check action is provided. """

        # Create manifest
        args = 'app.py --basedir tests/fixtures/test-data --manifest .test_manifest.yaml create'
        sys.argv = args.split()
        cli.main()

        # Compare without making changes. Should not raise exception.
        args = 'app.py --basedir tests/fixtures/test-data --manifest .test_manifest.yaml check'
        sys.argv = args.split()
        cli.main()

        # Create a file and run check agian. Should exit with 1
        with open('tests/fixtures/test-data/test-file', 'w') as text_file:
            text_file.write('This is a test file.')

        args = 'app.py --basedir tests/fixtures/test-data --manifest .test_manifest.yaml check'
        sys.argv = args.split()
        with self.assertRaises(SystemExit) as return_status:
            cli.main()
            self.assertEqual(return_status.exception.code, 1)

        # Add the new file to the manifest, then change it. Should exit with 1
        args = 'app.py --basedir tests/fixtures/test-data --manifest .test_manifest.yaml create'
        sys.argv = args.split()
        cli.main()

        with open('tests/fixtures/test-data/test-file', 'w') as text_file:
            text_file.write('This is a changed test file.')

        args = 'app.py --basedir tests/fixtures/test-data --manifest .test_manifest.yaml check'
        sys.argv = args.split()
        with self.assertRaises(SystemExit) as return_status:
            cli.main()
            self.assertEqual(return_status.exception.code, 1)

        # delete test file then run compare. Should exit with 1
        os.unlink('tests/fixtures/test-data/test-file')
        args = 'app.py --basedir tests/fixtures/test-data --manifest .test_manifest.yaml check'
        sys.argv = args.split()
        with self.assertRaises(SystemExit) as return_status:
            cli.main()
            self.assertEqual(return_status.exception.code, 1)

    def test_write_report_to_file(self):
        """ Ensure the diff report can be written to a file. """

        # Create manifest
        args = 'app.py --basedir tests/fixtures/test-data --manifest .test_manifest.yaml create'
        sys.argv = args.split()
        cli.main()

        # Check output report file
        args = 'app.py --basedir tests/fixtures/test-data --manifest .test_manifest.yaml check --report-output tests/fixtures/report.yml'
        sys.argv = args.split()
        cli.main()

        # Assert the file exists
        self.assertTrue(os.path.exists('tests/fixtures/report.yml'))


        # attempt to load the File
        with open('tests/fixtures/report.yml') as report_file:
            report = yaml.safe_load(report_file.read())
            self.assertTrue('changed' in report)
            self.assertTrue('added' in report)
            self.assertTrue('removed' in report)

    def tearDown(self):
        """ Common tearDown tasks for all tests in this test case """

        if os.path.exists('.test_manifest.yaml'):
            os.unlink('.test_manifest.yaml')
        if os.path.exists('tests/fixtures/test-data/test-file'):
            os.unlink('tests/fixtures/test-data/test-file')
        if os.path.exists('tests/fixtures/report.yml'):
            os.unlink('tests/fixtures/report.yml')

if __name__ == '__main__':
    unittest.main()