diff --git a/scripts/jupyterhub.py b/scripts/jupyterhub.py new file mode 100644 index 0000000..88a24d0 --- /dev/null +++ b/scripts/jupyterhub.py @@ -0,0 +1,15 @@ +from playwright.async_api import expect + +async def login(page, username, password, transition_timeout=30000): + # Login to JupyterHub + jupyterhub_signin_button = page.locator('//*[@id = "login_submit"]') + await expect(jupyterhub_signin_button).to_be_visible(timeout=transition_timeout) + await page.locator('//*[@id = "username_input"]').fill(username) + await page.locator('//*[@id = "password_input"]').fill(password) + await jupyterhub_signin_button.click() + +async def authorize(page, transition_timeout=30000): + # JupyterHub authorizes a service (e.g. BinderHub addon of RDM OSF Integration) + authorize_button = page.locator('//*[@value = "Authorize"]') + await expect(authorize_button).to_be_visible(timeout=transition_timeout) + await authorize_button.click() diff --git "a/\343\203\206\343\202\271\343\203\210\346\211\213\351\240\206-BinderHub-BinderHub\343\202\242\343\203\211\343\202\252\343\203\263-Dockerfile.ipynb" "b/\343\203\206\343\202\271\343\203\210\346\211\213\351\240\206-BinderHub-BinderHub\343\202\242\343\203\211\343\202\252\343\203\263-Dockerfile.ipynb" index f1f0d2a..b2fa1e8 100644 --- "a/\343\203\206\343\202\271\343\203\210\346\211\213\351\240\206-BinderHub-BinderHub\343\202\242\343\203\211\343\202\252\343\203\263-Dockerfile.ipynb" +++ "b/\343\203\206\343\202\271\343\203\210\346\211\213\351\240\206-BinderHub-BinderHub\343\202\242\343\203\211\343\202\252\343\203\263-Dockerfile.ipynb" @@ -20,6 +20,11 @@ "idp_name_1 = None\n", "idp_username_1 = None\n", "idp_password_1 = None\n", + "\n", + "binderhub_auth_mode = 'auto'\n", + "jupyterhub_username = None\n", + "jupyterhub_password = None\n", + "\n", "default_result_path = None\n", "close_on_fail = False\n", "transition_timeout = 60 * 1000\n", @@ -49,6 +54,15 @@ " idp_username_1 = input(prompt=f'Username for {idp_name_1}')\n", "if idp_password_1 is None:\n", " idp_password_1 = getpass(prompt=f'Password for {idp_username_1}@{idp_name_1}')\n", + "if binderhub_auth_mode == 'jupyterhub':\n", + " if jupyterhub_username is None:\n", + " jupyterhub_username = input(prompt='Username for JupyterHub')\n", + " if jupyterhub_password is None:\n", + " jupyterhub_password = getpass(prompt=f'Password for {jupyterhub_username}@JupyterHub')\n", + " if jupyterhub_username is None or jupyterhub_password is None:\n", + " raise ValueError(\n", + " \"binderhub_auth_mode='jupyterhub' requires jupyterhub_username and jupyterhub_password\"\n", + " )\n", "if project_name is None:\n", " project_name = datetime.now().strftime('TEST-BINDERHUB-%Y%m%d%H%M')\n", "\n", @@ -101,7 +115,7 @@ "importlib.reload(scripts.playwright)\n", "\n", "from scripts.playwright import *\n", - "from scripts import grdm\n", + "from scripts import grdm, jupyterhub\n", "\n", "await init_pw_context(close_on_fail=close_on_fail, last_path=default_result_path)\n" ] @@ -277,11 +291,25 @@ "source": [ "async def _step(page):\n", " await page.locator('//a[contains(text(), \"解析\")]').click()\n", + "\n", + " jh_login = page.locator('//*[@id = \"login_submit\"]')\n", " open_idp_list = page.locator('//*[@id = \"dropdown_img\"]')\n", " launch_button = page.locator('//*[@data-test-binderhub-launch]')\n", - " await expect(open_idp_list.or_(launch_button)).to_be_visible(timeout=transition_timeout)\n", "\n", - " if await open_idp_list.is_visible():\n", + " await expect(jh_login.or_(open_idp_list).or_(launch_button)).to_be_visible(timeout=transition_timeout)\n", + "\n", + " if await jh_login.is_visible():\n", + " if binderhub_auth_mode == 'sso':\n", + " raise AssertionError(\n", + " \"binderhub_auth_mode='sso' but JupyterHub login form appeared\"\n", + " )\n", + " await jupyterhub.login(page, jupyterhub_username, jupyterhub_password, transition_timeout)\n", + " await jupyterhub.authorize(page, transition_timeout)\n", + " elif await open_idp_list.is_visible():\n", + " if binderhub_auth_mode == 'jupyterhub':\n", + " raise AssertionError(\n", + " \"binderhub_auth_mode='jupyterhub' but SSO Discovery Service appeared\"\n", + " )\n", " await grdm.login(page, idp_name_1, idp_username_1, idp_password_1, transition_timeout=transition_timeout)\n", "\n", " await expect(launch_button).to_be_visible(timeout=transition_timeout)\n", @@ -428,11 +456,24 @@ "outputs": [], "source": [ "async def _step(page):\n", + " jh_login = page.locator('//*[@id = \"login_submit\"]')\n", " open_idp_list = page.locator('//*[@id = \"dropdown_img\"]')\n", " start_ipykernel = page.locator(f'//*[@class = \"jp-LauncherCard\" and @title = \"Python 3 (ipykernel)\" and @data-category = \"Notebook\"]')\n", - " await expect(open_idp_list.or_(start_ipykernel)).to_be_visible(timeout=transition_timeout)\n", "\n", - " if await open_idp_list.is_visible():\n", + " await expect(jh_login.or_(open_idp_list).or_(start_ipykernel)).to_be_visible(timeout=transition_timeout)\n", + "\n", + " if await jh_login.is_visible():\n", + " if binderhub_auth_mode == 'sso':\n", + " raise AssertionError(\n", + " \"binderhub_auth_mode='sso' but JupyterHub login form appeared\"\n", + " )\n", + " await jupyterhub.login(page, jupyterhub_username, jupyterhub_password, transition_timeout)\n", + " await jupyterhub.authorize(page, transition_timeout)\n", + " elif await open_idp_list.is_visible():\n", + " if binderhub_auth_mode == 'jupyterhub':\n", + " raise AssertionError(\n", + " \"binderhub_auth_mode='jupyterhub' but SSO Discovery Service appeared\"\n", + " )\n", " await grdm.login(page, idp_name_1, idp_username_1, idp_password_1, transition_timeout=transition_timeout)\n", "\n", " await expect(start_ipykernel).to_be_visible(timeout=transition_timeout)\n", diff --git "a/\343\203\206\343\202\271\343\203\210\346\211\213\351\240\206-BinderHub-BinderHub\343\202\242\343\203\211\343\202\252\343\203\263-repo2docker.ipynb" "b/\343\203\206\343\202\271\343\203\210\346\211\213\351\240\206-BinderHub-BinderHub\343\202\242\343\203\211\343\202\252\343\203\263-repo2docker.ipynb" index 9dedcaf..6aa8e2c 100644 --- "a/\343\203\206\343\202\271\343\203\210\346\211\213\351\240\206-BinderHub-BinderHub\343\202\242\343\203\211\343\202\252\343\203\263-repo2docker.ipynb" +++ "b/\343\203\206\343\202\271\343\203\210\346\211\213\351\240\206-BinderHub-BinderHub\343\202\242\343\203\211\343\202\252\343\203\263-repo2docker.ipynb" @@ -19,6 +19,11 @@ "idp_name_1 = None\n", "idp_username_1 = None\n", "idp_password_1 = None\n", + "\n", + "binderhub_auth_mode = 'auto'\n", + "jupyterhub_username = None\n", + "jupyterhub_password = None\n", + "\n", "default_result_path = None\n", "close_on_fail = False\n", "project_name = None\n", @@ -54,6 +59,15 @@ " idp_username_1 = input(prompt=f'Username for {idp_name_1}')\n", "if idp_password_1 is None:\n", " idp_password_1 = getpass(prompt=f'Password for {idp_username_1}@{idp_name_1}')\n", + "if binderhub_auth_mode == 'jupyterhub':\n", + " if jupyterhub_username is None:\n", + " jupyterhub_username = input(prompt='Username for JupyterHub')\n", + " if jupyterhub_password is None:\n", + " jupyterhub_password = getpass(prompt=f'Password for {jupyterhub_username}@JupyterHub')\n", + " if jupyterhub_username is None or jupyterhub_password is None:\n", + " raise ValueError(\n", + " \"binderhub_auth_mode='jupyterhub' requires jupyterhub_username and jupyterhub_password\"\n", + " )\n", "if project_name is None:\n", " project_name = datetime.now().strftime('TEST-BINDERHUB-%Y%m%d%H%M')\n", "\n", @@ -105,7 +119,7 @@ "importlib.reload(scripts.playwright)\n", "\n", "from scripts.playwright import *\n", - "from scripts import grdm\n", + "from scripts import grdm, jupyterhub\n", "\n", "await init_pw_context(close_on_fail=close_on_fail, last_path=default_result_path)\n" ] @@ -281,11 +295,25 @@ "source": [ "async def _step(page):\n", " await page.locator('//a[contains(text(), \"解析\")]').click()\n", + "\n", + " jh_login = page.locator('//*[@id = \"login_submit\"]')\n", " open_idp_list = page.locator('//*[@id = \"dropdown_img\"]')\n", " launch_button = page.locator('//*[@data-test-binderhub-launch]')\n", - " await expect(open_idp_list.or_(launch_button)).to_be_visible(timeout=transition_timeout)\n", "\n", - " if await open_idp_list.is_visible():\n", + " await expect(jh_login.or_(open_idp_list).or_(launch_button)).to_be_visible(timeout=transition_timeout)\n", + "\n", + " if await jh_login.is_visible():\n", + " if binderhub_auth_mode == 'sso':\n", + " raise AssertionError(\n", + " \"binderhub_auth_mode='sso' but JupyterHub login form appeared\"\n", + " )\n", + " await jupyterhub.login(page, jupyterhub_username, jupyterhub_password, transition_timeout)\n", + " await jupyterhub.authorize(page, transition_timeout)\n", + " elif await open_idp_list.is_visible():\n", + " if binderhub_auth_mode == 'jupyterhub':\n", + " raise AssertionError(\n", + " \"binderhub_auth_mode='jupyterhub' but SSO Discovery Service appeared\"\n", + " )\n", " await grdm.login(page, idp_name_1, idp_username_1, idp_password_1, transition_timeout=transition_timeout)\n", "\n", " await expect(launch_button).to_be_visible(timeout=transition_timeout)\n", @@ -678,11 +706,24 @@ "outputs": [], "source": [ "async def _step(page):\n", + " jh_login = page.locator('//*[@id = \"login_submit\"]')\n", " open_idp_list = page.locator('//*[@id = \"dropdown_img\"]')\n", " start_ipykernel = page.locator(f'//*[@class = \"jp-LauncherCard\" and @title = \"Python 3 (ipykernel)\" and @data-category = \"Notebook\"]')\n", - " await expect(open_idp_list.or_(start_ipykernel)).to_be_visible(timeout=transition_timeout)\n", "\n", - " if await open_idp_list.is_visible():\n", + " await expect(jh_login.or_(open_idp_list).or_(start_ipykernel)).to_be_visible(timeout=transition_timeout)\n", + "\n", + " if await jh_login.is_visible():\n", + " if binderhub_auth_mode == 'sso':\n", + " raise AssertionError(\n", + " \"binderhub_auth_mode='sso' but JupyterHub login form appeared\"\n", + " )\n", + " await jupyterhub.login(page, jupyterhub_username, jupyterhub_password, transition_timeout)\n", + " await jupyterhub.authorize(page, transition_timeout)\n", + " elif await open_idp_list.is_visible():\n", + " if binderhub_auth_mode == 'jupyterhub':\n", + " raise AssertionError(\n", + " \"binderhub_auth_mode='jupyterhub' but SSO Discovery Service appeared\"\n", + " )\n", " await grdm.login(page, idp_name_1, idp_username_1, idp_password_1, transition_timeout=transition_timeout)\n", "\n", " await expect(start_ipykernel).to_be_visible(timeout=transition_timeout)\n", diff --git "a/\343\203\206\343\202\271\343\203\210\346\211\213\351\240\206-BinderHub-BinderHub\343\202\242\343\203\211\343\202\252\343\203\263-\343\202\242\343\203\211\343\202\252\343\203\263\350\277\275\345\212\240.ipynb" "b/\343\203\206\343\202\271\343\203\210\346\211\213\351\240\206-BinderHub-BinderHub\343\202\242\343\203\211\343\202\252\343\203\263-\343\202\242\343\203\211\343\202\252\343\203\263\350\277\275\345\212\240.ipynb" index 75525c4..796fc08 100644 --- "a/\343\203\206\343\202\271\343\203\210\346\211\213\351\240\206-BinderHub-BinderHub\343\202\242\343\203\211\343\202\252\343\203\263-\343\202\242\343\203\211\343\202\252\343\203\263\350\277\275\345\212\240.ipynb" +++ "b/\343\203\206\343\202\271\343\203\210\346\211\213\351\240\206-BinderHub-BinderHub\343\202\242\343\203\211\343\202\252\343\203\263-\343\202\242\343\203\211\343\202\252\343\203\263\350\277\275\345\212\240.ipynb" @@ -18,6 +18,11 @@ "idp_name_1 = None\n", "idp_username_1 = None\n", "idp_password_1 = None\n", + "\n", + "binderhub_auth_mode = 'auto'\n", + "jupyterhub_username = None\n", + "jupyterhub_password = None\n", + "\n", "default_result_path = None\n", "close_on_fail = False\n", "transition_timeout = 60 * 1000\n", @@ -49,6 +54,15 @@ " idp_username_1 = input(prompt=f'Username for {idp_name_1}')\n", "if idp_password_1 is None:\n", " idp_password_1 = getpass(prompt=f'Password for {idp_username_1}@{idp_name_1}')\n", + "if binderhub_auth_mode == 'jupyterhub':\n", + " if jupyterhub_username is None:\n", + " jupyterhub_username = input(prompt='Username for JupyterHub')\n", + " if jupyterhub_password is None:\n", + " jupyterhub_password = getpass(prompt=f'Password for {jupyterhub_username}@JupyterHub')\n", + " if jupyterhub_username is None or jupyterhub_password is None:\n", + " raise ValueError(\n", + " \"binderhub_auth_mode='jupyterhub' requires jupyterhub_username and jupyterhub_password\"\n", + " )\n", "if project_name is None:\n", " project_name = datetime.now().strftime('TEST-BINDERHUB-%Y%m%d%H%M')\n", "\n", @@ -99,7 +113,7 @@ "importlib.reload(scripts.playwright)\n", "\n", "from scripts.playwright import *\n", - "from scripts import grdm\n", + "from scripts import grdm, jupyterhub\n", "\n", "await init_pw_context(close_on_fail=close_on_fail, last_path=default_result_path)\n" ] @@ -314,11 +328,25 @@ "source": [ "async def _step(page):\n", " await page.locator('//a[contains(text(), \"解析\")]').click()\n", + "\n", + " jh_login = page.locator('//*[@id = \"login_submit\"]')\n", " open_idp_list = page.locator('//*[@id = \"dropdown_img\"]')\n", " launch_button = page.locator('//*[@data-test-binderhub-launch]')\n", - " await expect(open_idp_list.or_(launch_button)).to_be_visible(timeout=transition_timeout)\n", "\n", - " if await open_idp_list.is_visible():\n", + " await expect(jh_login.or_(open_idp_list).or_(launch_button)).to_be_visible(timeout=transition_timeout)\n", + "\n", + " if await jh_login.is_visible():\n", + " if binderhub_auth_mode == 'sso':\n", + " raise AssertionError(\n", + " \"binderhub_auth_mode='sso' but JupyterHub login form appeared\"\n", + " )\n", + " await jupyterhub.login(page, jupyterhub_username, jupyterhub_password, transition_timeout)\n", + " await jupyterhub.authorize(page, transition_timeout)\n", + " elif await open_idp_list.is_visible():\n", + " if binderhub_auth_mode == 'jupyterhub':\n", + " raise AssertionError(\n", + " \"binderhub_auth_mode='jupyterhub' but SSO Discovery Service appeared\"\n", + " )\n", " await grdm.login(page, idp_name_1, idp_username_1, idp_password_1, transition_timeout=transition_timeout)\n", "\n", " await expect(launch_button).to_be_visible(timeout=transition_timeout)\n", @@ -408,11 +436,24 @@ "outputs": [], "source": [ "async def _step(page):\n", + " jh_login = page.locator('//*[@id = \"login_submit\"]')\n", " open_idp_list = page.locator('//*[@id = \"dropdown_img\"]')\n", " start_ipykernel = page.locator(f'//*[@class = \"jp-LauncherCard\" and @title = \"Python 3 (ipykernel)\" and @data-category = \"Notebook\"]')\n", - " await expect(open_idp_list.or_(start_ipykernel)).to_be_visible(timeout=transition_timeout)\n", "\n", - " if await open_idp_list.is_visible():\n", + " await expect(jh_login.or_(open_idp_list).or_(start_ipykernel)).to_be_visible(timeout=transition_timeout)\n", + "\n", + " if await jh_login.is_visible():\n", + " if binderhub_auth_mode == 'sso':\n", + " raise AssertionError(\n", + " \"binderhub_auth_mode='sso' but JupyterHub login form appeared\"\n", + " )\n", + " await jupyterhub.login(page, jupyterhub_username, jupyterhub_password, transition_timeout)\n", + " await jupyterhub.authorize(page, transition_timeout)\n", + " elif await open_idp_list.is_visible():\n", + " if binderhub_auth_mode == 'jupyterhub':\n", + " raise AssertionError(\n", + " \"binderhub_auth_mode='jupyterhub' but SSO Discovery Service appeared\"\n", + " )\n", " await grdm.login(page, idp_name_1, idp_username_1, idp_password_1, transition_timeout=transition_timeout)\n", "\n", " await expect(start_ipykernel).to_be_visible(timeout=transition_timeout)\n", diff --git "a/\343\203\206\343\202\271\343\203\210\346\211\213\351\240\206-BinderHub-BinderHub\343\202\242\343\203\211\343\202\252\343\203\263-\343\203\207\343\203\225\343\202\251\343\203\253\343\203\210\343\202\271\343\203\210\343\203\254\343\203\274\343\202\270\343\201\256\343\202\263\343\203\224\343\203\274\345\210\266\345\276\241.ipynb" "b/\343\203\206\343\202\271\343\203\210\346\211\213\351\240\206-BinderHub-BinderHub\343\202\242\343\203\211\343\202\252\343\203\263-\343\203\207\343\203\225\343\202\251\343\203\253\343\203\210\343\202\271\343\203\210\343\203\254\343\203\274\343\202\270\343\201\256\343\202\263\343\203\224\343\203\274\345\210\266\345\276\241.ipynb" index 871f84c..5e06346 100644 --- "a/\343\203\206\343\202\271\343\203\210\346\211\213\351\240\206-BinderHub-BinderHub\343\202\242\343\203\211\343\202\252\343\203\263-\343\203\207\343\203\225\343\202\251\343\203\253\343\203\210\343\202\271\343\203\210\343\203\254\343\203\274\343\202\270\343\201\256\343\202\263\343\203\224\343\203\274\345\210\266\345\276\241.ipynb" +++ "b/\343\203\206\343\202\271\343\203\210\346\211\213\351\240\206-BinderHub-BinderHub\343\202\242\343\203\211\343\202\252\343\203\263-\343\203\207\343\203\225\343\202\251\343\203\253\343\203\210\343\202\271\343\203\210\343\203\254\343\203\274\343\202\270\343\201\256\343\202\263\343\203\224\343\203\274\345\210\266\345\276\241.ipynb" @@ -21,6 +21,11 @@ "idp_name_1 = None\n", "idp_username_1 = None\n", "idp_password_1 = None\n", + "\n", + "binderhub_auth_mode = 'auto'\n", + "jupyterhub_username = None\n", + "jupyterhub_password = None\n", + "\n", "default_result_path = None\n", "close_on_fail = False\n", "transition_timeout = 60 * 1000\n", @@ -50,6 +55,15 @@ " idp_username_1 = input(prompt=f'Username for {idp_name_1}')\n", "if idp_password_1 is None:\n", " idp_password_1 = getpass(prompt=f'Password for {idp_username_1}@{idp_name_1}')\n", + "if binderhub_auth_mode == 'jupyterhub':\n", + " if jupyterhub_username is None:\n", + " jupyterhub_username = input(prompt='Username for JupyterHub')\n", + " if jupyterhub_password is None:\n", + " jupyterhub_password = getpass(prompt=f'Password for {jupyterhub_username}@JupyterHub')\n", + " if jupyterhub_username is None or jupyterhub_password is None:\n", + " raise ValueError(\n", + " \"binderhub_auth_mode='jupyterhub' requires jupyterhub_username and jupyterhub_password\"\n", + " )\n", "if project_name is None:\n", " project_name = datetime.now().strftime('TEST-BINDERHUB-%Y%m%d%H%M')\n", "\n", @@ -102,7 +116,7 @@ "importlib.reload(scripts.playwright)\n", "\n", "from scripts.playwright import *\n", - "from scripts import grdm\n", + "from scripts import grdm, jupyterhub\n", "\n", "await init_pw_context(close_on_fail=close_on_fail, last_path=default_result_path)\n" ] @@ -278,11 +292,25 @@ "source": [ "async def _step(page):\n", " await page.locator('//a[contains(text(), \"解析\")]').click()\n", + "\n", + " jh_login = page.locator('//*[@id = \"login_submit\"]')\n", " open_idp_list = page.locator('//*[@id = \"dropdown_img\"]')\n", " launch_button = page.locator('//*[@data-test-binderhub-launch]')\n", - " await expect(open_idp_list.or_(launch_button)).to_be_visible(timeout=transition_timeout)\n", "\n", - " if await open_idp_list.is_visible():\n", + " await expect(jh_login.or_(open_idp_list).or_(launch_button)).to_be_visible(timeout=transition_timeout)\n", + "\n", + " if await jh_login.is_visible():\n", + " if binderhub_auth_mode == 'sso':\n", + " raise AssertionError(\n", + " \"binderhub_auth_mode='sso' but JupyterHub login form appeared\"\n", + " )\n", + " await jupyterhub.login(page, jupyterhub_username, jupyterhub_password, transition_timeout)\n", + " await jupyterhub.authorize(page, transition_timeout)\n", + " elif await open_idp_list.is_visible():\n", + " if binderhub_auth_mode == 'jupyterhub':\n", + " raise AssertionError(\n", + " \"binderhub_auth_mode='jupyterhub' but SSO Discovery Service appeared\"\n", + " )\n", " await grdm.login(page, idp_name_1, idp_username_1, idp_password_1, transition_timeout=transition_timeout)\n", "\n", " await expect(launch_button).to_be_visible(timeout=transition_timeout)\n", @@ -365,14 +393,30 @@ "source": [ "async def _step(page):\n", " await page.locator('//a[contains(text(), \"解析\")]').click()\n", - " auth_page = page.locator('//*[@id = \"dropdown_img\"]')\n", - " analysis_page = page.locator('//*[@data-test-binderhub-launch]')\n", - " await expect(auth_page.or_(analysis_page)).to_be_visible(timeout=transition_timeout)\n", "\n", - " if await auth_page.is_visible():\n", + " jh_login = page.locator('//*[@id = \"login_submit\"]')\n", + " open_idp_list = page.locator('//*[@id = \"dropdown_img\"]')\n", + " launch_button = page.locator('//*[@data-test-binderhub-launch]')\n", + "\n", + " await expect(jh_login.or_(open_idp_list).or_(launch_button)).to_be_visible(timeout=transition_timeout)\n", + "\n", + " if await jh_login.is_visible():\n", + " if binderhub_auth_mode == 'sso':\n", + " raise AssertionError(\n", + " \"binderhub_auth_mode='sso' but JupyterHub login form appeared\"\n", + " )\n", + " await jupyterhub.login(page, jupyterhub_username, jupyterhub_password, transition_timeout)\n", + " await jupyterhub.authorize(page, transition_timeout)\n", + " elif await open_idp_list.is_visible():\n", + " if binderhub_auth_mode == 'jupyterhub':\n", + " raise AssertionError(\n", + " \"binderhub_auth_mode='jupyterhub' but SSO Discovery Service appeared\"\n", + " )\n", " await grdm.login(page, idp_name_1, idp_username_1, idp_password_1, transition_timeout=transition_timeout)\n", "\n", - "await run_pw(_step)\n" + " await expect(launch_button).to_be_visible(timeout=transition_timeout)\n", + "\n", + "await run_pw(_step)" ] }, { @@ -417,11 +461,24 @@ "outputs": [], "source": [ "async def _step(page):\n", + " jh_login = page.locator('//*[@id = \"login_submit\"]')\n", " open_idp_list = page.locator('//*[@id = \"dropdown_img\"]')\n", " start_ipykernel = page.locator(f'//*[@class = \"jp-LauncherCard\" and @title = \"Python 3 (ipykernel)\" and @data-category = \"Notebook\"]')\n", - " await expect(open_idp_list.or_(start_ipykernel)).to_be_visible(timeout=transition_timeout)\n", "\n", - " if await open_idp_list.is_visible():\n", + " await expect(jh_login.or_(open_idp_list).or_(start_ipykernel)).to_be_visible(timeout=transition_timeout)\n", + "\n", + " if await jh_login.is_visible():\n", + " if binderhub_auth_mode == 'sso':\n", + " raise AssertionError(\n", + " \"binderhub_auth_mode='sso' but JupyterHub login form appeared\"\n", + " )\n", + " await jupyterhub.login(page, jupyterhub_username, jupyterhub_password, transition_timeout)\n", + " await jupyterhub.authorize(page, transition_timeout)\n", + " elif await open_idp_list.is_visible():\n", + " if binderhub_auth_mode == 'jupyterhub':\n", + " raise AssertionError(\n", + " \"binderhub_auth_mode='jupyterhub' but SSO Discovery Service appeared\"\n", + " )\n", " await grdm.login(page, idp_name_1, idp_username_1, idp_password_1, transition_timeout=transition_timeout)\n", "\n", " await expect(start_ipykernel).to_be_visible(timeout=transition_timeout)\n", @@ -549,6 +606,7 @@ " checkbox = page.locator('//*[@data-test-copy-default-storage]')\n", " await expect(checkbox).to_be_checked(timeout=transition_timeout)\n", " await checkbox.click()\n", + " await asyncio.sleep(transition_timeout / 1000)\n", "\n", "await run_pw(_step)\n" ] @@ -595,11 +653,24 @@ "outputs": [], "source": [ "async def _step(page):\n", + " jh_login = page.locator('//*[@id = \"login_submit\"]')\n", " open_idp_list = page.locator('//*[@id = \"dropdown_img\"]')\n", " start_ipykernel = page.locator(f'//*[@class = \"jp-LauncherCard\" and @title = \"Python 3 (ipykernel)\" and @data-category = \"Notebook\"]')\n", - " await expect(open_idp_list.or_(start_ipykernel)).to_be_visible(timeout=transition_timeout)\n", "\n", - " if await open_idp_list.is_visible():\n", + " await expect(jh_login.or_(open_idp_list).or_(start_ipykernel)).to_be_visible(timeout=transition_timeout)\n", + "\n", + " if await jh_login.is_visible():\n", + " if binderhub_auth_mode == 'sso':\n", + " raise AssertionError(\n", + " \"binderhub_auth_mode='sso' but JupyterHub login form appeared\"\n", + " )\n", + " await jupyterhub.login(page, jupyterhub_username, jupyterhub_password, transition_timeout)\n", + " await jupyterhub.authorize(page, transition_timeout)\n", + " elif await open_idp_list.is_visible():\n", + " if binderhub_auth_mode == 'jupyterhub':\n", + " raise AssertionError(\n", + " \"binderhub_auth_mode='jupyterhub' but SSO Discovery Service appeared\"\n", + " )\n", " await grdm.login(page, idp_name_1, idp_username_1, idp_password_1, transition_timeout=transition_timeout)\n", "\n", " await expect(start_ipykernel).to_be_visible(timeout=transition_timeout)\n", @@ -700,6 +771,7 @@ " checkbox = page.locator('//*[@data-test-copy-default-storage]')\n", " await expect(checkbox).not_to_be_checked(timeout=transition_timeout)\n", " await checkbox.click()\n", + " await asyncio.sleep(transition_timeout / 1000)\n", "\n", "await run_pw(_step)\n" ] @@ -845,11 +917,24 @@ "outputs": [], "source": [ "async def _step(page):\n", + " jh_login = page.locator('//*[@id = \"login_submit\"]')\n", " open_idp_list = page.locator('//*[@id = \"dropdown_img\"]')\n", " start_ipykernel = page.locator(f'//*[@class = \"jp-LauncherCard\" and @title = \"Python 3 (ipykernel)\" and @data-category = \"Notebook\"]')\n", - " await expect(open_idp_list.or_(start_ipykernel)).to_be_visible(timeout=transition_timeout)\n", "\n", - " if await open_idp_list.is_visible():\n", + " await expect(jh_login.or_(open_idp_list).or_(start_ipykernel)).to_be_visible(timeout=transition_timeout)\n", + "\n", + " if await jh_login.is_visible():\n", + " if binderhub_auth_mode == 'sso':\n", + " raise AssertionError(\n", + " \"binderhub_auth_mode='sso' but JupyterHub login form appeared\"\n", + " )\n", + " await jupyterhub.login(page, jupyterhub_username, jupyterhub_password, transition_timeout)\n", + " await jupyterhub.authorize(page, transition_timeout)\n", + " elif await open_idp_list.is_visible():\n", + " if binderhub_auth_mode == 'jupyterhub':\n", + " raise AssertionError(\n", + " \"binderhub_auth_mode='jupyterhub' but SSO Discovery Service appeared\"\n", + " )\n", " await grdm.login(page, idp_name_1, idp_username_1, idp_password_1, transition_timeout=transition_timeout)\n", "\n", " await expect(start_ipykernel).to_be_visible(timeout=transition_timeout)\n", diff --git "a/\343\203\206\343\202\271\343\203\210\346\211\213\351\240\206-BinderHub-BinderHub\343\202\242\343\203\211\343\202\252\343\203\263-\345\201\234\346\255\242\344\270\255\343\201\256BinderHub\343\202\242\343\203\211\343\202\252\343\203\263.ipynb" "b/\343\203\206\343\202\271\343\203\210\346\211\213\351\240\206-BinderHub-BinderHub\343\202\242\343\203\211\343\202\252\343\203\263-\345\201\234\346\255\242\344\270\255\343\201\256BinderHub\343\202\242\343\203\211\343\202\252\343\203\263.ipynb" index 05e502f..d817e4c 100644 --- "a/\343\203\206\343\202\271\343\203\210\346\211\213\351\240\206-BinderHub-BinderHub\343\202\242\343\203\211\343\202\252\343\203\263-\345\201\234\346\255\242\344\270\255\343\201\256BinderHub\343\202\242\343\203\211\343\202\252\343\203\263.ipynb" +++ "b/\343\203\206\343\202\271\343\203\210\346\211\213\351\240\206-BinderHub-BinderHub\343\202\242\343\203\211\343\202\252\343\203\263-\345\201\234\346\255\242\344\270\255\343\201\256BinderHub\343\202\242\343\203\211\343\202\252\343\203\263.ipynb" @@ -18,6 +18,11 @@ "idp_name_1 = None\n", "idp_username_1 = None\n", "idp_password_1 = None\n", + "\n", + "binderhub_auth_mode = 'auto'\n", + "jupyterhub_username = None\n", + "jupyterhub_password = None\n", + "\n", "default_result_path = None\n", "close_on_fail = False\n", "transition_timeout = 60 * 1000\n", @@ -52,6 +57,15 @@ " idp_username_1 = input(prompt=f'Username for {idp_name_1}')\n", "if idp_password_1 is None:\n", " idp_password_1 = getpass(prompt=f'Password for {idp_username_1}@{idp_name_1}')\n", + "if binderhub_auth_mode == 'jupyterhub':\n", + " if jupyterhub_username is None:\n", + " jupyterhub_username = input(prompt='Username for JupyterHub')\n", + " if jupyterhub_password is None:\n", + " jupyterhub_password = getpass(prompt=f'Password for {jupyterhub_username}@JupyterHub')\n", + " if jupyterhub_username is None or jupyterhub_password is None:\n", + " raise ValueError(\n", + " \"binderhub_auth_mode='jupyterhub' requires jupyterhub_username and jupyterhub_password\"\n", + " )\n", "if project_name is None:\n", " project_name = datetime.now().strftime('TEST-BINDERHUB-%Y%m%d%H%M')\n", "\n", @@ -102,7 +116,7 @@ "importlib.reload(scripts.playwright)\n", "\n", "from scripts.playwright import *\n", - "from scripts import grdm\n", + "from scripts import grdm, jupyterhub\n", "\n", "await init_pw_context(close_on_fail=close_on_fail, last_path=default_result_path)\n" ] @@ -254,11 +268,24 @@ "source": [ "async def _step(page):\n", " await page.locator('//a[contains(text(), \"解析\")]').click()\n", + " jh_login = page.locator('//*[@id = \"login_submit\"]')\n", " open_idp_list = page.locator('//*[@id = \"dropdown_img\"]')\n", " launch_button = page.locator('//*[@data-test-binderhub-launch]')\n", - " await expect(open_idp_list.or_(launch_button)).to_be_visible(timeout=transition_timeout)\n", "\n", - " if await open_idp_list.is_visible():\n", + " await expect(jh_login.or_(open_idp_list).or_(launch_button)).to_be_visible(timeout=transition_timeout)\n", + "\n", + " if await jh_login.is_visible():\n", + " if binderhub_auth_mode == 'sso':\n", + " raise AssertionError(\n", + " \"binderhub_auth_mode='sso' but JupyterHub login form appeared\"\n", + " )\n", + " await jupyterhub.login(page, jupyterhub_username, jupyterhub_password, transition_timeout)\n", + " await jupyterhub.authorize(page, transition_timeout)\n", + " elif await open_idp_list.is_visible():\n", + " if binderhub_auth_mode == 'jupyterhub':\n", + " raise AssertionError(\n", + " \"binderhub_auth_mode='jupyterhub' but SSO Discovery Service appeared\"\n", + " )\n", " await grdm.login(page, idp_name_1, idp_username_1, idp_password_1, transition_timeout=transition_timeout)\n", "\n", " await expect(launch_button).to_be_visible(timeout=transition_timeout)\n", @@ -358,20 +385,13 @@ { "cell_type": "code", "execution_count": null, - "id": "6e4013a8", + "id": "5e52d3b7", "metadata": {}, "outputs": [], "source": [ "async def _step(page):\n", " await page.locator('//a[contains(text(), \"解析\")]').click()\n", - " open_idp_list = page.locator('//*[@id = \"dropdown_img\"]')\n", - " launch_button = page.locator('//*[@data-test-binderhub-launch]')\n", - " await expect(open_idp_list.or_(launch_button)).to_be_visible(timeout=transition_timeout)\n", - "\n", - " if await open_idp_list.is_visible():\n", - " await grdm.login(page, idp_name_1, idp_username_1, idp_password_1, transition_timeout=transition_timeout)\n", - "\n", - " await expect(launch_button).to_be_visible(timeout=transition_timeout)\n", + " await expect(page.locator('//*[@data-test-binderhub-launch]')).to_be_visible(timeout=transition_timeout)\n", "\n", "await run_pw(_step)" ] diff --git "a/\345\217\226\343\202\212\343\201\276\343\201\250\343\202\201-BinderHub-BinderHub\343\202\242\343\203\211\343\202\252\343\203\263.ipynb" "b/\345\217\226\343\202\212\343\201\276\343\201\250\343\202\201-BinderHub-BinderHub\343\202\242\343\203\211\343\202\252\343\203\263.ipynb" index 6f2a6fd..97b388b 100644 --- "a/\345\217\226\343\202\212\343\201\276\343\201\250\343\202\201-BinderHub-BinderHub\343\202\242\343\203\211\343\202\252\343\203\263.ipynb" +++ "b/\345\217\226\343\202\212\343\201\276\343\201\250\343\202\201-BinderHub-BinderHub\343\202\242\343\203\211\343\202\252\343\203\263.ipynb" @@ -45,6 +45,15 @@ "idp_name_1 = None\n", "idp_username_1 = None\n", "idp_password_1 = None\n", + "\n", + "# Auth flow when transitioning from RDM to BinderHub / JupyterLab.\n", + "# 'auto' : detect which login UI appears and follow it\n", + "# 'sso' : assert the GakuNin Discovery Service path\n", + "# 'jupyterhub' : assert the local JupyterHub form + OAuth Authorize path\n", + "binderhub_auth_mode = 'auto'\n", + "jupyterhub_username = None\n", + "jupyterhub_password = None\n", + "\n", "project_name_prefix = datetime.now().strftime('TEST-BINDERHUB-%Y%m%d%H%M')\n", "default_result_path = None\n", "close_on_fail = False\n", @@ -240,7 +249,16 @@ " idp_username_1 = input(prompt=f'Username for {idp_name_1}: ')\n", "if idp_password_1 is None:\n", " idp_password_1 = getpass(prompt=f'Password for {idp_username_1}@{idp_name_1}: ')\n", - "(rdm_url, idp_name_1, idp_username_1)" + "if binderhub_auth_mode == 'jupyterhub':\n", + " if jupyterhub_username is None:\n", + " jupyterhub_username = input(prompt='Username for JupyterHub')\n", + " if jupyterhub_password is None:\n", + " jupyterhub_password = getpass(prompt=f'Password for {jupyterhub_username}@JupyterHub')\n", + " if jupyterhub_username is None or jupyterhub_password is None:\n", + " raise ValueError(\n", + " \"binderhub_auth_mode='jupyterhub' requires jupyterhub_username and jupyterhub_password\"\n", + " )\n", + "(rdm_url, idp_name_1, idp_username_1, jupyterhub_username)" ] }, { @@ -640,7 +658,6 @@ "from datetime import datetime\n", "import os\n", "import papermill as pm\n", - "import traceback\n", "from scripts.papermillHelpers import gen_run_notebook\n", "\n", "def make_result_dir(base_path):\n", @@ -658,6 +675,8 @@ " idp_name_1=idp_name_1,\n", " idp_username_1=idp_username_1,\n", " idp_password_1=idp_password_1,\n", + " jupyterhub_username=jupyterhub_username,\n", + " jupyterhub_password=jupyterhub_password,\n", " transition_timeout=transition_timeout,\n", " binderhub_launch_timeout=binderhub_launch_timeout,\n", " ),\n", @@ -697,6 +716,7 @@ " dict(\n", " project_name=f'{project_name_prefix}-add-binderhub-addon',\n", " binderhub_binderhub_url=binderhub_binderhub_url,\n", + " binderhub_auth_mode=binderhub_auth_mode,\n", " ),\n", " )\n", ")\n", @@ -730,6 +750,7 @@ " 'テスト手順-BinderHub-BinderHubアドオン-repo2docker.ipynb',\n", " dict(\n", " project_name=f'{project_name_prefix}-repo2docker',\n", + " binderhub_auth_mode=binderhub_auth_mode,\n", " ),\n", " )\n", ")\n", @@ -764,6 +785,7 @@ " 'テスト手順-BinderHub-BinderHubアドオン-Dockerfile.ipynb',\n", " dict(\n", " project_name=f'{project_name_prefix}-Dockerfile',\n", + " binderhub_auth_mode=binderhub_auth_mode,\n", " )\n", " ),\n", ")\n", @@ -797,6 +819,7 @@ " 'テスト手順-BinderHub-BinderHubアドオン-デフォルトストレージのコピー制御.ipynb',\n", " dict(\n", " project_name=f'{project_name_prefix}-default-storage-copy-control',\n", + " binderhub_auth_mode=binderhub_auth_mode,\n", " ),\n", " )\n", ")\n", @@ -829,6 +852,7 @@ " 'テスト手順-BinderHub-BinderHubアドオン-停止中のBinderHubアドオン.ipynb',\n", " dict(\n", " project_name=f'{project_name_prefix}-halted-binderhub',\n", + " binderhub_auth_mode=binderhub_auth_mode,\n", " ),\n", " )\n", ")\n", diff --git "a/\347\265\220\345\220\210\350\251\246\351\250\223-\345\256\237\350\241\214.ipynb" "b/\347\265\220\345\220\210\350\251\246\351\250\223-\345\256\237\350\241\214.ipynb" index 59f7e22..5214eea 100644 --- "a/\347\265\220\345\220\210\350\251\246\351\250\223-\345\256\237\350\241\214.ipynb" +++ "b/\347\265\220\345\220\210\350\251\246\351\250\223-\345\256\237\350\241\214.ipynb" @@ -711,6 +711,7 @@ "skip_erad_completion_test = False\n", "skip_admin = False\n", "skip_binderhub = False\n", + "skip_local_binderhub = False\n", "\n", "storages_oauth = [\n", " {'id': 'dropbox', 'name': 'Dropbox'},\n", @@ -761,7 +762,11 @@ "\n", "# BinderHubアドオンのテスト\n", "# アドオン追加テストにおいて追加するBinderHubの情報\n", - "binderhub_binderhub_url = 'https://example.com/binderhub'" + "binderhub_binderhub_url = 'https://example.com/binderhub'\n", + "# ローカルでのBinderHubアドオンのテスト\n", + "# JupyterHubのユーザ情報\n", + "jupyterhub_username = None\n", + "jupyterhub_password = None" ] }, { @@ -4046,7 +4051,44 @@ "outputs": [], "source": [ "if not skip_binderhub:\n", - " result_notebooks.append(run_notebook(result_dir, '取りまとめ-BinderHub-BinderHubアドオン.ipynb', binderhub_binderhub_url=binderhub_binderhub_url))\n", + " result_notebooks.append(\n", + " run_notebook(\n", + " result_dir,\n", + " '取りまとめ-BinderHub-BinderHubアドオン.ipynb',\n", + " binderhub_binderhub_url=binderhub_binderhub_url,\n", + " binderhub_auth_mode='auto'\n", + " )\n", + " )\n", + "\n", + "result_notebooks" + ] + }, + { + "cell_type": "markdown", + "id": "cc24a05c", + "metadata": {}, + "source": [ + "## ローカル環境でのBinderHubアドオン関連テスト" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8e880b02", + "metadata": {}, + "outputs": [], + "source": [ + "if not skip_local_binderhub:\n", + " result_notebooks.append(\n", + " run_notebook(\n", + " result_dir,\n", + " '取りまとめ-BinderHub-BinderHubアドオン.ipynb',\n", + " binderhub_binderhub_url=binderhub_binderhub_url,\n", + " binderhub_auth_mode='jupyterhub',\n", + " jupyterhub_username=jupyterhub_username,\n", + " jupyterhub_password=jupyterhub_password,\n", + " )\n", + " )\n", "\n", "result_notebooks" ]