blob: 77b0e78ef118262e9146db7fda1298005bc3a939 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ignite_runner_suite.h"
#include "ignite/client/ignite_client.h"
#include "ignite/client/ignite_client_configuration.h"
#include <gmock/gmock-matchers.h>
#include <gtest/gtest.h>
#include <chrono>
#include <thread>
using namespace ignite;
#define TEST_TABLE_NAME "tbl1"
/**
* Test suite.
*/
class transactions_test : public ignite_runner_suite {
protected:
/**
* Set up for every test.
*/
void SetUp() override {
clear_table1();
ignite_client_configuration cfg{get_node_addrs()};
cfg.set_logger(get_logger());
m_client = ignite_client::start(cfg, std::chrono::seconds(30));
}
/**
* Tear down for every test.
*/
void TearDown() override { clear_table1(); }
/** Ignite client. */
ignite_client m_client;
};
TEST_F(transactions_test, empty_transaction_rollback) {
auto api = m_client.get_transactions();
auto tx = api.begin();
tx.rollback();
}
TEST_F(transactions_test, empty_transaction_commit) {
auto api = m_client.get_transactions();
auto tx = api.begin();
tx.commit();
}
TEST_F(transactions_test, commit_updates_data) {
auto record_view = m_client.get_tables().get_table(TABLE_1)->get_record_binary_view();
auto tx = m_client.get_transactions().begin();
auto expected = get_tuple(42, "Lorem ipsum");
record_view.upsert(&tx, expected);
tx.commit();
auto actual = record_view.get(nullptr, get_tuple(42));
ASSERT_TRUE(actual.has_value());
EXPECT_EQ(2, actual->column_count());
EXPECT_EQ(expected.get<int64_t>("key"), actual->get<int64_t>("key"));
EXPECT_EQ(expected.get<std::string>("val"), actual->get<std::string>("val"));
}
TEST_F(transactions_test, rollback_does_not_update_data) {
auto record_view = m_client.get_tables().get_table(TABLE_1)->get_record_binary_view();
auto tx = m_client.get_transactions().begin();
auto value0 = get_tuple(42, "Lorem ipsum");
record_view.upsert(&tx, value0);
tx.rollback();
auto actual = record_view.get(nullptr, get_tuple(42));
ASSERT_FALSE(actual.has_value());
}
// TODO https://issues.apache.org/jira/browse/IGNITE-22057
TEST_F(transactions_test, DISABLED_destruction_does_not_update_data) {
auto record_view = m_client.get_tables().get_table(TABLE_1)->get_record_binary_view();
{
auto tx = m_client.get_transactions().begin();
auto value0 = get_tuple(42, "Lorem ipsum");
record_view.upsert(&tx, value0);
}
auto actual = record_view.get(nullptr, get_tuple(42));
ASSERT_FALSE(actual.has_value());
}
TEST_F(transactions_test, non_committed_data_visible_for_tx) {
auto record_view = m_client.get_tables().get_table(TABLE_1)->get_record_binary_view();
auto tx = m_client.get_transactions().begin();
auto value0 = get_tuple(42, "Lorem ipsum");
record_view.upsert(&tx, value0);
auto value_in = record_view.get(&tx, get_tuple(42));
ASSERT_TRUE(value_in.has_value());
EXPECT_EQ(2, value_in->column_count());
EXPECT_EQ(value0.get<int64_t>("key"), value_in->get<int64_t>("key"));
EXPECT_EQ(value0.get<std::string>("val"), value_in->get<std::string>("val"));
}
TEST_F(transactions_test, sql_commit) {
auto record_view = m_client.get_tables().get_table(TABLE_1)->get_record_binary_view();
auto tx = m_client.get_transactions().begin();
m_client.get_sql().execute(&tx, nullptr, {"INSERT INTO " + std::string(TABLE_1) + " VALUES (?, ?)"},
{std::int64_t(42), std::string("Lorem ipsum")});
tx.commit();
auto value = record_view.get(nullptr, get_tuple(42));
ASSERT_TRUE(value.has_value());
EXPECT_EQ(2, value->column_count());
EXPECT_EQ(42, value->get<int64_t>("key"));
EXPECT_EQ("Lorem ipsum", value->get<std::string>("val"));
}
TEST_F(transactions_test, sql_rollback) {
auto record_view = m_client.get_tables().get_table(TABLE_1)->get_record_binary_view();
auto tx = m_client.get_transactions().begin();
m_client.get_sql().execute(&tx, nullptr, {"INSERT INTO " + std::string(TABLE_1) + " VALUES (?, ?)"},
{std::int64_t(42), std::string("Lorem ipsum")});
tx.rollback();
auto value = record_view.get(nullptr, get_tuple(42));
ASSERT_FALSE(value.has_value());
}
TEST_F(transactions_test, rollback_after_commit_works) {
auto tx = m_client.get_transactions().begin();
tx.commit();
tx.rollback();
}
TEST_F(transactions_test, commit_after_commit_works) {
auto tx = m_client.get_transactions().begin();
tx.commit();
tx.commit();
}
TEST_F(transactions_test, commit_after_rollback_works) {
auto tx = m_client.get_transactions().begin();
tx.rollback();
tx.commit();
}
TEST_F(transactions_test, rollback_after_rollback_works) {
auto tx = m_client.get_transactions().begin();
tx.rollback();
tx.rollback();
}
TEST_F(transactions_test, record_view_upsert_all) {
auto record_view = m_client.get_tables().get_table(TABLE_1)->get_record_binary_view();
auto tx = m_client.get_transactions().begin();
auto value0 = get_tuple(42, "Lorem ipsum");
record_view.upsert_all(&tx, {value0});
auto values1 = record_view.get_all(&tx, {get_tuple(42)});
ASSERT_EQ(1, values1.size());
EXPECT_EQ(2, values1.front()->column_count());
EXPECT_EQ(value0.get<int64_t>("key"), values1.front()->get<int64_t>("key"));
EXPECT_EQ(value0.get<std::string>("val"), values1.front()->get<std::string>("val"));
tx.rollback();
auto values2 = record_view.get_all(nullptr, {get_tuple(42)});
ASSERT_EQ(1, values2.size());
EXPECT_FALSE(values2.front().has_value());
}
TEST_F(transactions_test, record_view_get_and_upsert) {
auto record_view = m_client.get_tables().get_table(TABLE_1)->get_record_binary_view();
auto tx = m_client.get_transactions().begin();
auto value0 = get_tuple(42, "Lorem ipsum");
auto value1 = record_view.get_and_upsert(&tx, value0);
ASSERT_FALSE(value1.has_value());
auto value2 = record_view.get_and_upsert(&tx, get_tuple(42, "12"));
ASSERT_TRUE(value2.has_value());
EXPECT_EQ(2, value2->column_count());
EXPECT_EQ(value0.get<int64_t>("key"), value2->get<int64_t>("key"));
EXPECT_EQ(value0.get<std::string>("val"), value2->get<std::string>("val"));
tx.rollback();
auto value3 = record_view.get_and_upsert(nullptr, value0);
ASSERT_FALSE(value3.has_value());
}
TEST_F(transactions_test, record_view_insert) {
auto record_view = m_client.get_tables().get_table(TABLE_1)->get_record_binary_view();
auto tx = m_client.get_transactions().begin();
auto value0 = get_tuple(42, "Lorem ipsum");
record_view.insert(&tx, value0);
auto value1 = record_view.get(&tx, get_tuple(42));
ASSERT_TRUE(value1.has_value());
EXPECT_EQ(2, value1->column_count());
EXPECT_EQ(value0.get<int64_t>("key"), value1->get<int64_t>("key"));
EXPECT_EQ(value0.get<std::string>("val"), value1->get<std::string>("val"));
tx.rollback();
auto value2 = record_view.get(nullptr, get_tuple(42));
ASSERT_FALSE(value2.has_value());
}
TEST_F(transactions_test, record_view_insert_all) {
auto record_view = m_client.get_tables().get_table(TABLE_1)->get_record_binary_view();
auto tx = m_client.get_transactions().begin();
auto value0 = get_tuple(42, "Lorem ipsum");
record_view.insert_all(&tx, {value0});
auto values1 = record_view.get_all(&tx, {get_tuple(42)});
ASSERT_EQ(1, values1.size());
EXPECT_EQ(2, values1.front()->column_count());
EXPECT_EQ(value0.get<int64_t>("key"), values1.front()->get<int64_t>("key"));
EXPECT_EQ(value0.get<std::string>("val"), values1.front()->get<std::string>("val"));
tx.rollback();
auto values2 = record_view.get_all(nullptr, {get_tuple(42)});
ASSERT_EQ(1, values2.size());
EXPECT_FALSE(values2.front().has_value());
}
TEST_F(transactions_test, record_view_replace) {
auto record_view = m_client.get_tables().get_table(TABLE_1)->get_record_binary_view();
auto tx = m_client.get_transactions().begin();
auto value0 = get_tuple(42, "Lorem ipsum");
record_view.insert(&tx, value0);
auto success1 = record_view.replace(&tx, get_tuple(42, "13"));
ASSERT_TRUE(success1);
tx.rollback();
auto success2 = record_view.replace(nullptr, get_tuple(42, "13"));
ASSERT_FALSE(success2);
}
TEST_F(transactions_test, record_view_replace_exact) {
auto record_view = m_client.get_tables().get_table(TABLE_1)->get_record_binary_view();
auto tx = m_client.get_transactions().begin();
auto value0 = get_tuple(42, "Lorem ipsum");
record_view.insert(&tx, value0);
auto success1 = record_view.replace(&tx, value0, get_tuple(42, "13"));
ASSERT_TRUE(success1);
tx.rollback();
auto success2 = record_view.replace(nullptr, value0, get_tuple(42, "13"));
ASSERT_FALSE(success2);
}
TEST_F(transactions_test, record_view_get_and_replace) {
auto record_view = m_client.get_tables().get_table(TABLE_1)->get_record_binary_view();
auto tx = m_client.get_transactions().begin();
auto value0 = get_tuple(42, "Lorem ipsum");
record_view.insert(&tx, value0);
auto value1 = record_view.get_and_replace(&tx, get_tuple(42, "12"));
ASSERT_TRUE(value1.has_value());
EXPECT_EQ(2, value1->column_count());
EXPECT_EQ(value0.get<int64_t>("key"), value1->get<int64_t>("key"));
EXPECT_EQ(value0.get<std::string>("val"), value1->get<std::string>("val"));
tx.rollback();
auto value2 = record_view.get_and_replace(nullptr, value0);
ASSERT_FALSE(value2.has_value());
}
TEST_F(transactions_test, record_view_remove) {
auto record_view = m_client.get_tables().get_table(TABLE_1)->get_record_binary_view();
auto value0 = get_tuple(42, "Lorem ipsum");
record_view.insert(nullptr, value0);
auto tx = m_client.get_transactions().begin();
auto success1 = record_view.remove(&tx, get_tuple(42));
ASSERT_TRUE(success1);
tx.rollback();
auto success2 = record_view.remove(nullptr, get_tuple(42));
ASSERT_TRUE(success2);
}
TEST_F(transactions_test, record_view_remove_exact) {
auto record_view = m_client.get_tables().get_table(TABLE_1)->get_record_binary_view();
auto value0 = get_tuple(42, "Lorem ipsum");
record_view.insert(nullptr, value0);
auto tx = m_client.get_transactions().begin();
auto success1 = record_view.remove(&tx, value0);
ASSERT_TRUE(success1);
tx.rollback();
auto success2 = record_view.remove(nullptr, value0);
ASSERT_TRUE(success2);
}
TEST_F(transactions_test, record_view_get_and_remove) {
auto record_view = m_client.get_tables().get_table(TABLE_1)->get_record_binary_view();
auto value0 = get_tuple(42, "Lorem ipsum");
record_view.insert(nullptr, value0);
auto tx = m_client.get_transactions().begin();
auto value1 = record_view.get_and_remove(&tx, get_tuple(42));
ASSERT_TRUE(value1.has_value());
EXPECT_EQ(2, value1->column_count());
EXPECT_EQ(value0.get<int64_t>("key"), value1->get<int64_t>("key"));
EXPECT_EQ(value0.get<std::string>("val"), value1->get<std::string>("val"));
tx.rollback();
auto value2 = record_view.get_and_remove(nullptr, get_tuple(42));
ASSERT_TRUE(value2.has_value());
EXPECT_EQ(2, value2->column_count());
EXPECT_EQ(value0.get<int64_t>("key"), value2->get<int64_t>("key"));
EXPECT_EQ(value0.get<std::string>("val"), value2->get<std::string>("val"));
}
TEST_F(transactions_test, record_view_remove_all) {
auto record_view = m_client.get_tables().get_table(TABLE_1)->get_record_binary_view();
auto value0 = get_tuple(42, "Lorem ipsum");
record_view.insert(nullptr, value0);
auto tx = m_client.get_transactions().begin();
auto values1 = record_view.remove_all(&tx, {get_tuple(42)});
ASSERT_TRUE(values1.empty());
tx.rollback();
auto values2 = record_view.remove_all(nullptr, {get_tuple(42)});
ASSERT_TRUE(values2.empty());
}
TEST_F(transactions_test, record_view_remove_all_exact) {
auto record_view = m_client.get_tables().get_table(TABLE_1)->get_record_binary_view();
auto value0 = get_tuple(42, "Lorem ipsum");
record_view.insert(nullptr, value0);
auto tx = m_client.get_transactions().begin();
auto values1 = record_view.remove_all(&tx, {value0});
ASSERT_TRUE(values1.empty());
tx.rollback();
auto values2 = record_view.remove_all(nullptr, {value0});
ASSERT_TRUE(values2.empty());
}
TEST_F(transactions_test, tx_successful_when_timeout_does_not_exceed) {
auto record_view = m_client.get_tables().get_table(TABLE_1)->get_record_binary_view();
int64_t key = 42;
std::string val = "Lorem ipsum";
auto tx_opts = transaction_options().set_timeout_millis(10'000L).set_read_only(false);
auto tx = m_client.get_transactions().begin(tx_opts);
record_view.insert(&tx, get_tuple(key, val));
tx.commit();
auto value = record_view.get(nullptr, get_tuple(42));
ASSERT_TRUE(value.has_value());
EXPECT_EQ(key, value->get<int64_t>(KEY_COLUMN));
EXPECT_EQ(val, value->get<std::string>(VAL_COLUMN));
}
TEST_F(transactions_test, tx_failed_when_timeout_exceeds) {
auto record_view = m_client.get_tables().get_table(TABLE_1)->get_record_binary_view();
auto timeout_ms = 1'000L;
int64_t key = 42;
std::string val = "Lorem ipsum";
auto tx_opts = transaction_options()
.set_timeout_millis(timeout_ms)
.set_read_only(false);
auto tx = m_client.get_transactions().begin(tx_opts);
record_view.insert(&tx, get_tuple(key, val));
std::this_thread::sleep_for(std::chrono::milliseconds{timeout_ms * 2});
EXPECT_THROW(
{
try {
// TODO change to check tx.commit when IGNITE-24233 is implemented
// tx.commit();
auto rec = record_view.get(&tx, get_tuple(key));
} catch (const ignite_error& e) {
EXPECT_EQ(e.get_status_code(), error::code::TX_ALREADY_FINISHED_WITH_TIMEOUT);
throw;
}
},
ignite_error);
}