| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright 2017 The LUCI Authors. All rights reserved. | 2 # Copyright 2017 The LUCI Authors. All rights reserved. |
| 3 # Use of this source code is governed under the Apache License, Version 2.0 | 3 # Use of this source code is governed under the Apache License, Version 2.0 |
| 4 # that can be found in the LICENSE file. | 4 # that can be found in the LICENSE file. |
| 5 | 5 |
| 6 import json | 6 import json |
| 7 import os | 7 import os |
| 8 import shutil | 8 import shutil |
| 9 import subprocess | 9 import subprocess |
| 10 import sys | 10 import sys |
| (...skipping 539 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 550 self.assertEqual( | 550 self.assertEqual( |
| 551 self.json_generator | 551 self.json_generator |
| 552 .coverage_failure('recipe_modules/foo_module/api.py', [10]).get(), | 552 .coverage_failure('recipe_modules/foo_module/api.py', [10]).get(), |
| 553 self.json_contents) | 553 self.json_contents) |
| 554 | 554 |
| 555 def test_train_basic(self): | 555 def test_train_basic(self): |
| 556 rw = RecipeWriter(os.path.join(self._root_dir, 'recipes'), 'foo') | 556 rw = RecipeWriter(os.path.join(self._root_dir, 'recipes'), 'foo') |
| 557 rw.RunStepsLines = ['pass'] | 557 rw.RunStepsLines = ['pass'] |
| 558 rw.add_expectation('basic') | 558 rw.add_expectation('basic') |
| 559 rw.write() | 559 rw.write() |
| 560 self._run_recipes('test', 'run', '--train', '--json', self.json_path) | 560 self._run_recipes('test', 'train', '--json', self.json_path) |
| 561 self.assertEqual(self.json_generator.get(), self.json_contents) | 561 self.assertEqual(self.json_generator.get(), self.json_contents) |
| 562 | 562 |
| 563 def test_train_missing(self): | 563 def test_train_missing(self): |
| 564 rw = RecipeWriter(os.path.join(self._root_dir, 'recipes'), 'foo') | 564 rw = RecipeWriter(os.path.join(self._root_dir, 'recipes'), 'foo') |
| 565 rw.RunStepsLines = ['pass'] | 565 rw.RunStepsLines = ['pass'] |
| 566 rw.write() | 566 rw.write() |
| 567 self.assertFalse(os.path.exists(rw.expect_dir)) | 567 self.assertFalse(os.path.exists(rw.expect_dir)) |
| 568 self._run_recipes('test', 'run', '--train', '--json', self.json_path) | 568 self._run_recipes('test', 'train', '--json', self.json_path) |
| 569 self.assertTrue(os.path.exists(rw.expect_dir)) | 569 self.assertTrue(os.path.exists(rw.expect_dir)) |
| 570 expect_path = os.path.join(rw.expect_dir, 'basic.json') | 570 expect_path = os.path.join(rw.expect_dir, 'basic.json') |
| 571 self.assertTrue(os.path.exists(expect_path)) | 571 self.assertTrue(os.path.exists(expect_path)) |
| 572 with open(expect_path) as f: | 572 with open(expect_path) as f: |
| 573 expect_contents = json.load(f) | 573 expect_contents = json.load(f) |
| 574 self.assertEqual( | 574 self.assertEqual( |
| 575 [{u'status_code': 0, u'recipe_result': None, u'name': u'$result'}], | 575 [{u'status_code': 0, u'recipe_result': None, u'name': u'$result'}], |
| 576 expect_contents) | 576 expect_contents) |
| 577 self.assertEqual(self.json_generator.get(), self.json_contents) | 577 self.assertEqual(self.json_generator.get(), self.json_contents) |
| 578 | 578 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 589 rw.DEPS = ['recipe_engine/step'] | 589 rw.DEPS = ['recipe_engine/step'] |
| 590 rw.RunStepsLines = ['api.step("test", ["echo", "bar"])'] | 590 rw.RunStepsLines = ['api.step("test", ["echo", "bar"])'] |
| 591 rw.write() | 591 rw.write() |
| 592 with self.assertRaises(subprocess.CalledProcessError) as cm: | 592 with self.assertRaises(subprocess.CalledProcessError) as cm: |
| 593 self._run_recipes('test', 'run', '--json', self.json_path) | 593 self._run_recipes('test', 'run', '--json', self.json_path) |
| 594 self.assertIn('foo.basic failed', cm.exception.output) | 594 self.assertIn('foo.basic failed', cm.exception.output) |
| 595 self.assertEqual(self.json_generator.diff_failure('foo.basic').get(), | 595 self.assertEqual(self.json_generator.diff_failure('foo.basic').get(), |
| 596 self.json_contents) | 596 self.json_contents) |
| 597 | 597 |
| 598 # 3. Make sure training the recipe succeeds and produces correct results. | 598 # 3. Make sure training the recipe succeeds and produces correct results. |
| 599 self._run_recipes('test', 'run', '--train', '--json', self.json_path) | 599 self._run_recipes('test', 'train', '--json', self.json_path) |
| 600 expect_path = os.path.join(rw.expect_dir, 'basic.json') | 600 expect_path = os.path.join(rw.expect_dir, 'basic.json') |
| 601 with open(expect_path) as f: | 601 with open(expect_path) as f: |
| 602 expect_contents = json.load(f) | 602 expect_contents = json.load(f) |
| 603 self.assertEqual( | 603 self.assertEqual( |
| 604 [{u'cmd': [u'echo', u'bar'], u'name': u'test'}, | 604 [{u'cmd': [u'echo', u'bar'], u'name': u'test'}, |
| 605 {u'status_code': 0, u'recipe_result': None, u'name': u'$result'}], | 605 {u'status_code': 0, u'recipe_result': None, u'name': u'$result'}], |
| 606 expect_contents) | 606 expect_contents) |
| 607 self.assertEqual(self.json_generator.get(), self.json_contents) | 607 self.assertEqual(self.json_generator.get(), self.json_contents) |
| 608 | 608 |
| 609 def test_train_checks_coverage(self): | 609 def test_train_checks_coverage(self): |
| 610 rw = RecipeWriter(os.path.join(self._root_dir, 'recipes'), 'foo') | 610 rw = RecipeWriter(os.path.join(self._root_dir, 'recipes'), 'foo') |
| 611 rw.RunStepsLines = ['if False:', ' pass'] | 611 rw.RunStepsLines = ['if False:', ' pass'] |
| 612 rw.add_expectation('basic') | 612 rw.add_expectation('basic') |
| 613 rw.write() | 613 rw.write() |
| 614 with self.assertRaises(subprocess.CalledProcessError) as cm: | 614 with self.assertRaises(subprocess.CalledProcessError) as cm: |
| 615 self._run_recipes('test', 'run', '--train', '--json', self.json_path) | 615 self._run_recipes('test', 'train', '--json', self.json_path) |
| 616 self.assertIn('FATAL: Insufficient coverage', cm.exception.output) | 616 self.assertIn('FATAL: Insufficient coverage', cm.exception.output) |
| 617 self.assertNotIn('CHECK(FAIL)', cm.exception.output) | 617 self.assertNotIn('CHECK(FAIL)', cm.exception.output) |
| 618 self.assertNotIn('foo.basic failed', cm.exception.output) | 618 self.assertNotIn('foo.basic failed', cm.exception.output) |
| 619 self.assertEqual( | 619 self.assertEqual( |
| 620 self.json_generator.coverage_failure('recipes/foo.py', [7]).get(), | 620 self.json_generator.coverage_failure('recipes/foo.py', [7]).get(), |
| 621 self.json_contents) | 621 self.json_contents) |
| 622 | 622 |
| 623 def test_train_runs_checks(self): | 623 def test_train_runs_checks(self): |
| 624 rw = RecipeWriter(os.path.join(self._root_dir, 'recipes'), 'foo') | 624 rw = RecipeWriter(os.path.join(self._root_dir, 'recipes'), 'foo') |
| 625 rw.RunStepsLines = ['pass'] | 625 rw.RunStepsLines = ['pass'] |
| 626 rw.GenTestsLines = [ | 626 rw.GenTestsLines = [ |
| 627 'yield api.test("basic") + \\', | 627 'yield api.test("basic") + \\', |
| 628 ' api.post_process(post_process.MustRun, "bar")' | 628 ' api.post_process(post_process.MustRun, "bar")' |
| 629 ] | 629 ] |
| 630 rw.add_expectation('basic') | 630 rw.add_expectation('basic') |
| 631 rw.write() | 631 rw.write() |
| 632 with self.assertRaises(subprocess.CalledProcessError) as cm: | 632 with self.assertRaises(subprocess.CalledProcessError) as cm: |
| 633 self._run_recipes('test', 'run', '--train', '--json', self.json_path) | 633 self._run_recipes('test', 'train', '--json', self.json_path) |
| 634 self.assertNotIn('FATAL: Insufficient coverage', cm.exception.output) | 634 self.assertNotIn('FATAL: Insufficient coverage', cm.exception.output) |
| 635 self.assertIn('CHECK(FAIL)', cm.exception.output) | 635 self.assertIn('CHECK(FAIL)', cm.exception.output) |
| 636 self.assertIn('foo.basic failed', cm.exception.output) | 636 self.assertIn('foo.basic failed', cm.exception.output) |
| 637 self.assertEqual( | 637 self.assertEqual( |
| 638 self.json_generator.check_failure( | 638 self.json_generator.check_failure( |
| 639 'foo.basic', 'recipes/foo.py', 10, | 639 'foo.basic', 'recipes/foo.py', 10, |
| 640 'MustRun', args=['\'bar\'']).get(), | 640 'MustRun', args=['\'bar\'']).get(), |
| 641 self.json_contents) | 641 self.json_contents) |
| 642 | 642 |
| 643 def test_unused_expectation_file_test(self): | 643 def test_unused_expectation_file_test(self): |
| (...skipping 16 matching lines...) Expand all Loading... |
| 660 self.json_contents) | 660 self.json_contents) |
| 661 | 661 |
| 662 def test_unused_expectation_file_train(self): | 662 def test_unused_expectation_file_train(self): |
| 663 rw = RecipeWriter(os.path.join(self._root_dir, 'recipes'), 'foo') | 663 rw = RecipeWriter(os.path.join(self._root_dir, 'recipes'), 'foo') |
| 664 rw.RunStepsLines = ['pass'] | 664 rw.RunStepsLines = ['pass'] |
| 665 rw.add_expectation('basic') | 665 rw.add_expectation('basic') |
| 666 rw.add_expectation('unused') | 666 rw.add_expectation('unused') |
| 667 rw.write() | 667 rw.write() |
| 668 expectation_file = os.path.join(rw.expect_dir, 'unused.json') | 668 expectation_file = os.path.join(rw.expect_dir, 'unused.json') |
| 669 self.assertTrue(os.path.exists(expectation_file)) | 669 self.assertTrue(os.path.exists(expectation_file)) |
| 670 self._run_recipes('test', 'run', '--train', '--json', self.json_path) | 670 self._run_recipes('test', 'train', '--json', self.json_path) |
| 671 self.assertFalse(os.path.exists(expectation_file)) | 671 self.assertFalse(os.path.exists(expectation_file)) |
| 672 self.assertEqual(self.json_generator.get(), self.json_contents) | 672 self.assertEqual(self.json_generator.get(), self.json_contents) |
| 673 | 673 |
| 674 def test_unused_expectation_dir_test(self): | 674 def test_unused_expectation_dir_test(self): |
| 675 rw = RecipeWriter(os.path.join(self._root_dir, 'recipes'), 'foo') | 675 rw = RecipeWriter(os.path.join(self._root_dir, 'recipes'), 'foo') |
| 676 rw.RunStepsLines = ['pass'] | 676 rw.RunStepsLines = ['pass'] |
| 677 rw.add_expectation('basic') | 677 rw.add_expectation('basic') |
| 678 rw.write() | 678 rw.write() |
| 679 expectation_dir = os.path.join(rw.expect_dir, 'dir') | 679 expectation_dir = os.path.join(rw.expect_dir, 'dir') |
| 680 os.makedirs(expectation_dir) | 680 os.makedirs(expectation_dir) |
| 681 with self.assertRaises(subprocess.CalledProcessError) as cm: | 681 with self.assertRaises(subprocess.CalledProcessError) as cm: |
| 682 self._run_recipes('test', 'run', '--json', self.json_path) | 682 self._run_recipes('test', 'run', '--json', self.json_path) |
| 683 self.assertIn( | 683 self.assertIn( |
| 684 'FATAL: unused expectations found:\n%s' % expectation_dir, | 684 'FATAL: unused expectations found:\n%s' % expectation_dir, |
| 685 cm.exception.output) | 685 cm.exception.output) |
| 686 self.assertTrue(os.path.exists(expectation_dir)) | 686 self.assertTrue(os.path.exists(expectation_dir)) |
| 687 self.assertEqual( | 687 self.assertEqual( |
| 688 self.json_generator | 688 self.json_generator |
| 689 .unused_expectation('recipes/foo.expected/dir').get(), | 689 .unused_expectation('recipes/foo.expected/dir').get(), |
| 690 self.json_contents) | 690 self.json_contents) |
| 691 | 691 |
| 692 def test_unused_expectation_dir_train(self): | 692 def test_unused_expectation_dir_train(self): |
| 693 rw = RecipeWriter(os.path.join(self._root_dir, 'recipes'), 'foo') | 693 rw = RecipeWriter(os.path.join(self._root_dir, 'recipes'), 'foo') |
| 694 rw.RunStepsLines = ['pass'] | 694 rw.RunStepsLines = ['pass'] |
| 695 rw.add_expectation('basic') | 695 rw.add_expectation('basic') |
| 696 rw.write() | 696 rw.write() |
| 697 expectation_dir = os.path.join(rw.expect_dir, 'dir') | 697 expectation_dir = os.path.join(rw.expect_dir, 'dir') |
| 698 os.makedirs(expectation_dir) | 698 os.makedirs(expectation_dir) |
| 699 self._run_recipes('test', 'run', '--train', '--json', self.json_path) | 699 self._run_recipes('test', 'train', '--json', self.json_path) |
| 700 self.assertFalse(os.path.exists(expectation_dir)) | 700 self.assertFalse(os.path.exists(expectation_dir)) |
| 701 self.assertEqual(self.json_generator.get(), self.json_contents) | 701 self.assertEqual(self.json_generator.get(), self.json_contents) |
| 702 | 702 |
| 703 def test_drop_expectation_test(self): | 703 def test_drop_expectation_test(self): |
| 704 rw = RecipeWriter(os.path.join(self._root_dir, 'recipes'), 'foo') | 704 rw = RecipeWriter(os.path.join(self._root_dir, 'recipes'), 'foo') |
| 705 rw.RunStepsLines = ['pass'] | 705 rw.RunStepsLines = ['pass'] |
| 706 rw.GenTestsLines = [ | 706 rw.GenTestsLines = [ |
| 707 'yield api.test("basic") + \\', | 707 'yield api.test("basic") + \\', |
| 708 ' api.post_process(post_process.DropExpectation)' | 708 ' api.post_process(post_process.DropExpectation)' |
| 709 ] | 709 ] |
| 710 rw.write() | 710 rw.write() |
| 711 expectation_file = os.path.join(rw.expect_dir, 'basic.json') | 711 expectation_file = os.path.join(rw.expect_dir, 'basic.json') |
| 712 self.assertFalse(os.path.exists(expectation_file)) | 712 self.assertFalse(os.path.exists(expectation_file)) |
| 713 self._run_recipes('test', 'run', '--json', self.json_path) | 713 self._run_recipes('test', 'run', '--json', self.json_path) |
| 714 self.assertFalse(os.path.exists(expectation_file)) | 714 self.assertFalse(os.path.exists(expectation_file)) |
| 715 self.assertEqual(self.json_generator.get(), self.json_contents) | 715 self.assertEqual(self.json_generator.get(), self.json_contents) |
| 716 | 716 |
| 717 def test_drop_expectation_train(self): | 717 def test_drop_expectation_train(self): |
| 718 rw = RecipeWriter(os.path.join(self._root_dir, 'recipes'), 'foo') | 718 rw = RecipeWriter(os.path.join(self._root_dir, 'recipes'), 'foo') |
| 719 rw.RunStepsLines = ['pass'] | 719 rw.RunStepsLines = ['pass'] |
| 720 rw.GenTestsLines = [ | 720 rw.GenTestsLines = [ |
| 721 'yield api.test("basic") + \\', | 721 'yield api.test("basic") + \\', |
| 722 ' api.post_process(post_process.DropExpectation)' | 722 ' api.post_process(post_process.DropExpectation)' |
| 723 ] | 723 ] |
| 724 rw.write() | 724 rw.write() |
| 725 expectation_file = os.path.join(rw.expect_dir, 'basic.json') | 725 expectation_file = os.path.join(rw.expect_dir, 'basic.json') |
| 726 self.assertFalse(os.path.exists(expectation_file)) | 726 self.assertFalse(os.path.exists(expectation_file)) |
| 727 self._run_recipes('test', 'run', '--train', '--json', self.json_path) | 727 self._run_recipes('test', 'train', '--json', self.json_path) |
| 728 self.assertFalse(os.path.exists(expectation_file)) | 728 self.assertFalse(os.path.exists(expectation_file)) |
| 729 self.assertEqual(self.json_generator.get(), self.json_contents) | 729 self.assertEqual(self.json_generator.get(), self.json_contents) |
| 730 | 730 |
| 731 def test_drop_expectation_test_unused(self): | 731 def test_drop_expectation_test_unused(self): |
| 732 rw = RecipeWriter(os.path.join(self._root_dir, 'recipes'), 'foo') | 732 rw = RecipeWriter(os.path.join(self._root_dir, 'recipes'), 'foo') |
| 733 rw.RunStepsLines = ['pass'] | 733 rw.RunStepsLines = ['pass'] |
| 734 rw.GenTestsLines = [ | 734 rw.GenTestsLines = [ |
| 735 'yield api.test("basic") + \\', | 735 'yield api.test("basic") + \\', |
| 736 ' api.post_process(post_process.DropExpectation)' | 736 ' api.post_process(post_process.DropExpectation)' |
| 737 ] | 737 ] |
| (...skipping 18 matching lines...) Expand all Loading... |
| 756 rw = RecipeWriter(os.path.join(self._root_dir, 'recipes'), 'foo') | 756 rw = RecipeWriter(os.path.join(self._root_dir, 'recipes'), 'foo') |
| 757 rw.RunStepsLines = ['pass'] | 757 rw.RunStepsLines = ['pass'] |
| 758 rw.GenTestsLines = [ | 758 rw.GenTestsLines = [ |
| 759 'yield api.test("basic") + \\', | 759 'yield api.test("basic") + \\', |
| 760 ' api.post_process(post_process.DropExpectation)' | 760 ' api.post_process(post_process.DropExpectation)' |
| 761 ] | 761 ] |
| 762 rw.add_expectation('basic') | 762 rw.add_expectation('basic') |
| 763 rw.write() | 763 rw.write() |
| 764 expectation_file = os.path.join(rw.expect_dir, 'basic.json') | 764 expectation_file = os.path.join(rw.expect_dir, 'basic.json') |
| 765 self.assertTrue(os.path.exists(expectation_file)) | 765 self.assertTrue(os.path.exists(expectation_file)) |
| 766 self._run_recipes('test', 'run', '--train', '--json', self.json_path) | 766 self._run_recipes('test', 'train', '--json', self.json_path) |
| 767 self.assertFalse(os.path.exists(expectation_file)) | 767 self.assertFalse(os.path.exists(expectation_file)) |
| 768 self.assertFalse(os.path.exists(rw.expect_dir)) | 768 self.assertFalse(os.path.exists(rw.expect_dir)) |
| 769 self.assertEqual(self.json_generator.get(), self.json_contents) | 769 self.assertEqual(self.json_generator.get(), self.json_contents) |
| 770 | 770 |
| 771 def test_unused_expectation_preserves_owners_test(self): | 771 def test_unused_expectation_preserves_owners_test(self): |
| 772 rw = RecipeWriter(os.path.join(self._root_dir, 'recipes'), 'foo') | 772 rw = RecipeWriter(os.path.join(self._root_dir, 'recipes'), 'foo') |
| 773 rw.RunStepsLines = ['pass'] | 773 rw.RunStepsLines = ['pass'] |
| 774 rw.add_expectation('basic') | 774 rw.add_expectation('basic') |
| 775 rw.write() | 775 rw.write() |
| 776 owners_file = os.path.join(rw.expect_dir, 'OWNERS') | 776 owners_file = os.path.join(rw.expect_dir, 'OWNERS') |
| 777 with open(owners_file, 'w') as f: | 777 with open(owners_file, 'w') as f: |
| 778 pass | 778 pass |
| 779 self.assertTrue(os.path.exists(owners_file)) | 779 self.assertTrue(os.path.exists(owners_file)) |
| 780 self._run_recipes('test', 'run', '--json', self.json_path) | 780 self._run_recipes('test', 'run', '--json', self.json_path) |
| 781 self.assertTrue(os.path.exists(owners_file)) | 781 self.assertTrue(os.path.exists(owners_file)) |
| 782 self.assertEqual(self.json_generator.get(), self.json_contents) | 782 self.assertEqual(self.json_generator.get(), self.json_contents) |
| 783 | 783 |
| 784 def test_unused_expectation_preserves_owners_train(self): | 784 def test_unused_expectation_preserves_owners_train(self): |
| 785 rw = RecipeWriter(os.path.join(self._root_dir, 'recipes'), 'foo') | 785 rw = RecipeWriter(os.path.join(self._root_dir, 'recipes'), 'foo') |
| 786 rw.RunStepsLines = ['pass'] | 786 rw.RunStepsLines = ['pass'] |
| 787 rw.add_expectation('basic') | 787 rw.add_expectation('basic') |
| 788 rw.write() | 788 rw.write() |
| 789 owners_file = os.path.join(rw.expect_dir, 'OWNERS') | 789 owners_file = os.path.join(rw.expect_dir, 'OWNERS') |
| 790 with open(owners_file, 'w') as f: | 790 with open(owners_file, 'w') as f: |
| 791 pass | 791 pass |
| 792 self.assertTrue(os.path.exists(owners_file)) | 792 self.assertTrue(os.path.exists(owners_file)) |
| 793 self._run_recipes('test', 'run', '--train', '--json', self.json_path) | 793 self._run_recipes('test', 'train', '--json', self.json_path) |
| 794 self.assertTrue(os.path.exists(owners_file)) | 794 self.assertTrue(os.path.exists(owners_file)) |
| 795 self.assertEqual(self.json_generator.get(), self.json_contents) | 795 self.assertEqual(self.json_generator.get(), self.json_contents) |
| 796 | 796 |
| 797 def test_test_slash_in_name(self): | 797 def test_test_slash_in_name(self): |
| 798 test_name = 'bar/baz' | 798 test_name = 'bar/baz' |
| 799 rw = RecipeWriter(os.path.join(self._root_dir, 'recipes'), 'foo') | 799 rw = RecipeWriter(os.path.join(self._root_dir, 'recipes'), 'foo') |
| 800 rw.RunStepsLines = ['pass'] | 800 rw.RunStepsLines = ['pass'] |
| 801 rw.GenTestsLines = ['yield api.test(%r)' % test_name] | 801 rw.GenTestsLines = ['yield api.test(%r)' % test_name] |
| 802 rw.add_expectation(test_name) | 802 rw.add_expectation(test_name) |
| 803 rw.write() | 803 rw.write() |
| 804 self._run_recipes('test', 'run', '--json', self.json_path) | 804 self._run_recipes('test', 'run', '--json', self.json_path) |
| 805 self.assertEqual(self.json_generator.get(), self.json_contents) | 805 self.assertEqual(self.json_generator.get(), self.json_contents) |
| 806 | 806 |
| 807 | 807 |
| 808 if __name__ == '__main__': | 808 if __name__ == '__main__': |
| 809 sys.exit(unittest.main()) | 809 sys.exit(unittest.main()) |
| OLD | NEW |