Exemple #1
0
def test_attachment_revpos_when_ancestor_unavailable(
        params_from_base_test_setup, sg_conf_name):
    """
    Creates a document with an attachment, then updates that document so that
    the body of the revision that originally pushed the document is no
    longer available.  Add a new revision that's not a child of the
    active revision, and validate that it's uploaded successfully.
    Example:
       1. Document is created with attachment at rev-1
       2. Document is updated (strip digests and length, only put revpos & stub) multiple times on the server, goes to rev-10
       3. Client attempts to add a new (conflicting) revision 2, with parent rev-1.
       4. If the body of rev-1 is no longer available on the server (temporary backup of revision has expired, and is no longer stored
         in the in-memory rev cache), we were throwing an error to client
         because we couldn't verify based on the _attachments property in rev-1.
       5. In this scenario, before returning error, we are now checking if the active revision has a common ancestor with the incoming revision.
    If so, we can validate any revpos values equal to or earlier than the common ancestor against the active revision
    """

    cluster_config = params_from_base_test_setup["cluster_config"]
    mode = params_from_base_test_setup["mode"]
    no_conflicts_enabled = params_from_base_test_setup["no_conflicts_enabled"]

    if no_conflicts_enabled:
        pytest.skip('--no-conflicts is not enabled, so skipping the test')

    sg_conf = sync_gateway_config_path_for_mode(sg_conf_name, mode)

    cluster_helper = ClusterKeywords()
    cluster_helper.reset_cluster(cluster_config, sg_conf)

    topology = cluster_helper.get_cluster_topology(cluster_config)

    cbs_url = topology["couchbase_servers"][0]
    sg_url = topology["sync_gateways"][0]["public"]
    sg_url_admin = topology["sync_gateways"][0]["admin"]
    sg_db = "db"
    bucket = "data-bucket"

    log_info("Running 'test_attachment_revpos_when_ancestor_unavailable'")
    log_info("Using cbs_url: {}".format(cbs_url))
    log_info("Using sg_url: {}".format(sg_url))
    log_info("Using sg_url_admin: {}".format(sg_url_admin))
    log_info("Using sg_db: {}".format(sg_db))
    log_info("Using bucket: {}".format(bucket))

    channels_list = ["ABC"]

    client = MobileRestClient()
    sg_util = SyncGateway()
    cb_server = couchbaseserver.CouchbaseServer(cbs_url)

    user1 = client.create_user(url=sg_url_admin,
                               db=sg_db,
                               name="user1",
                               password="******",
                               channels=channels_list)
    atts = attachment.load_from_data_dir(["sample_text.txt"])
    doc_with_att = document.create_doc(doc_id="att_doc",
                                       content={"sample_key": "sample_val"},
                                       attachments=atts,
                                       channels=channels_list)

    doc_gen_1 = client.add_doc(url=sg_url,
                               db=sg_db,
                               doc=doc_with_att,
                               auth=user1)
    client.update_doc(url=sg_url,
                      db=sg_db,
                      doc_id=doc_gen_1["id"],
                      number_updates=10,
                      auth=user1)

    # Clear cached rev doc bodys from server and cycle sync_gateway
    sg_util.stop_sync_gateways(cluster_config=cluster_config, url=sg_url)

    cb_server.delete_couchbase_server_cached_rev_bodies(bucket=bucket)
    sg_util.start_sync_gateways(cluster_config=cluster_config,
                                url=sg_url,
                                config=sg_conf)

    client.add_conflict(url=sg_url,
                        db=sg_db,
                        doc_id=doc_gen_1["id"],
                        parent_revisions=doc_gen_1["rev"],
                        new_revision="2-foo",
                        auth=user1)
Exemple #2
0
def test_writing_attachment_to_couchbase_server(params_from_base_test_setup,
                                                sg_conf_name):
    """
    1. Start sync_gateway with sync function that rejects all writes:
    function(doc, oldDoc) {
      throw({forbidden:"No writes!"});
    }
    2. Create a doc with attachment
    3. Use CBS sdk to see if attachment doc exists.  Doc ID will look like _sync:att:sha1-Kq5sNclPz7QV2+lfQIuc6R7oRu0= (where the suffix is the digest)
    4. Assert att doc does not exist
    """

    cluster_config = params_from_base_test_setup["cluster_config"]
    mode = params_from_base_test_setup["mode"]

    sg_conf = sync_gateway_config_path_for_mode(sg_conf_name, mode)

    cluster_helper = ClusterKeywords()
    cluster_helper.reset_cluster(cluster_config, sg_conf)

    topology = cluster_helper.get_cluster_topology(cluster_config)

    cbs_url = topology["couchbase_servers"][0]
    sg_url = topology["sync_gateways"][0]["public"]
    sg_url_admin = topology["sync_gateways"][0]["admin"]
    sg_db = "db"
    bucket = "data-bucket"

    log_info("Running 'test_writing_attachment_to_couchbase_server'")
    log_info("Using cbs_url: {}".format(cbs_url))
    log_info("Using sg_url: {}".format(sg_url))
    log_info("Using sg_url_admin: {}".format(sg_url_admin))
    log_info("Using sg_db: {}".format(sg_db))
    log_info("Using bucket: {}".format(bucket))

    sg_user_name = "sg_user"
    sg_user_password = "******"

    sg_user_channels = ["NBC"]

    client = MobileRestClient()

    client.create_user(url=sg_url_admin,
                       db=sg_db,
                       name=sg_user_name,
                       password=sg_user_password,
                       channels=sg_user_channels)
    sg_user_session = client.create_session(url=sg_url_admin,
                                            db=sg_db,
                                            name=sg_user_name)

    docs = client.add_docs(url=sg_url,
                           db=sg_db,
                           number=100,
                           id_prefix=sg_db,
                           channels=sg_user_channels,
                           auth=sg_user_session)
    assert len(docs) == 100

    # Create doc with attachment and push to sync_gateway
    atts = attachment.load_from_data_dir(["sample_text.txt"])
    doc_with_att = document.create_doc(doc_id="att_doc",
                                       content={"sample_key": "sample_val"},
                                       attachments=atts,
                                       channels=sg_user_channels)

    client.add_doc(url=sg_url,
                   db=sg_db,
                   doc=doc_with_att,
                   auth=sg_user_session)
    server = couchbaseserver.CouchbaseServer(cbs_url)

    # Assert that the attachment doc gets written to couchbase server
    server_att_docs = server.get_server_docs_with_prefix(bucket=bucket,
                                                         prefix="_sync:att:")
    num_att_docs = len(server_att_docs)
    assert num_att_docs == 1
def test_log_number_backups(params_from_base_test_setup, sg_conf_name):
    """Test to check general behaviour for number of backups.
     In test the following params have been used:
        "maxsize": 1,
        "maxage": 30,
        "maxbackups": 2
    """
    cluster_conf = params_from_base_test_setup["cluster_config"]
    mode = params_from_base_test_setup["mode"]

    sg_conf = sync_gateway_config_path_for_mode(sg_conf_name, mode)

    log_info("Using cluster_conf: {}".format(cluster_conf))
    log_info("Using sg_conf: {}".format(sg_conf))

    cluster = Cluster(config=cluster_conf)
    cluster.reset(sg_config_path=sg_conf)

    remote_executor = RemoteExecutor(cluster.sync_gateways[0].ip)

    # Stop sync_gateways
    log_info(">>> Stopping sync_gateway")
    sg_helper = SyncGateway()
    cluster_helper = ClusterKeywords()
    cluster_hosts = cluster_helper.get_cluster_topology(cluster_conf)
    sg_one_url = cluster_hosts["sync_gateways"][0]["public"]
    sg_helper.stop_sync_gateways(cluster_config=cluster_conf, url=sg_one_url)

    remote_executor.execute("mkdir -p /tmp/sg_logs")
    remote_executor.execute("sudo rm -rf /tmp/sg_logs/sg_log_rotation*")
    # generate log file with almost 1MB
    remote_executor.execute(
        "sudo dd if=/dev/zero of=/tmp/sg_logs/sg_log_rotation.log bs=1030000 count=1"
    )
    remote_executor.execute("sudo chmod 777 -R /tmp/sg_logs")

    # iterate 5 times
    for i in xrange(5):
        sg_helper.start_sync_gateways(cluster_config=cluster_conf,
                                      url=sg_one_url,
                                      config=sg_conf)
        # ~1M MB will be added to log file after requests
        remote_executor.execute(
            "for ((i=1;i <= 1000;i += 1)); do curl -s http://localhost:4984/ > /dev/null; done"
        )

        _, stdout, _ = remote_executor.execute(
            "ls /tmp/sg_logs/ | grep sg_log_rotation | wc -l")
        # max 3 files: 2 backups + 1 log file
        assert stdout[0].rstrip() == str(min(3, i + 2))

        sg_helper.stop_sync_gateways(cluster_config=cluster_conf,
                                     url=sg_one_url)
        # generate log file with almost 1MB
        remote_executor.execute(
            "sudo dd if=/dev/zero of=/tmp/sg_logs/sg_log_rotation.log bs=1030000 count=1"
        )

    sg_helper.start_sync_gateways(cluster_config=cluster_conf,
                                  url=sg_one_url,
                                  config=sg_conf)
Exemple #4
0
def test_attachment_revpos_when_ancestor_unavailable_active_revision_doesnt_share_ancestor(
        params_from_base_test_setup, sg_conf_name):
    """
    Creates a document with an attachment, then updates that document so that
    the body of the revision that originally pushed the document is no
    longer available.  Add a new revision that's not a child of the
    active revision, and validate that it's uploaded successfully.
    Example:
       1. Document is created with no attachment at rev-1
       2. Server adds revision with attachment at rev-2 {"hello.txt", revpos=2}
       2. Document is updated multiple times on the server, goes to rev-4
       3. Client attempts to add a new (conflicting) revision 3a, with ancestors rev-2a (with it's own attachment), rev-1.
       4. When client attempts to push rev-3a with attachment stub {"hello.txt", revpos=2}.  Should throw an error, since the revpos
       of the attachment is later than the common ancestor (rev-1)
    """

    cluster_config = params_from_base_test_setup["cluster_config"]
    mode = params_from_base_test_setup["mode"]
    no_conflicts_enabled = params_from_base_test_setup["no_conflicts_enabled"]

    if no_conflicts_enabled:
        pytest.skip('--no-conflicts is not enabled, so skipping the test')

    sg_conf = sync_gateway_config_path_for_mode(sg_conf_name, mode)

    cluster_helper = ClusterKeywords()
    cluster_helper.reset_cluster(cluster_config, sg_conf)

    topology = cluster_helper.get_cluster_topology(cluster_config)

    cbs_url = topology["couchbase_servers"][0]
    sg_url = topology["sync_gateways"][0]["public"]
    sg_url_admin = topology["sync_gateways"][0]["admin"]
    sg_db = "db"
    bucket = "data-bucket"

    log_info(
        "Running 'test_attachment_revpos_when_ancestor_unavailable_active_revision_doesnt_share_ancestor'"
    )
    log_info("Using cbs_url: {}".format(cbs_url))
    log_info("Using sg_url: {}".format(sg_url))
    log_info("Using sg_url_admin: {}".format(sg_url_admin))
    log_info("Using sg_db: {}".format(sg_db))
    log_info("Using bucket: {}".format(bucket))

    sg_user_name = "sg_user"
    sg_user_password = "******"

    sg_user_channels = ["NBC"]

    client = MobileRestClient()

    client.create_user(url=sg_url_admin,
                       db=sg_db,
                       name=sg_user_name,
                       password=sg_user_password,
                       channels=sg_user_channels)
    sg_user_session = client.create_session(url=sg_url_admin,
                                            db=sg_db,
                                            name=sg_user_name)

    doc = document.create_doc(doc_id="doc_1",
                              content={"sample_key": "sample_val"},
                              channels=sg_user_channels)
    doc_gen_1 = client.add_doc(url=sg_url,
                               db=sg_db,
                               doc=doc,
                               auth=sg_user_session)
    client.update_doc(url=sg_url,
                      db=sg_db,
                      doc_id=doc_gen_1["id"],
                      attachment_name="sample_text.txt",
                      auth=sg_user_session)
    client.update_doc(url=sg_url,
                      db=sg_db,
                      doc_id=doc_gen_1["id"],
                      auth=sg_user_session)
    client.update_doc(url=sg_url,
                      db=sg_db,
                      doc_id=doc_gen_1["id"],
                      auth=sg_user_session)

    parent_rev_list = ["2-foo2", doc_gen_1["rev"]]

    # Sync Gateway should error since it has no references attachment in its ancestors
    with pytest.raises(HTTPError) as he:
        client.add_conflict(url=sg_url,
                            db=sg_db,
                            doc_id=doc_gen_1["id"],
                            parent_revisions=parent_rev_list,
                            new_revision="3-foo3",
                            auth=sg_user_session)
    assert he.value[0].startswith("400 Client Error: Bad Request for url: ")
