From a0ec216598b2f08dc0f60dab794ae190a8e225c0 Mon Sep 17 00:00:00 2001 From: Jac Fitzgerald Date: Fri, 18 Sep 2026 13:56:22 -0700 Subject: [PATCH 1/2] test(e2e): round-trip CSVImport bug coverage for #1811 Adds a two-row CSV fixture and one createsiteusers e2e test exercising every UserItem.CSVImport bug fixed in TSC #1811 (issue #1809): AUTH column readable at 8 columns, mixed-case usernames preserved, TableauIDWithMFA in the auth allowlist, case-insensitive validation of role/admin/publisher tokens, and the @property_is_enum guard active on the parsed auth_setting. Test runs under the same server-admin / site-admin gate as test_users_create_site_users and shares its ordering slot; skips cleanly when the caller lacks admin scope or a credentials file. Related: #297 (license-name case sensitivity still surfacing after partial fixes), #434 (Local auth accepted by the CLI but crashes on TSC call). --- tests/assets/users_csvimport_bugs_1811.csv | 2 ++ tests/e2e/online_tests.py | 27 ++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 tests/assets/users_csvimport_bugs_1811.csv diff --git a/tests/assets/users_csvimport_bugs_1811.csv b/tests/assets/users_csvimport_bugs_1811.csv new file mode 100644 index 00000000..13f50258 --- /dev/null +++ b/tests/assets/users_csvimport_bugs_1811.csv @@ -0,0 +1,2 @@ +UserMixedCase_1811_A@example.com, ,"Mixed Case LDAP User 1811A",Viewer,none,no,mixedcase_1811_a@example.com,TableauID +UserMixedCase_1811_B@example.com, ,"MFA User 1811B",Creator,none,no,mfa_1811_b@example.com,TableauIDWithMFA diff --git a/tests/e2e/online_tests.py b/tests/e2e/online_tests.py index 8f1d50d6..95f3af59 100644 --- a/tests/e2e/online_tests.py +++ b/tests/e2e/online_tests.py @@ -74,6 +74,7 @@ def get_publishable_name(file_value: str) -> str: TWB_FILE_WITH_EMBEDDED_CONNECTION = "EmbeddedCredentials.twb" USERS_DETAILS_FILE = "detailed_users.csv" + USERS_CSVIMPORT_1811_FILE = "users_csvimport_bugs_1811.csv" USERNAMES_FILE = "usernames.csv" @@ -316,6 +317,32 @@ def test_users_create_site_users(self): arguments = [command, users, "--role", "Publisher"] _test_command(arguments) + @pytest.mark.order(2) + def test_users_create_site_users_csvimport_bugs_1811(self): + """Round-trip coverage for the six ``UserItem.CSVImport`` bugs fixed in + tableau/server-client-python#1811 (issue #1809). Once tabcmd delegates + its CSV stack to TSC's ``CSVImport``, this fixture is the regression + guarantee that the delegation preserved each fix. + + Exercises, in one two-row CSV: + + * the 8-column AUTH bound (row length now readable), + * mixed-case usernames preserved verbatim (case-sensitive auth systems), + * ``TableauIDWithMFA`` accepted in the auth allowlist, + * capitalised role/admin/publisher tokens accepted case-insensitively, + * the ``@property_is_enum(Auth)`` guard active on the parsed + ``UserItem.auth_setting``. + + Related: tabcmd #297 (license-name case sensitivity), #434 (``Local`` + auth accepted by the CLI but rejected server-side). + """ + if not server_admin and not site_admin: + pytest.skip("Must be server or site administrator to create site users") + command = "createsiteusers" + users = os.path.join("tests", "assets", TestAssets.USERS_CSVIMPORT_1811_FILE) + arguments = [command, users, "--role", "Publisher"] + _test_command(arguments) + @pytest.mark.order(3) def test_group_creategroup(self): if not server_admin and not site_admin: From e79ce21f17e7f784a1dca793e16b41f6423a43b3 Mon Sep 17 00:00:00 2001 From: Jac Fitzgerald Date: Fri, 18 Sep 2026 17:21:53 -0700 Subject: [PATCH 2/2] test(e2e): pass --no-complete + drop --role Publisher on CSVImport 1811 test `createsiteusers` runs `--complete` by default, which invokes tabcmd's duplicate strict validator (`UserCommand._validate_user_or_throw`). That validator rejects `len(line) > 7` and validates license values case-sensitively -- both of which the CSVImport #1811 fixture is specifically meant to exercise. Under `--complete`, the CSV never reached TSC's `UserItem.CSVImport` and the test fell through tabcmd-side. `--no-complete` skips tabcmd's validator so the fixture reaches TSC's parser. Removing `--role Publisher` lets each row's own license field be validated -- restoring coverage of the case-insensitive-license fix. Also corrected the docstring: five of the six bugs, since the sixth (unknown-AUTH rejection) is a negative-path check that doesn't fit a single happy-path fixture and is already covered by TSC's unit tests. --- tests/e2e/online_tests.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/tests/e2e/online_tests.py b/tests/e2e/online_tests.py index 95f3af59..4c38d1fc 100644 --- a/tests/e2e/online_tests.py +++ b/tests/e2e/online_tests.py @@ -319,10 +319,10 @@ def test_users_create_site_users(self): @pytest.mark.order(2) def test_users_create_site_users_csvimport_bugs_1811(self): - """Round-trip coverage for the six ``UserItem.CSVImport`` bugs fixed in - tableau/server-client-python#1811 (issue #1809). Once tabcmd delegates - its CSV stack to TSC's ``CSVImport``, this fixture is the regression - guarantee that the delegation preserved each fix. + """Round-trip coverage for five of the six ``UserItem.CSVImport`` bugs + fixed in tableau/server-client-python#1811 (issue #1809). Once tabcmd + delegates its CSV stack to TSC's ``CSVImport``, this fixture is the + regression guarantee that the delegation preserved each fix. Exercises, in one two-row CSV: @@ -333,6 +333,15 @@ def test_users_create_site_users_csvimport_bugs_1811(self): * the ``@property_is_enum(Auth)`` guard active on the parsed ``UserItem.auth_setting``. + The sixth bug (unknown-AUTH rejection) is a negative-path check that + doesn't fit a single happy-path fixture; TSC's own unit tests cover it. + + ``--no-complete`` skips tabcmd's duplicate strict validator so the CSV + actually reaches TSC's ``UserItem.CSVImport`` — which is what this test + is meant to exercise. No ``--role`` override, so the role field in each + row is what gets validated (that's the point of the case-insensitivity + check). + Related: tabcmd #297 (license-name case sensitivity), #434 (``Local`` auth accepted by the CLI but rejected server-side). """ @@ -340,7 +349,7 @@ def test_users_create_site_users_csvimport_bugs_1811(self): pytest.skip("Must be server or site administrator to create site users") command = "createsiteusers" users = os.path.join("tests", "assets", TestAssets.USERS_CSVIMPORT_1811_FILE) - arguments = [command, users, "--role", "Publisher"] + arguments = [command, users, "--no-complete"] _test_command(arguments) @pytest.mark.order(3)