blob: 9698a65ccb2c023db1829dcc553e9187793ca0ce [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <grpc++/grpc++.h>
#include <grpc/support/log.h>
#include <gtest/gtest.h>
#include <src/lib/fxl/logging.h>
#include "src/virtualization/lib/guest_interaction/server/server_operation_state.h"
#include "test_lib.h"
// Server Get State Machine Test Cases
//
// 1. Requested file does not exist.
// 2. Server fails to open the requested file.
// 3. Requested file is below the fragmentation size.
// 4. Requested file is above the fragmentation size.
// 5. The file the server is reading from goes into a bad state.
TEST_F(AsyncEndToEndTest, ServerMissingFile) {
ResetStub();
// Accounting bits for managing CompletionQueue state.
void* tag;
bool cq_status;
// The server's call to check if the requested file exists will return false.
GetCallData<FakePlatform>* server_call_data =
new GetCallData<FakePlatform>(service_.get(), server_cq_.get());
server_call_data->platform_interface_.SetFileExistsReturn(false);
// Create components required to perform a client Get request.
grpc::ClientContext client_ctx_;
grpc::Status grpc_status;
OperationStatus op_status;
GetResponse get_response;
GetRequest get_request;
get_request.set_source("/some/bogus/path");
std::unique_ptr<grpc::ClientAsyncReader<GetResponse>> reader_ =
stub_->AsyncGet(&client_ctx_, get_request, client_cq_.get(), nullptr);
// Wait for the request to go out, and then request to read from the server.
client_cq_->Next(&tag, &cq_status);
reader_->Read(&get_response, nullptr);
// Server CompletionQueue should get the client request and reply that the
// requested file does not exist.
server_cq_->Next(&tag, &cq_status);
server_call_data->Proceed(cq_status);
// Client should get the server's message and then wait for the server to
// call Finish.
client_cq_->Next(&tag, &cq_status);
op_status = get_response.status();
ASSERT_EQ(op_status, OperationStatus::SERVER_MISSING_FILE_FAILURE);
reader_->Finish(&grpc_status, nullptr);
// Server finishes.
server_cq_->Next(&tag, &cq_status);
server_call_data->Proceed(cq_status);
// Client gets final status from server.
client_cq_->Next(&tag, &cq_status);
ASSERT_TRUE(grpc_status.ok());
}
TEST_F(AsyncEndToEndTest, ServerFileOpenFailure) {
ResetStub();
// Accounting bits for managing CompletionQueue state.
void* tag;
bool cq_status;
// The server's call to check if the requested file exists will return false.
GetCallData<FakePlatform>* server_call_data =
new GetCallData<FakePlatform>(service_.get(), server_cq_.get());
server_call_data->platform_interface_.SetFileExistsReturn(true);
server_call_data->platform_interface_.SetOpenFileReturn(-1);
// Create components required to perform a client Get request.
grpc::ClientContext client_ctx_;
grpc::Status grpc_status;
OperationStatus op_status;
GetResponse get_response;
GetRequest get_request;
get_request.set_source("/file/with/permissions/issues");
std::unique_ptr<grpc::ClientAsyncReader<GetResponse>> reader_ =
stub_->AsyncGet(&client_ctx_, get_request, client_cq_.get(), nullptr);
// Wait for the request to go out, and then request to read from the server.
client_cq_->Next(&tag, &cq_status);
reader_->Read(&get_response, nullptr);
// Server CompletionQueue should get the client request and reply that the
// requested file does not exist.
server_cq_->Next(&tag, &cq_status);
server_call_data->Proceed(cq_status);
// Client should get the server's message and then wait for the server to
// call Finish.
client_cq_->Next(&tag, &cq_status);
op_status = get_response.status();
ASSERT_EQ(op_status, OperationStatus::SERVER_FILE_READ_FAILURE);
reader_->Finish(&grpc_status, nullptr);
// Server finishes.
server_cq_->Next(&tag, &cq_status);
server_call_data->Proceed(cq_status);
// Client gets final status from server.
client_cq_->Next(&tag, &cq_status);
ASSERT_TRUE(grpc_status.ok());
}
TEST_F(AsyncEndToEndTest, ServerUnfragmentedRead) {
ResetStub();
// Accounting bits for managing CompletionQueue state.
void* tag;
bool cq_status;
// The server will be told that the file exists and that it was able to open
// open it. It will be notified that the file is not bad, and EOF will be
// false the first time and then true the second. The call to read from the
// file will return empty.
GetCallData<FakePlatform>* server_call_data =
new GetCallData<FakePlatform>(service_.get(), server_cq_.get());
server_call_data->platform_interface_.SetFileExistsReturn(true);
server_call_data->platform_interface_.SetOpenFileReturn(1);
server_call_data->platform_interface_.SetReadFileContents("test");
// Create components required to perform a client Get request.
grpc::ClientContext client_ctx_;
grpc::Status grpc_status;
OperationStatus op_status;
GetResponse get_response;
GetRequest get_request;
get_request.set_source("/some/test/file");
std::unique_ptr<grpc::ClientAsyncReader<GetResponse>> reader_ =
stub_->AsyncGet(&client_ctx_, get_request, client_cq_.get(), nullptr);
// Wait for the request to go out, and then request to read from the server.
client_cq_->Next(&tag, &cq_status);
reader_->Read(&get_response, nullptr);
// Server CompletionQueue should get the client request, open the file, and
// send back the first chunk of contents.
server_cq_->Next(&tag, &cq_status);
server_call_data->Proceed(cq_status);
// Client should get the server's message and then wait for more data.
client_cq_->Next(&tag, &cq_status);
ASSERT_STREQ(get_response.data().c_str(), "test");
op_status = get_response.status();
reader_->Read(&get_response, nullptr);
// The server should hit EOF and send an empty chunk of data back to the
// client.
server_call_data->platform_interface_.SetReadFileContents("");
server_cq_->Next(&tag, &cq_status);
server_call_data->Proceed(cq_status);
client_cq_->Next(&tag, &cq_status);
op_status = get_response.status();
reader_->Read(&get_response, nullptr);
// The server should then call Finish.
server_cq_->Next(&tag, &cq_status);
server_call_data->Proceed(cq_status);
// The client read should fail and then it should finish.
client_cq_->Next(&tag, &cq_status);
ASSERT_FALSE(cq_status);
reader_->Finish(&grpc_status, nullptr);
// Client gets final status from server.
client_cq_->Next(&tag, &cq_status);
ASSERT_TRUE(grpc_status.ok());
}
TEST_F(AsyncEndToEndTest, ServerFragmentedRead) {
ResetStub();
// Accounting bits for managing CompletionQueue state.
void* tag;
bool cq_status;
// The server will be told that the file exists and that it was able to open
// open it. It will be notified that the file is not bad, and EOF will be
// false the first time and then true the second. The call to read from the
// file will return empty.
GetCallData<FakePlatform>* server_call_data =
new GetCallData<FakePlatform>(service_.get(), server_cq_.get());
server_call_data->platform_interface_.SetFileExistsReturn(true);
server_call_data->platform_interface_.SetOpenFileReturn(1);
server_call_data->platform_interface_.SetReadFileContents("test");
// Create components required to perform a client Get request.
grpc::ClientContext client_ctx_;
grpc::Status grpc_status;
OperationStatus op_status;
GetResponse get_response;
GetRequest get_request;
get_request.set_source("/some/test/file");
std::unique_ptr<grpc::ClientAsyncReader<GetResponse>> reader_ =
stub_->AsyncGet(&client_ctx_, get_request, client_cq_.get(), nullptr);
// Wait for the request to go out, and then request to read from the server.
client_cq_->Next(&tag, &cq_status);
reader_->Read(&get_response, nullptr);
// Server CompletionQueue should get the client request, open the file, and
// send back the first chunk of contents.
server_cq_->Next(&tag, &cq_status);
server_call_data->Proceed(cq_status);
// Client should get the server's message and then wait for more data.
client_cq_->Next(&tag, &cq_status);
ASSERT_EQ(get_response.data(), std::string("test"));
op_status = get_response.status();
reader_->Read(&get_response, nullptr);
// Repeat the process.
server_cq_->Next(&tag, &cq_status);
server_call_data->Proceed(cq_status);
client_cq_->Next(&tag, &cq_status);
ASSERT_EQ(get_response.data(), std::string("test"));
op_status = get_response.status();
reader_->Read(&get_response, nullptr);
// The server should hit EOF and send an empty chunk of data back to the
// client.
server_call_data->platform_interface_.SetReadFileContents("");
server_cq_->Next(&tag, &cq_status);
server_call_data->Proceed(cq_status);
client_cq_->Next(&tag, &cq_status);
op_status = get_response.status();
reader_->Read(&get_response, nullptr);
// The server should then call Finish.
server_cq_->Next(&tag, &cq_status);
server_call_data->Proceed(cq_status);
// The client read should fail and then it should finish.
client_cq_->Next(&tag, &cq_status);
ASSERT_FALSE(cq_status);
reader_->Finish(&grpc_status, nullptr);
// Client gets final status from server.
client_cq_->Next(&tag, &cq_status);
ASSERT_TRUE(grpc_status.ok());
}
TEST_F(AsyncEndToEndTest, ServerBadFile) {
ResetStub();
// Accounting bits for managing CompletionQueue state.
void* tag;
bool cq_status;
// The server will be told that the file exists and that it was able to open
// open it. When the server goes to read from the file, it will be informed
// that the file is bad.
GetCallData<FakePlatform>* server_call_data =
new GetCallData<FakePlatform>(service_.get(), server_cq_.get());
server_call_data->platform_interface_.SetFileExistsReturn(true);
server_call_data->platform_interface_.SetOpenFileReturn(1);
server_call_data->platform_interface_.SetReadFileReturn(-1);
// Create components required to perform a client Get request.
grpc::ClientContext client_ctx_;
grpc::Status grpc_status;
OperationStatus op_status;
GetResponse get_response;
GetRequest get_request;
get_request.set_source("/some/test/file");
std::unique_ptr<grpc::ClientAsyncReader<GetResponse>> reader_ =
stub_->AsyncGet(&client_ctx_, get_request, client_cq_.get(), nullptr);
// Wait for the request to go out and then request to read from the server.
client_cq_->Next(&tag, &cq_status);
reader_->Read(&get_response, nullptr);
// Server CompletionQueue should get the client request, open the file, and
// send back a response indicating the read failed.
server_cq_->Next(&tag, &cq_status);
server_call_data->Proceed(cq_status);
// Client should get the server's message and then wait for more data.
client_cq_->Next(&tag, &cq_status);
op_status = get_response.status();
reader_->Read(&get_response, nullptr);
// The server should finish.
server_cq_->Next(&tag, &cq_status);
server_call_data->Proceed(cq_status);
// The client will get back a bad status and finish.
client_cq_->Next(&tag, &cq_status);
ASSERT_FALSE(cq_status);
op_status = get_response.status();
ASSERT_EQ(op_status, OperationStatus::SERVER_FILE_READ_FAILURE);
reader_->Finish(&grpc_status, nullptr);
// Client gets final status from server.
client_cq_->Next(&tag, &cq_status);
ASSERT_TRUE(grpc_status.ok());
}