Exemple #5
0
def test_openidconnect_expired_token(params_from_base_test_setup, sg_conf_name):
    """Authenticate and create an ID token that only lasts for 5 seconds, wait 10 seconds
       and make sure the token is rejected
    """

    cluster_config = params_from_base_test_setup["cluster_config"]
    mode = params_from_base_test_setup["mode"]
    sg_conf = sync_gateway_config_path_for_mode(sg_conf_name, mode)

    cluster_helper = ClusterKeywords()
    topology = cluster_helper.get_cluster_topology(cluster_config)
    sg_url = topology["sync_gateways"][0]["public"]
    sg_db = "db"

    log_info("Running 'test_openidconnect_expired_token'")
    log_info("Using cluster_config: {}".format(cluster_config))
    log_info("Using sg_url: {}".format(sg_url))
    log_info("Using sg_db: {}".format(sg_db))

    cluster_helper = ClusterKeywords()
    cluster_helper.reset_cluster(
        cluster_config=cluster_config,
        sync_gateway_config=sg_conf
    )

    token_expiry_seconds = 5

    # multipart/form data content
    formdata = {
        'username': ('', 'testuser'),
        'authenticated': ('', 'Return a valid authorization code for this user'),
        'tokenttl': ('', "{}".format(token_expiry_seconds)),
    }

    # get the authenticate endpoint and query params, should look something like:
    #     authenticate?client_id=sync_gateway&redirect_uri= ...
    authenticate_endpoint = discover_authenticate_endpoint(sg_url, sg_db, DEFAULT_PROVIDER)

    # build the full url
    url = "{}/{}/_oidc_testing/{}".format(
        sg_url,
        sg_db,
        authenticate_endpoint
    )

    # Make the request to _oidc_testing
    response = requests.post(url, files=formdata)
    log_r(response)

    # extract the token from the response
    response_json = response.json()
    id_token = response_json["id_token"]

    # wait until token expires
    time.sleep(token_expiry_seconds + 1)

    # make a request using the ID token against the db and expect a 200 response
    headers = {"Authorization": "Bearer {}".format(id_token)}
    db_url = "{}/{}".format(sg_url, sg_db)
    resp = requests.get(db_url, headers=headers)
    log_r(resp)
    assert resp.status_code != 200, "Expected non-200 response"
Exemple #6
0
def test_openidconnect_public_session_endpoint(params_from_base_test_setup, sg_conf_name):
    """Create a new session from the OpenID Connect token returned by hitting
    the public _session endpoint and make sure the response contains the Set-Cookie header."""

    cluster_config = params_from_base_test_setup["cluster_config"]
    mode = params_from_base_test_setup["mode"]
    sg_conf = sync_gateway_config_path_for_mode(sg_conf_name, mode)

    cluster_helper = ClusterKeywords()
    topology = cluster_helper.get_cluster_topology(cluster_config)
    sg_url = topology["sync_gateways"][0]["public"]
    sg_db = "db"

    log_info("Running 'test_openidconnect_public_session_endpoint'")
    log_info("Using cluster_config: {}".format(cluster_config))
    log_info("Using sg_url: {}".format(sg_url))
    log_info("Using sg_db: {}".format(sg_db))

    cluster_helper = ClusterKeywords()
    cluster_helper.reset_cluster(
        cluster_config=cluster_config,
        sync_gateway_config=sg_conf
    )

    # multipart/form data content
    formdata = {
        'username': ('', 'testuser'),
        'authenticated': ('', 'Return a valid authorization code for this user')
    }

    # get the authenticate endpoint and query params, should look something like:
    #     authenticate?client_id=sync_gateway&redirect_uri= ...
    authenticate_endpoint = discover_authenticate_endpoint(sg_url, sg_db, DEFAULT_PROVIDER)

    # build the full url
    url = "{}/{}/_oidc_testing/{}".format(
        sg_url,
        sg_db,
        authenticate_endpoint
    )

    # Make the request to _oidc_testing
    response = requests.post(url, files=formdata)
    log_r(response)

    # extract the token from the response
    response_json = response.json()
    id_token = response_json["id_token"]

    headers = {
        "Authorization": "Bearer {}".format(id_token),
        "Content-Type": "application/json"
    }
    url = "{}/{}/_session".format(
        sg_url,
        sg_db
    )

    response = requests.post(url, headers=headers)
    assert "Set-Cookie" in response.headers.keys()
    set_cookie_response = response.headers['Set-Cookie']
    assert "SyncGatewaySession" in set_cookie_response
def test_server_goes_down_sanity(params_from_base_test_setup):
    """
    1. Start with a two node couchbase server cluster
    2. Starting adding docs
    3. Kill one of the server nodes and signal completion
    4. Stop adding docs
    5. Verify that that the expected docs are present and in the changes feed.
    6. Start server again and add to cluster
    """

    cluster_config = params_from_base_test_setup["cluster_config"]
    mode = params_from_base_test_setup["mode"]

    sg_version = get_sg_version(cluster_config)
    if compare_versions(sg_version, '1.5') < 0:
        pytest.skip("This test needs multiple URLs in the SG config, not supported by SG < 1.5")

    cluster_helper = ClusterKeywords()

    sg_conf_name = "sync_gateway_default_functional_tests"
    sg_conf_path = sync_gateway_config_path_for_mode(sg_conf_name, mode)

    cluster_helper.reset_cluster(cluster_config=cluster_config,
                                 sync_gateway_config=sg_conf_path)

    topology = cluster_helper.get_cluster_topology(cluster_config)

    admin_sg = topology["sync_gateways"][0]["admin"]
    sg_url = topology["sync_gateways"][0]["public"]
    coucbase_servers = topology["couchbase_servers"]

    cbs_one_url = coucbase_servers[0]
    cbs_two_url = coucbase_servers[1]

    log_info("Running: 'test_server_goes_down_sanity'")
    log_info("cluster_config: {}".format(cluster_config))
    log_info("admin_sg: {}".format(admin_sg))
    log_info("sg_url: {}".format(sg_url))
    log_info("cbs_one_url: {}".format(cbs_one_url))
    log_info("cbs_two_url: {}".format(cbs_two_url))

    sg_db = "db"
    num_docs = 100
    sg_user_name = "seth"
    sg_user_password = "******"
    channels = ["ABC", "CBS"]

    client = MobileRestClient()
    main_server = couchbaseserver.CouchbaseServer(cbs_one_url)
    flakey_server = couchbaseserver.CouchbaseServer(cbs_two_url)

    client.create_user(admin_sg, sg_db, sg_user_name, sg_user_password, channels=channels)
    session = client.create_session(admin_sg, sg_db, sg_user_name)

    # Stop second server
    flakey_server.stop()

    # Try to add 100 docs in a loop until all succeed, if the never do, fail with timeout
    errors = num_docs

    # Wait 30 seconds for auto failover
    # (Minimum value suggested - http://docs.couchbase.com/admin/admin/Tasks/tasks-nodeFailover.html)
    # + 15 seconds to add docs
    timeout = 45
    start = time.time()

    successful_add = False
    while not successful_add:

        # Fail tests if all docs do not succeed before timeout
        if (time.time() - start) > timeout:
            # Bring server back up before failing the test
            flakey_server.start()
            main_server.rebalance_in(coucbase_servers, flakey_server)
            raise TimeoutError("Failed to successfully put docs before timeout")

        try:
            docs = client.add_docs(url=sg_url, db=sg_db, number=num_docs, id_prefix=None, auth=session, channels=channels)

            # If the above add doc does not throw, it was a successfull add.
            successful_add = True
        except requests.exceptions.HTTPError as he:
            log_info("Failed to add docs: {}".format(he))

        log_info("Seeing: {} errors".format(errors))
        time.sleep(1)

    assert len(docs) == 100
    client.verify_docs_present(url=sg_url, db=sg_db, expected_docs=docs, auth=session)

    try:
        client.verify_docs_in_changes(url=sg_url, db=sg_db, expected_docs=docs, auth=session, polling_interval=5)
    except keywords.exceptions.TimeoutException:
        # timeout verifying docs. Bring server back in to restore topology, then fail
        # Failing due to https://github.com/couchbase/sync_gateway/issues/2197
        flakey_server.start()
        main_server.recover(flakey_server)
        main_server.rebalance_in(coucbase_servers, flakey_server)
        raise keywords.exceptions.TimeoutException("Failed to get all changes")

    # Test succeeded without timeout, bring server back into topology
    flakey_server.start()
    main_server.recover(flakey_server)
    main_server.rebalance_in(coucbase_servers, flakey_server)

    # Make sure all docs were not added before server was
    log_info("test_server_goes_down_sanity complete!")
