diff --git a/docs/changelog-fragments.d/944.bugfix.md b/docs/changelog-fragments.d/944.bugfix.md new file mode 100644 index 000000000..42d45c54b --- /dev/null +++ b/docs/changelog-fragments.d/944.bugfix.md @@ -0,0 +1 @@ +Fixed presentation of unicode characters while using mode interactive. -- by {user}`cidrblock` diff --git a/src/ansible_navigator/_yaml.py b/src/ansible_navigator/_yaml.py index 6c4f9e80c..c681a0f22 100644 --- a/src/ansible_navigator/_yaml.py +++ b/src/ansible_navigator/_yaml.py @@ -27,6 +27,7 @@ class YamlStyle(NamedTuple): default_flow_style: bool = False explicit_start: bool = True + allow_unicode: bool = True def human_dump(obj: Any, filename: str = None, file_mode: str = "w") -> Union[str, None]: diff --git a/src/ansible_navigator/ui_framework/ui.py b/src/ansible_navigator/ui_framework/ui.py index a9c929629..1f0b7065e 100644 --- a/src/ansible_navigator/ui_framework/ui.py +++ b/src/ansible_navigator/ui_framework/ui.py @@ -502,7 +502,7 @@ def _serialize_color(self, obj: Any) -> CursesLines: if self.serialization_format() == "source.yaml": string = human_dump(obj) elif self.serialization_format() == "source.json": - string = json.dumps(obj, indent=4, sort_keys=True) + string = json.dumps(obj, indent=4, sort_keys=True, ensure_ascii=False) else: string = obj diff --git a/tests/fixtures/integration/actions/run_unicode/inventory b/tests/fixtures/integration/actions/run_unicode/inventory new file mode 100644 index 000000000..2fbb50c4a --- /dev/null +++ b/tests/fixtures/integration/actions/run_unicode/inventory @@ -0,0 +1 @@ +localhost diff --git a/tests/fixtures/integration/actions/run_unicode/site.yaml b/tests/fixtures/integration/actions/run_unicode/site.yaml new file mode 100644 index 000000000..e6f51dbbc --- /dev/null +++ b/tests/fixtures/integration/actions/run_unicode/site.yaml @@ -0,0 +1,11 @@ +- name: Simple unicode output test + hosts: localhost + connection: local + gather_facts: false + tasks: + - name: Raw with unicode arg and output + raw: echo 航海家 + register: output + - name: Debug the output + debug: + var: output diff --git a/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_ee.py/test/0.json b/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_ee.py/test/0.json new file mode 100644 index 000000000..723e520a7 --- /dev/null +++ b/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_ee.py/test/0.json @@ -0,0 +1,15 @@ +{ + "name": "test[0-ansible-navigator run /tests/fixtures/integration/actions/run_unicode/site.yaml -i /tests/fixtures/integration/actions/run_unicode/inventory --ee True --ll debug --mode interactive-ansible-navigator run playbook]", + "index": 0, + "comment": "ansible-navigator run playbook", + "additional_information": { + "present": [], + "absent": [], + "compared_fixture": true + }, + "output": [ + " PLAY NAME OK CHANGED UNREACHABLE FAILED SKIPPED IGNORED IN PROGRESS TASK COUNT PROGRESS", + "0│Simple unicode output test 2 1 0 0 0 0 0 2 COMPLETE", + "^f/PgUp page up ^b/PgDn page down ↑↓ scroll esc back [0-9] goto :help help SUCCESSFUL" + ] +} diff --git a/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_ee.py/test/1.json b/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_ee.py/test/1.json new file mode 100644 index 000000000..470d2d238 --- /dev/null +++ b/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_ee.py/test/1.json @@ -0,0 +1,16 @@ +{ + "name": "test[1-:0-play-1 details]", + "index": 1, + "comment": "play-1 details", + "additional_information": { + "present": [], + "absent": [], + "compared_fixture": true + }, + "output": [ + " RESULT HOST NUMBER CHANGED TASK TASK ACTION DURATION", + "0│OK localhost 0 True Raw with unicode arg and output raw 0s", + "1│OK localhost 1 False Debug the output debug 0s", + "^f/PgUp page up ^b/PgDn page down ↑↓ scroll esc back [0-9] goto :help help SUCCESSFUL" + ] +} diff --git a/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_ee.py/test/2.json b/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_ee.py/test/2.json new file mode 100644 index 000000000..c458982d6 --- /dev/null +++ b/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_ee.py/test/2.json @@ -0,0 +1,42 @@ +{ + "name": "test[2-:0-task-1 yaml]", + "index": 2, + "comment": "task-1 yaml", + "additional_information": { + "present": [ + "航海家" + ], + "absent": [], + "compared_fixture": false + }, + "output": [ + "PLAY [Simple unicode output test:0] ********************************************************************************************************************************************************************", + "TASK [Raw with unicode arg and output] *****************************************************************************************************************************************************************", + "CHANGED: [localhost]", + " 0│---", + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + " 3│event_loop: null", + " 4│host: localhost", + " 5│play: Simple unicode output test", + " 6│play_pattern: localhost", + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + " 8│remote_addr: localhost", + " 9│res:", + "10│ _ansible_no_log: false", + "11│ changed: true", + "12│ rc: 0", + "13│ stderr: ''", + "14│ stderr_lines: []", + "15│ stdout: |-", + "16│ 航海家", + "17│ stdout_lines:", + "18│ - 航海家", + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + "20│task: Raw with unicode arg and output", + "21│task_action: raw", + "22│task_args: ''", + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + "^f/PgUp page up ^b/PgDn page down ↑↓ scroll esc back - previous + next [0-9] goto :help help SUCCESSFUL" + ] +} diff --git a/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_ee.py/test/3.json b/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_ee.py/test/3.json new file mode 100644 index 000000000..341bb87ba --- /dev/null +++ b/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_ee.py/test/3.json @@ -0,0 +1,44 @@ +{ + "name": "test[3-:json-task-1 json]", + "index": 3, + "comment": "task-1 json", + "additional_information": { + "present": [ + "航海家" + ], + "absent": [], + "compared_fixture": false + }, + "output": [ + "PLAY [Simple unicode output test:0] ********************************************************************************************************************************************************************", + "TASK [Raw with unicode arg and output] *****************************************************************************************************************************************************************", + "CHANGED: [localhost]", + " 0│{", + " 1│ \"duration\": 0.057188,", + " 2│ \"end\": \"2022-02-13T18:28:45.394242\",", + " 3│ \"event_loop\": null,", + " 4│ \"host\": \"localhost\",", + " 5│ \"play\": \"Simple unicode output test\",", + " 6│ \"play_pattern\": \"localhost\",", + " 7│ \"playbook\": \"/home/user/github/ansible-navigator/tests/fixtures/integration/actions/run_unicode/site.yaml\",", + " 8│ \"remote_addr\": \"localhost\",", + " 9│ \"res\": {", + "10│ \"_ansible_no_log\": false,", + "11│ \"changed\": true,", + "12│ \"rc\": 0,", + "13│ \"stderr\": \"\",", + "14│ \"stderr_lines\": [],", + "15│ \"stdout\": \"航海家,n\"", + "16│ \"stdout_lines\": [", + "17│ \"航海家\"", + "18│ ]", + "19│ },", + "20│ \"start\": \"2022-02-13T18:28:45.337054\",", + "21│ \"task\": \"Raw with unicode arg and output\",", + "22│ \"task_action\": \"raw\",", + "23│ \"task_args\": \"\",", + "24│ \"task_path\": \"/home/user/github/ansible-navigator/tests/fixtures/integration/actions/run_unicode/site.yaml:6\"", + "25│}", + "^f/PgUp page up ^b/PgDn page down ↑↓ scroll esc back - previous + next [0-9] goto :help help SUCCESSFUL" + ] +} diff --git a/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_ee.py/test/4.json b/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_ee.py/test/4.json new file mode 100644 index 000000000..33fc0daa5 --- /dev/null +++ b/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_ee.py/test/4.json @@ -0,0 +1,16 @@ +{ + "name": "test[4-:back-play-1 details]", + "index": 4, + "comment": "play-1 details", + "additional_information": { + "present": [], + "absent": [], + "compared_fixture": true + }, + "output": [ + " RESULT HOST NUMBER CHANGED TASK TASK ACTION DURATION", + "0│OK localhost 0 True Raw with unicode arg and output raw 0s", + "1│OK localhost 1 False Debug the output debug 0s", + "^f/PgUp page up ^b/PgDn page down ↑↓ scroll esc back [0-9] goto :help help SUCCESSFUL" + ] +} diff --git a/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_ee.py/test/5.json b/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_ee.py/test/5.json new file mode 100644 index 000000000..a143dca77 --- /dev/null +++ b/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_ee.py/test/5.json @@ -0,0 +1,49 @@ +{ + "name": "test[5-:1-task-2 json]", + "index": 5, + "comment": "task-2 json", + "additional_information": { + "present": [ + "航海家" + ], + "absent": [], + "compared_fixture": false + }, + "output": [ + "PLAY [Simple unicode output test:1] ********************************************************************************************************************************************************************", + "TASK [Debug the output] ********************************************************************************************************************************************************************************", + "OK: [localhost]", + " 0│{", + " 1│ \"duration\": 0.109558,", + " 2│ \"end\": \"2022-02-13T18:28:45.525577\",", + " 3│ \"event_loop\": null,", + " 4│ \"host\": \"localhost\",", + " 5│ \"play\": \"Simple unicode output test\",", + " 6│ \"play_pattern\": \"localhost\",", + " 7│ \"playbook\": \"/home/user/github/ansible-navigator/tests/fixtures/integration/actions/run_unicode/site.yaml\",", + " 8│ \"remote_addr\": \"localhost\",", + " 9│ \"res\": {", + "10│ \"_ansible_no_log\": false,", + "11│ \"_ansible_verbose_always\": true,", + "12│ \"changed\": false,", + "13│ \"output\": {", + "14│ \"changed\": true,", + "15│ \"failed\": false,", + "16│ \"rc\": 0,", + "17│ \"stderr\": \"\",", + "18│ \"stderr_lines\": [],", + "19│ \"stdout\": \"航海家,n\"", + "20│ \"stdout_lines\": [", + "21│ \"航海家\"", + "22│ ]", + "23│ }", + "24│ },", + "25│ \"start\": \"2022-02-13T18:28:45.416019\",", + "26│ \"task\": \"Debug the output\",", + "27│ \"task_action\": \"debug\",", + "28│ \"task_args\": \"\",", + "29│ \"task_path\": \"/home/user/github/ansible-navigator/tests/fixtures/integration/actions/run_unicode/site.yaml:9\"", + "30│}", + "^f/PgUp page up ^b/PgDn page down ↑↓ scroll esc back - previous + next [0-9] goto :help help SUCCESSFUL" + ] +} diff --git a/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_ee.py/test/6.json b/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_ee.py/test/6.json new file mode 100644 index 000000000..6f7c02b39 --- /dev/null +++ b/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_ee.py/test/6.json @@ -0,0 +1,46 @@ +{ + "name": "test[6-:yaml-task-2 yaml]", + "index": 6, + "comment": "task-2 yaml", + "additional_information": { + "present": [ + "航海家" + ], + "absent": [], + "compared_fixture": false + }, + "output": [ + "PLAY [Simple unicode output test:1] ********************************************************************************************************************************************************************", + "TASK [Debug the output] ********************************************************************************************************************************************************************************", + "OK: [localhost]", + " 0│---", + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + " 3│event_loop: null", + " 4│host: localhost", + " 5│play: Simple unicode output test", + " 6│play_pattern: localhost", + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + " 8│remote_addr: localhost", + " 9│res:", + "10│ _ansible_no_log: false", + "11│ _ansible_verbose_always: true", + "12│ changed: false", + "13│ output:", + "14│ changed: true", + "15│ failed: false", + "16│ rc: 0", + "17│ stderr: ''", + "18│ stderr_lines: []", + "19│ stdout: |-", + "20│ 航海家", + "21│ stdout_lines:", + "22│ - 航海家", + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + "24│task: Debug the output", + "25│task_action: debug", + "26│task_args: ''", + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + "^f/PgUp page up ^b/PgDn page down ↑↓ scroll esc back - previous + next [0-9] goto :help help SUCCESSFUL" + ] +} diff --git a/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_ee.py/test/7.json b/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_ee.py/test/7.json new file mode 100644 index 000000000..20bd46459 --- /dev/null +++ b/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_ee.py/test/7.json @@ -0,0 +1,16 @@ +{ + "name": "test[7-:back-play-1 details]", + "index": 7, + "comment": "play-1 details", + "additional_information": { + "present": [], + "absent": [], + "compared_fixture": true + }, + "output": [ + " RESULT HOST NUMBER CHANGED TASK TASK ACTION DURATION", + "0│OK localhost 0 True Raw with unicode arg and output raw 0s", + "1│OK localhost 1 False Debug the output debug 0s", + "^f/PgUp page up ^b/PgDn page down ↑↓ scroll esc back [0-9] goto :help help SUCCESSFUL" + ] +} diff --git a/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_ee.py/test/8.json b/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_ee.py/test/8.json new file mode 100644 index 000000000..33ba4ff3c --- /dev/null +++ b/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_ee.py/test/8.json @@ -0,0 +1,15 @@ +{ + "name": "test[8-:back-all play details]", + "index": 8, + "comment": "all play details", + "additional_information": { + "present": [], + "absent": [], + "compared_fixture": true + }, + "output": [ + " PLAY NAME OK CHANGED UNREACHABLE FAILED SKIPPED IGNORED IN PROGRESS TASK COUNT PROGRESS", + "0│Simple unicode output test 2 1 0 0 0 0 0 2 COMPLETE", + "^f/PgUp page up ^b/PgDn page down ↑↓ scroll esc back [0-9] goto :help help SUCCESSFUL" + ] +} diff --git a/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_ee.py/test/9.json b/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_ee.py/test/9.json new file mode 100644 index 000000000..76528905a --- /dev/null +++ b/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_ee.py/test/9.json @@ -0,0 +1,36 @@ +{ + "name": "test[9-:st-display stream]", + "index": 9, + "comment": "display stream", + "additional_information": { + "present": [], + "absent": [], + "compared_fixture": true + }, + "output": [ + " 0│", + " 1│PLAY [Simple unicode output test] **********************************************", + " 2│", + " 3│TASK [Raw with unicode arg and output] *****************************************", + " 4│changed: [localhost]", + " 5│", + " 6│TASK [Debug the output] ********************************************************", + " 7│ok: [localhost] => {", + " 8│ \"output\": {", + " 9│ \"changed\": true,", + "10│ \"failed\": false,", + "11│ \"rc\": 0,", + "12│ \"stderr\": \"\",", + "13│ \"stderr_lines\": [],", + "14│ \"stdout\": \"航海家\\n\",", + "15│ \"stdout_lines\": [", + "16│ \"航海家\"", + "17│ ]", + "18│ }", + "19│}", + "20│", + "21│PLAY RECAP *********************************************************************", + "22│localhost : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0", + "^f/PgUp page up ^b/PgDn page down ↑↓ scroll esc back :help help SUCCESSFUL" + ] +} diff --git a/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_noee.py/test/0.json b/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_noee.py/test/0.json new file mode 100644 index 000000000..33e4862a5 --- /dev/null +++ b/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_noee.py/test/0.json @@ -0,0 +1,15 @@ +{ + "name": "test[0-ansible-navigator run /tests/fixtures/integration/actions/run_unicode/site.yaml -i /tests/fixtures/integration/actions/run_unicode/inventory --ee False --ll debug --mode interactive-ansible-navigator run playbook]", + "index": 0, + "comment": "ansible-navigator run playbook", + "additional_information": { + "present": [], + "absent": [], + "compared_fixture": true + }, + "output": [ + " PLAY NAME OK CHANGED UNREACHABLE FAILED SKIPPED IGNORED IN PROGRESS TASK COUNT PROGRESS", + "0│Simple unicode output test 2 1 0 0 0 0 0 2 COMPLETE", + "^f/PgUp page up ^b/PgDn page down ↑↓ scroll esc back [0-9] goto :help help SUCCESSFUL" + ] +} diff --git a/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_noee.py/test/1.json b/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_noee.py/test/1.json new file mode 100644 index 000000000..470d2d238 --- /dev/null +++ b/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_noee.py/test/1.json @@ -0,0 +1,16 @@ +{ + "name": "test[1-:0-play-1 details]", + "index": 1, + "comment": "play-1 details", + "additional_information": { + "present": [], + "absent": [], + "compared_fixture": true + }, + "output": [ + " RESULT HOST NUMBER CHANGED TASK TASK ACTION DURATION", + "0│OK localhost 0 True Raw with unicode arg and output raw 0s", + "1│OK localhost 1 False Debug the output debug 0s", + "^f/PgUp page up ^b/PgDn page down ↑↓ scroll esc back [0-9] goto :help help SUCCESSFUL" + ] +} diff --git a/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_noee.py/test/2.json b/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_noee.py/test/2.json new file mode 100644 index 000000000..c458982d6 --- /dev/null +++ b/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_noee.py/test/2.json @@ -0,0 +1,42 @@ +{ + "name": "test[2-:0-task-1 yaml]", + "index": 2, + "comment": "task-1 yaml", + "additional_information": { + "present": [ + "航海家" + ], + "absent": [], + "compared_fixture": false + }, + "output": [ + "PLAY [Simple unicode output test:0] ********************************************************************************************************************************************************************", + "TASK [Raw with unicode arg and output] *****************************************************************************************************************************************************************", + "CHANGED: [localhost]", + " 0│---", + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + " 3│event_loop: null", + " 4│host: localhost", + " 5│play: Simple unicode output test", + " 6│play_pattern: localhost", + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + " 8│remote_addr: localhost", + " 9│res:", + "10│ _ansible_no_log: false", + "11│ changed: true", + "12│ rc: 0", + "13│ stderr: ''", + "14│ stderr_lines: []", + "15│ stdout: |-", + "16│ 航海家", + "17│ stdout_lines:", + "18│ - 航海家", + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + "20│task: Raw with unicode arg and output", + "21│task_action: raw", + "22│task_args: ''", + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + "^f/PgUp page up ^b/PgDn page down ↑↓ scroll esc back - previous + next [0-9] goto :help help SUCCESSFUL" + ] +} diff --git a/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_noee.py/test/3.json b/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_noee.py/test/3.json new file mode 100644 index 000000000..f3b908703 --- /dev/null +++ b/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_noee.py/test/3.json @@ -0,0 +1,44 @@ +{ + "name": "test[3-:json-task-1 json]", + "index": 3, + "comment": "task-1 json", + "additional_information": { + "present": [ + "航海家" + ], + "absent": [], + "compared_fixture": false + }, + "output": [ + "PLAY [Simple unicode output test:0] ********************************************************************************************************************************************************************", + "TASK [Raw with unicode arg and output] *****************************************************************************************************************************************************************", + "CHANGED: [localhost]", + " 0│{", + " 1│ \"duration\": 0.040641,", + " 2│ \"end\": \"2022-02-13T18:28:55.230601\",", + " 3│ \"event_loop\": null,", + " 4│ \"host\": \"localhost\",", + " 5│ \"play\": \"Simple unicode output test\",", + " 6│ \"play_pattern\": \"localhost\",", + " 7│ \"playbook\": \"/home/user/github/ansible-navigator/tests/fixtures/integration/actions/run_unicode/site.yaml\",", + " 8│ \"remote_addr\": \"localhost\",", + " 9│ \"res\": {", + "10│ \"_ansible_no_log\": false,", + "11│ \"changed\": true,", + "12│ \"rc\": 0,", + "13│ \"stderr\": \"\",", + "14│ \"stderr_lines\": [],", + "15│ \"stdout\": \"航海家,n\"", + "16│ \"stdout_lines\": [", + "17│ \"航海家\"", + "18│ ]", + "19│ },", + "20│ \"start\": \"2022-02-13T18:28:55.189960\",", + "21│ \"task\": \"Raw with unicode arg and output\",", + "22│ \"task_action\": \"raw\",", + "23│ \"task_args\": \"\",", + "24│ \"task_path\": \"/home/user/github/ansible-navigator/tests/fixtures/integration/actions/run_unicode/site.yaml:6\"", + "25│}", + "^f/PgUp page up ^b/PgDn page down ↑↓ scroll esc back - previous + next [0-9] goto :help help SUCCESSFUL" + ] +} diff --git a/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_noee.py/test/4.json b/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_noee.py/test/4.json new file mode 100644 index 000000000..33fc0daa5 --- /dev/null +++ b/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_noee.py/test/4.json @@ -0,0 +1,16 @@ +{ + "name": "test[4-:back-play-1 details]", + "index": 4, + "comment": "play-1 details", + "additional_information": { + "present": [], + "absent": [], + "compared_fixture": true + }, + "output": [ + " RESULT HOST NUMBER CHANGED TASK TASK ACTION DURATION", + "0│OK localhost 0 True Raw with unicode arg and output raw 0s", + "1│OK localhost 1 False Debug the output debug 0s", + "^f/PgUp page up ^b/PgDn page down ↑↓ scroll esc back [0-9] goto :help help SUCCESSFUL" + ] +} diff --git a/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_noee.py/test/5.json b/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_noee.py/test/5.json new file mode 100644 index 000000000..3c10a19cd --- /dev/null +++ b/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_noee.py/test/5.json @@ -0,0 +1,49 @@ +{ + "name": "test[5-:1-task-2 json]", + "index": 5, + "comment": "task-2 json", + "additional_information": { + "present": [ + "航海家" + ], + "absent": [], + "compared_fixture": false + }, + "output": [ + "PLAY [Simple unicode output test:1] ********************************************************************************************************************************************************************", + "TASK [Debug the output] ********************************************************************************************************************************************************************************", + "OK: [localhost]", + " 0│{", + " 1│ \"duration\": 0.045443,", + " 2│ \"end\": \"2022-02-13T18:28:55.302230\",", + " 3│ \"event_loop\": null,", + " 4│ \"host\": \"localhost\",", + " 5│ \"play\": \"Simple unicode output test\",", + " 6│ \"play_pattern\": \"localhost\",", + " 7│ \"playbook\": \"/home/user/github/ansible-navigator/tests/fixtures/integration/actions/run_unicode/site.yaml\",", + " 8│ \"remote_addr\": \"localhost\",", + " 9│ \"res\": {", + "10│ \"_ansible_no_log\": false,", + "11│ \"_ansible_verbose_always\": true,", + "12│ \"changed\": false,", + "13│ \"output\": {", + "14│ \"changed\": true,", + "15│ \"failed\": false,", + "16│ \"rc\": 0,", + "17│ \"stderr\": \"\",", + "18│ \"stderr_lines\": [],", + "19│ \"stdout\": \"航海家,n\"", + "20│ \"stdout_lines\": [", + "21│ \"航海家\"", + "22│ ]", + "23│ }", + "24│ },", + "25│ \"start\": \"2022-02-13T18:28:55.256787\",", + "26│ \"task\": \"Debug the output\",", + "27│ \"task_action\": \"debug\",", + "28│ \"task_args\": \"\",", + "29│ \"task_path\": \"/home/user/github/ansible-navigator/tests/fixtures/integration/actions/run_unicode/site.yaml:9\"", + "30│}", + "^f/PgUp page up ^b/PgDn page down ↑↓ scroll esc back - previous + next [0-9] goto :help help SUCCESSFUL" + ] +} diff --git a/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_noee.py/test/6.json b/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_noee.py/test/6.json new file mode 100644 index 000000000..6f7c02b39 --- /dev/null +++ b/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_noee.py/test/6.json @@ -0,0 +1,46 @@ +{ + "name": "test[6-:yaml-task-2 yaml]", + "index": 6, + "comment": "task-2 yaml", + "additional_information": { + "present": [ + "航海家" + ], + "absent": [], + "compared_fixture": false + }, + "output": [ + "PLAY [Simple unicode output test:1] ********************************************************************************************************************************************************************", + "TASK [Debug the output] ********************************************************************************************************************************************************************************", + "OK: [localhost]", + " 0│---", + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + " 3│event_loop: null", + " 4│host: localhost", + " 5│play: Simple unicode output test", + " 6│play_pattern: localhost", + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + " 8│remote_addr: localhost", + " 9│res:", + "10│ _ansible_no_log: false", + "11│ _ansible_verbose_always: true", + "12│ changed: false", + "13│ output:", + "14│ changed: true", + "15│ failed: false", + "16│ rc: 0", + "17│ stderr: ''", + "18│ stderr_lines: []", + "19│ stdout: |-", + "20│ 航海家", + "21│ stdout_lines:", + "22│ - 航海家", + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + "24│task: Debug the output", + "25│task_action: debug", + "26│task_args: ''", + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + "^f/PgUp page up ^b/PgDn page down ↑↓ scroll esc back - previous + next [0-9] goto :help help SUCCESSFUL" + ] +} diff --git a/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_noee.py/test/7.json b/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_noee.py/test/7.json new file mode 100644 index 000000000..20bd46459 --- /dev/null +++ b/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_noee.py/test/7.json @@ -0,0 +1,16 @@ +{ + "name": "test[7-:back-play-1 details]", + "index": 7, + "comment": "play-1 details", + "additional_information": { + "present": [], + "absent": [], + "compared_fixture": true + }, + "output": [ + " RESULT HOST NUMBER CHANGED TASK TASK ACTION DURATION", + "0│OK localhost 0 True Raw with unicode arg and output raw 0s", + "1│OK localhost 1 False Debug the output debug 0s", + "^f/PgUp page up ^b/PgDn page down ↑↓ scroll esc back [0-9] goto :help help SUCCESSFUL" + ] +} diff --git a/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_noee.py/test/8.json b/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_noee.py/test/8.json new file mode 100644 index 000000000..33ba4ff3c --- /dev/null +++ b/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_noee.py/test/8.json @@ -0,0 +1,15 @@ +{ + "name": "test[8-:back-all play details]", + "index": 8, + "comment": "all play details", + "additional_information": { + "present": [], + "absent": [], + "compared_fixture": true + }, + "output": [ + " PLAY NAME OK CHANGED UNREACHABLE FAILED SKIPPED IGNORED IN PROGRESS TASK COUNT PROGRESS", + "0│Simple unicode output test 2 1 0 0 0 0 0 2 COMPLETE", + "^f/PgUp page up ^b/PgDn page down ↑↓ scroll esc back [0-9] goto :help help SUCCESSFUL" + ] +} diff --git a/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_noee.py/test/9.json b/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_noee.py/test/9.json new file mode 100644 index 000000000..76528905a --- /dev/null +++ b/tests/fixtures/integration/actions/run_unicode/test_direct_interactive_noee.py/test/9.json @@ -0,0 +1,36 @@ +{ + "name": "test[9-:st-display stream]", + "index": 9, + "comment": "display stream", + "additional_information": { + "present": [], + "absent": [], + "compared_fixture": true + }, + "output": [ + " 0│", + " 1│PLAY [Simple unicode output test] **********************************************", + " 2│", + " 3│TASK [Raw with unicode arg and output] *****************************************", + " 4│changed: [localhost]", + " 5│", + " 6│TASK [Debug the output] ********************************************************", + " 7│ok: [localhost] => {", + " 8│ \"output\": {", + " 9│ \"changed\": true,", + "10│ \"failed\": false,", + "11│ \"rc\": 0,", + "12│ \"stderr\": \"\",", + "13│ \"stderr_lines\": [],", + "14│ \"stdout\": \"航海家\\n\",", + "15│ \"stdout_lines\": [", + "16│ \"航海家\"", + "17│ ]", + "18│ }", + "19│}", + "20│", + "21│PLAY RECAP *********************************************************************", + "22│localhost : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0", + "^f/PgUp page up ^b/PgDn page down ↑↓ scroll esc back :help help SUCCESSFUL" + ] +} diff --git a/tests/fixtures/integration/actions/run_unicode/test_stdout_tmux.py/test/0.json b/tests/fixtures/integration/actions/run_unicode/test_stdout_tmux.py/test/0.json new file mode 100644 index 000000000..8722b04c6 --- /dev/null +++ b/tests/fixtures/integration/actions/run_unicode/test_stdout_tmux.py/test/0.json @@ -0,0 +1,36 @@ +{ + "name": "test[run playbook with ee clear && ansible-navigator run /tests/fixtures/integration/actions/run_unicode/site.yaml -i /tests/fixtures/integration/actions/run_unicode/inventory --pae false --ee True --ll debug --mode stdout]", + "index": 0, + "comment": "run playbook with ee", + "additional_information": { + "present": [ + "航海家", + "ok=2", + "failed=0" + ], + "absent": [], + "compared_fixture": false + }, + "output": [ + "PLAY [Simple unicode output test] **********************************************************************************************************************************************************************", + "TASK [Raw with unicode arg and output] *****************************************************************************************************************************************************************", + "changed: [localhost]", + "TASK [Debug the output] ********************************************************************************************************************************************************************************", + "ok: [localhost] => {", + " \"output\": {", + " \"changed\": true,", + " \"failed\": false,", + " \"rc\": 0,", + " \"stderr\": \"\",", + " \"stderr_lines\": [],", + " \"stdout\": \"航海家\\n\",", + " \"stdout_lines\": [", + " \"航海家\"", + " ]", + " }", + "}", + "PLAY RECAP *********************************************************************************************************************************************************************************************", + "localhost : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0", + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + ] +} diff --git a/tests/fixtures/integration/actions/run_unicode/test_stdout_tmux.py/test/1.json b/tests/fixtures/integration/actions/run_unicode/test_stdout_tmux.py/test/1.json new file mode 100644 index 000000000..597380184 --- /dev/null +++ b/tests/fixtures/integration/actions/run_unicode/test_stdout_tmux.py/test/1.json @@ -0,0 +1,36 @@ +{ + "name": "test[run playbook without ee clear && ansible-navigator run /tests/fixtures/integration/actions/run_unicode/site.yaml -i /tests/fixtures/integration/actions/run_unicode/inventory --pae false --ee False --ll debug --mode stdout]", + "index": 1, + "comment": "run playbook without ee", + "additional_information": { + "present": [ + "航海家", + "ok=2", + "failed=0" + ], + "absent": [], + "compared_fixture": false + }, + "output": [ + "PLAY [Simple unicode output test] **********************************************************************************************************************************************************************", + "TASK [Raw with unicode arg and output] *****************************************************************************************************************************************************************", + "changed: [localhost]", + "TASK [Debug the output] ********************************************************************************************************************************************************************************", + "ok: [localhost] => {", + " \"output\": {", + " \"changed\": true,", + " \"failed\": false,", + " \"rc\": 0,", + " \"stderr\": \"\",", + " \"stderr_lines\": [],", + " \"stdout\": \"航海家\\n\",", + " \"stdout_lines\": [", + " \"航海家\"", + " ]", + " }", + "}", + "PLAY RECAP *********************************************************************************************************************************************************************************************", + "localhost : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0", + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + ] +} diff --git a/tests/integration/actions/run_unicode/__init__.py b/tests/integration/actions/run_unicode/__init__.py new file mode 100644 index 000000000..9128d16c7 --- /dev/null +++ b/tests/integration/actions/run_unicode/__init__.py @@ -0,0 +1 @@ +"""Integration tests for the ``run`` subcommand, confirming unicode output.""" diff --git a/tests/integration/actions/run_unicode/base.py b/tests/integration/actions/run_unicode/base.py new file mode 100644 index 000000000..fc448e66f --- /dev/null +++ b/tests/integration/actions/run_unicode/base.py @@ -0,0 +1,128 @@ +"""Base class for run interactive/stdout tests, with unicode.""" +import difflib +import os + +from typing import List +from typing import Optional +from typing import Union + +import pytest + +from ....defaults import FIXTURES_DIR +from ..._common import retrieve_fixture_for_step +from ..._common import update_fixtures +from ..._interactions import SearchFor +from ..._interactions import UiTestStep +from ..._tmux_session import TmuxSession + + +# run playbook +run_fixture_dir = os.path.join(FIXTURES_DIR, "integration", "actions", "run_unicode") +inventory_path = os.path.join(run_fixture_dir, "inventory") +playbook_path = os.path.join(run_fixture_dir, "site.yaml") + +base_steps = ( + UiTestStep(user_input=":0", comment="play-1 details"), + UiTestStep(user_input=":0", comment="task-1 yaml", present=["航海家"]), + UiTestStep(user_input=":json", comment="task-1 json", present=["航海家"]), + UiTestStep(user_input=":back", comment="play-1 details"), + UiTestStep(user_input=":1", comment="task-2 json", present=["航海家"]), + UiTestStep(user_input=":yaml", comment="task-2 yaml", present=["航海家"]), + UiTestStep(user_input=":back", comment="play-1 details"), + UiTestStep(user_input=":back", comment="all play details"), + UiTestStep(user_input=":st", comment="display stream"), +) + + +class BaseClass: + """Base class for run interactive/stdout tests, with unicode.""" + + UPDATE_FIXTURES = False + TEST_FOR_MODE: Optional[str] = None + + @staticmethod + @pytest.fixture(scope="module", name="tmux_session") + def fixture_tmux_session(request: pytest.FixtureRequest): + """Tmux fixture for this module. + + :param request: The request for this fixture from a test + :yields: A tmux session + """ + params = { + "pane_height": "100", + "setup_commands": [ + "export ANSIBLE_DEVEL_WARNING=False", + "export ANSIBLE_DEPRECATION_WARNINGS=False", + ], + "unique_test_id": request.node.nodeid, + } + with TmuxSession(**params) as tmux_session: + yield tmux_session + + def test( + self, + request: pytest.FixtureRequest, + tmux_session: pytest.FixtureRequest, + step: UiTestStep, + ): + # pylint: disable=too-many-branches + """Run the tests for run, mode and ``ee`` set in child class. + + :param request: The request for a test + :param tmux_session: The tmux session + :param step: A step within a series of tests + """ + search_within_response: Union[str, List[str]] + if step.search_within_response is SearchFor.HELP: + search_within_response = ":help help" + elif step.search_within_response is SearchFor.PROMPT: + search_within_response = tmux_session.cli_prompt + else: + search_within_response = step.search_within_response + + received_output = tmux_session.interaction( + value=step.user_input, + search_within_response=search_within_response, + ) + + if step.mask: + # mask out some configuration that is subject to change each run + mask = "X" * 50 + for idx, line in enumerate(received_output): + if tmux_session.cli_prompt in line: + received_output[idx] = mask + else: + for out in ["duration:", "playbook:", "start:", "end:", "task_path:"]: + if out in line: + received_output[idx] = mask + + fixtures_update_requested = ( + self.UPDATE_FIXTURES + or os.environ.get("ANSIBLE_NAVIGATOR_UPDATE_TEST_FIXTURES") == "true" + ) + if fixtures_update_requested: + update_fixtures( + request, + step.step_index, + received_output, + step.comment, + additional_information={ + "present": step.present, + "absent": step.absent, + "compared_fixture": not any((step.present, step.absent)), + }, + ) + page = " ".join(received_output) + + if step.present: + assert all(present in page for present in step.present) + + if step.absent: + assert not any(absent in page for absent in step.absent) + + if not any((step.present, step.absent)): + expected_output = retrieve_fixture_for_step(request, step.step_index) + + assert expected_output == received_output, "\n" + "\n".join( + difflib.unified_diff(expected_output, received_output, "expected", "received"), + ) diff --git a/tests/integration/actions/run_unicode/test_direct_interactive_ee.py b/tests/integration/actions/run_unicode/test_direct_interactive_ee.py new file mode 100644 index 000000000..c62fe3bf9 --- /dev/null +++ b/tests/integration/actions/run_unicode/test_direct_interactive_ee.py @@ -0,0 +1,32 @@ +"""Tests for run from CLI, interactive, with an EE, with unicode.""" +import pytest + +from ..._interactions import Command +from ..._interactions import UiTestStep +from ..._interactions import add_indices +from ..._interactions import step_id +from .base import BaseClass +from .base import base_steps +from .base import inventory_path +from .base import playbook_path + + +cmdline = f"{playbook_path} -i {inventory_path}" +CLI = Command(subcommand="run", cmdline=cmdline, execution_environment=True).join() + +initial_steps = ( + UiTestStep( + user_input=CLI, + comment="ansible-navigator run playbook", + search_within_response=["COMPLETE", "SUCCESSFUL"], + ), +) + +steps = add_indices(initial_steps + base_steps) + + +@pytest.mark.parametrize("step", steps, ids=step_id) +class Test(BaseClass): + """Run the tests for run from CLI, interactive, with an EE.""" + + UPDATE_FIXTURES = False diff --git a/tests/integration/actions/run_unicode/test_direct_interactive_noee.py b/tests/integration/actions/run_unicode/test_direct_interactive_noee.py new file mode 100644 index 000000000..1a5696fab --- /dev/null +++ b/tests/integration/actions/run_unicode/test_direct_interactive_noee.py @@ -0,0 +1,32 @@ +"""Tests for run from CLI, interactive, without an EE, with unicode.""" +import pytest + +from ..._interactions import Command +from ..._interactions import UiTestStep +from ..._interactions import add_indices +from ..._interactions import step_id +from .base import BaseClass +from .base import base_steps +from .base import inventory_path +from .base import playbook_path + + +cmdline = f"{playbook_path} -i {inventory_path}" +CLI = Command(subcommand="run", cmdline=cmdline, execution_environment=False).join() + +initial_steps = ( + UiTestStep( + user_input=CLI, + comment="ansible-navigator run playbook", + search_within_response=["COMPLETE", "SUCCESSFUL"], + ), +) + +steps = add_indices(initial_steps + base_steps) + + +@pytest.mark.parametrize("step", steps, ids=step_id) +class Test(BaseClass): + """Run the tests for run from CLI, interactive, without an EE.""" + + UPDATE_FIXTURES = False diff --git a/tests/integration/actions/run_unicode/test_stdout_tmux.py b/tests/integration/actions/run_unicode/test_stdout_tmux.py new file mode 100644 index 000000000..99bfc05d3 --- /dev/null +++ b/tests/integration/actions/run_unicode/test_stdout_tmux.py @@ -0,0 +1,63 @@ +"""Tests for run from CLI, stdout, with unicode.""" +import pytest + +from ..._interactions import Command +from ..._interactions import SearchFor +from ..._interactions import UiTestStep +from ..._interactions import add_indices +from .base import BaseClass +from .base import inventory_path +from .base import playbook_path + + +class StdoutCommand(Command): + """A command to run in the terminal.""" + + subcommand = "run" + preclear = True + + +class ShellCommand(UiTestStep): + """A test step, specifically in mode stdout.""" + + search_within_response = SearchFor.PROMPT + + +stdout_tests = ( + ShellCommand( + comment="run playbook with ee", + user_input=StdoutCommand( + cmdline=f"{playbook_path} -i {inventory_path} --pae false", + mode="stdout", + execution_environment=True, + ).join(), + present=["航海家", "ok=2", "failed=0"], + ), + ShellCommand( + comment="run playbook without ee", + user_input=StdoutCommand( + cmdline=f"{playbook_path} -i {inventory_path} --pae false", + mode="stdout", + execution_environment=False, + ).join(), + present=["航海家", "ok=2", "failed=0"], + ), +) + +steps = add_indices(stdout_tests) + + +def step_id(value): + """Return a test id for the test step object. + + :param value: The data to generate the id from + :returns: The test id + """ + return f"{value.comment} {value.user_input}" + + +@pytest.mark.parametrize("step", steps, ids=step_id) +class Test(BaseClass): + """Run the tests for run from CLI, stdout.""" + + UPDATE_FIXTURES = False diff --git a/tests/integration/actions/run_unicode/test_welcome_interactive_ee.py b/tests/integration/actions/run_unicode/test_welcome_interactive_ee.py new file mode 100644 index 000000000..5c1889441 --- /dev/null +++ b/tests/integration/actions/run_unicode/test_welcome_interactive_ee.py @@ -0,0 +1 @@ +"""Not included, presentation of unicode should not vary with entrypoint.""" diff --git a/tests/integration/actions/run_unicode/test_welcome_interactive_noee.py b/tests/integration/actions/run_unicode/test_welcome_interactive_noee.py new file mode 100644 index 000000000..5c1889441 --- /dev/null +++ b/tests/integration/actions/run_unicode/test_welcome_interactive_noee.py @@ -0,0 +1 @@ +"""Not included, presentation of unicode should not vary with entrypoint."""