def grant_users_access(users, channels, sg_admin_url, sg_db): sg_client = MobileRestClient() for username in users: sg_client.update_user(url=sg_admin_url, db=sg_db, name=username, channels=channels)
def test_backfill_channels_looping_longpoll_changes(params_from_base_test_setup, sg_conf_name, grant_type): cluster_config = params_from_base_test_setup["cluster_config"] topology = params_from_base_test_setup["cluster_topology"] mode = params_from_base_test_setup["mode"] sg_url = topology["sync_gateways"][0]["public"] sg_admin_url = topology["sync_gateways"][0]["admin"] sg_db = "db" log_info("grant_type: {}".format(grant_type)) sg_conf = sync_gateway_config_path_for_mode(sg_conf_name, mode) cluster = Cluster(cluster_config) cluster.reset(sg_conf) client = MobileRestClient() admin_user_info = userinfo.UserInfo("admin", "pass", channels=["A"], roles=[]) user_b_user_info = userinfo.UserInfo("USER_B", "pass", channels=["B"], roles=[]) # Create users / sessions client.create_user(url=sg_admin_url, db=sg_db, name=admin_user_info.name, password=admin_user_info.password, channels=admin_user_info.channels) client.create_user(url=sg_admin_url, db=sg_db, name=user_b_user_info.name, password=user_b_user_info.password, channels=user_b_user_info.channels) admin_session = client.create_session(url=sg_admin_url, db=sg_db, name=admin_user_info.name, password=admin_user_info.password) user_b_session = client.create_session(url=sg_admin_url, db=sg_db, name=user_b_user_info.name, password=user_b_user_info.password) # Create 50 "A" channel docs a_docs = client.add_docs(url=sg_url, db=sg_db, number=50, id_prefix=None, auth=admin_session, channels=["A"]) assert len(a_docs) == 50 b_docs = client.add_docs(url=sg_url, db=sg_db, number=1, id_prefix="b_doc", auth=user_b_session, channels=["B"]) assert len(b_docs) == 1 user_doc = {"id": "_user/USER_B", "rev": None} b_docs.append(user_doc) # Loop until user_b sees b_doc_0 doc and _user/USER_B doc client.verify_docs_in_changes(url=sg_url, db=sg_db, expected_docs=b_docs, auth=user_b_session, strict=True) # Create a dictionary keyed on doc id for all of channel A docs ids_and_revs_from_a_docs = {doc["id"]: doc["rev"] for doc in a_docs} assert len(ids_and_revs_from_a_docs.keys()) == 50 # Get last_seq for user_b user_b_changes = client.get_changes(url=sg_url, db=sg_db, since=0, auth=user_b_session, feed="normal") with concurrent.futures.ProcessPoolExecutor() as ex: # Start long poll changes feed. changes_task = ex.submit(client.get_changes, url=sg_url, db=sg_db, since=user_b_changes["last_seq"], auth=user_b_session, timeout=10, limit=20) # Grant access to channel "A" if grant_type == "CHANNEL-REST": log_info("Granting user access to channel A via Admin REST user update") # Grant via update to user in Admin API client.update_user(url=sg_admin_url, db=sg_db, name=user_b_user_info.name, channels=["A", "B"]) elif grant_type == "CHANNEL-SYNC": log_info("Granting user access to channel A sync function access()") # Grant via access() in sync_function, then id 'channel_access' will trigger an access(doc.users, doc.channels) access_doc = document.create_doc("channel_access", channels=["A"]) access_doc["users"] = ["USER_B"] client.add_doc(url=sg_url, db=sg_db, doc=access_doc, auth=admin_session) elif grant_type == "ROLE-REST": log_info("Granting user access to channel A via Admin REST role grant") # Create role with channel A client.create_role(url=sg_admin_url, db=sg_db, name="channel-A-role", channels=["A"]) client.update_user(url=sg_admin_url, db=sg_db, name="USER_B", roles=["channel-A-role"]) elif grant_type == "ROLE-SYNC": log_info("Granting user access to channel A via sync function role() grant") # Create role with channel A client.create_role(url=sg_admin_url, db=sg_db, name="channel-A-role", channels=["A"]) # Grant via role() in sync_function, then id 'role_access' will trigger an role(doc.users, doc.roles) role_access_doc = document.create_doc("role_access") role_access_doc["users"] = ["USER_B"] role_access_doc["roles"] = ["role:channel-A-role"] client.add_doc(sg_url, db=sg_db, doc=role_access_doc, auth=admin_session) else: pytest.fail("Unsupported grant_type!!!!") # Block on return of longpoll changes, feed should wake up and return 20 results changes = changes_task.result() assert len(changes["results"]) == 20 num_requests = 1 # Cross the results off from the 'a_docs' dictionary for doc in changes["results"]: del ids_and_revs_from_a_docs[doc["id"]] # Start looping longpoll changes with limit, cross off changes from dictionary each time one is found # Since 20 changes should be crossed off already, this should execute 2x. log_info("Starting looping longpoll changes with limit!") last_seq = changes["last_seq"] while True: if len(ids_and_revs_from_a_docs.keys()) == 0: log_info("All docs were found! Exiting polling loop") break changes = client.get_changes(url=sg_url, db=sg_db, since=last_seq, auth=user_b_session, limit=20, timeout=10) num_requests += 1 # There are more than 2 requests, throw an exception. if num_requests == 2: assert len(changes["results"]) == 20 elif num_requests == 3: # This will be 10 or 11 depending on if the _user/ doc is returned assert 10 <= len(changes["results"]) <= 11 else: raise exceptions.ChangesError("Looping longpoll should only have to perform 3 requests to get all the changes!!") # Cross the results off from the 'a_docs' dictionary. # This will blow up in docs duplicate docs are sent to changes for doc in changes["results"]: if doc["id"] != "_user/USER_B": del ids_and_revs_from_a_docs[doc["id"]] last_seq = changes["last_seq"] # Shanges after longpoll zero_results = client.get_changes(url=sg_url, db=sg_db, since=last_seq, auth=user_b_session, feed="normal") # Changes should be caught up and there should be no results assert len(zero_results["results"]) == 0
def test_backfill_channels_oneshot_changes(params_from_base_test_setup, sg_conf_name, grant_type): cluster_config = params_from_base_test_setup["cluster_config"] topology = params_from_base_test_setup["cluster_topology"] mode = params_from_base_test_setup["mode"] sg_url = topology["sync_gateways"][0]["public"] sg_admin_url = topology["sync_gateways"][0]["admin"] sg_db = "db" log_info("grant_type: {}".format(grant_type)) sg_conf = sync_gateway_config_path_for_mode(sg_conf_name, mode) cluster = Cluster(cluster_config) cluster.reset(sg_conf) client = MobileRestClient() admin_user_info = userinfo.UserInfo("admin", "pass", channels=["A"], roles=[]) user_b_user_info = userinfo.UserInfo("USER_B", "pass", channels=["B"], roles=[]) # Create users / sessions client.create_user(url=sg_admin_url, db=sg_db, name=admin_user_info.name, password=admin_user_info.password, channels=admin_user_info.channels) client.create_user(url=sg_admin_url, db=sg_db, name=user_b_user_info.name, password=user_b_user_info.password, channels=user_b_user_info.channels) admin_session = client.create_session(url=sg_admin_url, db=sg_db, name=admin_user_info.name, password=admin_user_info.password) user_b_session = client.create_session(url=sg_admin_url, db=sg_db, name=user_b_user_info.name, password=user_b_user_info.password) # Create 50 "A" channel docs a_docs = client.add_docs(url=sg_url, db=sg_db, number=50, id_prefix=None, auth=admin_session, channels=["A"]) assert len(a_docs) == 50 b_docs = client.add_docs(url=sg_url, db=sg_db, number=1, id_prefix="b_doc", auth=user_b_session, channels=["B"]) assert len(b_docs) == 1 user_doc = {"id": "_user/USER_B", "rev": None} b_docs.append(user_doc) # Loop until user_b sees b_doc_0 doc and _user/USER_B doc client.verify_docs_in_changes(url=sg_url, db=sg_db, expected_docs=b_docs, auth=user_b_session, strict=True) # Get last_seq for user_b user_b_changes = client.get_changes(url=sg_url, db=sg_db, since=0, auth=user_b_session, feed="normal") # Grant access to channel "A" if grant_type == "CHANNEL-REST": log_info("Granting user access to channel A via Admin REST user update") # Grant via update to user in Admin API client.update_user(url=sg_admin_url, db=sg_db, name=user_b_user_info.name, channels=["A", "B"]) elif grant_type == "CHANNEL-SYNC": log_info("Granting user access to channel A sync function access()") # Grant via access() in sync_function, then id 'channel_access' will trigger an access(doc.users, doc.channels) access_doc = document.create_doc("channel_access", channels=["A"]) access_doc["users"] = ["USER_B"] client.add_doc(url=sg_url, db=sg_db, doc=access_doc, auth=admin_session) elif grant_type == "ROLE-REST": log_info("Granting user access to channel A via Admin REST role grant") # Create role with channel A client.create_role(url=sg_admin_url, db=sg_db, name="channel-A-role", channels=["A"]) client.update_user(url=sg_admin_url, db=sg_db, name="USER_B", roles=["channel-A-role"]) elif grant_type == "ROLE-SYNC": log_info("Granting user access to channel A via sync function role() grant") # Create role with channel A client.create_role(url=sg_admin_url, db=sg_db, name="channel-A-role", channels=["A"]) # Grant via role() in sync_function, then id 'role_access' will trigger an role(doc.users, doc.roles) role_access_doc = document.create_doc("role_access") role_access_doc["users"] = ["USER_B"] role_access_doc["roles"] = ["role:channel-A-role"] client.add_doc(sg_url, db=sg_db, doc=role_access_doc, auth=admin_session) else: pytest.fail("Unsupported grant_type!!!!") user_b_changes_after_grant = client.get_changes(url=sg_url, db=sg_db, since=user_b_changes["last_seq"], auth=user_b_session, feed="normal") # User B shoud have recieved 51 docs (a_docs + 1 _user/USER_B doc) if a REST grant or 50 changes if the grant # is via the sync function changes_results = user_b_changes_after_grant["results"] assert 50 <= len(changes_results) <= 51 # Create a dictionary of id rev pair of all the docs that are not "_user/" docs from changes ids_and_revs_from_user_changes = { change["id"]: change["changes"][0]["rev"] for change in changes_results if not change["id"].startswith("_user/") } assert len(ids_and_revs_from_user_changes) == 50 # Create a list of id rev pair of all of the channel A docs ids_and_revs_from_a_docs = {doc["id"]: doc["rev"] for doc in a_docs} assert len(ids_and_revs_from_a_docs) == 50 # Check that the changes and the a_docs are identical in id and rev assert ids_and_revs_from_user_changes == ids_and_revs_from_a_docs # Get changes from last_seq of the changes request after the grant. There should be no new changes user_b_changes = client.get_changes(url=sg_url, db=sg_db, since=user_b_changes_after_grant["last_seq"], auth=user_b_session, feed="normal") assert len(user_b_changes["results"]) == 0
def test_backfill_channels_oneshot_limit_changes(params_from_base_test_setup, sg_conf_name, grant_type): cluster_config = params_from_base_test_setup["cluster_config"] topology = params_from_base_test_setup["cluster_topology"] mode = params_from_base_test_setup["mode"] sg_url = topology["sync_gateways"][0]["public"] sg_admin_url = topology["sync_gateways"][0]["admin"] sg_db = "db" log_info("grant_type: {}".format(grant_type)) sg_conf = sync_gateway_config_path_for_mode(sg_conf_name, mode) cluster = Cluster(cluster_config) cluster.reset(sg_conf) client = MobileRestClient() admin_user_info = userinfo.UserInfo("admin", "pass", channels=["A"], roles=[]) user_b_user_info = userinfo.UserInfo("USER_B", "pass", channels=["B"], roles=[]) # Create users / sessions client.create_user(url=sg_admin_url, db=sg_db, name=admin_user_info.name, password=admin_user_info.password, channels=admin_user_info.channels) client.create_user(url=sg_admin_url, db=sg_db, name=user_b_user_info.name, password=user_b_user_info.password, channels=user_b_user_info.channels) admin_session = client.create_session(url=sg_admin_url, db=sg_db, name=admin_user_info.name, password=admin_user_info.password) user_b_session = client.create_session(url=sg_admin_url, db=sg_db, name=user_b_user_info.name, password=user_b_user_info.password) # Create 50 "A" channel docs a_docs = client.add_docs(url=sg_url, db=sg_db, number=50, id_prefix=None, auth=admin_session, channels=["A"]) assert len(a_docs) == 50 b_docs = client.add_docs(url=sg_url, db=sg_db, number=1, id_prefix="b_doc", auth=user_b_session, channels=["B"]) assert len(b_docs) == 1 user_doc = {"id": "_user/USER_B", "rev": None} b_docs.append(user_doc) # Loop until user_b sees b_doc_0 doc and _user/USER_B doc client.verify_docs_in_changes(url=sg_url, db=sg_db, expected_docs=b_docs, auth=user_b_session, strict=True) # Get last_seq for user_b user_b_changes = client.get_changes(url=sg_url, db=sg_db, since=0, auth=user_b_session, feed="normal") # Grant access to channel "A" if grant_type == "CHANNEL-REST": log_info("Granting user access to channel A via Admin REST user update") # Grant via update to user in Admin API client.update_user(url=sg_admin_url, db=sg_db, name=user_b_user_info.name, channels=["A", "B"]) elif grant_type == "CHANNEL-SYNC": log_info("Granting user access to channel A sync function access()") # Grant via access() in sync_function, then id 'channel_access' will trigger an access(doc.users, doc.channels) access_doc = document.create_doc("channel_access", channels=["A"]) access_doc["users"] = ["USER_B"] client.add_doc(url=sg_url, db=sg_db, doc=access_doc, auth=admin_session) elif grant_type == "ROLE-REST": log_info("Granting user access to channel A via Admin REST role grant") # Create role with channel A client.create_role(url=sg_admin_url, db=sg_db, name="channel-A-role", channels=["A"]) client.update_user(url=sg_admin_url, db=sg_db, name="USER_B", roles=["channel-A-role"]) elif grant_type == "ROLE-SYNC": log_info("Granting user access to channel A via sync function role() grant") # Create role with channel A client.create_role(url=sg_admin_url, db=sg_db, name="channel-A-role", channels=["A"]) # Grant via role() in sync_function, then id 'role_access' will trigger an role(doc.users, doc.roles) role_access_doc = document.create_doc("role_access") role_access_doc["users"] = ["USER_B"] role_access_doc["roles"] = ["role:channel-A-role"] client.add_doc(sg_url, db=sg_db, doc=role_access_doc, auth=admin_session) else: pytest.fail("Unsupported grant_type!!!!") # Create a dictionary keyed on doc id for all of channel A docs ids_and_revs_from_a_docs = {doc["id"]: doc["rev"] for doc in a_docs} assert len(ids_and_revs_from_a_docs.keys()) == 50 log_info("Doing 3, 1 shot changes with limit and last seq!") # Issue 3 oneshot changes with a limit of 20 ################# # Changes Req #1 ################# user_b_changes_after_grant_one = client.get_changes(url=sg_url, db=sg_db, since=user_b_changes["last_seq"], auth=user_b_session, feed="normal", limit=20) # User B shoud have recieved 20 docs due to limit assert len(user_b_changes_after_grant_one["results"]) == 20 for doc in user_b_changes_after_grant_one["results"]: # cross off keys found from 'a_docs' dictionary del ids_and_revs_from_a_docs[doc["id"]] ################# # Changes Req #2 ################# user_b_changes_after_grant_two = client.get_changes(url=sg_url, db=sg_db, since=user_b_changes_after_grant_one["last_seq"], auth=user_b_session, feed="normal", limit=20) # User B shoud have recieved 20 docs due to limit assert len(user_b_changes_after_grant_two["results"]) == 20 for doc in user_b_changes_after_grant_two["results"]: # cross off keys found from 'a_docs' dictionary del ids_and_revs_from_a_docs[doc["id"]] ################# # Changes Req #3 ################# user_b_changes_after_grant_three = client.get_changes(url=sg_url, db=sg_db, since=user_b_changes_after_grant_two["last_seq"], auth=user_b_session, feed="normal", limit=20) # User B shoud have recieved 20 docs due to limit assert len(user_b_changes_after_grant_three["results"]) == 10 for doc in user_b_changes_after_grant_three["results"]: # cross off keys found from 'a_docs' dictionary del ids_and_revs_from_a_docs[doc["id"]] # Make sure all the docs have been crossed out assert len(ids_and_revs_from_a_docs) == 0 ################# # Changes Req #4 ################# user_b_changes_after_grant_four = client.get_changes(url=sg_url, db=sg_db, since=user_b_changes_after_grant_three["last_seq"], auth=user_b_session, feed="normal", limit=20) # Changes should be caught up and there should be no results assert len(user_b_changes_after_grant_four["results"]) == 0
def test_longpoll_awaken_roles(params_from_base_test_setup, sg_conf_name): cluster_conf = params_from_base_test_setup["cluster_config"] cluster_topology = params_from_base_test_setup["cluster_topology"] mode = params_from_base_test_setup["mode"] sg_conf = sync_gateway_config_path_for_mode(sg_conf_name, mode) sg_admin_url = cluster_topology["sync_gateways"][0]["admin"] sg_url = cluster_topology["sync_gateways"][0]["public"] log_info("sg_conf: {}".format(sg_conf)) log_info("sg_admin_url: {}".format(sg_admin_url)) log_info("sg_url: {}".format(sg_url)) cluster = Cluster(config=cluster_conf) cluster.reset(sg_config_path=sg_conf) admin_role = "admin_role" admin_channel = "admin_channel" admin_user_info = userinfo.UserInfo(name="admin", password="******", channels=[], roles=[admin_role]) adam_user_info = userinfo.UserInfo(name="adam", password="******", channels=[], roles=[]) traun_user_info = userinfo.UserInfo(name="traun", password="******", channels=[], roles=[]) andy_user_info = userinfo.UserInfo(name="andy", password="******", channels=[], roles=[]) sg_db = "db" client = MobileRestClient() # Create a role on sync_gateway client.create_role(url=sg_admin_url, db=sg_db, name=admin_role, channels=[admin_channel]) # Create users with no channels or roles admin_auth = client.create_user(url=sg_admin_url, db=sg_db, name=admin_user_info.name, password=admin_user_info.password, roles=[admin_role]) adam_auth = client.create_user(url=sg_admin_url, db=sg_db, name=adam_user_info.name, password=adam_user_info.password) traun_auth = client.create_user(url=sg_admin_url, db=sg_db, name=traun_user_info.name, password=traun_user_info.password) andy_auth = client.create_user(url=sg_admin_url, db=sg_db, name=andy_user_info.name, password=andy_user_info.password) ################################ # change feed wakes for role add ################################ # Get starting sequence of docs, use the last seq to progress past any _user docs. adam_changes = client.get_changes(url=sg_url, db=sg_db, since=0, feed="normal", auth=adam_auth) traun_changes = client.get_changes(url=sg_url, db=sg_db, since=0, feed="normal", auth=traun_auth) andy_changes = client.get_changes(url=sg_url, db=sg_db, since=0, feed="normal", auth=andy_auth) # Add doc with channel associated with the admin role admin_doc = client.add_docs(url=sg_url, db=sg_db, number=1, id_prefix="admin_doc", auth=admin_auth, channels=[admin_channel]) client.verify_docs_in_changes(url=sg_url, db=sg_db, expected_docs=admin_doc, auth=admin_auth) with concurrent.futures.ProcessPoolExecutor() as ex: # Start changes feed for 3 users from latest last_seq adam_changes_task = ex.submit(client.get_changes, url=sg_url, db=sg_db, since=adam_changes["last_seq"], timeout=10, auth=adam_auth) traun_changes_task = ex.submit(client.get_changes, url=sg_url, db=sg_db, since=traun_changes["last_seq"], timeout=10, auth=traun_auth) andy_changes_task = ex.submit(client.get_changes, url=sg_url, db=sg_db, since=andy_changes["last_seq"], timeout=10, auth=andy_auth) # Wait for changes feed to notice there are no changes and enter wait. 2 seconds should be more than enough time.sleep(2) # Make sure the changes future is still running and has not exited due to any new changes, the feed should be caught up # and waiting assert not adam_changes_task.done() assert not traun_changes_task.done() assert not andy_changes_task.done() adam_auth = client.update_user(url=sg_admin_url, db=sg_db, name=adam_user_info.name, password=adam_user_info.password, roles=[admin_role]) traun_auth = client.update_user(url=sg_admin_url, db=sg_db, name=traun_user_info.name, password=traun_user_info.password, roles=[admin_role]) andy_auth = client.update_user(url=sg_admin_url, db=sg_db, name=andy_user_info.name, password=andy_user_info.password, roles=[admin_role]) adam_changes = adam_changes_task.result() assert 1 <= len(adam_changes["results"]) <= 2 assert adam_changes["results"][0]["id"] == "admin_doc_0" or adam_changes["results"][0]["id"] == "_user/adam" traun_changes = traun_changes_task.result() assert 1 <= len(traun_changes["results"]) <= 2 assert traun_changes["results"][0]["id"] == "admin_doc_0" or traun_changes["results"][0]["id"] == "_user/traun" andy_changes = andy_changes_task.result() assert 1 <= len(andy_changes["results"]) <= 2 assert andy_changes["results"][0]["id"] == "admin_doc_0" or andy_changes["results"][0]["id"] == "_user/andy" # Check that the user docs all show up in changes feed client.verify_doc_id_in_changes(url=sg_url, db=sg_db, expected_doc_id="_user/adam", auth=adam_auth) client.verify_doc_id_in_changes(url=sg_url, db=sg_db, expected_doc_id="_user/traun", auth=traun_auth) client.verify_doc_id_in_changes(url=sg_url, db=sg_db, expected_doc_id="_user/andy", auth=andy_auth) # Check that the admin doc made it to all the changes feeds client.verify_docs_in_changes(url=sg_url, db=sg_db, expected_docs=admin_doc, auth=adam_auth) client.verify_docs_in_changes(url=sg_url, db=sg_db, expected_docs=admin_doc, auth=traun_auth) client.verify_docs_in_changes(url=sg_url, db=sg_db, expected_docs=admin_doc, auth=andy_auth) # At this point, each user should have a changes feed that is caught up for the next section ########################################### # change feed wakes for channel add to role ########################################### abc_channel = "ABC" abc_pusher_info = userinfo.UserInfo(name="abc_pusher", password="******", channels=[abc_channel], roles=[]) abc_pusher_auth = client.create_user(url=sg_admin_url, db=sg_db, name=abc_pusher_info.name, password=abc_pusher_info.password, channels=abc_pusher_info.channels) # Add doc with ABC channel client.add_docs(url=sg_url, db=sg_db, number=1, id_prefix="abc_doc", auth=abc_pusher_auth, channels=[abc_channel]) # Get latest last_seq for next test section adam_changes = client.get_changes(url=sg_url, db=sg_db, since=0, feed="normal", auth=adam_auth) traun_changes = client.get_changes(url=sg_url, db=sg_db, since=0, feed="normal", auth=traun_auth) andy_changes = client.get_changes(url=sg_url, db=sg_db, since=0, feed="normal", auth=andy_auth) with concurrent.futures.ProcessPoolExecutor() as ex: # Start changes feed for 3 users from latest last_seq adam_changes_task = ex.submit(client.get_changes, url=sg_url, db=sg_db, since=adam_changes["last_seq"], timeout=10, auth=adam_auth) traun_changes_task = ex.submit(client.get_changes, url=sg_url, db=sg_db, since=traun_changes["last_seq"], timeout=10, auth=traun_auth) andy_changes_task = ex.submit(client.get_changes, url=sg_url, db=sg_db, since=andy_changes["last_seq"], timeout=10, auth=andy_auth) # Wait for changes feed to notice there are no changes and enter wait. 2 seconds should be more than enough time.sleep(2) # Make sure the changes future is still running and has not exited due to any new changes, the feed should be caught up # and waiting assert not adam_changes_task.done() assert not traun_changes_task.done() assert not andy_changes_task.done() # Update admin role to include ABC channel # Since adam, traun, and andy are assigned to that role, they should wake up and get the 'abc_pusher_0' doc client.update_role(url=sg_admin_url, db=sg_db, name=admin_role, channels=[admin_channel, abc_channel]) adam_changes = adam_changes_task.result() assert len(adam_changes["results"]) == 1 assert adam_changes["results"][0]["id"] == "abc_doc_0" traun_changes = traun_changes_task.result() assert len(traun_changes["results"]) == 1 assert traun_changes["results"][0]["id"] == "abc_doc_0" andy_changes = adam_changes_task.result() assert len(andy_changes["results"]) == 1 assert andy_changes["results"][0]["id"] == "abc_doc_0"
def test_awaken_backfill_channels_longpoll_changes_with_limit( params_from_base_test_setup, sg_conf_name, grant_type): """ Test that checks that docs are backfilled for logpoll changes with limit for a access grant (via REST or SYNC) CHANNEL-REST = Channel is granted to user via REST CHANNEL-SYNC = Channel is granted to user via sync function access() ROLE-REST = Role is granted to user via REST ROLE-SYNC = Role is granted to user via sync function role() CHANNEL-TO-ROLE-REST = Channel is added to existing role via REST CHANNEL-TO-ROLE-SYNC = Channel is added to existing role via sync access() """ cluster_config = params_from_base_test_setup["cluster_config"] topology = params_from_base_test_setup["cluster_topology"] mode = params_from_base_test_setup["mode"] sg_url = topology["sync_gateways"][0]["public"] sg_admin_url = topology["sync_gateways"][0]["admin"] sg_db = "db" log_info("grant_type: {}".format(grant_type)) sg_conf = sync_gateway_config_path_for_mode(sg_conf_name, mode) cluster = Cluster(cluster_config) cluster.reset(sg_conf) client = MobileRestClient() admin_user_info = userinfo.UserInfo("admin", "pass", channels=["A"], roles=[]) if grant_type == "CHANNEL-TO-ROLE-REST" or grant_type == "CHANNEL-TO-ROLE-SYNC": client.create_role(url=sg_admin_url, db=sg_db, name="empty_role", channels=[]) user_b_user_info = userinfo.UserInfo("USER_B", "pass", channels=["B"], roles=["empty_role"]) else: user_b_user_info = userinfo.UserInfo("USER_B", "pass", channels=["B"], roles=[]) # Create users / sessions client.create_user( url=sg_admin_url, db=sg_db, name=admin_user_info.name, password=admin_user_info.password, channels=admin_user_info.channels, ) client.create_user(url=sg_admin_url, db=sg_db, name=user_b_user_info.name, password=user_b_user_info.password, channels=user_b_user_info.channels, roles=user_b_user_info.roles) admin_session = client.create_session(url=sg_admin_url, db=sg_db, name=admin_user_info.name, password=admin_user_info.password) user_b_session = client.create_session(url=sg_admin_url, db=sg_db, name=user_b_user_info.name, password=user_b_user_info.password) # Create 50 "A" channel docs a_docs = client.add_docs(url=sg_url, db=sg_db, number=50, id_prefix=None, auth=admin_session, channels=["A"]) assert len(a_docs) == 50 b_docs = client.add_docs(url=sg_url, db=sg_db, number=1, id_prefix="b_doc", auth=user_b_session, channels=["B"]) assert len(b_docs) == 1 user_doc = {"id": "_user/USER_B", "rev": None} b_docs.append(user_doc) # Loop until user_b sees b_doc_0 doc and _user/USER_B doc client.verify_docs_in_changes(url=sg_url, db=sg_db, expected_docs=b_docs, auth=user_b_session, strict=True) # Create a dictionary keyed on doc id for all of channel A docs ids_and_revs_from_a_docs = {doc["id"]: doc["rev"] for doc in a_docs} assert len(ids_and_revs_from_a_docs.keys()) == 50 # Get last_seq for user_b user_b_changes = client.get_changes(url=sg_url, db=sg_db, since=0, auth=user_b_session, feed="normal") with concurrent.futures.ThreadPoolExecutor(max_workers=10) as ex: # Start long poll changes feed. changes_task = ex.submit(client.get_changes, url=sg_url, db=sg_db, since=user_b_changes["last_seq"], auth=user_b_session, timeout=10, limit=20) # Grant access to channel "A" if grant_type == "CHANNEL-REST": log_info( "Granting user access to channel A via Admin REST user update") # Grant via update to user in Admin API client.update_user(url=sg_admin_url, db=sg_db, name=user_b_user_info.name, channels=["A", "B"]) elif grant_type == "CHANNEL-SYNC": log_info( "Granting user access to channel A sync function access()") # Grant via access() in sync_function, # then id 'channel_access' will trigger an access(doc.users, doc.channels) access_doc = document.create_doc("channel_access", channels=["A"]) access_doc["users"] = ["USER_B"] client.add_doc(url=sg_url, db=sg_db, doc=access_doc, auth=admin_session) elif grant_type == "ROLE-REST": log_info( "Granting user access to channel A via Admin REST role grant") # Create role with channel A client.create_role(url=sg_admin_url, db=sg_db, name="channel-A-role", channels=["A"]) client.update_user(url=sg_admin_url, db=sg_db, name=user_b_user_info.name, roles=["channel-A-role"]) elif grant_type == "ROLE-SYNC": log_info( "Granting user access to channel A via sync function role() grant" ) # Create role with channel A client.create_role(url=sg_admin_url, db=sg_db, name="channel-A-role", channels=["A"]) # Grant via role() in sync_function, then id 'role_access' will trigger an role(doc.users, doc.roles) role_access_doc = document.create_doc("role_access") role_access_doc["users"] = ["USER_B"] role_access_doc["roles"] = ["role:channel-A-role"] client.add_doc(sg_url, db=sg_db, doc=role_access_doc, auth=admin_session) elif grant_type == "CHANNEL-TO-ROLE-REST": # Update the empty_role to have channel "A" client.update_role(url=sg_admin_url, db=sg_db, name="empty_role", channels=["A"]) elif grant_type == "CHANNEL-TO-ROLE-SYNC": # Grant empty_role access to channel "A" via sync function # Grant channel access to role via sync function access_doc = document.create_doc("channel_grant_to_role") access_doc["roles"] = ["role:empty_role"] access_doc["channels"] = ["A"] client.add_doc(url=sg_url, db=sg_db, doc=access_doc, auth=admin_session, use_post=True) else: pytest.fail("Unsupported grant_type!!!!") # Block on return of longpoll changes, feed should wake up and return 20 results changes = changes_task.result() assert len(changes["results"]) == 20 num_requests = 1 # append _user/doc to the doc scratch pad if a REST grant if grant_type == "CHANNEL-REST" or grant_type == "ROLE-REST": ids_and_revs_from_a_docs["_user/USER_B"] = None # Cross the results off from the 'a_docs' dictionary for doc in changes["results"]: del ids_and_revs_from_a_docs[doc["id"]] # Start looping longpoll changes with limit, cross off changes from dictionary each time one is found # Since 20 changes should be crossed off already, this should execute 2x. log_info("Starting looping longpoll changes with limit!") last_seq = changes["last_seq"] while True: if len(ids_and_revs_from_a_docs.keys()) == 0: log_info("All docs were found! Exiting polling loop") break changes = client.get_changes(url=sg_url, db=sg_db, since=last_seq, auth=user_b_session, limit=20, timeout=10) num_requests += 1 # There are more than 2 requests, throw an exception. if num_requests == 2: assert len(changes["results"]) == 20 elif num_requests == 3: # This will be 10 or 11 depending on if the _user/ doc is returned if grant_type == "CHANNEL-REST" or grant_type == "ROLE-REST": assert len(changes["results"]) == 11 else: assert len(changes["results"]) == 10 else: raise exceptions.ChangesError( "Looping longpoll should only have to perform 3 requests to get all the changes!!" ) # Cross the results off from the 'a_docs' dictionary. # This will blow up in docs duplicate docs are sent to changes for doc in changes["results"]: del ids_and_revs_from_a_docs[doc["id"]] last_seq = changes["last_seq"] # Shanges after longpoll zero_results = client.get_changes(url=sg_url, db=sg_db, since=last_seq, auth=user_b_session, feed="normal") # Changes should be caught up and there should be no results assert len(zero_results["results"]) == 0
def test_backfill_channels_oneshot_changes(params_from_base_test_setup, sg_conf_name, grant_type): """ Test that checks that docs are backfilled for one shot changes for a access grant (via REST or SYNC) CHANNEL-REST = Channel is granted to user via REST CHANNEL-SYNC = Channel is granted to user via sync function access() ROLE-REST = Role is granted to user via REST ROLE-SYNC = Role is granted to user via sync function role() CHANNEL-TO-ROLE-REST = Channel is added to existing role via REST CHANNEL-TO-ROLE-SYNC = Channel is added to existing role via sync access() """ cluster_config = params_from_base_test_setup["cluster_config"] topology = params_from_base_test_setup["cluster_topology"] mode = params_from_base_test_setup["mode"] sg_url = topology["sync_gateways"][0]["public"] sg_admin_url = topology["sync_gateways"][0]["admin"] sg_db = "db" log_info("grant_type: {}".format(grant_type)) sg_conf = sync_gateway_config_path_for_mode(sg_conf_name, mode) cluster = Cluster(cluster_config) cluster.reset(sg_conf) client = MobileRestClient() admin_user_info = userinfo.UserInfo("admin", "pass", channels=["A"], roles=[]) if grant_type == "CHANNEL-TO-ROLE-REST" or grant_type == "CHANNEL-TO-ROLE-SYNC": client.create_role(url=sg_admin_url, db=sg_db, name="empty_role", channels=[]) user_b_user_info = userinfo.UserInfo("USER_B", "pass", channels=["B"], roles=["empty_role"]) else: user_b_user_info = userinfo.UserInfo("USER_B", "pass", channels=["B"], roles=[]) # Create users / sessions client.create_user(url=sg_admin_url, db=sg_db, name=admin_user_info.name, password=admin_user_info.password, channels=admin_user_info.channels) client.create_user(url=sg_admin_url, db=sg_db, name=user_b_user_info.name, password=user_b_user_info.password, channels=user_b_user_info.channels, roles=user_b_user_info.roles) admin_session = client.create_session(url=sg_admin_url, db=sg_db, name=admin_user_info.name, password=admin_user_info.password) user_b_session = client.create_session(url=sg_admin_url, db=sg_db, name=user_b_user_info.name, password=user_b_user_info.password) # Create 50 "A" channel docs a_docs = client.add_docs(url=sg_url, db=sg_db, number=50, id_prefix=None, auth=admin_session, channels=["A"]) assert len(a_docs) == 50 b_docs = client.add_docs(url=sg_url, db=sg_db, number=1, id_prefix="b_doc", auth=user_b_session, channels=["B"]) assert len(b_docs) == 1 user_doc = {"id": "_user/USER_B", "rev": None} b_docs.append(user_doc) # Loop until admin user sees docs in changes client.verify_docs_in_changes(url=sg_url, db=sg_db, expected_docs=a_docs, auth=admin_session) # Loop until user_b sees b_doc_0 doc and _user/USER_B doc client.verify_docs_in_changes(url=sg_url, db=sg_db, expected_docs=b_docs, auth=user_b_session, strict=True) # Get last_seq for user_b user_b_changes = client.get_changes(url=sg_url, db=sg_db, since=0, auth=user_b_session, feed="normal") # Grant access to channel "A" if grant_type == "CHANNEL-REST": log_info( "Granting user access to channel A via Admin REST user update") # Grant via update to user in Admin API client.update_user(url=sg_admin_url, db=sg_db, name=user_b_user_info.name, channels=["A", "B"]) elif grant_type == "CHANNEL-SYNC": log_info("Granting user access to channel A sync function access()") # Grant via access() in sync_function, then id 'channel_access' will trigger an access(doc.users, doc.channels) access_doc = document.create_doc("channel_access", channels=["A"]) access_doc["users"] = ["USER_B"] client.add_doc(url=sg_url, db=sg_db, doc=access_doc, auth=admin_session) elif grant_type == "ROLE-REST": log_info("Granting user access to channel A via Admin REST role grant") # Create role with channel A client.create_role(url=sg_admin_url, db=sg_db, name="channel-A-role", channels=["A"]) client.update_user(url=sg_admin_url, db=sg_db, name="USER_B", channels=["B"], roles=["channel-A-role"]) elif grant_type == "ROLE-SYNC": log_info( "Granting user access to channel A via sync function role() grant") # Create role with channel A client.create_role(url=sg_admin_url, db=sg_db, name="channel-A-role", channels=["A"]) # Grant via role() in sync_function, then id 'role_access' will trigger an role(doc.users, doc.roles) role_access_doc = document.create_doc("role_access") role_access_doc["users"] = ["USER_B"] role_access_doc["roles"] = ["role:channel-A-role"] client.add_doc(sg_url, db=sg_db, doc=role_access_doc, auth=admin_session) elif grant_type == "CHANNEL-TO-ROLE-REST": # Update the empty_role to have channel "A" client.update_role(url=sg_admin_url, db=sg_db, name="empty_role", channels=["A"]) elif grant_type == "CHANNEL-TO-ROLE-SYNC": # Grant empty_role access to channel "A" via sync function # Grant channel access to role via sync function access_doc = document.create_doc("channel_grant_to_role") access_doc["roles"] = ["role:empty_role"] access_doc["channels"] = ["A"] client.add_doc(url=sg_url, db=sg_db, doc=access_doc, auth=admin_session, use_post=True) else: pytest.fail("Unsupported grant_type!!!!") # Issue one shot changes to make sure access grant is successful, the change may not propagate immediately so retry. num_retries = 3 count = 0 while True: if count == num_retries: raise exceptions.ChangesError( "Didn't get all expected changes before timing out!") user_b_changes_after_grant = client.get_changes( url=sg_url, db=sg_db, since=user_b_changes["last_seq"], auth=user_b_session, feed="normal") if len(user_b_changes_after_grant["results"]) > 0: # Found changes, break out an validate changes! break time.sleep(1) count += 1 # User B shoud have recieved 51 docs (a_docs + 1 _user/USER_B doc) if a REST grant or 50 changes if the grant # is via the sync function changes_results = user_b_changes_after_grant["results"] assert 50 <= len(changes_results) <= 51 # Create a dictionary of id rev pair of all the docs that are not "_user/" docs from changes ids_and_revs_from_user_changes = { change["id"]: change["changes"][0]["rev"] for change in changes_results if not change["id"].startswith("_user/") } assert len(ids_and_revs_from_user_changes) == 50 # Create a list of id rev pair of all of the channel A docs ids_and_revs_from_a_docs = {doc["id"]: doc["rev"] for doc in a_docs} assert len(ids_and_revs_from_a_docs) == 50 # Check that the changes and the a_docs are identical in id and rev assert ids_and_revs_from_user_changes == ids_and_revs_from_a_docs # Get changes from last_seq of the changes request after the grant. There should be no new changes user_b_changes = client.get_changes( url=sg_url, db=sg_db, since=user_b_changes_after_grant["last_seq"], auth=user_b_session, feed="normal") assert len(user_b_changes["results"]) == 0
def test_backfill_channels_oneshot_limit_changes(params_from_base_test_setup, sg_conf_name, grant_type): """ Test that checks that docs are backfilled for one shot changes with limit for a access grant (via REST or SYNC) CHANNEL-REST = Channel is granted to user via REST CHANNEL-SYNC = Channel is granted to user via sync function access() ROLE-REST = Role is granted to user via REST ROLE-SYNC = Role is granted to user via sync function role() CHANNEL-TO-ROLE-REST = Channel is added to existing role via REST CHANNEL-TO-ROLE-SYNC = Channel is added to existing role via sync access() """ cluster_config = params_from_base_test_setup["cluster_config"] topology = params_from_base_test_setup["cluster_topology"] mode = params_from_base_test_setup["mode"] sg_url = topology["sync_gateways"][0]["public"] sg_admin_url = topology["sync_gateways"][0]["admin"] sg_db = "db" log_info("grant_type: {}".format(grant_type)) sg_conf = sync_gateway_config_path_for_mode(sg_conf_name, mode) cluster = Cluster(cluster_config) cluster.reset(sg_conf) client = MobileRestClient() admin_user_info = userinfo.UserInfo("admin", "pass", channels=["A"], roles=[]) if grant_type == "CHANNEL-TO-ROLE-REST" or grant_type == "CHANNEL-TO-ROLE-SYNC": client.create_role(url=sg_admin_url, db=sg_db, name="empty_role", channels=[]) user_b_user_info = userinfo.UserInfo("USER_B", "pass", channels=["B"], roles=["empty_role"]) else: user_b_user_info = userinfo.UserInfo("USER_B", "pass", channels=["B"], roles=[]) # Create users / sessions client.create_user(url=sg_admin_url, db=sg_db, name=admin_user_info.name, password=admin_user_info.password, channels=admin_user_info.channels) client.create_user(url=sg_admin_url, db=sg_db, name=user_b_user_info.name, password=user_b_user_info.password, channels=user_b_user_info.channels, roles=user_b_user_info.roles) admin_session = client.create_session(url=sg_admin_url, db=sg_db, name=admin_user_info.name, password=admin_user_info.password) user_b_session = client.create_session(url=sg_admin_url, db=sg_db, name=user_b_user_info.name, password=user_b_user_info.password) # Create 50 "A" channel docs a_docs = client.add_docs(url=sg_url, db=sg_db, number=50, id_prefix=None, auth=admin_session, channels=["A"]) assert len(a_docs) == 50 b_docs = client.add_docs(url=sg_url, db=sg_db, number=1, id_prefix="b_doc", auth=user_b_session, channels=["B"]) assert len(b_docs) == 1 # Loop until admin user sees docs in changes client.verify_docs_in_changes(url=sg_url, db=sg_db, expected_docs=a_docs, auth=admin_session) user_doc = {"id": "_user/USER_B", "rev": None} b_docs.append(user_doc) # Loop until user_b sees b_doc_0 doc and _user/USER_B doc client.verify_docs_in_changes(url=sg_url, db=sg_db, expected_docs=b_docs, auth=user_b_session, strict=True) # Get last_seq for user_b user_b_changes = client.get_changes(url=sg_url, db=sg_db, since=0, auth=user_b_session, feed="normal") # Grant access to channel "A" if grant_type == "CHANNEL-REST": log_info( "Granting user access to channel A via Admin REST user update") # Grant via update to user in Admin API client.update_user(url=sg_admin_url, db=sg_db, name=user_b_user_info.name, channels=["A", "B"]) elif grant_type == "CHANNEL-SYNC": log_info("Granting user access to channel A sync function access()") # Grant via access() in sync_function, then id 'channel_access' will trigger an access(doc.users, doc.channels) access_doc = document.create_doc("channel_access", channels=["A"]) access_doc["users"] = ["USER_B"] client.add_doc(url=sg_url, db=sg_db, doc=access_doc, auth=admin_session) elif grant_type == "ROLE-REST": log_info("Granting user access to channel A via Admin REST role grant") # Create role with channel A client.create_role(url=sg_admin_url, db=sg_db, name="channel-A-role", channels=["A"]) client.update_user(url=sg_admin_url, db=sg_db, name="USER_B", roles=["channel-A-role"]) elif grant_type == "ROLE-SYNC": log_info( "Granting user access to channel A via sync function role() grant") # Create role with channel A client.create_role(url=sg_admin_url, db=sg_db, name="channel-A-role", channels=["A"]) # Grant via role() in sync_function, then id 'role_access' will trigger an role(doc.users, doc.roles) role_access_doc = document.create_doc("role_access") role_access_doc["users"] = ["USER_B"] role_access_doc["roles"] = ["role:channel-A-role"] client.add_doc(sg_url, db=sg_db, doc=role_access_doc, auth=admin_session) elif grant_type == "CHANNEL-TO-ROLE-REST": # Update the empty_role to have channel "A" client.update_role(url=sg_admin_url, db=sg_db, name="empty_role", channels=["A"]) elif grant_type == "CHANNEL-TO-ROLE-SYNC": # Grant empty_role access to channel "A" via sync function # Grant channel access to role via sync function access_doc = document.create_doc("channel_grant_to_role") access_doc["roles"] = ["role:empty_role"] access_doc["channels"] = ["A"] client.add_doc(url=sg_url, db=sg_db, doc=access_doc, auth=admin_session, use_post=True) else: pytest.fail("Unsupported grant_type!!!!") # Create a dictionary keyed on doc id for all of channel A docs ids_and_revs_from_a_docs = {doc["id"]: doc["rev"] for doc in a_docs} assert len(ids_and_revs_from_a_docs.keys()) == 50 log_info("Doing 3, 1 shot changes with limit and last seq!") # Issue 3 oneshot changes with a limit of 20 # Issue one shot changes to make sure access grant is successful, the change may not propagate immediately so retry. num_retries = 3 count = 0 while True: if count == num_retries: raise exceptions.ChangesError( "Didn't get all expected changes before timing out!") user_b_changes_after_grant_one = client.get_changes( url=sg_url, db=sg_db, since=user_b_changes["last_seq"], auth=user_b_session, feed="normal", limit=20) if len(user_b_changes_after_grant_one["results"]) > 0: # Found changes, break out an validate changes! break time.sleep(1) count += 1 ################# # Changes Req #1 ################# # Expect a user doc in the changes if grant_type == "CHANNEL-REST" or grant_type == "ROLE-REST": ids_and_revs_from_a_docs["_user/USER_B"] = None # User B shoud have recieved 20 docs due to limit assert len(user_b_changes_after_grant_one["results"]) == 20 for doc in user_b_changes_after_grant_one["results"]: # cross off keys found from 'a_docs' dictionary del ids_and_revs_from_a_docs[doc["id"]] ################# # Changes Req #2 ################# user_b_changes_after_grant_two = client.get_changes( url=sg_url, db=sg_db, since=user_b_changes_after_grant_one["last_seq"], auth=user_b_session, feed="normal", limit=20) # User B shoud have recieved 20 docs due to limit assert len(user_b_changes_after_grant_two["results"]) == 20 for doc in user_b_changes_after_grant_two["results"]: # cross off keys found from 'a_docs' dictionary del ids_and_revs_from_a_docs[doc["id"]] ################# # Changes Req #3 ################# user_b_changes_after_grant_three = client.get_changes( url=sg_url, db=sg_db, since=user_b_changes_after_grant_two["last_seq"], auth=user_b_session, feed="normal", limit=20) # User B should have recieved 10 docs due to limit or 11 docs with with a terminating _user doc # The terminating user doc only happens with a grant via REST if grant_type == "CHANNEL-REST" or grant_type == "ROLE-REST": assert len(user_b_changes_after_grant_three["results"]) == 11 else: assert len(user_b_changes_after_grant_three["results"]) == 10 for doc in user_b_changes_after_grant_three["results"]: # cross off non user doc keys found from 'a_docs' dictionary del ids_and_revs_from_a_docs[doc["id"]] # Make sure all the docs have been crossed out assert len(ids_and_revs_from_a_docs) == 0 ################# # Changes Req #4 ################# user_b_changes_after_grant_four = client.get_changes( url=sg_url, db=sg_db, since=user_b_changes_after_grant_three["last_seq"], auth=user_b_session, feed="normal", limit=20) # Changes should be caught up and there should be no results assert len(user_b_changes_after_grant_four["results"]) == 0