Exemple #8
0
def params_from_base_suite_setup(request):
    log_info("Setting up 'params_from_base_suite_setup' ...")

    # pytest command line parameters
    server_version = request.config.getoption("--server-version")
    sync_gateway_version = request.config.getoption("--sync-gateway-version")
    mode = request.config.getoption("--mode")
    use_sequoia = request.config.getoption("--sequoia")
    skip_provisioning = request.config.getoption("--skip-provisioning")
    cbs_ssl = request.config.getoption("--server-ssl")
    xattrs_enabled = request.config.getoption("--xattrs")
    server_seed_docs = request.config.getoption("--server-seed-docs")
    max_docs = request.config.getoption("--max-docs")
    num_users = request.config.getoption("--num-users")
    create_batch_size = request.config.getoption("--create-batch-size")
    create_delay = request.config.getoption("--create-delay")
    update_runtime_sec = request.config.getoption("--update-runtime-sec")
    update_batch_size = request.config.getoption("--update-batch-size")
    update_docs_percentage = request.config.getoption(
        "--update-docs-percentage")
    update_delay = request.config.getoption("--update-delay")
    changes_delay = request.config.getoption("--changes-delay")
    changes_limit = request.config.getoption("--changes-limit")

    if xattrs_enabled and version_is_binary(sync_gateway_version):
        check_xattr_support(server_version, sync_gateway_version)

    log_info("server_version: {}".format(server_version))
    log_info("sync_gateway_version: {}".format(sync_gateway_version))
    log_info("mode: {}".format(mode))
    log_info("skip_provisioning: {}".format(skip_provisioning))
    log_info("cbs_ssl: {}".format(cbs_ssl))
    log_info("xattrs_enabled: {}".format(xattrs_enabled))

    # Make sure mode for sync_gateway is supported ('cc' or 'di')
    validate_sync_gateway_mode(mode)

    # use ci_lb_cc cluster config if mode is "cc" or ci_lb_di cluster config if more is "di"
    log_info("Using 'ci_lb_{}' config!".format(mode))
    cluster_config = "{}/ci_lb_{}".format(CLUSTER_CONFIGS_DIR, mode)

    try:
        server_version
    except NameError:
        log_info("Server version is not provided")
        persist_cluster_config_environment_prop(cluster_config,
                                                'server_version', "")
    else:
        log_info("Running test with server version {}".format(server_version))
        persist_cluster_config_environment_prop(cluster_config,
                                                'server_version',
                                                server_version)

    try:
        sync_gateway_version
    except NameError:
        log_info("Sync gateway version is not provided")
        persist_cluster_config_environment_prop(cluster_config,
                                                'sync_gateway_version', "")
    else:
        log_info("Running test with sync_gateway version {}".format(
            sync_gateway_version))
        persist_cluster_config_environment_prop(cluster_config,
                                                'sync_gateway_version',
                                                sync_gateway_version)

    # Only works with load balancer configs
    persist_cluster_config_environment_prop(cluster_config, 'sg_lb_enabled',
                                            True)

    if cbs_ssl:
        log_info("Running tests with cbs <-> sg ssl enabled")
        # Enable ssl in cluster configs
        persist_cluster_config_environment_prop(cluster_config,
                                                'cbs_ssl_enabled', True)
    else:
        log_info("Running tests with cbs <-> sg ssl disabled")
        # Disable ssl in cluster configs
        persist_cluster_config_environment_prop(cluster_config,
                                                'cbs_ssl_enabled', False)

    if xattrs_enabled:
        log_info("Running test with xattrs for sync meta storage")
        persist_cluster_config_environment_prop(cluster_config,
                                                'xattrs_enabled', True)
    else:
        log_info("Using document storage for sync meta data")
        persist_cluster_config_environment_prop(cluster_config,
                                                'xattrs_enabled', False)

    sg_config = sync_gateway_config_path_for_mode(
        "sync_gateway_default_functional_tests", mode)

    # Skip provisioning if user specifies '--skip-provisoning' or '--sequoia'
    should_provision = True
    if skip_provisioning or use_sequoia:
        should_provision = False

    cluster_utils = ClusterKeywords()
    if should_provision:
        try:
            cluster_utils.provision_cluster(
                cluster_config=cluster_config,
                server_version=server_version,
                sync_gateway_version=sync_gateway_version,
                sync_gateway_config=sg_config)
        except ProvisioningError:
            logging_helper = Logging()
            logging_helper.fetch_and_analyze_logs(
                cluster_config=cluster_config, test_name=request.node.name)
            raise

    # Hit this intalled running services to verify the correct versions are installed
    cluster_utils.verify_cluster_versions(
        cluster_config,
        expected_server_version=server_version,
        expected_sync_gateway_version=sync_gateway_version)

    # Load topology as a dictionary
    cluster_topology = cluster_utils.get_cluster_topology(cluster_config)

    yield {
        "cluster_config": cluster_config,
        "cluster_topology": cluster_topology,
        "mode": mode,
        "xattrs_enabled": xattrs_enabled,
        "server_seed_docs": server_seed_docs,
        "max_docs": max_docs,
        "num_users": num_users,
        "create_batch_size": create_batch_size,
        "create_delay": create_delay,
        "update_runtime_sec": update_runtime_sec,
        "update_batch_size": update_batch_size,
        "update_docs_percentage": update_docs_percentage,
        "update_delay": update_delay,
        "changes_delay": changes_delay,
        "changes_limit": changes_limit
    }

    log_info("Tearing down 'params_from_base_suite_setup' ...")
Exemple #9
0
def setup_client_syncgateway_test(request, setup_client_syncgateway_suite):
    """Test setup fixture for client sync_gateway tests"""

    log_info("Setting up client sync_gateway test ...")

    liteserv = setup_client_syncgateway_suite["liteserv"]
    cluster_config = setup_client_syncgateway_suite["cluster_config"]
    xattrs_enabled = setup_client_syncgateway_suite["xattrs_enabled"]
    device_enabled = setup_client_syncgateway_suite["device_enabled"]
    liteserv_platform = setup_client_syncgateway_suite["liteserv_platform"]
    test_name = request.node.name

    if request.config.getoption("--liteserv-platform") == "macosx" and \
            str(request.config.getoption("--liteserv-version")).startswith("1.3.1") and \
            str(test_name).startswith("test_longpoll_changes_termination"):
        pytest.skip(
            "test_longpoll_changes_termination tests are known to fail on macosx with 1.3.1 CBL"
        )

    client = MobileRestClient()

    # Start LiteServ and delete any databases
    log_info("Listener going to start and launch,")
    if device_enabled and liteserv_platform == "ios":
        ls_url = liteserv.start_device("{}/logs/{}-{}-{}.txt".format(
            RESULTS_DIR,
            type(liteserv).__name__, test_name, datetime.datetime.now()))
    else:
        ls_url = liteserv.start("{}/logs/{}-{}-{}.txt".format(
            RESULTS_DIR,
            type(liteserv).__name__, test_name, datetime.datetime.now()))
    client.delete_databases(ls_url)

    cluster_helper = ClusterKeywords()
    cluster_hosts = cluster_helper.get_cluster_topology(
        cluster_config=cluster_config)

    sg_url = cluster_hosts["sync_gateways"][0]["public"]
    sg_admin_url = cluster_hosts["sync_gateways"][0]["admin"]

    # Yield values to test case via fixture argument
    yield {
        "cluster_config": cluster_config,
        "sg_mode": setup_client_syncgateway_suite["sg_mode"],
        "ls_url": ls_url,
        "sg_url": sg_url,
        "sg_admin_url": sg_admin_url,
        "xattrs_enabled": xattrs_enabled,
        "liteserv": liteserv,
        "liteserv_platform": liteserv_platform
    }

    log_info("Tearing down test")

    client.delete_databases(ls_url)
    liteserv.stop()

    # if the test failed pull logs
    if request.node.rep_call.failed:
        logging_helper = Logging()
        logging_helper.fetch_and_analyze_logs(cluster_config=cluster_config,
                                              test_name=test_name)
Exemple #10
0
def setup_client_syncgateway_suite(request):
    """Suite setup fixture for client sync_gateway tests"""

    log_info("Setting up client sync_gateway suite ...")

    liteserv_platform = request.config.getoption("--liteserv-platform")
    liteserv_version = request.config.getoption("--liteserv-version")
    liteserv_host = request.config.getoption("--liteserv-host")
    liteserv_port = request.config.getoption("--liteserv-port")
    liteserv_storage_engine = request.config.getoption(
        "--liteserv-storage-engine")

    skip_provisioning = request.config.getoption("--skip-provisioning")
    sync_gateway_version = request.config.getoption("--sync-gateway-version")
    sync_gateway_mode = request.config.getoption("--sync-gateway-mode")

    server_version = request.config.getoption("--server-version")
    xattrs_enabled = request.config.getoption("--xattrs")
    device_enabled = request.config.getoption("--device")

    liteserv = LiteServFactory.create(platform=liteserv_platform,
                                      version_build=liteserv_version,
                                      host=liteserv_host,
                                      port=liteserv_port,
                                      storage_engine=liteserv_storage_engine)

    if xattrs_enabled and version_is_binary(sync_gateway_version):
        check_xattr_support(server_version, sync_gateway_version)

    log_info("Downloading LiteServ ...")
    # Download LiteServ
    liteserv.download()

    # Install LiteServ
    if device_enabled and liteserv_platform == "ios":
        liteserv.install_device()
    else:
        liteserv.install()

    cluster_config = "{}/base_{}".format(CLUSTER_CONFIGS_DIR,
                                         sync_gateway_mode)

    try:
        server_version
    except NameError:
        log_info("Server version is not provided")
        persist_cluster_config_environment_prop(cluster_config,
                                                'server_version', "")
    else:
        log_info("Running test with server version {}".format(server_version))
        persist_cluster_config_environment_prop(cluster_config,
                                                'server_version',
                                                server_version)

    try:
        sync_gateway_version
    except NameError:
        log_info("Sync gateway version is not provided")
        persist_cluster_config_environment_prop(cluster_config,
                                                'sync_gateway_version', "")
    else:
        log_info("Running test with sync_gateway version {}".format(
            sync_gateway_version))
        persist_cluster_config_environment_prop(cluster_config,
                                                'sync_gateway_version',
                                                sync_gateway_version)

    if xattrs_enabled:
        log_info("Running test with xattrs for sync meta storage")
        persist_cluster_config_environment_prop(cluster_config,
                                                'xattrs_enabled', True)
    else:
        log_info("Using document storage for sync meta data")
        persist_cluster_config_environment_prop(cluster_config,
                                                'xattrs_enabled', False)

    sg_config = sync_gateway_config_path_for_mode(
        "listener_tests/listener_tests", sync_gateway_mode)

    if not skip_provisioning:
        log_info(
            "Installing Sync Gateway + Couchbase Server + Accels ('di' only)")
        cluster_utils = ClusterKeywords()
        cluster_utils.provision_cluster(
            cluster_config=cluster_config,
            server_version=server_version,
            sync_gateway_version=sync_gateway_version,
            sync_gateway_config=sg_config)

    # Wait at the yeild until tests referencing this suite setup have run,
    # Then execute the teardown
    yield {
        "liteserv": liteserv,
        "cluster_config": cluster_config,
        "sg_mode": sync_gateway_mode,
        "xattrs_enabled": xattrs_enabled,
        "device_enabled": device_enabled,
        "liteserv_platform": liteserv_platform
    }

    log_info("Tearing down suite ...")
    if not (device_enabled and liteserv_platform == "ios"):
        liteserv.remove()
