# -*- coding: utf-8; -*- from __future__ import unicode_literals, absolute_import import os import csv import datetime import argparse import shutil import tempfile from unittest import TestCase from six import StringIO import six # from sqlalchemy import func from mock import patch, Mock from rattail.commands import core from rattail.db import Session, model from rattail.db.auth import authenticate_user class TestArgumentParser(TestCase): def test_parse_args_preserves_extra_argv(self): parser = core.ArgumentParser() parser.add_argument('--some-optional-arg') parser.add_argument('some_required_arg') args = parser.parse_args([ '--some-optional-arg', 'optional-value', 'required-value', 'some', 'extra', 'args']) self.assertEqual(args.some_required_arg, 'required-value') self.assertEqual(args.some_optional_arg, 'optional-value') self.assertEqual(args.argv, ['some', 'extra', 'args']) class TestDateArgument(TestCase): def test_valid_date_string_returns_date_object(self): date = core.date_argument('2014-01-01') self.assertEqual(date, datetime.date(2014, 1, 1)) def test_invalid_date_string_raises_error(self): self.assertRaises(argparse.ArgumentTypeError, core.date_argument, 'invalid-date') class TestCommand(TestCase): def test_initial_subcommands_are_sane(self): command = core.Command() self.assertTrue('filemon' in command.subcommands) def test_unicode(self): command = core.Command() command.name = 'some-app' self.assertEqual(six.text_type(command), 'some-app') def test_iter_subcommands_includes_expected_item(self): command = core.Command() found = False for subcommand in command.iter_subcommands(): if subcommand.name == 'filemon': found = True break self.assertTrue(found) def test_print_help(self): command = core.Command() stdout = StringIO() command.stdout = stdout command.print_help() output = stdout.getvalue() stdout.close() self.assertTrue('Usage:' in output) self.assertTrue('Options:' in output) def test_run_with_no_args_prints_help(self): command = core.Command() with patch.object(command, 'print_help') as print_help: self.assertRaises(SystemExit, command.run) print_help.assert_called_once_with() def test_run_with_single_help_arg_prints_help(self): command = core.Command() with patch.object(command, 'print_help') as print_help: command.run('help') print_help.assert_called_once_with() def test_run_with_help_and_unknown_subcommand_args_prints_help(self): command = core.Command() with patch.object(command, 'print_help') as print_help: command.run('help', 'invalid-subcommand-name') print_help.assert_called_once_with() def test_run_with_help_and_subcommand_args_prints_subcommand_help(self): command = core.Command() fake = command.subcommands['fake'] = Mock() command.run('help', 'fake') fake.return_value.parser.print_help.assert_called_once_with() def test_run_with_unknown_subcommand_arg_prints_help(self): command = core.Command() with patch.object(command, 'print_help') as print_help: self.assertRaises(SystemExit, command.run, 'invalid-command-name') print_help.assert_called_once_with() # TODO: the following 2 tests are disabled b/c depending on when # they run under pytest, they may fail. has to do with # make_config() modifying default bind for db sessions etc. # need to come up with a better way to handle all that... # def test_stdout_may_be_redirected(self): # class Fake(core.Subcommand): # def run(self, args): # self.stdout.write("standard output stuff") # self.stdout.flush() # command = core.Command() # fake = command.subcommands['fake'] = Fake # tempdir = tempfile.mkdtemp() # config_path = os.path.join(tempdir, 'test.ini') # with open(config_path, 'wt') as f: # f.write('') # out_path = os.path.join(tempdir, 'out.txt') # with open(out_path, 'wt') as f: # f.write('') # command.run('fake', '--config', config_path, '--stdout', out_path) # with open(out_path) as f: # self.assertEqual(f.read(), "standard output stuff") # shutil.rmtree(tempdir) # def test_stderr_may_be_redirected(self): # class Fake(core.Subcommand): # def run(self, args): # self.stderr.write("standard error stuff") # self.stderr.flush() # command = core.Command() # fake = command.subcommands['fake'] = Fake # tempdir = tempfile.mkdtemp() # config_path = os.path.join(tempdir, 'test.ini') # with open(config_path, 'wt') as f: # f.write('') # err_path = os.path.join(tempdir, 'err.txt') # with open(err_path, 'wt') as f: # f.write('') # command.run('fake', '--config', config_path, '--stderr', err_path) # with open(err_path) as f: # self.assertEqual(f.read(), "standard error stuff") # shutil.rmtree(tempdir) # # # TODO: Figure out a better way to test this, or don't bother. # # def test_noinit_flag_means_no_config(self): # # command = commands.Command() # # fake = command.subcommands['fake'] = Mock() # # command.run('fake', '--no-init') # # self.assertEqual(len(fake.return_value.config.files_requested), 0) class TestSubcommand(TestCase): def test_add_parser_args_does_nothing(self): command = core.Command() subcommand = core.Subcommand(command) # Not sure this is really the way to test this, but... self.assertEqual(len(subcommand.parser._action_groups[0]._actions), 1) subcommand.add_parser_args(subcommand.parser) self.assertEqual(len(subcommand.parser._action_groups[0]._actions), 1) def test_run_not_implemented(self): command = core.Command() subcommand = core.Subcommand(command) args = subcommand.parser.parse_args([]) self.assertRaises(NotImplementedError, subcommand.run, args) # TODO: more broken tests..ugh. these aren't very good or else i might bother # fixing them... # class TestFileMonitor(TestCase): # @patch('rattail.filemon.linux.start_daemon') # def test_start_daemon_with_default_args(self, start_daemon): # commands.main('filemon', '--no-init', 'start') # start_daemon.assert_called_once_with(None, None, True) # @patch('rattail.filemon.linux.start_daemon') # def test_start_daemon_with_explicit_args(self, start_daemon): # tmp = TempIO() # pid_path = tmp.putfile('test.pid', '') # commands.main('filemon', '--no-init', '--pidfile', pid_path, '--do-not-daemonize', 'start') # start_daemon.assert_called_once_with(None, pid_path, False) # @patch('rattail.filemon.linux.stop_daemon') # def test_stop_daemon_with_default_args(self, stop_daemon): # commands.main('filemon', '--no-init', 'stop') # stop_daemon.assert_called_once_with(None, None) # @patch('rattail.filemon.linux.stop_daemon') # def test_stop_daemon_with_explicit_args(self, stop_daemon): # tmp = TempIO() # pid_path = tmp.putfile('test.pid', '') # commands.main('filemon', '--no-init', '--pidfile', pid_path, 'stop') # stop_daemon.assert_called_once_with(None, pid_path) # @patch('rattail.commands.sys') # def test_unknown_platform_not_supported(self, sys): # tmp = TempIO() # stderr_path = tmp.putfile('stderr.txt', '') # sys.platform = 'bogus' # commands.main('--no-init', '--stderr', stderr_path, 'filemon', 'start') # sys.exit.assert_called_once_with(1) # with open(stderr_path) as f: # self.assertEqual(f.read(), "File monitor is not supported on platform: bogus\n")