|
7 | 7 |
|
8 | 8 | "github.com/j3ssie/osmedeus/v5/internal/config" |
9 | 9 | "github.com/j3ssie/osmedeus/v5/internal/core" |
| 10 | + "github.com/j3ssie/osmedeus/v5/internal/parser" |
10 | 11 | "github.com/stretchr/testify/assert" |
11 | 12 | "github.com/stretchr/testify/require" |
12 | 13 | ) |
@@ -1677,3 +1678,143 @@ func TestExecutor_StepDependencies_FailedDep_SkipsDependent(t *testing.T) { |
1677 | 1678 | assert.NotEqual(t, core.StepStatusSuccess, stepBExists) |
1678 | 1679 | } |
1679 | 1680 | } |
| 1681 | + |
| 1682 | +func TestExecutor_SkipModule(t *testing.T) { |
| 1683 | + ctx := context.Background() |
| 1684 | + cfg := testConfig(t) |
| 1685 | + |
| 1686 | + module := &core.Workflow{ |
| 1687 | + Name: "test-skip", |
| 1688 | + Kind: core.KindModule, |
| 1689 | + Steps: []core.Step{ |
| 1690 | + { |
| 1691 | + Name: "step-before", |
| 1692 | + Type: core.StepTypeFunction, |
| 1693 | + Function: "log_info('before skip')", |
| 1694 | + }, |
| 1695 | + { |
| 1696 | + Name: "step-skip", |
| 1697 | + Type: core.StepTypeFunction, |
| 1698 | + Function: "skip('target not applicable')", |
| 1699 | + }, |
| 1700 | + { |
| 1701 | + Name: "step-after", |
| 1702 | + Type: core.StepTypeFunction, |
| 1703 | + Function: "log_info('after skip')", |
| 1704 | + }, |
| 1705 | + }, |
| 1706 | + } |
| 1707 | + |
| 1708 | + executor := NewExecutor() |
| 1709 | + executor.SetDryRun(false) |
| 1710 | + executor.SetSpinner(false) |
| 1711 | + |
| 1712 | + result, err := executor.ExecuteModule(ctx, module, map[string]string{ |
| 1713 | + "target": "test", |
| 1714 | + }, cfg) |
| 1715 | + |
| 1716 | + // skip() returns nil error (not a failure) |
| 1717 | + require.NoError(t, err) |
| 1718 | + assert.Equal(t, core.RunStatusSkipped, result.Status) |
| 1719 | + assert.Equal(t, "target not applicable", result.Message) |
| 1720 | + |
| 1721 | + // step-before should have executed, step-after should NOT |
| 1722 | + assert.GreaterOrEqual(t, len(result.Steps), 2, "should have at least step-before and step-skip") |
| 1723 | + |
| 1724 | + // Find step-after in results - it should not be present |
| 1725 | + for _, s := range result.Steps { |
| 1726 | + assert.NotEqual(t, "step-after", s.StepName, "step-after should not have executed") |
| 1727 | + } |
| 1728 | +} |
| 1729 | + |
| 1730 | +func TestExecutor_SkipModulePreservesExports(t *testing.T) { |
| 1731 | + ctx := context.Background() |
| 1732 | + cfg := testConfig(t) |
| 1733 | + |
| 1734 | + module := &core.Workflow{ |
| 1735 | + Name: "test-skip-exports", |
| 1736 | + Kind: core.KindModule, |
| 1737 | + Steps: []core.Step{ |
| 1738 | + { |
| 1739 | + Name: "set-var", |
| 1740 | + Type: core.StepTypeFunction, |
| 1741 | + Function: "set_var('my_key', 'my_value')", |
| 1742 | + }, |
| 1743 | + { |
| 1744 | + Name: "do-skip", |
| 1745 | + Type: core.StepTypeFunction, |
| 1746 | + Function: "skip('done early')", |
| 1747 | + }, |
| 1748 | + }, |
| 1749 | + } |
| 1750 | + |
| 1751 | + executor := NewExecutor() |
| 1752 | + executor.SetDryRun(false) |
| 1753 | + executor.SetSpinner(false) |
| 1754 | + |
| 1755 | + result, err := executor.ExecuteModule(ctx, module, map[string]string{ |
| 1756 | + "target": "test", |
| 1757 | + }, cfg) |
| 1758 | + |
| 1759 | + require.NoError(t, err) |
| 1760 | + assert.Equal(t, core.RunStatusSkipped, result.Status) |
| 1761 | + assert.Equal(t, "done early", result.Message) |
| 1762 | +} |
| 1763 | + |
| 1764 | +func TestIsFuzzyModuleExcluded(t *testing.T) { |
| 1765 | + tests := []struct { |
| 1766 | + name string |
| 1767 | + moduleName string |
| 1768 | + fuzzyList []string |
| 1769 | + expected bool |
| 1770 | + }{ |
| 1771 | + {"exact substring match", "recon-spider", []string{"spider"}, true}, |
| 1772 | + {"prefix match", "spider-crawl", []string{"spider"}, true}, |
| 1773 | + {"no match", "recon-dns", []string{"spider"}, false}, |
| 1774 | + {"empty list", "recon-spider", nil, false}, |
| 1775 | + {"empty pattern list", "recon-spider", []string{}, false}, |
| 1776 | + {"multiple patterns first matches", "recon-spider", []string{"spider", "dns"}, true}, |
| 1777 | + {"multiple patterns second matches", "recon-dns", []string{"spider", "dns"}, true}, |
| 1778 | + {"multiple patterns none match", "recon-http", []string{"spider", "dns"}, false}, |
| 1779 | + {"full name as pattern", "recon-spider", []string{"recon-spider"}, true}, |
| 1780 | + } |
| 1781 | + |
| 1782 | + for _, tt := range tests { |
| 1783 | + t.Run(tt.name, func(t *testing.T) { |
| 1784 | + result := isFuzzyModuleExcluded(tt.moduleName, tt.fuzzyList) |
| 1785 | + assert.Equal(t, tt.expected, result) |
| 1786 | + }) |
| 1787 | + } |
| 1788 | +} |
| 1789 | + |
| 1790 | +func TestExecutor_FuzzyExcludeModules(t *testing.T) { |
| 1791 | + ctx := context.Background() |
| 1792 | + cfg := testConfig(t) |
| 1793 | + |
| 1794 | + // Create a flow where all modules will be excluded by fuzzy match |
| 1795 | + flow := &core.Workflow{ |
| 1796 | + Name: "test-fuzzy-exclude", |
| 1797 | + Kind: core.KindFlow, |
| 1798 | + Modules: []core.ModuleRef{ |
| 1799 | + {Name: "recon-spider", Path: ""}, |
| 1800 | + {Name: "spider-crawl", Path: ""}, |
| 1801 | + }, |
| 1802 | + } |
| 1803 | + |
| 1804 | + loader := parser.NewLoader(cfg.WorkflowsPath) |
| 1805 | + |
| 1806 | + exec := NewExecutor() |
| 1807 | + exec.SetDryRun(true) |
| 1808 | + exec.SetSpinner(false) |
| 1809 | + exec.SetLoader(loader) |
| 1810 | + |
| 1811 | + // fuzzy_exclude_modules=spider should skip both recon-spider and spider-crawl |
| 1812 | + result, err := exec.ExecuteFlow(ctx, flow, map[string]string{ |
| 1813 | + "target": "test.example.com", |
| 1814 | + "fuzzy_exclude_modules": "spider", |
| 1815 | + }, cfg) |
| 1816 | + |
| 1817 | + require.NoError(t, err) |
| 1818 | + assert.NotNil(t, result) |
| 1819 | + assert.Equal(t, core.RunStatusCompleted, result.Status) |
| 1820 | +} |
0 commit comments