def test_upgrade(params_from_base_test_setup):
    """
    @summary
        The initial versions of SG and CBS has already been provisioned at this point
        We have to upgrade them to the upgraded versions
    """
    cluster_config = params_from_base_test_setup['cluster_config']
    mode = params_from_base_test_setup['mode']
    xattrs_enabled = params_from_base_test_setup['xattrs_enabled']
    ls_url = params_from_base_test_setup["ls_url"]
    server_version = params_from_base_test_setup['server_version']
    sync_gateway_version = params_from_base_test_setup['sync_gateway_version']
    server_upgraded_version = params_from_base_test_setup[
        'server_upgraded_version']
    sync_gateway_upgraded_version = params_from_base_test_setup[
        'sync_gateway_upgraded_version']
    sg_url = params_from_base_test_setup['sg_url']
    sg_admin_url = params_from_base_test_setup['sg_admin_url']
    num_docs = int(params_from_base_test_setup['num_docs'])
    cbs_platform = params_from_base_test_setup['cbs_platform']
    cbs_toy_build = params_from_base_test_setup['cbs_toy_build']
    sg_conf = "{}/resources/sync_gateway_configs/sync_gateway_default_functional_tests_{}.json".format(
        os.getcwd(), mode)

    # Add data to liteserv
    client = MobileRestClient()
    log_info("ls_url: {}".format(ls_url))
    ls_db = client.create_database(ls_url, name="ls_db")

    # Create user and session on SG
    sg_user_channels = ["sg_user_channel"]
    sg_db = "db"
    sg_user_name = "sg_user"
    sg_user_password = "******"
    client.create_user(url=sg_admin_url,
                       db=sg_db,
                       name=sg_user_name,
                       password=sg_user_password,
                       channels=sg_user_channels)
    sg_session = client.create_session(url=sg_admin_url,
                                       db=sg_db,
                                       name=sg_user_name,
                                       password=sg_user_password)

    log_info(
        "Starting continuous push pull replication from liteserv to sync gateway"
    )
    repl_one = client.start_replication(url=ls_url,
                                        continuous=True,
                                        from_db=ls_db,
                                        to_url=sg_url,
                                        to_db=sg_db,
                                        to_auth=sg_session)
    client.wait_for_replication_status_idle(ls_url, repl_one)

    log_info("Starting replication from sync gateway to liteserv")
    client.start_replication(url=ls_url,
                             continuous=True,
                             from_url=sg_url,
                             from_db=sg_db,
                             from_auth=sg_session,
                             to_db=ls_db)

    # Add docs to liteserv
    added_docs = add_docs_to_client_task(client=client,
                                         url=ls_url,
                                         db=ls_db,
                                         channels=sg_user_channels,
                                         num_docs=num_docs)
    log_info("Added {} docs".format(len(added_docs)))

    # start updating docs
    terminator_doc_id = 'terminator'
    with ProcessPoolExecutor() as up:
        # Start updates in background process
        updates_future = up.submit(update_docs, client, ls_url, ls_db,
                                   added_docs, sg_session, terminator_doc_id)

        # Supported upgrade process
        # 1. Upgrade SGs first docmeta -> docmeta - CBS 5.0.0 does not support TAP.
        # 2. Upgrade the CBS cluster.
        # 3. Enable import/xattrs on SGs

        # Upgrade SG docmeta -> docmeta
        cluster_util = ClusterKeywords()
        topology = cluster_util.get_cluster_topology(cluster_config,
                                                     lb_enable=False)
        sync_gateways = topology["sync_gateways"]
        sg_accels = topology["sg_accels"]

        upgrade_sync_gateway(sync_gateways, sync_gateway_version,
                             sync_gateway_upgraded_version, sg_conf,
                             cluster_config)

        if mode == "di":
            upgrade_sg_accel(sg_accels, sync_gateway_version,
                             sync_gateway_upgraded_version, sg_conf,
                             cluster_config)

        # Upgrade CBS
        cluster = Cluster(config=cluster_config)
        if len(cluster.servers) < 2:
            raise Exception("Please provide at least 3 servers")

        server_urls = []
        for server in cluster.servers:
            server_urls.append(server.url)

        primary_server = cluster.servers[0]
        secondary_server = cluster.servers[1]
        servers = cluster.servers[1:]

        upgrade_server_cluster(servers,
                               primary_server,
                               secondary_server,
                               server_version,
                               server_upgraded_version,
                               server_urls,
                               cluster_config,
                               cbs_platform,
                               toy_build=cbs_toy_build)

        # Restart SGs after the server upgrade
        sg_obj = SyncGateway()
        for sg in sync_gateways:
            sg_ip = host_for_url(sg["admin"])
            log_info("Restarting sync gateway {}".format(sg_ip))
            sg_obj.restart_sync_gateways(cluster_config=cluster_config,
                                         url=sg_ip)
            time.sleep(5)

        if mode == "di":
            ac_obj = SyncGateway()
            for ac in sg_accels:
                ac_ip = host_for_url(ac)
                log_info("Restarting sg accel {}".format(ac_ip))
                ac_obj.restart_sync_gateways(cluster_config=cluster_config,
                                             url=ac_ip)
                time.sleep(5)

        if xattrs_enabled:
            # Enable xattrs on all SG/SGAccel nodes
            # cc - Start 1 SG with import enabled, all with XATTRs enabled
            # di - All SGs/SGAccels with xattrs enabled - this will also enable import on SGAccel
            #    - Do not enable import in SG.
            if mode == "cc":
                enable_import = True
            elif mode == "di":
                enable_import = False

            if mode == "di":
                ac_obj = SyncGateway()
                for ac in sg_accels:
                    ac_ip = host_for_url(ac)
                    ac_obj.enable_import_xattrs(cluster_config=cluster_config,
                                                sg_conf=sg_conf,
                                                url=ac_ip,
                                                enable_import=False)

            sg_obj = SyncGateway()
            for sg in sync_gateways:
                sg_ip = host_for_url(sg["admin"])
                sg_obj.enable_import_xattrs(cluster_config=cluster_config,
                                            sg_conf=sg_conf,
                                            url=sg_ip,
                                            enable_import=enable_import)
                enable_import = False
                # Check Import showing up on all nodes

        send_changes_termination_doc(auth=sg_session,
                                     terminator_doc_id=terminator_doc_id,
                                     terminator_channel=sg_user_channels,
                                     ls_url=ls_url,
                                     ls_db=ls_db)
        log_info("Waiting for doc updates to complete")
        updated_doc_revs = updates_future.result()

        log_info("Stopping replication from liteserv to sync gateway")
        # Stop repl_one
        client.stop_replication(url=ls_url,
                                continuous=True,
                                from_db=ls_db,
                                to_url=sg_url,
                                to_db=sg_db,
                                to_auth=sg_session)

        log_info("Stopping replication from sync gateway to liteserv")
        # Stop repl_two
        client.stop_replication(url=ls_url,
                                continuous=True,
                                from_url=sg_url,
                                from_db=sg_db,
                                from_auth=sg_session,
                                to_db=ls_db)
        # Gather the new revs for verification
        log_info("Gathering the updated revs for verification")
        doc_ids = []
        for i in range(len(added_docs)):
            doc_ids.append(added_docs[i]["id"])
            if added_docs[i]["id"] in updated_doc_revs:
                added_docs[i]["rev"] = updated_doc_revs[added_docs[i]["id"]]

        # Verify rev, doc bdy and revision history of all docs
        verify_sg_docs_revision_history(url=sg_admin_url,
                                        db=sg_db,
                                        added_docs=added_docs)

        if xattrs_enabled:
            # Verify through SDK that there is no _sync property in the doc body
            bucket_name = 'data-bucket'
            sdk_client = Bucket('couchbase://{}/{}'.format(
                primary_server.host, bucket_name),
                                password='******',
                                timeout=SDK_TIMEOUT)
            log_info("Fetching docs from SDK")
            docs_from_sdk = sdk_client.get_multi(doc_ids)

            log_info("Verifying that there is no _sync property in the docs")
            for i in docs_from_sdk:
                if "_sync" in docs_from_sdk[i].value:
                    raise Exception(
                        "_sync section found in docs after upgrade")
def test_log_maxbackups_0(params_from_base_test_setup, sg_conf_name):
    """Test with maxbackups=0 that means do not limit the number of backups
    """
    cluster_conf = params_from_base_test_setup["cluster_config"]
    mode = params_from_base_test_setup["mode"]
    xattrs_enabled = params_from_base_test_setup["xattrs_enabled"]

    sg_conf = sync_gateway_config_path_for_mode(sg_conf_name, mode)

    log_info("Using cluster_conf: {}".format(cluster_conf))
    log_info("Using sg_conf: {}".format(sg_conf))

    cluster = Cluster(config=cluster_conf)
    cluster.reset(sg_config_path=sg_conf)

    cluster_helper = ClusterKeywords()
    cluster_hosts = cluster_helper.get_cluster_topology(cluster_conf)
    sg_one_url = cluster_hosts["sync_gateways"][0]["public"]

    remote_executor = RemoteExecutor(cluster.sync_gateways[0].ip)

    # Stop sync_gateways
    log_info(">>> Stopping sync_gateway")
    sg_helper = SyncGateway()
    sg_helper.stop_sync_gateways(cluster_config=cluster_conf, url=sg_one_url)

    remote_executor.execute("mkdir -p /tmp/sg_logs")
    remote_executor.execute("sudo rm -rf /tmp/sg_logs/sg_log_rotation*")
    # generate log file with almost 1MB
    remote_executor.execute(
        "sudo dd if=/dev/zero of=/tmp/sg_logs/sg_log_rotation.log bs=1030000 count=1"
    )
    remote_executor.execute("sudo chmod 777 -R /tmp/sg_logs")

    # read sample sg_conf
    data = load_sync_gateway_config(sg_conf, mode,
                                    cluster_hosts["couchbase_servers"][0],
                                    xattrs_enabled, cluster_conf)

    # set maxbackups=0 in config file
    data['logging']["default"]["rotation"]["maxbackups"] = 0
    # create temp config file in the same folder as sg_conf
    temp_conf = "/".join(sg_conf.split('/')[:-2]) + '/temp_conf.json'

    with open(temp_conf, 'w') as fp:
        json.dump(data, fp)

    sg_helper.start_sync_gateways(cluster_config=cluster_conf,
                                  url=sg_one_url,
                                  config=temp_conf)
    # ~1M MB will be added to log file after requests
    remote_executor.execute(
        "for ((i=1;i <= 1000;i += 1)); do curl -s http://localhost:4984/ > /dev/null; done"
    )

    status, stdout, stderr = remote_executor.execute(
        "ls /tmp/sg_logs/ | grep sg_log_rotation | wc -l")
    assert stdout[0].rstrip() == '2'

    # Remove generated conf file
    os.remove(temp_conf)
def test_log_rotation_default_values(params_from_base_test_setup,
                                     sg_conf_name):
    """Test to verify default values for rotation section:
    maxsize = 100 MB
    MaxAge = 0(do not limit the number of MaxAge)
    MaxBackups = 0(do not limit the number of backups)
    """
    cluster_conf = params_from_base_test_setup["cluster_config"]
    mode = params_from_base_test_setup["mode"]
    xattrs_enabled = params_from_base_test_setup["xattrs_enabled"]

    sg_conf = sync_gateway_config_path_for_mode(sg_conf_name, mode)

    log_info("Using cluster_conf: {}".format(cluster_conf))
    log_info("Using sg_conf: {}".format(sg_conf))

    cluster = Cluster(config=cluster_conf)
    cluster.reset(sg_config_path=sg_conf)

    remote_executor = RemoteExecutor(cluster.sync_gateways[0].ip)

    # Stop sync_gateways
    log_info(">>> Stopping sync_gateway")
    sg_helper = SyncGateway()
    cluster_helper = ClusterKeywords()
    cluster_hosts = cluster_helper.get_cluster_topology(cluster_conf)
    sg_one_url = cluster_hosts["sync_gateways"][0]["public"]
    sg_helper.stop_sync_gateways(cluster_config=cluster_conf, url=sg_one_url)

    # read sample sg_conf
    data = load_sync_gateway_config(sg_conf, mode,
                                    cluster_hosts["couchbase_servers"][0],
                                    xattrs_enabled, cluster_conf)

    # delete rotation from sample config
    del data['logging']["default"]["rotation"]
    # create temp config file in the same folder as sg_conf
    temp_conf = "/".join(sg_conf.split('/')[:-2]) + '/temp_conf.json'

    log_info("TEMP_CONF: {}".format(temp_conf))

    with open(temp_conf, 'w') as fp:
        json.dump(data, fp)

    remote_executor.execute("mkdir -p /tmp/sg_logs")

    remote_executor.execute("sudo rm -rf /tmp/sg_logs/sg_log_rotation*")
    # generate log file  with size  ~94MB to check that backup file not created while 100MB not reached
    remote_executor.execute(
        "sudo dd if=/dev/zero of=/tmp/sg_logs/sg_log_rotation.log bs=94850000 count=1"
    )

    remote_executor.execute("sudo chmod 777 -R /tmp/sg_logs")
    # iterate 5th times to verify that every time we get new backup file with ~100MB
    for i in xrange(5):
        sg_helper.start_sync_gateways(cluster_config=cluster_conf,
                                      url=sg_one_url,
                                      config=temp_conf)
        # ~1M MB will be added to log file after requests
        remote_executor.execute(
            "for ((i=1;i <= 1000;i += 1)); do curl -s http://localhost:4984/ > /dev/null; done"
        )

        _, stdout, _ = remote_executor.execute(
            "ls /tmp/sg_logs/ | grep sg_log_rotation | wc -l")
        # verify num of log files
        assert stdout[0].rstrip() == str(i + 1)

        sg_helper.stop_sync_gateways(cluster_config=cluster_conf,
                                     url=sg_one_url)
        # generate log file  with size  ~99MB
        remote_executor.execute(
            "sudo dd if=/dev/zero of=/tmp/sg_logs/sg_log_rotation.log bs=104850000 count=1"
        )

    sg_helper.start_sync_gateways(cluster_config=cluster_conf,
                                  url=sg_one_url,
                                  config=sg_conf)

    # Remove generated conf file
    os.remove(temp_conf)
