def test_upgrade_project( self, fix, run_global_version_update, gather, get_errors, remove_version, subprocess, ) -> None: arguments = MagicMock() arguments.lint = False gather.return_value = [] upgrade.run_fixme_all(arguments) fix.assert_not_called() subprocess.assert_not_called() errors = [ { "line": 2, "column": 4, "path": "local.py", "code": 7, "name": "Kind", "concise_description": "Error", "inference": {}, "ignore_error": False, "external_to_global_root": False, } ] get_errors.return_value = errors configuration = upgrade.Configuration( "/root/local/.pyre_configuration.local", {"version": 123} ) configuration.get_path() upgrade._upgrade_project(arguments, configuration, "/root") run_global_version_update.assert_not_called() fix.called_once_with(arguments, upgrade.sort_errors(errors)) subprocess.assert_called_once_with( ["hg", "commit", "--message", upgrade._commit_message("local")] ) # Test with lint subprocess.reset_mock() fix.reset_mock() arguments.lint = True upgrade._upgrade_project(arguments, configuration, "/root") run_global_version_update.assert_not_called() fix.called_once_with(arguments, upgrade.sort_errors(errors)) calls = [ call(["arc", "lint", "--never-apply-patches", "--output", "none"]), call().__bool__(), call(["arc", "lint", "--apply-patches", "--output", "none"]), call(["hg", "commit", "--message", upgrade._commit_message("local")]), ] subprocess.assert_has_calls(calls)
def test_run_global_version_update( self, open_mock, gather_local_configurations, find_project_configuration, subprocess, ) -> None: arguments = MagicMock() arguments.hash = "abcd" arguments.push_blocking_only = False with patch("json.dump") as dump: mocks = [ mock_open(read_data='{"version": "old"}').return_value, mock_open(read_data="{}").return_value, mock_open(read_data='{"push_blocking": false}').return_value, mock_open(read_data="{}").return_value, mock_open(read_data='{"push_blocking": true}').return_value, mock_open(read_data="{}").return_value, ] open_mock.side_effect = mocks upgrade.run_global_version_update(arguments) dump.assert_has_calls( [ call({"version": "abcd"}, mocks[1], indent=2, sort_keys=True), call( {"push_blocking": False, "version": "old"}, mocks[3], indent=2, sort_keys=True, ), call( {"push_blocking": True, "version": "old"}, mocks[5], indent=2, sort_keys=True, ), ] ) subprocess.assert_called_once_with( [ "hg", "commit", "--message", upgrade._commit_message( "global configuration", summary_override="Automatic upgrade to hash `abcd`", ), ] ) # Push blocking argument: Since the push blocking only argument is only used when # gathering local configurations (mocked here), this is a no-op. Documents it. subprocess.reset_mock() arguments.push_blocking_only = True arguments.submit = True with patch("json.dump") as dump: mocks = [ mock_open(read_data='{"version": "old"}').return_value, mock_open(read_data="{}").return_value, mock_open(read_data='{"push_blocking": false}').return_value, mock_open(read_data="{}").return_value, mock_open(read_data='{"push_blocking": true}').return_value, mock_open(read_data="{}").return_value, ] open_mock.side_effect = mocks upgrade.run_global_version_update(arguments) dump.assert_has_calls( [ call({"version": "abcd"}, mocks[1], indent=2, sort_keys=True), call( {"push_blocking": False, "version": "old"}, mocks[3], indent=2, sort_keys=True, ), call( {"push_blocking": True, "version": "old"}, mocks[5], indent=2, sort_keys=True, ), ] ) calls = [ call( [ "hg", "commit", "--message", upgrade._commit_message( "global configuration", summary_override="Automatic upgrade to hash `abcd`", ), ] ), call(["jf", "submit", "--update-fields", "--no-deps"]), ] subprocess.assert_has_calls(calls)
def test_run_fixme_all( self, fix, run_global_version_update, get_errors, remove_version, find_configuration, gather, subprocess, ) -> None: arguments = MagicMock() arguments.lint = False gather.return_value = [ upgrade.Configuration("local/.pyre_configuration.local", {"version": 123}) ] get_errors.return_value = [] upgrade.run_fixme_all(arguments) run_global_version_update.assert_not_called() fix.assert_not_called() subprocess.assert_called_once_with( ["hg", "commit", "--message", upgrade._commit_message("local")] ) fix.reset_mock() subprocess.reset_mock() errors = [ { "line": 2, "column": 4, "path": "local.py", "code": 7, "name": "Kind", "concise_description": "Error", "inference": {}, "ignore_error": False, "external_to_global_root": False, } ] get_errors.return_value = errors upgrade.run_fixme_all(arguments) run_global_version_update.assert_not_called() fix.called_once_with(arguments, upgrade.sort_errors(errors)) subprocess.assert_called_once_with( ["hg", "commit", "--message", upgrade._commit_message("local")] ) # Test configuraton with no version set fix.reset_mock() subprocess.reset_mock() gather.return_value = [ upgrade.Configuration("local/.pyre_configuration.local", {}) ] upgrade.run_fixme_all(arguments) fix.assert_not_called() subprocess.assert_not_called() # Test with given hash fix.reset_mock() subprocess.reset_mock() gather.return_value = [ upgrade.Configuration("local/.pyre_configuration.local", {"version": 123}) ] arguments.hash = "abc" arguments.submit = True upgrade.run_fixme_all(arguments) run_global_version_update.assert_called_once_with(arguments) fix.called_once_with(arguments, upgrade.sort_errors(errors)) calls = [ call(["hg", "commit", "--message", upgrade._commit_message("local")]), call(["jf", "submit", "--update-fields", "--no-deps"]), ] subprocess.assert_has_calls(calls) # Test with linting fix.reset_mock() subprocess.reset_mock() run_global_version_update.reset_mock() arguments.lint = True upgrade.run_fixme_all(arguments) run_global_version_update.assert_called_once_with(arguments) fix.called_once_with(arguments, upgrade.sort_errors(errors)) calls = [ call(["hg", "commit", "--message", upgrade._commit_message("local")]), call(["jf", "submit", "--update-fields", "--no-deps"]), ] subprocess.assert_has_calls(calls)
def test_run_fixme_targets_file(self, suppress_errors, subprocess) -> None: arguments = MagicMock() arguments.subdirectory = None arguments.no_commit = False arguments.lint = False buck_return = MagicMock() buck_return.returncode = 1 buck_return.stderr = b"stderr" subprocess.return_value = buck_return FixmeTargets(arguments, repository)._run_fixme_targets_file( Path("."), "a/b", [ Target("derp", strict=False, pyre=True), Target("herp", strict=False, pyre=True), ], ) subprocess.assert_called_once_with( [ "buck", "test", "--show-full-json-output", "a/b:derp-pyre-typecheck", "a/b:herp-pyre-typecheck", "--", "--run-disabled", ], stdout=-1, stderr=-1, ) suppress_errors.assert_not_called() buck_return.returncode = 0 subprocess.return_value = buck_return FixmeTargets(arguments, repository)._run_fixme_targets_file( Path("."), "a/b", [ Target("derp", strict=False, pyre=True), Target("herp", strict=False, pyre=True), ], ) suppress_errors.assert_not_called() buck_return.returncode = 32 buck_return.stdout = b""" Discovering tests Running 1 tests Started new test run: https://url a/b:c-typecheck - a.b.c (c.TypeCheck) 57.547 1/1 (failed) Test output: > All OK. > WARNING: Invoking pyre through buck TARGETS may... > See `https://wiki/configuration/` to set up Pyre for your project. > > a/b/x.py:278:28 %s > a/b/x.py:325:41 %s > a/b/y.py:86:26 %s a/b:c-typecheck - main 0.000 (passed) Finished test run: https://url Summary (total time 58.75s): PASS: 1 FAIL: 1 a/b:c-typecheck - a.b.c (c.TypeCheck) SKIP: 0 FATAL: 0 TIMEOUT: 0 OMIT: 0 """ % ( b"Undefined attribute [16]: `Optional` has no attribute `derp`.", b"Undefined attribute [16]: `Optional` has no attribute `herp`.", b"Incompatible parameter type [6]: Expected `str` for 1st positional only " + b"parameter to call `merp` but got `Optional[str]`.", ) subprocess.return_value = buck_return expected_errors = errors.Errors([ { "line": 278, "column": 28, "path": Path("a/b/x.py"), "code": "16", "description": "Undefined attribute [16]: `Optional` has no " + "attribute `derp`.", "concise_description": "Undefined attribute [16]: `Optional` has " + "no attribute `derp`.", }, { "line": 325, "column": 41, "path": Path("a/b/x.py"), "code": "16", "description": "Undefined attribute [16]: `Optional` has no " + "attribute `herp`.", "concise_description": "Undefined attribute [16]: `Optional` has " + "no attribute `herp`.", }, { "line": 86, "column": 26, "path": Path("a/b/y.py"), "code": "6", "description": "Incompatible parameter type [6]: Expected `str` " + "for 1st positional only parameter to call `merp` but got " + "`Optional[str]`.", "concise_description": "Incompatible parameter type [6]: Expected " + "`str` for 1st positional only parameter to call `merp` but got " + "`Optional[str]`.", }, ]) FixmeTargets(arguments, repository)._run_fixme_targets_file( Path("."), "a/b", [ Target("derp", strict=False, pyre=True), Target("herp", strict=False, pyre=True), ], ) suppress_errors.assert_called_once_with(expected_errors) # Test fallback to type check targets with modified names subprocess.reset_mock() suppress_errors.reset_mock() failed_buck_return = MagicMock() failed_buck_return.returncode = 5 failed_buck_return.stdout = b"" buck_query_return = MagicMock() buck_query_return.stdout = b"//target/to:retry-pyre-typecheck" subprocess.side_effect = [ failed_buck_return, buck_query_return, buck_return ] FixmeTargets(arguments, repository)._run_fixme_targets_file( Path("."), "a/b", [Target("derp", strict=False, pyre=True)]) subprocess.assert_has_calls([ call( [ "buck", "test", "--show-full-json-output", "a/b:derp-pyre-typecheck", "--", "--run-disabled", ], stdout=-1, stderr=-1, ), call(["buck", "query", "a/b:derp-pyre-typecheck"], stdout=-1, stderr=-1), call( [ "buck", "test", "--show-full-json-output", "//target/to:retry-pyre-typecheck", "--", "--run-disabled", ], stdout=-1, stderr=-1, ), ]) suppress_errors.assert_called_once_with(expected_errors) subprocess.reset_mock() suppress_errors.reset_mock() failed_buck_return = MagicMock() failed_buck_return.returncode = 5 failed_buck_return.stdout = b"" buck_query_return = MagicMock() buck_query_return.stdout = b"" buck_query_return.stderr = b""" Error in preloading targets. The rule //a/b:derp-pyre-typecheck could \ not be found. Please check the spelling and whether it is one of the 10 targets in \ /a/b/TARGETS. (1000 bytes) 2 similar targets in \ /data/users/szhu/fbsource/fbcode/tools/build/test/TARGETS are: //target/to:retry-pyre-typecheck //target/to:retry_non_typecheck """ subprocess.side_effect = [ failed_buck_return, buck_query_return, buck_return ] FixmeTargets(arguments, repository)._run_fixme_targets_file( Path("."), "a/b", [Target("derp", strict=False, pyre=True)]) subprocess.assert_has_calls([ call( [ "buck", "test", "--show-full-json-output", "a/b:derp-pyre-typecheck", "--", "--run-disabled", ], stdout=-1, stderr=-1, ), call(["buck", "query", "a/b:derp-pyre-typecheck"], stdout=-1, stderr=-1), call( [ "buck", "test", "--show-full-json-output", "//target/to:retry-pyre-typecheck", "--", "--run-disabled", ], stdout=-1, stderr=-1, ), ]) suppress_errors.assert_called_once_with(expected_errors)
def test_upgrade_project( self, fix, run_global_version_update, errors_from_stdin, gather, get_errors, remove_version, subprocess, ) -> None: arguments = MagicMock() arguments.lint = False arguments.from_stdin = False gather.return_value = [] upgrade.run_fixme_all(arguments) fix.assert_not_called() subprocess.assert_not_called() pyre_errors = [{ "line": 2, "column": 4, "path": "local.py", "code": 7, "name": "Kind", "concise_description": "Error", "inference": {}, "ignore_error": False, "external_to_global_root": False, }] get_errors.return_value = pyre_errors configuration = upgrade.Configuration( Path("/root/local/.pyre_configuration.local"), {"version": 123}) configuration.get_path() upgrade._upgrade_project(arguments, configuration, Path("/root")) run_global_version_update.assert_not_called() fix.called_once_with(arguments, errors.sort_errors(pyre_errors)) subprocess.assert_called_once_with( ["hg", "commit", "--message", upgrade._commit_message("local")]) # Test with lint subprocess.reset_mock() fix.reset_mock() arguments.from_stdin = False arguments.lint = True upgrade._upgrade_project(arguments, configuration, Path("/root")) errors_from_stdin.assert_not_called() run_global_version_update.assert_not_called() fix.called_once_with(arguments, errors.sort_errors(pyre_errors)) calls = [ call([ "arc", "lint", "--never-apply-patches", "--enforce-lint-clean", "--output", "none", ]), call().__bool__(), call(["arc", "lint", "--apply-patches", "--output", "none"]), call([ "hg", "commit", "--message", upgrade._commit_message("local") ]), ] subprocess.assert_has_calls(calls) # Test with from_stdin and lint subprocess.reset_mock() fix.reset_mock() get_errors.reset_mock() arguments.from_stdin = True arguments.lint = True errors_from_stdin.return_value = pyre_errors get_errors.return_value = pyre_errors upgrade._upgrade_project(arguments, configuration, Path("/root")) # Called in the first round to get initial errors errors_from_stdin.assert_called() # Called in the second round to get new errors after applying lint. get_errors.assert_called_once() run_global_version_update.assert_not_called() fix.called_once_with(arguments, errors.sort_errors(pyre_errors)) calls = [ call([ "arc", "lint", "--never-apply-patches", "--enforce-lint-clean", "--output", "none", ]), call().__bool__(), call(["arc", "lint", "--apply-patches", "--output", "none"]), call([ "hg", "commit", "--message", upgrade._commit_message("local") ]), ] subprocess.assert_has_calls(calls)