polardbxengine/unittest/gunit/xplugin/xpl/expect_noerror_t.cc

524 lines
14 KiB
C++

/* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 2.0,
as published by the Free Software Foundation.
This program is also distributed with certain software (including
but not limited to OpenSSL) that is licensed under separate terms,
as designated in a particular file or component or in included license
documentation. The authors of MySQL hereby grant you an additional
permission to link the program and your derivative works with the
separately licensed software that they have included with MySQL.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License, version 2.0, for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#include <gtest/gtest.h>
#include <sys/types.h>
#include "plugin/x/ngs/include/ngs/error_code.h"
#include "plugin/x/ngs/include/ngs/protocol/protocol_protobuf.h"
#include "plugin/x/src/expect/expect.h"
#include "plugin/x/src/expect/expect_stack.h"
#include "plugin/x/src/xpl_error.h"
static const int EXPECT_NO_ERROR = 1;
namespace xpl {
namespace test {
static ngs::Error_code success;
static ngs::Error_code simulate_instruction(Expectation_stack &xs, int8_t mid,
ngs::Error_code fail) {
ngs::Error_code err = xs.pre_client_stmt(mid);
if (!err) {
// execution would come here
err = fail;
xs.post_client_stmt(mid, fail);
}
return err;
}
static ngs::Error_code simulate_close(Expectation_stack &xs) {
ngs::Error_code err =
xs.pre_client_stmt(Mysqlx::ClientMessages::EXPECT_CLOSE);
if (!err) {
err = xs.close();
xs.post_client_stmt(Mysqlx::ClientMessages::EXPECT_CLOSE, err);
}
return err;
}
static ngs::Error_code simulate_open(Expectation_stack &xs,
const Mysqlx::Expect::Open &open) {
ngs::Error_code err = xs.pre_client_stmt(Mysqlx::ClientMessages::EXPECT_OPEN);
if (!err) {
err = xs.open(open);
xs.post_client_stmt(Mysqlx::ClientMessages::EXPECT_OPEN, err);
}
return err;
}
static Mysqlx::Expect::Open Inherit() {
Mysqlx::Expect::Open open;
open.set_op(Mysqlx::Expect::Open::EXPECT_CTX_COPY_PREV);
return open;
}
static Mysqlx::Expect::Open Noerror() {
Mysqlx::Expect::Open open;
open.set_op(Mysqlx::Expect::Open::EXPECT_CTX_EMPTY);
Mysqlx::Expect::Open::Condition *cond = open.mutable_cond()->Add();
cond->set_condition_key(EXPECT_NO_ERROR);
cond->set_op(Mysqlx::Expect::Open::Condition::EXPECT_OP_SET);
return open;
}
static Mysqlx::Expect::Open Plain() {
Mysqlx::Expect::Open open;
open.set_op(Mysqlx::Expect::Open::EXPECT_CTX_EMPTY);
return open;
}
static Mysqlx::Expect::Open Inherit_and_clear_noerror() {
Mysqlx::Expect::Open open = Inherit();
Mysqlx::Expect::Open::Condition *cond = open.mutable_cond()->Add();
cond->set_condition_key(EXPECT_NO_ERROR);
cond->set_op(Mysqlx::Expect::Open::Condition::EXPECT_OP_UNSET);
return open;
}
static Mysqlx::Expect::Open Inherit_and_add_noerror() {
Mysqlx::Expect::Open open = Inherit();
Mysqlx::Expect::Open::Condition *cond = open.mutable_cond()->Add();
cond->set_condition_key(EXPECT_NO_ERROR);
cond->set_op(Mysqlx::Expect::Open::Condition::EXPECT_OP_SET);
return open;
}
#define EXPECT_ok_cmd() \
ASSERT_EQ(success, simulate_instruction(xs, 1, ngs::Error_code()))
#define EXPECT_error_cmd() \
ASSERT_EQ(ngs::Error_code(1234, "whatever"), \
simulate_instruction(xs, 2, ngs::Error_code(1234, "whatever")))
#define EXPECT_fail(error_code, exp) \
ASSERT_EQ(ngs::Error_code(error_code, "Expectation failed: " exp), \
simulate_instruction(xs, 3, ngs::Error_code()))
#define EXPECT_open_ok(msg) ASSERT_EQ(success, simulate_open(xs, msg))
#define EXPECT_open_fail(msg, error_code, exp) \
ASSERT_EQ(ngs::Error_code(error_code, "Expectation failed: " exp), \
simulate_open(xs, msg))
#define EXPECT_close_ok() ASSERT_EQ(success, simulate_close(xs))
#define EXPECT_close_fail(error_code, exp) \
ASSERT_EQ(ngs::Error_code(error_code, "Expectation failed: " exp), \
simulate_close(xs))
TEST(expect, plain) {
Expectation_stack xs;
// open expect block
EXPECT_open_ok(Plain());
// ok command 1
EXPECT_ok_cmd();
EXPECT_ok_cmd();
// error command 2
EXPECT_error_cmd();
// subsequent cmds succeed normally
EXPECT_ok_cmd();
EXPECT_error_cmd();
// now close the block
EXPECT_close_ok();
EXPECT_ok_cmd();
// close too much should fail
EXPECT_EQ(
ngs::Error_code(ER_X_EXPECT_NOT_OPEN, "Expect block currently not open"),
xs.close());
}
TEST(expect, noerror) {
Expectation_stack xs;
// open expect block
EXPECT_open_ok(Noerror());
// ok command 1
EXPECT_ok_cmd();
// error command 2
EXPECT_error_cmd();
// now everything fails
EXPECT_fail(ER_X_EXPECT_NO_ERROR_FAILED, "no_error");
EXPECT_fail(ER_X_EXPECT_NO_ERROR_FAILED, "no_error");
// now close the block
EXPECT_close_fail(ER_X_EXPECT_NO_ERROR_FAILED, "no_error");
// now commands should succeed again
EXPECT_ok_cmd();
}
TEST(expect, noerror_in_noerror) {
Expectation_stack xs;
// fail in the inner block
EXPECT_open_ok(Noerror());
EXPECT_ok_cmd();
{
EXPECT_open_ok(Noerror());
EXPECT_ok_cmd();
EXPECT_error_cmd();
EXPECT_fail(ER_X_EXPECT_NO_ERROR_FAILED, "no_error");
EXPECT_close_fail(ER_X_EXPECT_NO_ERROR_FAILED, "no_error");
}
EXPECT_fail(ER_X_EXPECT_NO_ERROR_FAILED, "no_error");
EXPECT_close_fail(ER_X_EXPECT_NO_ERROR_FAILED, "no_error");
EXPECT_ok_cmd();
EXPECT_EQ(
ngs::Error_code(ER_X_EXPECT_NOT_OPEN, "Expect block currently not open"),
xs.close());
// fail in the outer block
EXPECT_open_ok(Noerror());
EXPECT_ok_cmd();
EXPECT_error_cmd();
{
EXPECT_open_fail(Noerror(), ER_X_EXPECT_NO_ERROR_FAILED, "no_error");
EXPECT_fail(ER_X_EXPECT_NO_ERROR_FAILED, "no_error");
EXPECT_close_fail(ER_X_EXPECT_NO_ERROR_FAILED, "no_error");
}
EXPECT_fail(ER_X_EXPECT_NO_ERROR_FAILED, "no_error");
EXPECT_close_fail(ER_X_EXPECT_NO_ERROR_FAILED, "no_error");
EXPECT_ok_cmd();
EXPECT_EQ(
ngs::Error_code(ER_X_EXPECT_NOT_OPEN, "Expect block currently not open"),
xs.close());
// fail in inner block again
EXPECT_open_ok(Noerror());
EXPECT_ok_cmd();
{
EXPECT_open_ok(Inherit());
EXPECT_ok_cmd();
EXPECT_error_cmd();
EXPECT_fail(ER_X_EXPECT_NO_ERROR_FAILED, "no_error");
EXPECT_close_fail(ER_X_EXPECT_NO_ERROR_FAILED, "no_error");
}
EXPECT_fail(ER_X_EXPECT_NO_ERROR_FAILED, "no_error");
EXPECT_close_fail(ER_X_EXPECT_NO_ERROR_FAILED, "no_error");
EXPECT_ok_cmd();
}
TEST(expect, plain_in_noerror) {
Expectation_stack xs;
// fail in the inner block
EXPECT_open_ok(Noerror());
EXPECT_ok_cmd();
{
EXPECT_open_ok(Plain());
EXPECT_ok_cmd();
EXPECT_error_cmd();
EXPECT_ok_cmd();
EXPECT_close_ok();
}
EXPECT_close_ok();
EXPECT_ok_cmd();
EXPECT_EQ(
ngs::Error_code(ER_X_EXPECT_NOT_OPEN, "Expect block currently not open"),
xs.close());
// fail in the outer block
EXPECT_open_ok(Noerror());
EXPECT_ok_cmd();
EXPECT_error_cmd();
{
EXPECT_open_fail(Plain(), ER_X_EXPECT_NO_ERROR_FAILED, "no_error");
EXPECT_fail(ER_X_EXPECT_NO_ERROR_FAILED, "no_error");
EXPECT_close_fail(ER_X_EXPECT_NO_ERROR_FAILED, "no_error");
}
EXPECT_fail(ER_X_EXPECT_NO_ERROR_FAILED, "no_error");
EXPECT_close_fail(ER_X_EXPECT_NO_ERROR_FAILED, "no_error");
EXPECT_ok_cmd();
EXPECT_EQ(
ngs::Error_code(ER_X_EXPECT_NOT_OPEN, "Expect block currently not open"),
xs.close());
// fail in inner block again
EXPECT_open_ok(Noerror());
EXPECT_ok_cmd();
{
EXPECT_open_ok(Inherit());
EXPECT_ok_cmd();
EXPECT_error_cmd();
EXPECT_fail(ER_X_EXPECT_NO_ERROR_FAILED, "no_error");
EXPECT_close_fail(ER_X_EXPECT_NO_ERROR_FAILED, "no_error");
}
EXPECT_fail(ER_X_EXPECT_NO_ERROR_FAILED, "no_error");
EXPECT_close_fail(ER_X_EXPECT_NO_ERROR_FAILED, "no_error");
EXPECT_open_ok(Noerror());
EXPECT_ok_cmd();
{
EXPECT_open_ok(Inherit_and_add_noerror());
EXPECT_ok_cmd();
EXPECT_error_cmd();
EXPECT_fail(ER_X_EXPECT_NO_ERROR_FAILED, "no_error");
EXPECT_close_fail(ER_X_EXPECT_NO_ERROR_FAILED, "no_error");
}
EXPECT_fail(ER_X_EXPECT_NO_ERROR_FAILED, "no_error");
EXPECT_close_fail(ER_X_EXPECT_NO_ERROR_FAILED, "no_error");
EXPECT_open_ok(Noerror());
EXPECT_ok_cmd();
{
EXPECT_open_ok(Inherit_and_clear_noerror());
EXPECT_ok_cmd();
EXPECT_error_cmd();
EXPECT_ok_cmd();
EXPECT_close_ok();
}
EXPECT_close_ok();
EXPECT_ok_cmd();
}
TEST(expect, noerror_in_plain) {
Expectation_stack xs;
// fail in the inner block
EXPECT_open_ok(Plain());
EXPECT_ok_cmd();
{
EXPECT_open_ok(Noerror());
EXPECT_ok_cmd();
EXPECT_error_cmd();
EXPECT_fail(ER_X_EXPECT_NO_ERROR_FAILED, "no_error");
EXPECT_close_fail(ER_X_EXPECT_NO_ERROR_FAILED, "no_error");
}
EXPECT_ok_cmd();
EXPECT_close_ok();
EXPECT_ok_cmd();
EXPECT_EQ(
ngs::Error_code(ER_X_EXPECT_NOT_OPEN, "Expect block currently not open"),
xs.close());
// fail in the outer block
EXPECT_open_ok(Plain());
EXPECT_ok_cmd();
EXPECT_error_cmd();
{
EXPECT_open_ok(Noerror());
EXPECT_ok_cmd();
EXPECT_close_ok();
}
EXPECT_ok_cmd();
EXPECT_close_ok();
EXPECT_ok_cmd();
EXPECT_EQ(
ngs::Error_code(ER_X_EXPECT_NOT_OPEN, "Expect block currently not open"),
xs.close());
// fail in inner block again
EXPECT_open_ok(Plain());
EXPECT_ok_cmd();
{
EXPECT_open_ok(Inherit());
EXPECT_ok_cmd();
EXPECT_error_cmd();
EXPECT_ok_cmd();
EXPECT_close_ok();
}
EXPECT_close_ok();
EXPECT_open_ok(Plain());
EXPECT_ok_cmd();
{
EXPECT_open_ok(Inherit_and_add_noerror());
EXPECT_ok_cmd();
EXPECT_error_cmd();
EXPECT_fail(ER_X_EXPECT_NO_ERROR_FAILED, "no_error");
EXPECT_close_fail(ER_X_EXPECT_NO_ERROR_FAILED, "no_error");
}
EXPECT_ok_cmd();
EXPECT_close_ok();
EXPECT_ok_cmd();
}
TEST(expect, nested_inheriting) {
Expectation_stack xs;
EXPECT_open_ok(Noerror());
EXPECT_ok_cmd();
{
EXPECT_open_ok(Inherit_and_add_noerror());
EXPECT_ok_cmd();
EXPECT_error_cmd();
EXPECT_fail(ER_X_EXPECT_NO_ERROR_FAILED, "no_error");
EXPECT_close_fail(ER_X_EXPECT_NO_ERROR_FAILED, "no_error");
}
EXPECT_close_fail(ER_X_EXPECT_NO_ERROR_FAILED, "no_error");
EXPECT_open_ok(Noerror());
EXPECT_ok_cmd();
{
EXPECT_open_ok(Inherit_and_clear_noerror());
EXPECT_ok_cmd();
EXPECT_error_cmd();
EXPECT_ok_cmd();
EXPECT_close_ok();
}
EXPECT_close_ok();
EXPECT_open_ok(Plain());
EXPECT_ok_cmd();
{
EXPECT_open_ok(Inherit_and_add_noerror());
EXPECT_ok_cmd();
EXPECT_error_cmd();
EXPECT_fail(ER_X_EXPECT_NO_ERROR_FAILED, "no_error");
EXPECT_close_fail(ER_X_EXPECT_NO_ERROR_FAILED, "no_error");
}
EXPECT_close_ok();
EXPECT_open_ok(Plain());
EXPECT_ok_cmd();
{
EXPECT_open_ok(Inherit_and_clear_noerror());
EXPECT_ok_cmd();
EXPECT_error_cmd();
EXPECT_ok_cmd();
EXPECT_close_ok();
}
EXPECT_close_ok();
}
TEST(expect, invalid) {
{
Expectation exp;
EXPECT_EQ(
ngs::Error_code(ER_X_EXPECT_BAD_CONDITION, "Unknown condition key"),
exp.set(1234, "1"));
}
{
Expectation exp;
EXPECT_EQ(ngs::Error_code(), exp.set(1, ""));
EXPECT_EQ(true, exp.fail_on_error());
EXPECT_EQ(ngs::Error_code(), exp.set(1, "1"));
EXPECT_EQ(true, exp.fail_on_error());
EXPECT_EQ(ngs::Error_code(), exp.set(1, "0"));
EXPECT_FALSE(exp.fail_on_error());
EXPECT_EQ(ngs::Error_code(ER_X_EXPECT_BAD_CONDITION_VALUE,
"Invalid value 'bla' for expectation no_error"),
exp.set(1, "bla"));
EXPECT_FALSE(exp.fail_on_error());
}
}
class Expect_surprise : public Expect_condition {
public:
Expect_surprise(const uint32_t k, const std::string &v)
: Expect_condition(k, ""), m_surprise_value(v) {}
Expect_condition_ptr clone() override {
return Expect_condition_ptr{new Expect_surprise(key(), m_surprise_value)};
}
ngs::Error_code check_if_error() override {
const std::string valid_value = "true";
if (m_surprise_value == valid_value) return {};
return ngs::Error_code(ER_X_EXPECT_NO_ERROR_FAILED, "");
}
void set(const std::string &flag) { m_surprise_value = flag; }
const std::string &value() override { return m_surprise_value; }
private:
std::string m_surprise_value;
};
TEST(expect, condition) {
Expectation expect;
Expect_surprise *surp = new Expect_surprise(1234, "false");
ASSERT_FALSE(expect.check_conditions());
expect.add_condition(std::unique_ptr<Expect_condition>{surp});
ASSERT_TRUE(expect.check_conditions());
surp->set("true");
ASSERT_FALSE(expect.check_conditions());
surp->set("false");
{
Expectation copy(expect);
ASSERT_TRUE(expect.check_conditions());
ASSERT_TRUE(copy.check_conditions());
expect.unset(1234, "");
ASSERT_FALSE(expect.check_conditions());
ASSERT_TRUE(copy.check_conditions());
}
}
TEST(expect, condition_unset) {
const uint32_t expect_key = 1234u;
Expectation expect;
Expect_surprise *surp[4];
ASSERT_FALSE(expect.check_conditions());
for (int i = 0; i < 4; ++i) {
surp[i] = new Expect_surprise(expect_key, "true");
expect.add_condition(std::unique_ptr<Expect_condition>{surp[i]});
}
ASSERT_FALSE(expect.check_conditions());
surp[0]->set("false");
ASSERT_TRUE(expect.check_conditions());
const auto cond_value = surp[0]->value();
expect.unset(surp[0]->key(), cond_value);
ASSERT_FALSE(expect.check_conditions());
surp[1]->set("false");
ASSERT_TRUE(expect.check_conditions());
expect.unset(expect_key, "");
ASSERT_FALSE(expect.check_conditions());
}
} // namespace test
} // namespace xpl