Exemple #14
0
def test_system_test(params_from_base_test_setup):

    cluster_config = params_from_base_test_setup['cluster_config']
    mode = params_from_base_test_setup['mode']

    # Scenario parameters
    server_seed_docs = int(params_from_base_test_setup['server_seed_docs'])
    max_docs = int(params_from_base_test_setup['max_docs'])
    num_users = int(params_from_base_test_setup['num_users'])

    # Create paramters
    create_batch_size = int(params_from_base_test_setup['create_batch_size'])
    create_delay = float(params_from_base_test_setup['create_delay'])

    # Update parameters
    update_runtime_sec = int(params_from_base_test_setup['update_runtime_sec'])
    update_batch_size = int(params_from_base_test_setup['update_batch_size'])
    update_docs_percentage = float(
        params_from_base_test_setup['update_docs_percentage'])
    update_delay = float(params_from_base_test_setup['update_delay'])

    # Changes parameters
    changes_delay = float(params_from_base_test_setup['changes_delay'])
    changes_limit = int(params_from_base_test_setup['changes_limit'])

    changes_terminator_doc_id = 'terminator'

    docs_per_user = max_docs / num_users
    docs_per_user_per_update = int(update_docs_percentage * docs_per_user)

    log_info('Running System Test #1')
    log_info('> server_seed_docs          = {}'.format(server_seed_docs))
    log_info('> max_docs                  = {}'.format(max_docs))
    log_info('> num_users                 = {}'.format(num_users))
    log_info('> docs_per_user             = {}'.format(docs_per_user))
    log_info('> create_batch_size         = {}'.format(create_batch_size))
    log_info('> create_delay              = {}'.format(create_delay))
    log_info('> update_batch_size         = {}'.format(update_batch_size))
    log_info('> update_docs_percentage    = {}'.format(update_docs_percentage))
    log_info(
        '> docs_per_user_per_update  = {}'.format(docs_per_user_per_update))
    log_info('> update_delay              = {}'.format(update_delay))
    log_info('> update_runtime_sec        = {}'.format(update_runtime_sec))
    log_info('> changes_delay             = {}'.format(changes_delay))
    log_info('> changes_limit             = {}'.format(changes_limit))
    log_info(
        '> changes_terminator_doc_id = {}'.format(changes_terminator_doc_id))

    # Validate
    # Server docs should be a multiple of 1000 for batching purposes
    if server_seed_docs % 1000 != 0:
        raise ValueError('server_seed_docs must be divisible by 1000')

    # Number of docs should be equally divisible by number of users
    if max_docs % num_users != 0:
        raise ValueError('max_docs must be divisible by number_of_users')

    # Number of docs per user (max_docs / num_users) should be equally
    # divisible by the batch size for easier computation
    if docs_per_user % create_batch_size != 0:
        raise ValueError(
            'docs_per_user ({}) must be devisible by create_batch_size ({})'.
            format(docs_per_user, create_batch_size))

    # We want an even distributed of users per type
    if num_users % len(USER_TYPES) != 0:
        raise ValueError("'num_users' should be a multiple of 4")

    # Make sure that the 'update_batch_size' is complatible with
    # then number of users per type
    num_users_per_type = num_users / len(USER_TYPES)
    if update_batch_size > num_users_per_type:
        raise ValueError(
            "'batch_size' cannot be larger than number of users per type")

    if num_users_per_type % update_batch_size != 0:
        raise ValueError(
            "'update_batch_size' ({}) should be a multiple of number_users_per_type ({})"
            .format(update_batch_size, num_users_per_type))

    sg_conf_name = 'sync_gateway_default'
    sg_conf = sync_gateway_config_path_for_mode(sg_conf_name, mode)

    # Reset cluster state
    c = Cluster(config=cluster_config)
    c.reset(sg_config_path=sg_conf)

    cluster_helper = ClusterKeywords()
    topology = cluster_helper.get_cluster_topology(cluster_config)

    cbs_url = topology['couchbase_servers'][0]
    cbs_admin_url = cbs_url.replace('8091', '8092')
    cb_server = couchbaseserver.CouchbaseServer(cbs_url)
    bucket_name = "data-bucket"

    cbs_ip = cb_server.host

    headers = {'Content-Type': 'application/json'}
    cbs_session = Session()
    cbs_session.headers = headers
    cbs_session.auth = ('Administrator', 'password')

    log_info('Seeding {} with {} docs'.format(cbs_ip, server_seed_docs))
    sdk_client = Bucket('couchbase://{}/{}'.format(cbs_ip, bucket_name),
                        password='******',
                        timeout=300)

    # Stop SG before loading the server
    lb_url = topology['sync_gateways'][0]['public']
    sg_admin_url = topology['sync_gateways'][0]['admin']
    sg_db = 'db'

    sg_helper = SyncGateway()
    sg_helper.stop_sync_gateways(cluster_config=cluster_config)

    # Scenario Actions
    delete_views(cbs_session, cbs_admin_url, bucket_name)
    load_bucket(sdk_client, server_seed_docs)
    sg_helper.start_sync_gateways(cluster_config, config=sg_conf)
    wait_for_view_creation(cbs_session, cbs_admin_url, bucket_name)

    # Start concurrent creation of docs (max docs / num users)
    # Each user will add batch_size number of docs via bulk docs and sleep for 'create_delay'
    # Once a user has added number of expected docs 'docs_per_user', it will terminate.
    log_info('------------------------------------------')
    log_info('START concurrent user / doc creation')
    log_info('------------------------------------------')
    users = create_docs(sg_admin_url=sg_admin_url,
                        sg_url=lb_url,
                        sg_db=sg_db,
                        num_users=num_users,
                        number_docs_per_user=docs_per_user,
                        create_batch_size=create_batch_size,
                        create_delay=create_delay)
    assert len(users) == num_users
    log_info('------------------------------------------')
    log_info('END concurrent user / doc creation')
    log_info('------------------------------------------')

    # Start changes processing
    with ProcessPoolExecutor(max_workers=((len(users) * 3) +
                                          update_batch_size + 3)) as pex:

        # Start changes feeds in background process
        changes_workers_task = pex.submit(start_changes_processing, lb_url,
                                          sg_db, users, changes_delay,
                                          changes_limit,
                                          changes_terminator_doc_id)

        log_info('------------------------------------------')
        log_info('START concurrent updates')
        log_info('------------------------------------------')
        # Start concurrent updates of update
        # Update batch size is the number of users that will concurrently update all of their docs
        users = update_docs(sg_url=lb_url,
                            sg_db=sg_db,
                            users=users,
                            update_runtime_sec=update_runtime_sec,
                            batch_size=update_batch_size,
                            docs_per_user_per_update=docs_per_user_per_update,
                            update_delay=update_delay)

        all_user_channels = []
        for k, v in users.items():
            log_info('User ({}) updated docs {} times!'.format(
                k, v['updates']))
            all_user_channels.append(k)

        log_info('------------------------------------------')
        log_info('END concurrent updates')
        log_info('------------------------------------------')

        # Broadcast termination doc to all users
        terminator_channel = 'terminator'
        send_changes_termination_doc(lb_url, sg_db, users,
                                     changes_terminator_doc_id,
                                     terminator_channel)

        # Overwrite each users channels with 'terminator' so their changes feed will backfill with the termination doc
        grant_users_access(users, [terminator_channel], sg_admin_url, sg_db)

        # Block on changes completion
        users = changes_workers_task.result()

        # Print the summary of the system test
        print_summary(users)
def test_server_goes_down_rebuild_channels(params_from_base_test_setup):
    """
    1. Start with a two node couchbase server cluster
    2. Starting adding docs
    3. Kill one of the server nodes and signal completion
    4. Stop adding docs
    5. Verify that that the expected docs are present and in the changes feed.
    6. Start server again and add to cluster
    """

    cluster_config = params_from_base_test_setup["cluster_config"]
    mode = params_from_base_test_setup["mode"]

    sg_version = get_sg_version(cluster_config)
    if compare_versions(sg_version, '1.5') < 0:
        pytest.skip("This test needs multiple URLs in the SG config, not supported by SG < 1.5")

    cluster_helper = ClusterKeywords()

    sg_conf_name = "sync_gateway_default_functional_tests"
    sg_conf_path = sync_gateway_config_path_for_mode(sg_conf_name, mode)

    cluster_helper.reset_cluster(cluster_config=cluster_config,
                                 sync_gateway_config=sg_conf_path)

    topology = cluster_helper.get_cluster_topology(cluster_config)

    admin_sg = topology["sync_gateways"][0]["admin"]
    sg_url = topology["sync_gateways"][0]["public"]
    coucbase_servers = topology["couchbase_servers"]

    cbs_one_url = coucbase_servers[0]
    cbs_two_url = coucbase_servers[1]

    log_info("Running: 'test_server_goes_down_sanity'")
    log_info("cluster_config: {}".format(cluster_config))
    log_info("admin_sg: {}".format(admin_sg))
    log_info("sg_url: {}".format(sg_url))
    log_info("cbs_one_url: {}".format(cbs_one_url))
    log_info("cbs_two_url: {}".format(cbs_two_url))

    sg_db = "db"
    num_docs = 100

    admin_user_info = userinfo.UserInfo(
        name="admin",
        password="******",
        channels=["ABC"],
        roles=[]
    )

    seth_user_info = userinfo.UserInfo(
        name="seth",
        password="******",
        channels=["ABC"],
        roles=[]
    )

    client = MobileRestClient()
    main_server = couchbaseserver.CouchbaseServer(cbs_one_url)
    flakey_server = couchbaseserver.CouchbaseServer(cbs_two_url)

    admin_auth = client.create_user(
        admin_sg,
        sg_db,
        admin_user_info.name,
        admin_user_info.password,
        channels=admin_user_info.channels
    )

    client.create_user(
        admin_sg,
        sg_db,
        seth_user_info.name,
        seth_user_info.password,
        channels=seth_user_info.channels
    )
    seth_session = client.create_session(admin_sg, sg_db, seth_user_info.name)

    # allow any user docs to make it to changes
    initial_changes = client.get_changes(url=sg_url, db=sg_db, since=0, auth=seth_session)

    # push docs from admin
    docs = client.add_docs(
        url=sg_url,
        db=sg_db,
        number=num_docs,
        id_prefix=None,
        channels=admin_user_info.channels,
        auth=admin_auth
    )

    assert len(docs) == num_docs

    client.verify_docs_in_changes(url=sg_url, db=sg_db, expected_docs=docs, auth=seth_session)
    changes_before_failover = client.get_changes(url=sg_url, db=sg_db, since=initial_changes["last_seq"], auth=seth_session)
    assert len(changes_before_failover["results"]) == num_docs

    # Stop server via 'service stop'
    flakey_server.stop()

    start = time.time()
    while True:
        # Fail tests if all docs do not succeed before timeout
        if (time.time() - start) > 60:
            # Bring server back up before failing the test
            flakey_server.start()
            main_server.recover(flakey_server)
            main_server.rebalance_in(coucbase_servers, flakey_server)
            raise keywords.exceptions.TimeoutError("Failed to rebuild changes")

        try:
            # Poll until failover happens (~30 second)
            client.verify_docs_in_changes(url=sg_url, db=sg_db, expected_docs=docs, auth=seth_session)
            # changes requests succeeded, exit loop
            break
        except requests.exceptions.HTTPError:
            # Changes will fail until failover of the down server happens. Wait and try again.
            log_info("/db/_changes failed due to server down. Retrying ...")
            time.sleep(1)

    # Verify no new changes
    changes = client.get_changes(
        url=sg_url,
        db=sg_db,
        since=changes_before_failover["last_seq"],
        auth=seth_session,
        feed="normal"
    )
    assert len(changes["results"]) == 0

    # Check that all changes are intact from initial changes request
    changes = client.get_changes(url=sg_url, db=sg_db, since=initial_changes["last_seq"], auth=seth_session)
    assert len(changes["results"]) == num_docs

    coucbase_servers = topology["couchbase_servers"]

    # Test succeeded without timeout, bring server back into topology
    flakey_server.start()
    main_server.recover(flakey_server)
    main_server.rebalance_in(coucbase_servers, flakey_server)
