From 5357d1f52617d58f6151b9d17770d69385e6501e Mon Sep 17 00:00:00 2001 From: dineshbaburam91 Date: Fri, 3 Apr 2026 12:47:51 +0530 Subject: [PATCH 1/5] Added unit test case generator and code quality tool skills --- .github/skills/generate-test-cases/SKILL.md | 107 ++++++++++++++++++ .github/skills/run-code-quality-tool/SKILL.md | 56 +++++++++ 2 files changed, 163 insertions(+) create mode 100644 .github/skills/generate-test-cases/SKILL.md create mode 100644 .github/skills/run-code-quality-tool/SKILL.md diff --git a/.github/skills/generate-test-cases/SKILL.md b/.github/skills/generate-test-cases/SKILL.md new file mode 100644 index 000000000..86d2a4f54 --- /dev/null +++ b/.github/skills/generate-test-cases/SKILL.md @@ -0,0 +1,107 @@ +--- +name: generate-test-cases +description: "Use when source code changes under lib/jnpr/junos and the user wants unit tests created or updated for those changes." +allowed-tools: + - read_file + - file_search + - grep_search + - run_in_terminal + - apply_patch + - get_errors + - get_changed_files +context: fork +--- + +# Generate Unit Tests For PyEZ Source Changes + +## Goal +Create or update unit tests for code changes under `lib/jnpr/junos`, matching the existing project style in `tests/unit`. + +## Use This Skill When +- The user asks to write unit tests for modified source code. +- The requested scope is changes under `lib/jnpr/junos`. +- The user expects actual test files/edits, not only a coverage review. + +## Do Not Use This Skill When +- The task is only test planning or test-case enumeration without code changes. +- The task is functional/integration test authoring under `tests/functional`. + +## Required Workflow + +### 1) Detect changed source files +Collect changed files and keep only paths under `lib/jnpr/junos`. + +Preferred commands: +- `git diff --name-only -- lib/jnpr/junos` +- `git diff --name-only --cached -- lib/jnpr/junos` + +If both are empty, ask for the exact files or compare against the upstream default branch: +- `git diff --name-only origin/master...HEAD -- lib/jnpr/junos` + +### 2) Map source file to unit test location +Use these conventions first, then adjust to existing repository layout: +- `lib/jnpr/junos/device.py` -> `tests/unit/test_device.py` +- `lib/jnpr/junos/console.py` -> `tests/unit/test_console.py` +- `lib/jnpr/junos/facts/.py` -> `tests/unit/facts/test_.py` +- `lib/jnpr/junos/factory/.py` -> `tests/unit/factory/test_.py` +- `lib/jnpr/junos/utils/.py` -> `tests/unit/utils/test_.py` + +If no matching test file exists, create one in the appropriate test subdirectory with naming `test_.py`. + +### 3) Learn local testing style before writing +Read nearby tests and follow established conventions: +- `unittest`/`unittest2` style classes and `test_*` methods. +- Heavy use of `unittest.mock` (`patch`, `MagicMock`, `mock_open`). +- Keep fixtures and mocked RPC replies consistent with existing patterns in `tests/unit/**/rpc-reply`. + +### 4) Implement tests for behavior, not implementation details +Cover only behavior changed by the source diff. + +For each changed behavior, include positive and negative paths when applicable: +- successful path and return value/side effects +- raised exception or error mapping +- edge cases (None, empty input, malformed values) +- compatibility branches if present (for example Python-version or platform branches) + +Avoid brittle assertions on internal private state unless that is the public contract used across this repo. + +### 5) Keep edits minimal and scoped +- Do not refactor unrelated tests. +- Do not reformat unrelated files. +- Reuse existing helpers and fixtures before adding new ones. + +### 6) Validate quickly with targeted test runs +Install required dependencies before executing tests: +- `python -m pip install ntc_templates==1.4.1 textfsm==0.4.1 ` +- `python -m pip install -r requirements.txt` +- `python -m pip install nose2 junos-eznc` + + +Run generated/updated testcase modules first (targeted validation), for example: +- `nose2 -vvv tests.unit.facts.test_ --plugin nose2.plugins.junitxml --junit-xml` +- `nose2 -vvv tests.unit.test_ --plugin nose2.plugins.junitxml --junit-xml` + +Only after targeted tests pass, optionally run the broader unit suite: +- `nose2 -vvv tests.unit --plugin nose2.plugins.junitxml --junit-xml` + +### 7) Report results +Summarize: +- changed source files detected +- test files created/updated +- scenarios covered +- test command(s) run and pass/fail outcome +- remaining risks or uncovered branches + +Include the generated testcase execution output in verbose format from `nose2 -vvv`. +At minimum, include: +- one line per testcase with status (`... ok` / `... FAIL` / `... ERROR`) +- final summary block (`Ran X tests in Ys` and final status) + +## Output Contract +When this skill is invoked, the final response must include: +1. Source-to-test mapping used. +2. Exact test files modified. +3. What behaviors each new/updated test verifies. +4. Validation command summary and outcomes. +5. Verbose generated testcase output (or key excerpt) from `nose2 -vvv`. + diff --git a/.github/skills/run-code-quality-tool/SKILL.md b/.github/skills/run-code-quality-tool/SKILL.md new file mode 100644 index 000000000..986e6560e --- /dev/null +++ b/.github/skills/run-code-quality-tool/SKILL.md @@ -0,0 +1,56 @@ +--- +name: run-code-quality-tool +description: "Use when source code changes under lib/jnpr/junos and the user wants to run static code analysis and code format using pylint and ruff" +allowed-tools: + - run_in_terminal + - read_file + - get_changed_files + - grep_search +context: fork +--- + +# Run Code Quality Tool + +## Goal +Run formatting checks and static analysis for Python changes under `lib/jnpr/junos`. + +## Required Workflow + +### 1) Install required code-quality tools +Install pylint and ruff before running checks: +- `python -m pip install pylint ruff` + +### 2) Detect changed Python source files +Collect changed files under `lib/jnpr/junos` and keep only `.py` files. + +Preferred commands: +- `git diff --name-only -- lib/jnpr/junos | grep -E '\\.py$'` +- `git diff --name-only --cached -- lib/jnpr/junos | grep -E '\\.py$'` + +### 3) Run ruff format check for diff files +Run formatting check for only changed Python files under `lib/jnpr/junos`: +- `CHANGED=$( (git diff --name-only -- lib/jnpr/junos; git diff --name-only --cached -- lib/jnpr/junos) | grep -E '\\.py$' | sort -u )` +- `if [ -n "$CHANGED" ]; then echo "$CHANGED" | xargs -I{} ruff format --check "{}"; else echo "No changed Python files under lib/jnpr/junos"; fi` + +### 4) Run pylint for changed files under lib/jnpr/junos +Run pylint for only changed Python files first: +- `CHANGED=$( (git diff --name-only -- lib/jnpr/junos; git diff --name-only --cached -- lib/jnpr/junos) | grep -E '\\.py$' | sort -u )` +- `if [ -n "$CHANGED" ]; then pylint $CHANGED --exit-zero; else echo "No changed Python files under lib/jnpr/junos"; fi` + +### 5) Optional full ruff format for all Python files +If requested, run ruff format across all tracked Python files: +- `git ls-files '*.py' | xargs -I{} ruff format "{}"` + +### 6) Optional full pylint command +If requested, run the broader pylint command: +- `pylint $(git ls-files '*.py' | grep -vE '^(docs/|build/|tests/|samples/|setup.py|versioneer.py)') --exit-zero` + +## Output Contract +When this skill is invoked, the final response must include: +1. Changed Python files detected under `lib/jnpr/junos`. +2. `ruff format --check` result for changed files. +3. `pylint` result for changed files. +4. If optional full ruff format was run, include that result separately. +5. If full pylint was run, include that result separately. + + From da4b5598d18ef1670eed4f86106b8dad72d6d01f Mon Sep 17 00:00:00 2001 From: dineshbaburam91 Date: Thu, 16 Apr 2026 12:12:24 +0530 Subject: [PATCH 2/5] Supported routing instance option and satellite option in sw.install() API --- lib/jnpr/junos/utils/sw.py | 8 ++++++++ tests/unit/utils/test_sw.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/lib/jnpr/junos/utils/sw.py b/lib/jnpr/junos/utils/sw.py index d0964216a..4bebc9ef9 100644 --- a/lib/jnpr/junos/utils/sw.py +++ b/lib/jnpr/junos/utils/sw.py @@ -705,6 +705,8 @@ def install( cleanfs_timeout=300, checksum_timeout=300, checksum_algorithm="md5", + routing_instance=None, + satellite_name=None, force_copy=False, all_re=True, member_id=None, @@ -889,6 +891,12 @@ def _progress(report): self.log = _progress + if routing_instance is not None and "routing_instance" not in kwargs: + kwargs["routing_instance"] = routing_instance + + if satellite_name is not None and "device_list" not in kwargs: + kwargs["device_list"] = satellite_name + # --------------------------------------------------------------------- # Before doing anything, Do check if any pending install exists. # --------------------------------------------------------------------- diff --git a/tests/unit/utils/test_sw.py b/tests/unit/utils/test_sw.py index f4ee54c76..da7ff9c2c 100644 --- a/tests/unit/utils/test_sw.py +++ b/tests/unit/utils/test_sw.py @@ -866,6 +866,40 @@ def test_sw_install_kwargs_force_host(self, mock_execute): etree.tostring(mock_execute.call_args[0][0]).decode("utf-8") in rpc ) + @patch("jnpr.junos.Device.execute") + def test_sw_install_with_routing_instance(self, mock_execute): + self.sw.install("file", no_copy=True, routing_instance="mgmt_junos") + rpc = etree.tostring(mock_execute.call_args[0][0]).decode("utf-8") + self.assertTrue("mgmt_junos" in rpc) + + @patch("jnpr.junos.Device.execute") + def test_sw_install_with_satellite_name(self, mock_execute): + self.sw.install("file", no_copy=True, satellite_name="sat1") + rpc = etree.tostring(mock_execute.call_args[0][0]).decode("utf-8") + self.assertTrue("sat1" in rpc) + + @patch("jnpr.junos.Device.execute") + def test_sw_install_with_satellite_name_list(self, mock_execute): + self.sw.install("file", no_copy=True, satellite_name=["sat1", "sat2"]) + rpc = etree.tostring(mock_execute.call_args[0][0]).decode("utf-8") + self.assertTrue(rpc.count("") == 2) + self.assertTrue("sat1" in rpc) + self.assertTrue("sat2" in rpc) + + @patch("jnpr.junos.Device.execute") + def test_sw_install_issu_with_routing_instance(self, mock_execute): + self.sw.install( + "file", no_copy=True, issu=True, routing_instance="mgmt_junos" + ) + rpc = etree.tostring(mock_execute.call_args[0][0]).decode("utf-8") + self.assertTrue("mgmt_junos" in rpc) + + @patch("jnpr.junos.Device.execute") + def test_sw_install_nssu_with_satellite_name(self, mock_execute): + self.sw.install("file", no_copy=True, nssu=True, satellite_name="sat1") + rpc = etree.tostring(mock_execute.call_args[0][0]).decode("utf-8") + self.assertTrue("sat1" in rpc) + @patch("jnpr.junos.Device.execute") def test_sw_rollback(self, mock_execute): rsp = ( From 1398556d57667fe8d4288e324301d65e513bf723 Mon Sep 17 00:00:00 2001 From: dineshbaburam91 Date: Thu, 16 Apr 2026 12:56:06 +0530 Subject: [PATCH 3/5] Fixed ruff format --- tests/unit/utils/test_sw.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/unit/utils/test_sw.py b/tests/unit/utils/test_sw.py index da7ff9c2c..bd9c143a3 100644 --- a/tests/unit/utils/test_sw.py +++ b/tests/unit/utils/test_sw.py @@ -888,9 +888,7 @@ def test_sw_install_with_satellite_name_list(self, mock_execute): @patch("jnpr.junos.Device.execute") def test_sw_install_issu_with_routing_instance(self, mock_execute): - self.sw.install( - "file", no_copy=True, issu=True, routing_instance="mgmt_junos" - ) + self.sw.install("file", no_copy=True, issu=True, routing_instance="mgmt_junos") rpc = etree.tostring(mock_execute.call_args[0][0]).decode("utf-8") self.assertTrue("mgmt_junos" in rpc) From 10042e3314edb763952cc34025a18f467fdb9e52 Mon Sep 17 00:00:00 2001 From: Dinesh babu Date: Fri, 24 Apr 2026 12:44:59 +0530 Subject: [PATCH 4/5] Change Python installation commands to python3 Updated installation commands to use 'python3' instead of 'python'. --- .github/skills/generate-test-cases/SKILL.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/skills/generate-test-cases/SKILL.md b/.github/skills/generate-test-cases/SKILL.md index 86d2a4f54..5ad41749a 100644 --- a/.github/skills/generate-test-cases/SKILL.md +++ b/.github/skills/generate-test-cases/SKILL.md @@ -72,9 +72,9 @@ Avoid brittle assertions on internal private state unless that is the public con ### 6) Validate quickly with targeted test runs Install required dependencies before executing tests: -- `python -m pip install ntc_templates==1.4.1 textfsm==0.4.1 ` -- `python -m pip install -r requirements.txt` -- `python -m pip install nose2 junos-eznc` +- `python3 -m pip install ntc_templates==1.4.1 textfsm==0.4.1 ` +- `python3 -m pip install -r requirements.txt` +- `python3 -m pip install nose2 junos-eznc` Run generated/updated testcase modules first (targeted validation), for example: From 624682181a4b9100001141eddb8d4a014aaf5ff1 Mon Sep 17 00:00:00 2001 From: Dinesh babu Date: Fri, 24 Apr 2026 12:45:29 +0530 Subject: [PATCH 5/5] Update SKILL.md --- .github/skills/run-code-quality-tool/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/skills/run-code-quality-tool/SKILL.md b/.github/skills/run-code-quality-tool/SKILL.md index 986e6560e..242cc10f8 100644 --- a/.github/skills/run-code-quality-tool/SKILL.md +++ b/.github/skills/run-code-quality-tool/SKILL.md @@ -18,7 +18,7 @@ Run formatting checks and static analysis for Python changes under `lib/jnpr/jun ### 1) Install required code-quality tools Install pylint and ruff before running checks: -- `python -m pip install pylint ruff` +- `python3 -m pip install pylint ruff` ### 2) Detect changed Python source files Collect changed files under `lib/jnpr/junos` and keep only `.py` files.