sapling/eden/mononoke/bonsai_git_mapping/test/main.rs
Stanislau Hlebik f6d06a266a mononoke: check conflicts correctly when doing bulk adds in transaction
Summary:
`bulk_add()` method was checking for conflicts correctly i.e. it wouldn't fail
if we try to insert the same mapping twice.
`bulk_add_git_mapping_in_transaction` wasn't doing this check i.e. it would
fail.

This caused us a few problems and this diff fixes them - now
`bulk_add_git_mapping_in_transaction` would do the same checks as bulk_add was
doing previously.

There is another important change in behaviour: if we try to insert two entries, one of them
has a conflict another don't then previously we'd insert the second entry.
Now we don't insert any, arguably that's a preferred behaviour.

Reviewed By: krallin

Differential Revision: D22332001

fbshipit-source-id: 86fff8c23c43eeca0fb36b01b10cdaa73b3ce4ab
2020-07-02 05:31:29 -07:00

248 lines
7.0 KiB
Rust

/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This software may be used and distributed according to the terms of the
* GNU General Public License version 2.
*/
#![deny(warnings)]
use anyhow::Error;
use assert_matches::assert_matches;
use bonsai_git_mapping::{
AddGitMappingErrorKind, BonsaiGitMapping, BonsaiGitMappingEntry, BonsaisOrGitShas,
SqlBonsaiGitMappingConnection,
};
use context::CoreContext;
use fbinit::FacebookInit;
use futures::compat::Future01CompatExt;
use mononoke_types_mocks::changesetid as bonsai;
use mononoke_types_mocks::hash::*;
use mononoke_types_mocks::repo::REPO_ZERO;
use sql::Connection;
use sql_construct::SqlConstruct;
use sql_ext::{open_sqlite_in_memory, SqlConnections};
#[fbinit::test]
async fn test_add_and_get(fb: FacebookInit) -> Result<(), Error> {
let ctx = CoreContext::test_mock(fb);
let mapping = SqlBonsaiGitMappingConnection::with_sqlite_in_memory()?.with_repo_id(REPO_ZERO);
let entry = BonsaiGitMappingEntry {
bcs_id: bonsai::ONES_CSID,
git_sha1: ONES_GIT_SHA1,
};
mapping.bulk_add(&ctx, &[entry.clone()]).await?;
let result = mapping
.get(&ctx, BonsaisOrGitShas::Bonsai(vec![bonsai::ONES_CSID]))
.await?;
assert_eq!(result, vec![entry.clone()]);
let result = mapping
.get_git_sha1_from_bonsai(&ctx, bonsai::ONES_CSID)
.await?;
assert_eq!(result, Some(ONES_GIT_SHA1));
let result = mapping
.get_bonsai_from_git_sha1(&ctx, ONES_GIT_SHA1)
.await?;
assert_eq!(result, Some(bonsai::ONES_CSID));
Ok(())
}
#[fbinit::test]
async fn test_add_duplicate(fb: FacebookInit) -> Result<(), Error> {
// Inserting duplicate entries should just be a successful no-op.
let ctx = CoreContext::test_mock(fb);
let mapping = SqlBonsaiGitMappingConnection::with_sqlite_in_memory()?.with_repo_id(REPO_ZERO);
let entry = BonsaiGitMappingEntry {
bcs_id: bonsai::ONES_CSID,
git_sha1: ONES_GIT_SHA1,
};
mapping.bulk_add(&ctx, &[entry.clone()]).await?;
mapping.bulk_add(&ctx, &[entry.clone()]).await?;
let result = mapping
.get_git_sha1_from_bonsai(&ctx, bonsai::ONES_CSID)
.await?;
assert_eq!(result, Some(ONES_GIT_SHA1));
Ok(())
}
#[fbinit::test]
async fn test_add_conflict(fb: FacebookInit) -> Result<(), Error> {
// Adding conflicting entries should fail. Other entries inserted in the
// same bulk_add should be inserted.
let ctx = CoreContext::test_mock(fb);
let mapping = SqlBonsaiGitMappingConnection::with_sqlite_in_memory()?.with_repo_id(REPO_ZERO);
let entry = BonsaiGitMappingEntry {
bcs_id: bonsai::ONES_CSID,
git_sha1: ONES_GIT_SHA1,
};
mapping.bulk_add(&ctx, &[entry.clone()]).await?;
let entries = vec![
BonsaiGitMappingEntry {
// This entry could be inserted normally, but it won't because we have a conflicting
// entry
bcs_id: bonsai::TWOS_CSID,
git_sha1: TWOS_GIT_SHA1,
},
BonsaiGitMappingEntry {
// Conflicting entry.
bcs_id: bonsai::ONES_CSID,
git_sha1: THREES_GIT_SHA1,
},
];
let res = mapping.bulk_add(&ctx, &entries).await;
assert_matches!(res, Err(AddGitMappingErrorKind::Conflict(_)));
let result = mapping
.get_git_sha1_from_bonsai(&ctx, bonsai::TWOS_CSID)
.await?;
assert_eq!(result, None);
let entries = vec![BonsaiGitMappingEntry {
// Now this entry will be inserted normally
bcs_id: bonsai::TWOS_CSID,
git_sha1: TWOS_GIT_SHA1,
}];
mapping.bulk_add(&ctx, &entries).await?;
let result = mapping
.get_git_sha1_from_bonsai(&ctx, bonsai::TWOS_CSID)
.await?;
assert_eq!(result, Some(TWOS_GIT_SHA1));
Ok(())
}
#[fbinit::test]
async fn test_bulk_add(fb: FacebookInit) -> Result<(), Error> {
let ctx = CoreContext::test_mock(fb);
let mapping = SqlBonsaiGitMappingConnection::with_sqlite_in_memory()?.with_repo_id(REPO_ZERO);
let entry1 = BonsaiGitMappingEntry {
bcs_id: bonsai::ONES_CSID,
git_sha1: ONES_GIT_SHA1,
};
let entry2 = BonsaiGitMappingEntry {
bcs_id: bonsai::TWOS_CSID,
git_sha1: TWOS_GIT_SHA1,
};
let entry3 = BonsaiGitMappingEntry {
bcs_id: bonsai::THREES_CSID,
git_sha1: THREES_GIT_SHA1,
};
mapping
.bulk_add(&ctx, &[entry1.clone(), entry2.clone(), entry3.clone()])
.await?;
Ok(())
}
#[fbinit::test]
async fn test_missing(fb: FacebookInit) -> Result<(), Error> {
let ctx = CoreContext::test_mock(fb);
let mapping = SqlBonsaiGitMappingConnection::with_sqlite_in_memory()?.with_repo_id(REPO_ZERO);
let result = mapping
.get(&ctx, BonsaisOrGitShas::Bonsai(vec![bonsai::ONES_CSID]))
.await?;
assert_eq!(result, vec![]);
Ok(())
}
#[fbinit::test]
async fn test_add_with_transaction(fb: FacebookInit) -> Result<(), Error> {
let ctx = CoreContext::test_mock(fb);
let conn = open_sqlite_in_memory()?;
conn.execute_batch(SqlBonsaiGitMappingConnection::CREATION_QUERY)?;
let conn = Connection::with_sqlite(conn);
let mapping = SqlBonsaiGitMappingConnection::from_sql_connections(SqlConnections::new_single(
conn.clone(),
))
.with_repo_id(REPO_ZERO);
let entry1 = BonsaiGitMappingEntry {
bcs_id: bonsai::ONES_CSID,
git_sha1: ONES_GIT_SHA1,
};
let entry2 = BonsaiGitMappingEntry {
bcs_id: bonsai::TWOS_CSID,
git_sha1: TWOS_GIT_SHA1,
};
let txn = conn.start_transaction().compat().await?;
mapping
.bulk_add_git_mapping_in_transaction(&ctx, &[entry1.clone()], txn)
.await?
.commit()
.compat()
.await?;
assert_eq!(
Some(ONES_GIT_SHA1),
mapping
.get_git_sha1_from_bonsai(&ctx, bonsai::ONES_CSID)
.await?
);
let txn = conn.start_transaction().compat().await?;
mapping
.bulk_add_git_mapping_in_transaction(&ctx, &[entry2.clone()], txn)
.await?
.commit()
.compat()
.await?;
assert_eq!(
Some(TWOS_GIT_SHA1),
mapping
.get_git_sha1_from_bonsai(&ctx, bonsai::TWOS_CSID)
.await?
);
// Inserting duplicates fails
let txn = conn.start_transaction().compat().await?;
let res = {
let ctx = ctx.clone();
let mapping = mapping.clone();
async move {
let entry_conflict = BonsaiGitMappingEntry {
bcs_id: bonsai::TWOS_CSID,
git_sha1: THREES_GIT_SHA1,
};
mapping
.bulk_add_git_mapping_in_transaction(&ctx, &[entry_conflict], txn)
.await?
.commit()
.compat()
.await?;
Result::<_, AddGitMappingErrorKind>::Ok(())
}
}
.await;
assert_matches!(res, Err(AddGitMappingErrorKind::Conflict(_)));
assert_eq!(
Some(TWOS_GIT_SHA1),
mapping
.get_git_sha1_from_bonsai(&ctx, bonsai::TWOS_CSID)
.await?
);
Ok(())
}