Exemple #16
0
def params_from_base_suite_setup(request):
    log_info("Setting up 'params_from_base_suite_setup' ...")

    # pytest command line parameters
    server_version = request.config.getoption("--server-version")
    sync_gateway_version = request.config.getoption("--sync-gateway-version")
    mode = request.config.getoption("--mode")
    skip_provisioning = request.config.getoption("--skip-provisioning")
    race_enabled = request.config.getoption("--race")
    cbs_ssl = request.config.getoption("--server-ssl")
    xattrs_enabled = request.config.getoption("--xattrs")
    sg_ce = request.config.getoption("--sg-ce")
    sg_lb = request.config.getoption("--sg-lb")
    use_sequoia = request.config.getoption("--sequoia")
    no_conflicts_enabled = request.config.getoption("--no-conflicts")

    if xattrs_enabled and version_is_binary(sync_gateway_version):
        check_xattr_support(server_version, sync_gateway_version)

    log_info("server_version: {}".format(server_version))
    log_info("sync_gateway_version: {}".format(sync_gateway_version))
    log_info("mode: {}".format(mode))
    log_info("skip_provisioning: {}".format(skip_provisioning))
    log_info("race_enabled: {}".format(race_enabled))
    log_info("cbs_ssl: {}".format(cbs_ssl))
    log_info("xattrs_enabled: {}".format(xattrs_enabled))
    log_info("sg_ce: {}".format(sg_ce))
    log_info("sg_lb: {}".format(sg_lb))
    log_info("no conflicts enabled {}".format(no_conflicts_enabled))

    # sg-ce is invalid for di mode
    if mode == "di" and sg_ce:
        raise FeatureSupportedError(
            "SGAccel is only available as an enterprise edition")

    if no_conflicts_enabled and sync_gateway_version < "2.0":
        raise FeatureSupportedError(
            'No conflicts feature not available for sync-gateway version below 2.0, so skipping the test'
        )

    # Make sure mode for sync_gateway is supported ('cc' or 'di')
    validate_sync_gateway_mode(mode)

    # use base_cc cluster config if mode is "cc" or base_di cluster config if more is "di"
    cluster_config = "{}/multiple_sync_gateways_{}".format(
        constants.CLUSTER_CONFIGS_DIR, mode)
    sg_config = sync_gateway_config_path_for_mode(
        "sync_gateway_default_functional_tests", mode)

    # Add load balancer prop and check if load balancer IP is available
    if sg_lb:
        persist_cluster_config_environment_prop(cluster_config,
                                                'sg_lb_enabled', True)
        log_info("Running tests with load balancer enabled: {}".format(
            get_load_balancer_ip(cluster_config)))
    else:
        log_info("Running tests with load balancer disabled")
        persist_cluster_config_environment_prop(cluster_config,
                                                'sg_lb_enabled', False)

    if cbs_ssl:
        log_info("Running tests with cbs <-> sg ssl enabled")
        # Enable ssl in cluster configs
        persist_cluster_config_environment_prop(cluster_config,
                                                'cbs_ssl_enabled', True)
    else:
        log_info("Running tests with cbs <-> sg ssl disabled")
        # Disable ssl in cluster configs
        persist_cluster_config_environment_prop(cluster_config,
                                                'cbs_ssl_enabled', False)

    if xattrs_enabled:
        log_info("Running test with xattrs for sync meta storage")
        persist_cluster_config_environment_prop(cluster_config,
                                                'xattrs_enabled', True)
    else:
        log_info("Using document storage for sync meta data")
        persist_cluster_config_environment_prop(cluster_config,
                                                'xattrs_enabled', False)

    try:
        server_version
    except NameError:
        log_info("Server version is not provided")
        persist_cluster_config_environment_prop(cluster_config,
                                                'server_version', "")
    else:
        log_info("Running test with server version {}".format(server_version))
        persist_cluster_config_environment_prop(cluster_config,
                                                'server_version',
                                                server_version)

    try:
        sync_gateway_version
    except NameError:
        log_info("Sync gateway version is not provided")
        persist_cluster_config_environment_prop(cluster_config,
                                                'sync_gateway_version', "")
    else:
        log_info("Running test with sync_gateway version {}".format(
            sync_gateway_version))

        persist_cluster_config_environment_prop(cluster_config,
                                                'sync_gateway_version',
                                                sync_gateway_version)

    if no_conflicts_enabled:
        log_info("Running with no conflicts")
        persist_cluster_config_environment_prop(cluster_config,
                                                'no_conflicts_enabled', True)
    else:
        log_info("Running with allow conflicts")
        persist_cluster_config_environment_prop(cluster_config,
                                                'no_conflicts_enabled', False)

    if sync_gateway_version < "2.0.0" and no_conflicts_enabled:
        pytest.skip(
            "Test cannot run with no-conflicts with sg version < 2.0.0")

    # Skip provisioning if user specifies '--skip-provisoning' or '--sequoia'
    should_provision = True
    if skip_provisioning or use_sequoia:
        should_provision = False

    cluster_utils = ClusterKeywords()
    if should_provision:
        try:
            cluster_utils.provision_cluster(
                cluster_config=cluster_config,
                server_version=server_version,
                sync_gateway_version=sync_gateway_version,
                sync_gateway_config=sg_config,
                race_enabled=race_enabled,
                sg_ce=sg_ce)
        except ProvisioningError:
            logging_helper = Logging()
            logging_helper.fetch_and_analyze_logs(
                cluster_config=cluster_config, test_name=request.node.name)
            raise

    # Hit this intalled running services to verify the correct versions are installed
    cluster_utils.verify_cluster_versions(
        cluster_config,
        expected_server_version=server_version,
        expected_sync_gateway_version=sync_gateway_version)

    yield {
        "cluster_config": cluster_config,
        "mode": mode,
        "xattrs_enabled": xattrs_enabled
    }

    log_info("Tearing down 'params_from_base_suite_setup' ...")

    # Stop all sync_gateway and sg_accels as test finished
    c = cluster.Cluster(cluster_config)
    c.stop_sg_and_accel()
def test_rebalance_sanity(params_from_base_test_setup):

    cluster_config = params_from_base_test_setup["cluster_config"]
    mode = params_from_base_test_setup["mode"]

    sg_version = get_sg_version(cluster_config)
    if compare_versions(sg_version, '1.5') < 0:
        pytest.skip("This test needs multiple URLs in the SG config, not supported by SG < 1.5")

    cluster_helper = ClusterKeywords()

    sg_conf_name = "sync_gateway_default_functional_tests"
    sg_conf_path = sync_gateway_config_path_for_mode(sg_conf_name, mode)

    cluster_helper.reset_cluster(cluster_config=cluster_config,
                                 sync_gateway_config=sg_conf_path)

    topology = cluster_helper.get_cluster_topology(cluster_config)

    admin_sg_one = topology["sync_gateways"][0]["admin"]
    sg_one_url = topology["sync_gateways"][0]["public"]

    cluster_servers = topology["couchbase_servers"]
    cbs_one_url = cluster_servers[0]
    cbs_two_url = cluster_servers[1]

    log_info("Running: 'test_distributed_index_rebalance_sanity'")
    log_info("cluster_config: {}".format(cluster_config))
    log_info("admin_sg: {}".format(admin_sg_one))
    log_info("sg_url: {}".format(sg_one_url))
    log_info("cbs_one_url: {}".format(cbs_one_url))
    log_info("cbs_two_url: {}".format(cbs_two_url))

    sg_db = "db"
    num_docs = 100
    num_updates = 100
    sg_user_name = "seth"
    sg_user_password = "******"
    channels = ["ABC", "CBS"]

    client = MobileRestClient()
    cb_server = couchbaseserver.CouchbaseServer(cbs_one_url)
    server_to_remove = couchbaseserver.CouchbaseServer(cbs_two_url)

    client.create_user(admin_sg_one, sg_db, sg_user_name, sg_user_password, channels=channels)
    session = client.create_session(admin_sg_one, sg_db, sg_user_name)

    with concurrent.futures.ThreadPoolExecutor(5) as executor:

        # Add docs to sg
        log_info("Adding docs to sync_gateway")
        docs = client.add_docs(sg_one_url, sg_db, num_docs, "test_doc", channels=channels, auth=session)
        assert len(docs) == num_docs

        # Start updating docs and rebalance out one CBS node
        log_info("Updating docs on sync_gateway")
        update_docs_task = executor.submit(client.update_docs, sg_one_url, sg_db, docs, num_updates, auth=session)

        # Run rebalance in background
        cb_server.rebalance_out(cluster_servers, server_to_remove)

        updated_docs = update_docs_task.result()
        log_info(updated_docs)

    # Verify docs / revisions present
    client.verify_docs_present(sg_one_url, sg_db, updated_docs, auth=session)

    # Verify docs revisions in changes feed
    client.verify_docs_in_changes(sg_one_url, sg_db, updated_docs, auth=session)

    # Rebalance Server back in to the pool
    cb_server.add_node(server_to_remove)
    cb_server.rebalance_in(cluster_servers, server_to_remove)
Exemple #18
0
def test_openidconnect_basic_test(params_from_base_test_setup, sg_conf_name, is_admin_port, expect_signed_id_token):
    """Tests the basic OpenIDConnect login flow against the non-admin port when is_admin_port=False
    Tests the basic OpenIDConnect login flow against the admin port when is_admin_port=True
    """

    cluster_config = params_from_base_test_setup["cluster_config"]
    mode = params_from_base_test_setup["mode"]
    sg_conf = sync_gateway_config_path_for_mode(sg_conf_name, mode)

    cluster_helper = ClusterKeywords()
    topology = cluster_helper.get_cluster_topology(cluster_config)
    sg_url = topology["sync_gateways"][0]["public"]
    sg_db = "db"

    log_info("Running 'test_openidconnect_basic_test'")
    log_info("Using cluster_config: {}".format(cluster_config))
    log_info("Using sg_url: {}".format(sg_url))
    log_info("Using sg_db: {}".format(sg_db))
    log_info("Using is_admin_port: {}".format(is_admin_port))
    log_info("Using expect_signed_id_token: {}".format(expect_signed_id_token))

    cluster_helper = ClusterKeywords()
    cluster_helper.reset_cluster(
        cluster_config=cluster_config,
        sync_gateway_config=sg_conf
    )

    # make a request against the db and expect a 401 response since we haven't authenticated yet.
    # (but there's no point in doing this on the admin port since we'll never get a 401)
    if not is_admin_port:
        db_url = "{}/{}".format(sg_url, sg_db)
        resp = requests.get(db_url)
        assert resp.status_code == 401, "Expected 401 response"

    # get the authenticate endpoint and query params, should look something like:
    #     authenticate?client_id=sync_gateway&redirect_uri= ...
    authenticate_endpoint = discover_authenticate_endpoint(sg_url, sg_db, DEFAULT_PROVIDER)

    # build the full url
    authenticate_endpoint_url = "{}/{}/_oidc_testing/{}".format(
        sg_url,
        sg_db,
        authenticate_endpoint
    )

    # Make the request to _oidc_testing
    # multipart/form data content
    formdata = {
        'username': ('', 'testuser'),
        'authenticated': ('', 'Return a valid authorization code for this user')
    }
    authenticate_response = requests.post(authenticate_endpoint_url, files=formdata)
    set_cookie_response_header = authenticate_response.headers['Set-Cookie']
    log_r(authenticate_response)

    # extract the token from the response
    authenticate_response_json = authenticate_response.json()
    id_token = authenticate_response_json["id_token"]
    refresh_token = authenticate_response_json["refresh_token"]

    # make sure the id token has the email field in it
    decoded_id_token = jwt.decode(id_token, verify=False)
    assert "email" in decoded_id_token.keys()

    # make a request using the ID token against the db and expect a 200 response
    headers = {"Authorization": "Bearer {}".format(id_token)}
    db_url = "{}/{}".format(sg_url, sg_db)
    resp = requests.get(db_url, headers=headers)
    log_r(resp)
    if expect_signed_id_token:
        assert resp.status_code == 200, "Expected 200 response for bearer ID token"
    else:
        assert resp.status_code == 401, "Expected 401 response for bearer ID token"

    # make a request using the cookie against the db and expect a 200 response
    db_url = "{}/{}".format(sg_url, sg_db)
    resp = requests.get(db_url, cookies=extract_cookie(set_cookie_response_header))
    log_r(resp)
    assert resp.status_code == 200, "Expected 200 response when using session cookie"

    # make a request using the session_id that's sent in the body
    resp = requests.get(db_url, cookies={"SyncGatewaySession": authenticate_response_json["session_id"]})
    assert resp.status_code == 200, "Expected 200 response using session_id from body"

    # try to use the refresh token to get a few new id_tokens
    id_tokens = [id_token]
    for i in xrange(3):

        # This pause is required because according to @ajres:
        # The id_token will only be unique if the two calls are more than a second apart.
        # It would be easy to add an atomically incrementing nonce claim to each token to ensure that they are always unique
        time.sleep(2)

        refresh_token_url = "{}/{}/_oidc_refresh?refresh_token={}&provider={}".format(sg_url, sg_db, refresh_token, "test")
        authenticate_response = requests.get(refresh_token_url)
        authenticate_response_json = authenticate_response.json()
        id_token_refresh = authenticate_response_json["id_token"]
        # make sure we get a unique id token each time
        assert id_token_refresh not in id_tokens

        # make a request using the ID token against the db and expect a 200 response
        headers = {"Authorization": "Bearer {}".format(id_token_refresh)}
        resp = requests.get(db_url, headers=headers)
        log_r(resp)
        if expect_signed_id_token:
            assert resp.status_code == 200, "Expected 200 response for bearer ID token on refresh"
        else:
            assert resp.status_code == 401, "Expected 401 response for bearer ID token on refresh"

        id_tokens.append(id_token_refresh)
Exemple #19
0
def params_from_base_suite_setup(request):
    log_info("Setting up 'params_from_base_suite_setup' ...")

    # pytest command line parameters
    server_version = request.config.getoption("--server-version")
    sync_gateway_version = request.config.getoption("--sync-gateway-version")
    server_upgraded_version = request.config.getoption(
        "--server-upgraded-version")
    sync_gateway_upgraded_version = request.config.getoption(
        "--sync-gateway-upgraded-version")
    mode = request.config.getoption("--mode")
    cluster_config = request.config.getoption("--cluster-config")
    # use_sequoia = request.config.getoption("--sequoia")
    skip_provisioning = request.config.getoption("--skip-provisioning")
    cbs_ssl = request.config.getoption("--server-ssl")
    xattrs_enabled = request.config.getoption("--xattrs")
    liteserv_host = request.config.getoption("--liteserv-host")
    liteserv_port = request.config.getoption("--liteserv-port")
    liteserv_version = request.config.getoption("--liteserv-version")
    liteserv_platform = request.config.getoption("--liteserv-platform")
    liteserv_storage_engine = request.config.getoption(
        "--liteserv-storage-engine")
    num_docs = request.config.getoption("--num-docs")
    cbs_platform = request.config.getoption("--cbs-platform")
    cbs_toy_build = request.config.getoption("--cbs-upgrade-toybuild")

    if xattrs_enabled and version_is_binary(sync_gateway_version):
        check_xattr_support(server_upgraded_version,
                            sync_gateway_upgraded_version)

    log_info("server_version: {}".format(server_version))
    log_info("sync_gateway_version: {}".format(sync_gateway_version))
    log_info("server_upgraded_version: {}".format(server_upgraded_version))
    log_info("sync_gateway_upgraded_version: {}".format(
        sync_gateway_upgraded_version))
    log_info("mode: {}".format(mode))
    log_info("skip_provisioning: {}".format(skip_provisioning))
    log_info("cbs_ssl: {}".format(cbs_ssl))
    log_info("xattrs_enabled: {}".format(xattrs_enabled))
    log_info("liteserv_host: {}".format(liteserv_host))
    log_info("liteserv_port: {}".format(liteserv_port))
    log_info("liteserv_version: {}".format(liteserv_version))
    log_info("liteserv_platform: {}".format(liteserv_platform))
    log_info("liteserv_storage_engine: {}".format(liteserv_storage_engine))
    log_info("num_docs: {}".format(num_docs))
    log_info("cbs_platform: {}".format(cbs_platform))
    log_info("cbs_toy_build: {}".format(cbs_toy_build))

    # Make sure mode for sync_gateway is supported ('cc' or 'di')
    validate_sync_gateway_mode(mode)

    # use ci_lb_cc cluster config if mode is "cc" or ci_lb_di cluster config if more is "di"
    # use base_(lb_)cc cluster config if mode is "cc" or base_(lb_)di cluster config if mode is "di"
    cluster_config = "{}/{}_{}".format(CLUSTER_CONFIGS_DIR, cluster_config,
                                       mode)
    log_info("Using '{}' config!".format(cluster_config))

    try:
        server_version
    except NameError:
        log_info("Server version is not provided")
        persist_cluster_config_environment_prop(cluster_config,
                                                'server_version', "")
    else:
        log_info("Running test with server version {}".format(server_version))
        persist_cluster_config_environment_prop(cluster_config,
                                                'server_version',
                                                server_version)

    try:
        sync_gateway_version
    except NameError:
        log_info("Sync gateway version is not provided")
        persist_cluster_config_environment_prop(cluster_config,
                                                'sync_gateway_version', "")
    else:
        log_info("Running test with sync_gateway version {}".format(
            sync_gateway_version))
        persist_cluster_config_environment_prop(cluster_config,
                                                'sync_gateway_version',
                                                sync_gateway_version)

    # Only works with load balancer configs
    persist_cluster_config_environment_prop(cluster_config, 'sg_lb_enabled',
                                            True)

    if cbs_ssl:
        log_info("Running tests with cbs <-> sg ssl enabled")
        # Enable ssl in cluster configs
        persist_cluster_config_environment_prop(cluster_config,
                                                'cbs_ssl_enabled', True)
    else:
        log_info("Running tests with cbs <-> sg ssl disabled")
        # Disable ssl in cluster configs
        persist_cluster_config_environment_prop(cluster_config,
                                                'cbs_ssl_enabled', False)

    sg_config = sync_gateway_config_path_for_mode(
        "sync_gateway_default_functional_tests", mode)

    liteserv = LiteServFactory.create(platform=liteserv_platform,
                                      version_build=liteserv_version,
                                      host=liteserv_host,
                                      port=liteserv_port,
                                      storage_engine=liteserv_storage_engine)

    log_info("Downloading LiteServ ...")
    # Download LiteServ
    liteserv.download()

    # Install LiteServ
    liteserv.install()

    # Skip provisioning if user specifies '--skip-provisoning' or '--sequoia'
    should_provision = True
    if skip_provisioning:
        should_provision = False

    cluster_utils = ClusterKeywords()
    if should_provision:
        try:
            cluster_utils.provision_cluster(
                cluster_config=cluster_config,
                server_version=server_version,
                sync_gateway_version=sync_gateway_version,
                sync_gateway_config=sg_config,
                cbs_platform=cbs_platform)
        except ProvisioningError:
            logging_helper = Logging()
            logging_helper.fetch_and_analyze_logs(
                cluster_config=cluster_config, test_name=request.node.name)
            raise

    # Hit this intalled running services to verify the correct versions are installed
    cluster_utils.verify_cluster_versions(
        cluster_config,
        expected_server_version=server_version,
        expected_sync_gateway_version=sync_gateway_version)

    # Load topology as a dictionary
    cluster_topology = cluster_utils.get_cluster_topology(cluster_config)

    yield {
        "cluster_config": cluster_config,
        "cluster_topology": cluster_topology,
        "mode": mode,
        "xattrs_enabled": xattrs_enabled,
        "server_version": server_version,
        "sync_gateway_version": sync_gateway_version,
        "server_upgraded_version": server_upgraded_version,
        "sync_gateway_upgraded_version": sync_gateway_upgraded_version,
        "liteserv_host": liteserv_host,
        "liteserv_port": liteserv_port,
        "liteserv_version": liteserv_version,
        "liteserv_platform": liteserv_platform,
        "liteserv_storage_engine": liteserv_storage_engine,
        "liteserv": liteserv,
        "num_docs": num_docs,
        "cbs_platform": cbs_platform,
        "cbs_toy_build": cbs_toy_build
    }

    log_info("Tearing down 'params_from_base_suite_setup' ...")
Exemple #20
0
def test_openidconnect_garbage_token(params_from_base_test_setup, sg_conf_name):
    """Send a garbage/invalid token and make sure it cannot be used"""

    # WARNING!!!! SHOULD THERE BE A RESET?

    cluster_config = params_from_base_test_setup["cluster_config"]

    cluster_helper = ClusterKeywords()
    topology = cluster_helper.get_cluster_topology(cluster_config)
    sg_url = topology["sync_gateways"][0]["public"]
    sg_db = "db"

    log_info("Running 'test_openidconnect_garbage_token'")
    log_info("Using cluster_config: {}".format(cluster_config))
    log_info("Using sg_url: {}".format(sg_url))
    log_info("Using sg_db: {}".format(sg_db))

    token_expiry_seconds = 5

    # multipart/form data content
    formdata = {
        'username': ('', 'testuser'),
        'authenticated': ('', 'Return a valid authorization code for this user'),
        'tokenttl': ('', "{}".format(token_expiry_seconds)),
    }

    # get the authenticate endpoint and query params, should look something like:
    #     authenticate?client_id=sync_gateway&redirect_uri= ...
    authenticate_endpoint = discover_authenticate_endpoint(sg_url, sg_db, DEFAULT_PROVIDER)

    # build the full url
    url = "{}/{}/_oidc_testing/{}".format(
        sg_url,
        sg_db,
        authenticate_endpoint
    )

    # Make the request to _oidc_testing
    response = requests.post(url, files=formdata)
    log_r(response)

    # extract the token from the response
    response_json = response.json()
    id_token = response_json["id_token"]

    # Complete garbage Token
    # make a request using the ID token against the db and expect a 200 response
    headers = {"Authorization": "Bearer {}".format("garbage")}
    db_url = "{}/{}".format(sg_url, sg_db)
    resp = requests.get(db_url, headers=headers)
    log_r(resp)
    assert resp.status_code != 200, "Expected non-200 response"

    # Partial garbage Token

    # get all the components split by "."
    token_components = id_token.split(".")

    # get subset of components except for last one
    all_components_except_last = token_components[:-1]

    # add a garbage last component
    all_components_except_last.append("garbage")

    # create a string out of the components
    partial_garbage_token = ".".join(all_components_except_last)

    headers = {"Authorization": "Bearer {}".format(partial_garbage_token)}
    db_url = "{}/{}".format(sg_url, sg_db)
    resp = requests.get(db_url, headers=headers)
    log_r(resp)
    assert resp.status_code != 200, "Expected non-200 response"
Exemple #21
0
def params_from_base_test_setup(request, params_from_base_suite_setup):
    # Code before the yeild will execute before each test starts

    # pytest command line parameters
    cluster_config = params_from_base_suite_setup["cluster_config"]
    cluster_topology = params_from_base_suite_setup["cluster_topology"]
    mode = params_from_base_suite_setup["mode"]
    xattrs_enabled = params_from_base_suite_setup["xattrs_enabled"]
    server_version = params_from_base_suite_setup["server_version"]
    sync_gateway_version = params_from_base_suite_setup["sync_gateway_version"]
    server_upgraded_version = params_from_base_suite_setup[
        "server_upgraded_version"]
    sync_gateway_upgraded_version = params_from_base_suite_setup[
        "sync_gateway_upgraded_version"]
    liteserv_host = params_from_base_suite_setup["liteserv_host"]
    liteserv_port = params_from_base_suite_setup["liteserv_port"]
    liteserv_version = params_from_base_suite_setup["liteserv_version"]
    liteserv_platform = params_from_base_suite_setup["liteserv_platform"]
    liteserv_storage_engine = params_from_base_suite_setup[
        "liteserv_storage_engine"]
    liteserv = params_from_base_suite_setup["liteserv"]
    num_docs = params_from_base_suite_setup["num_docs"]
    cbs_platform = params_from_base_suite_setup["cbs_platform"]
    cbs_toy_build = params_from_base_suite_setup["cbs_toy_build"]

    test_name = request.node.name
    log_info("Running test '{}'".format(test_name))
    log_info("cluster_config: {}".format(cluster_config))
    log_info("cluster_topology: {}".format(cluster_topology))
    log_info("mode: {}".format(mode))
    log_info("xattrs_enabled: {}".format(xattrs_enabled))

    client = MobileRestClient()

    # Start LiteServ and delete any databases
    ls_url = liteserv.start("{}/logs/{}-{}-{}.txt".format(
        RESULTS_DIR,
        type(liteserv).__name__, test_name, datetime.datetime.now()))
    client.delete_databases(ls_url)

    cluster_helper = ClusterKeywords()
    cluster_hosts = cluster_helper.get_cluster_topology(
        cluster_config=cluster_config)
    sg_url = cluster_hosts["sync_gateways"][0]["public"]
    sg_admin_url = cluster_hosts["sync_gateways"][0]["admin"]

    if xattrs_enabled:
        log_info("Running upgrade with xattrs for sync meta storage")
        persist_cluster_config_environment_prop(cluster_config,
                                                'xattrs_enabled', True)
    else:
        log_info("Using document storage for sync meta data")
        persist_cluster_config_environment_prop(cluster_config,
                                                'xattrs_enabled', False)

    # This dictionary is passed to each test
    yield {
        "cluster_config": cluster_config,
        "cluster_topology": cluster_topology,
        "mode": mode,
        "xattrs_enabled": xattrs_enabled,
        "server_version": server_version,
        "sync_gateway_version": sync_gateway_version,
        "server_upgraded_version": server_upgraded_version,
        "sync_gateway_upgraded_version": sync_gateway_upgraded_version,
        "liteserv_host": liteserv_host,
        "liteserv_port": liteserv_port,
        "liteserv_version": liteserv_version,
        "liteserv_platform": liteserv_platform,
        "liteserv_storage_engine": liteserv_storage_engine,
        "ls_url": ls_url,
        "sg_url": sg_url,
        "sg_admin_url": sg_admin_url,
        "num_docs": num_docs,
        "cbs_platform": cbs_platform,
        "cbs_toy_build": cbs_toy_build
    }

    client.delete_databases(ls_url)
    liteserv.stop()

    # Code after the yield will execute when each test finishes
    log_info("Tearing down test '{}'".format(test_name))

    network_utils = NetworkUtils()
    network_utils.list_connections()

    # Verify all sync_gateways and sg_accels are reachable
    c = cluster.Cluster(cluster_config)
    errors = c.verify_alive(mode)

    # Fetch logs
    logging_helper = Logging()
    logging_helper.fetch_and_analyze_logs(cluster_config=cluster_config,
                                          test_name=test_name)

    assert len(errors) == 0

    # Scan logs
    # SG logs for panic, data race
    # System logs for OOM
    ansible_runner = AnsibleRunner(cluster_config)
    script_name = "{}/utilities/check_logs.sh".format(os.getcwd())
    status = ansible_runner.run_ansible_playbook(
        "check-logs.yml", extra_vars={"script_name": script_name})

    if status != 0:
        raise LogScanningError("Errors found in the logs")
def provision_cluster(cluster_config, couchbase_server_config, sync_gateway_config, sg_ce=False, cbs_platform="centos7", sg_platform="centos", sa_platform="centos"):

    log_info("\n>>> Cluster info:\n")
    server_version = "{}-{}".format(couchbase_server_config.version, couchbase_server_config.build)
    sg_version = "{}-{}".format(sync_gateway_config._version_number, sync_gateway_config._build_number)

    try:
        server_version
    except NameError:
        log_info("Server version is not provided")
        persist_cluster_config_environment_prop(cluster_config, 'server_version', "")
    else:
        log_info("Running test with server version {}".format(server_version))
        persist_cluster_config_environment_prop(cluster_config, 'server_version', server_version)

    try:
        sg_version
    except NameError:
        log_info("Sync gateway version is not provided")
        persist_cluster_config_environment_prop(cluster_config, 'sync_gateway_version', "")
    else:
        log_info("Running test with sync_gateway version {}".format(sg_version))
        persist_cluster_config_environment_prop(cluster_config, 'sync_gateway_version', sg_version)

    with open(cluster_config, "r") as ansible_hosts:
        log_info(ansible_hosts.read())

    log_info(couchbase_server_config)
    log_info(sync_gateway_config)

    if not sync_gateway_config.is_valid():
        log_info("Invalid sync_gateway provisioning configuration. Exiting ...")
        sys.exit(1)

    cluster = Cluster(config=cluster_config)
    config_path_full = os.path.abspath(sync_gateway_config.config_path)
    config = Config(config_path_full)

    is_valid, reason = validate_cluster(
        cluster.sync_gateways,
        cluster.sg_accels,
        config,
    )
    if not is_valid:
        raise ProvisioningError(reason)

    log_info(">>> Provisioning cluster...")

    # Get server base url and package name
    cluster_keywords = ClusterKeywords()
    cluster_topology = cluster_keywords.get_cluster_topology(cluster_config)
    server_url = cluster_topology["couchbase_servers"][0]
    cb_server = CouchbaseServer(server_url)
    server_baseurl, server_package_name = couchbase_server_config.get_baseurl_package(cb_server, cbs_platform)

    log_info(">>> Server package: {0}/{1}".format(server_baseurl, server_package_name))
    log_info(">>> Using sync_gateway config: {}".format(sync_gateway_config.config_path))

    # Reset previous installs
    clean_cluster(cluster_config)

    # Install server package
    log_info("Installing Couchbase Server")
    install_couchbase_server.install_couchbase_server(
        cluster_config=cluster_config,
        couchbase_server_config=couchbase_server_config,
        cbs_platform=cbs_platform
    )

    # Install sync_gateway
    log_info("Installing Sync Gateway")
    install_sync_gateway.install_sync_gateway(
        cluster_config=cluster_config,
        sync_gateway_config=sync_gateway_config,
        sg_platform=sg_platform,
        sa_platform=sa_platform,
        sg_ce=sg_ce
    )

    # Install nginx
    install_nginx(cluster_config)

    log_info(">>> Done provisioning cluster...")
def test_log_maxage_10_timestamp_ignored(params_from_base_test_setup,
                                         sg_conf_name):
    """Test to verify SG continues to wrile logs in the same file even when
     timestamp for the log file has been changed
    """
    cluster_conf = params_from_base_test_setup["cluster_config"]
    mode = params_from_base_test_setup["mode"]
    xattrs_enabled = params_from_base_test_setup["xattrs_enabled"]

    sg_conf = sync_gateway_config_path_for_mode(sg_conf_name, mode)

    log_info("Using cluster_conf: {}".format(cluster_conf))
    log_info("Using sg_conf: {}".format(sg_conf))

    cluster = Cluster(config=cluster_conf)
    cluster.reset(sg_config_path=sg_conf)

    remote_executor = RemoteExecutor(cluster.sync_gateways[0].ip)

    # Stop sync_gateways
    log_info(">>> Stopping sync_gateway")
    sg_helper = SyncGateway()
    cluster_helper = ClusterKeywords()
    cluster_hosts = cluster_helper.get_cluster_topology(cluster_conf)
    sg_one_url = cluster_hosts["sync_gateways"][0]["public"]

    sg_helper.stop_sync_gateways(cluster_config=cluster_conf, url=sg_one_url)

    remote_executor.execute("mkdir -p /tmp/sg_logs")
    remote_executor.execute("sudo rm -rf /tmp/sg_logs/sg_log_rotation*")
    # generate log file with almost 1MB
    remote_executor.execute(
        "sudo dd if=/dev/zero of=/tmp/sg_logs/sg_log_rotation.log bs=1030000 count=1"
    )
    remote_executor.execute("sudo chmod 777 -R /tmp/sg_logs")

    # read sample sg_conf
    data = load_sync_gateway_config(sg_conf, mode,
                                    cluster_hosts["couchbase_servers"][0],
                                    xattrs_enabled, cluster_conf)

    # set maxage = 10 days
    data['logging']["default"]["rotation"]["maxage"] = 10
    # create temp config file in the same folder as sg_conf
    temp_conf = "/".join(sg_conf.split('/')[:-2]) + '/temp_conf.json'

    with open(temp_conf, 'w') as fp:
        json.dump(data, fp)

    sg_helper.start_sync_gateways(cluster_config=cluster_conf,
                                  url=sg_one_url,
                                  config=temp_conf)
    # ~1M MB will be added to log file after requests
    remote_executor.execute(
        "for ((i=1;i <= 1000;i += 1)); do curl -s http://localhost:4984/ > /dev/null; done"
    )

    sg_helper.stop_sync_gateways(cluster_config=cluster_conf, url=sg_one_url)
    # change timestamp for log when SG stopped( we don't change file naming)
    remote_executor.execute(
        "sudo touch -d \"10 days ago\" /tmp/sg_logs/sg_log_rotation*")

    sg_helper.start_sync_gateways(cluster_config=cluster_conf,
                                  url=sg_one_url,
                                  config=temp_conf)

    _, stdout, _ = remote_executor.execute(
        "ls /tmp/sg_logs/ | grep sg_log_rotation | wc -l")
    # verify that new log file was not created
    assert stdout[0].rstrip() == '2'

    # Remove generated conf file
    os.remove(temp_conf)