blob: b5e806f7e7821884c795ca067af9002f60302692 [file] [log] [blame]
// Copyright 2018 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 "src/bin/test_app/test_app.h"
#include <map>
#include <memory>
#include <string>
#include <vector>
#include <google/protobuf/text_format.h>
#include <gtest/gtest.h>
#include "gflags/gflags.h"
#include "src/bin/test_app/test_registry/test_registry.cb.h"
#include "src/logger/logger_test_utils.h"
#include "src/logger/project_context.h"
#include "src/logger/project_context_factory.h"
#include "src/logging.h"
#include "third_party/abseil-cpp/absl/strings/escaping.h"
namespace cobalt {
using logger::LoggerInterface;
using logger::ProjectContext;
using logger::ProjectContextFactory;
using logger::testing::FakeObservationStore;
DECLARE_uint32(num_clients);
DECLARE_string(values);
namespace {
constexpr char kErrorOccurredMetricName[] = "ErrorOccurred";
// The number of locally aggregated Observations that should be generated for
// each day. Since Observation generation is faked here, this number does not
// need to correspond to a test Metric registry. It just needs to be a positive
// number.
constexpr int kNumAggregatedObservations = 20;
bool PopulateCobaltRegistry(CobaltRegistry* cobalt_registry) {
std::string proto;
if (!absl::Base64Unescape(test_app::testing::kConfig, &proto)) {
return false;
}
return cobalt_registry->ParseFromString(proto);
}
class TestLoggerFactory : public LoggerFactory {
public:
explicit TestLoggerFactory(const ProjectContext* project_context);
std::unique_ptr<LoggerInterface> NewLogger(uint32_t day_index) override;
const ProjectContext* project_context() override;
size_t ObservationCount() override;
void ResetObservationCount() override;
void ResetLocalAggregation() override;
bool GenerateAggregatedObservations(uint32_t day_index) override;
bool SendAccumulatedObservations() override;
private:
const ProjectContext* project_context_;
std::unique_ptr<FakeObservationStore> observation_store_;
uint32_t last_obs_generation_ = 0;
};
TestLoggerFactory::TestLoggerFactory(const ProjectContext* project_context)
: project_context_(project_context),
observation_store_(new FakeObservationStore) {}
std::unique_ptr<LoggerInterface> TestLoggerFactory::NewLogger(uint32_t /*day_index*/) {
return nullptr;
}
size_t TestLoggerFactory::ObservationCount() {
return observation_store_->num_observations_added();
}
void TestLoggerFactory::ResetObservationCount() {
return observation_store_->ResetObservationCounter();
}
void TestLoggerFactory::ResetLocalAggregation() { last_obs_generation_ = 0; }
bool TestLoggerFactory::GenerateAggregatedObservations(uint32_t day_index) {
if (day_index > last_obs_generation_) {
for (int i = 0; i < kNumAggregatedObservations; i++) {
if (!observation_store_
->StoreObservation(std::make_unique<EncryptedMessage>(),
std::make_unique<ObservationMetadata>(), false)
.ok()) {
return false;
}
}
last_obs_generation_ = day_index;
}
return true;
}
bool TestLoggerFactory::SendAccumulatedObservations() { return true; }
const ProjectContext* TestLoggerFactory::project_context() { return project_context_; }
} // namespace
// Tests of the TestApp class.
class TestAppTest : public ::testing::Test {
public:
void SetUp() override {
auto cobalt_registry = std::make_unique<CobaltRegistry>();
ASSERT_TRUE(PopulateCobaltRegistry(cobalt_registry.get()));
ProjectContextFactory project_context_factory(std::move(cobalt_registry));
ASSERT_TRUE(project_context_factory.is_single_project());
project_context_ = project_context_factory.TakeSingleProjectContext();
test_app_ =
std::make_unique<TestApp>(std::make_unique<TestLoggerFactory>(project_context_.get()),
kErrorOccurredMetricName, TestApp::kInteractive, &output_stream_);
}
protected:
// Clears the contents of the TestApp's output stream and returns the
// contents prior to clearing.
std::string ClearOutput() {
std::string s = output_stream_.str();
output_stream_.str("");
return s;
}
// Does the current contents of the TestApp's output stream contain the
// given text.
bool OutputContains(const std::string& text) {
return std::string::npos != output_stream_.str().find(text);
}
// Is the TestApp's output stream curently empty?
bool NoOutput() { return output_stream_.str().empty(); }
std::unique_ptr<ProjectContext> project_context_;
// The output stream that the TestApp has been given.
std::ostringstream output_stream_;
// The TestApp under test.
std::unique_ptr<TestApp> test_app_;
};
//////////////////////////////////////
// Tests of interactive mode.
/////////////////////////////////////
// Tests ParseInt utility function.
TEST_F(TestAppTest, ParseInt) {
int64_t x;
// Test basic valid inputs.
EXPECT_TRUE(test_app_->ParseInt("1", true, &x));
EXPECT_EQ(x, 1);
EXPECT_TRUE(test_app_->ParseInt("-3", true, &x));
EXPECT_EQ(x, -3);
EXPECT_TRUE(test_app_->ParseInt("503", true, &x));
EXPECT_EQ(x, 503);
EXPECT_TRUE(test_app_->ParseInt("1534", true, &x));
EXPECT_EQ(x, 1534);
ClearOutput();
// Input should only contain one number.
EXPECT_FALSE(test_app_->ParseInt("1 2", true, &x));
EXPECT_TRUE(OutputContains("Expected positive integer instead of 1 2"));
ClearOutput();
// Input shouldn't contain non-numeric characters or floats.
EXPECT_FALSE(test_app_->ParseInt("1.5asdf", true, &x));
EXPECT_TRUE(OutputContains("Expected positive integer instead of 1.5asdf"));
ClearOutput();
EXPECT_FALSE(test_app_->ParseInt("$10#%", true, &x));
EXPECT_TRUE(OutputContains("Expected positive integer instead of $10#%"));
ClearOutput();
EXPECT_FALSE(test_app_->ParseInt("10.0", true, &x));
EXPECT_TRUE(OutputContains("Expected positive integer instead of 10.0"));
ClearOutput();
}
// Tests ParseNonNegativeInt utility function.
TEST_F(TestAppTest, ParseNonNegativeInt) {
int64_t x;
// Test basic valid inputs.
EXPECT_TRUE(test_app_->ParseNonNegativeInt("1", true, &x));
EXPECT_EQ(x, 1);
EXPECT_TRUE(test_app_->ParseNonNegativeInt("503", true, &x));
EXPECT_EQ(x, 503);
EXPECT_TRUE(test_app_->ParseNonNegativeInt("1534", true, &x));
EXPECT_EQ(x, 1534);
EXPECT_TRUE(test_app_->ParseNonNegativeInt("0", true, &x));
EXPECT_EQ(x, 0);
ClearOutput();
// Negative numbers should return an error.
EXPECT_FALSE(test_app_->ParseNonNegativeInt("-3", true, &x));
EXPECT_TRUE(OutputContains("Expected non-negative integer instead of -3"));
ClearOutput();
// Input should only contain one number.
EXPECT_FALSE(test_app_->ParseNonNegativeInt("1 2", true, &x));
EXPECT_TRUE(OutputContains("Expected non-negative integer instead of 1 2"));
ClearOutput();
// Input shouldn't contain non-numeric characters or floats.
EXPECT_FALSE(test_app_->ParseNonNegativeInt("1.5asdf", true, &x));
EXPECT_TRUE(OutputContains("Expected non-negative integer instead of 1.5asdf"));
ClearOutput();
EXPECT_FALSE(test_app_->ParseNonNegativeInt("$10#%", true, &x));
EXPECT_TRUE(OutputContains("Expected non-negative integer instead of $10#%"));
ClearOutput();
EXPECT_FALSE(test_app_->ParseNonNegativeInt("10.0", true, &x));
EXPECT_TRUE(OutputContains("Expected non-negative integer instead of 10.0"));
ClearOutput();
}
// Tests ParseFloat utility function.
TEST_F(TestAppTest, ParseFloat) {
float f;
// Test basic valid inputs.
EXPECT_TRUE(test_app_->ParseFloat("1.5", true, &f));
EXPECT_EQ(f, static_cast<float>(1.5));
EXPECT_TRUE(test_app_->ParseFloat("-2.3", true, &f));
EXPECT_EQ(f, static_cast<float>(-2.3));
EXPECT_TRUE(test_app_->ParseFloat("503.9", true, &f));
EXPECT_EQ(f, static_cast<float>(503.9));
EXPECT_TRUE(test_app_->ParseFloat("1534.0", true, &f));
EXPECT_EQ(f, static_cast<float>(1534.0));
EXPECT_TRUE(test_app_->ParseFloat("0", true, &f));
EXPECT_EQ(f, static_cast<float>(0));
EXPECT_TRUE(test_app_->ParseFloat("100", true, &f));
EXPECT_EQ(f, static_cast<float>(100));
ClearOutput();
// Input should only contain one number.
EXPECT_FALSE(test_app_->ParseFloat("1.5 2.0", true, &f));
EXPECT_TRUE(OutputContains("Expected float instead of 1.5 2.0"));
ClearOutput();
// Input shouldn't contain non-numeric characters.
EXPECT_FALSE(test_app_->ParseFloat("1.5asdf", true, &f));
EXPECT_TRUE(OutputContains("Expected float instead of 1.5asdf"));
ClearOutput();
EXPECT_FALSE(test_app_->ParseFloat("$10#%", true, &f));
EXPECT_TRUE(OutputContains("Expected float instead of $10#%"));
ClearOutput();
}
// Tests ParseIndex utility function.
TEST_F(TestAppTest, ParseIndex) {
uint32_t x;
// Test basic valid inputs.
EXPECT_TRUE(test_app_->ParseIndex("index=1", &x));
EXPECT_EQ(x, (uint32_t)1);
EXPECT_TRUE(test_app_->ParseIndex("index=503", &x));
EXPECT_EQ(x, (uint32_t)503);
EXPECT_TRUE(test_app_->ParseIndex("index=1534", &x));
EXPECT_EQ(x, (uint32_t)1534);
ClearOutput();
// Input should contain 'index='.
EXPECT_FALSE(test_app_->ParseIndex("1", &x));
ClearOutput();
// Input should only contain one element.
EXPECT_FALSE(test_app_->ParseIndex("index=1 2", &x));
EXPECT_TRUE(OutputContains("Expected small non-negative integer instead of 1 2"));
ClearOutput();
// Input shouldn't contain non-numeric characters or floats.
EXPECT_FALSE(test_app_->ParseIndex("index=1.5asdf", &x));
EXPECT_TRUE(OutputContains("Expected small non-negative integer instead of 1.5asdf"));
ClearOutput();
EXPECT_FALSE(test_app_->ParseIndex("index=$10#%", &x));
EXPECT_TRUE(OutputContains("Expected small non-negative integer instead of $10#%"));
ClearOutput();
EXPECT_FALSE(test_app_->ParseIndex("index=10.0", &x));
EXPECT_TRUE(OutputContains("Expected small non-negative integer instead of 10.0"));
ClearOutput();
}
// Tests ParseDay utility function.
TEST_F(TestAppTest, ParseDay) {
uint32_t d;
uint32_t today = test_app_->CurrentDayIndex();
// Test basic valid inputs.
EXPECT_TRUE(test_app_->ParseDay("day=42", &d));
EXPECT_EQ(d, (uint32_t)42);
EXPECT_TRUE(test_app_->ParseDay("day=today", &d));
EXPECT_EQ(d, today);
EXPECT_TRUE(test_app_->ParseDay("day=today-1", &d));
EXPECT_EQ(d, today - 1);
EXPECT_TRUE(test_app_->ParseDay("day=today+1", &d));
EXPECT_EQ(d, today + 1);
ClearOutput();
// Input should start with 'day='.
EXPECT_FALSE(test_app_->ParseDay("1", &d));
EXPECT_TRUE(OutputContains("Expected prefix 'day='."));
ClearOutput();
// Input should contain only one element.
EXPECT_FALSE(test_app_->ParseDay("day=1 2", &d));
EXPECT_FALSE(test_app_->ParseDay("day=today 2", &d));
ClearOutput();
// Input shouldn't contain non-numerical characters other than prefixes
// "day=", "day=today", "day=today+", or "day=today-"
EXPECT_FALSE(test_app_->ParseDay("day=yesterday", &d));
EXPECT_TRUE(OutputContains("Expected small non-negative integer instead of yesterday."));
ClearOutput();
EXPECT_FALSE(test_app_->ParseDay("day=today+two", &d));
EXPECT_TRUE(OutputContains("Expected non-negative integer instead of two."));
ClearOutput();
// Disallow input of the form "day=today-N" with N greater than today's day
// index.
EXPECT_FALSE(test_app_->ParseDay("day=today-20000000000", &d));
EXPECT_TRUE(OutputContains("Negative offset cannot be larger than the current day index."));
ClearOutput();
}
// Tests processing a bad command line.
TEST_F(TestAppTest, ProcessCommandLineBad) {
EXPECT_TRUE(test_app_->ProcessCommandLine("this is not a command"));
EXPECT_TRUE(OutputContains("Unrecognized command: this"));
}
// Tests processing the "help" command
TEST_F(TestAppTest, ProcessCommandLineHelp) {
EXPECT_TRUE(test_app_->ProcessCommandLine("help"));
// We don't want to test the actual output too rigorously because that would
// be a very fragile test. Just doing a sanity test.
EXPECT_TRUE(OutputContains("Print this help message."));
}
// Tests processing a bad set command line.
TEST_F(TestAppTest, ProcessCommandLineSetBad) {
EXPECT_TRUE(test_app_->ProcessCommandLine("set"));
EXPECT_TRUE(OutputContains("Malformed set command."));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("set a b c"));
EXPECT_TRUE(OutputContains("Malformed set command."));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("set a b"));
EXPECT_TRUE(OutputContains("a is not a settable parameter"));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("set metric b"));
EXPECT_TRUE(OutputContains("There is no metric named 'b'"));
EXPECT_TRUE(OutputContains("Current metric unchanged."));
ClearOutput();
}
// Tests processing the set and ls commands
TEST_F(TestAppTest, ProcessCommandLineSetAndLs) {
EXPECT_TRUE(test_app_->ProcessCommandLine("ls"));
EXPECT_TRUE(OutputContains("Metric: 'ErrorOccurred'"));
EXPECT_TRUE(OutputContains("Customer: 1"));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("set metric CacheMiss"));
EXPECT_TRUE(OutputContains("Metric set."));
EXPECT_TRUE(test_app_->ProcessCommandLine("ls"));
EXPECT_TRUE(OutputContains("Metric: 'CacheMiss'"));
EXPECT_TRUE(OutputContains("Customer: 1"));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("set metric update_duration"));
EXPECT_TRUE(OutputContains("Metric set."));
EXPECT_TRUE(test_app_->ProcessCommandLine("ls"));
EXPECT_TRUE(OutputContains("Metric: 'update_duration'"));
EXPECT_TRUE(OutputContains("Customer: 1"));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("set metric game_frame_rate"));
EXPECT_TRUE(OutputContains("Metric set."));
EXPECT_TRUE(test_app_->ProcessCommandLine("ls"));
EXPECT_TRUE(OutputContains("Metric: 'game_frame_rate'"));
EXPECT_TRUE(OutputContains("Customer: 1"));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("set metric application_memory"));
EXPECT_TRUE(OutputContains("Metric set."));
EXPECT_TRUE(test_app_->ProcessCommandLine("ls"));
EXPECT_TRUE(OutputContains("Metric: 'application_memory'"));
EXPECT_TRUE(OutputContains("Customer: 1"));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("set metric power_usage"));
EXPECT_TRUE(OutputContains("Metric set."));
EXPECT_TRUE(test_app_->ProcessCommandLine("ls"));
EXPECT_TRUE(OutputContains("Metric: 'power_usage'"));
EXPECT_TRUE(OutputContains("Customer: 1"));
ClearOutput();
}
// Tests processing a bad show command line.
TEST_F(TestAppTest, ProcessCommandLineShowBad) {
EXPECT_TRUE(test_app_->ProcessCommandLine("show"));
EXPECT_TRUE(OutputContains("Expected 'show config'."));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("show confi"));
EXPECT_TRUE(OutputContains("Expected 'show config'."));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("show config foo"));
EXPECT_TRUE(OutputContains("Expected 'show config'."));
ClearOutput();
}
// Tests processing the set and show config commands
TEST_F(TestAppTest, ProcessCommandLineSetAndShowConfig) {
EXPECT_TRUE(test_app_->ProcessCommandLine("show config"));
EXPECT_TRUE(OutputContains("metric_name: \"ErrorOccurred\""));
EXPECT_TRUE(OutputContains("metric_type: EVENT_OCCURRED"));
EXPECT_TRUE(OutputContains("report_name: \"ErrorCountsByType\""));
EXPECT_TRUE(OutputContains("report_type: SIMPLE_OCCURRENCE_COUNT"));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("set metric CacheMiss"));
EXPECT_TRUE(OutputContains("Metric set."));
EXPECT_TRUE(test_app_->ProcessCommandLine("show config"));
EXPECT_TRUE(OutputContains("metric_name: \"CacheMiss\""));
EXPECT_TRUE(OutputContains("metric_type: EVENT_COUNT"));
EXPECT_TRUE(OutputContains("report_name: \"CacheMissCounts\""));
EXPECT_TRUE(OutputContains("report_type: EVENT_COMPONENT_OCCURRENCE_COUNT"));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("set metric update_duration"));
EXPECT_TRUE(OutputContains("Metric set."));
EXPECT_TRUE(test_app_->ProcessCommandLine("show config"));
EXPECT_TRUE(OutputContains("metric_name: \"update_duration\""));
EXPECT_TRUE(OutputContains("metric_type: ELAPSED_TIME"));
EXPECT_TRUE(OutputContains("report_name: \"update_duration_report\""));
EXPECT_TRUE(OutputContains("report_type: INT_RANGE_HISTOGRAM"));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("set metric game_frame_rate"));
EXPECT_TRUE(OutputContains("Metric set."));
EXPECT_TRUE(test_app_->ProcessCommandLine("show config"));
EXPECT_TRUE(OutputContains("metric_name: \"game_frame_rate\""));
EXPECT_TRUE(OutputContains("metric_type: FRAME_RATE"));
EXPECT_TRUE(OutputContains("report_name: \"game_frame_rate_histograms\""));
EXPECT_TRUE(OutputContains("report_type: INT_RANGE_HISTOGRAM"));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("set metric application_memory"));
EXPECT_TRUE(OutputContains("Metric set."));
EXPECT_TRUE(test_app_->ProcessCommandLine("show config"));
EXPECT_TRUE(OutputContains("metric_name: \"application_memory\""));
EXPECT_TRUE(OutputContains("metric_type: MEMORY_USAGE"));
EXPECT_TRUE(OutputContains("report_name: \"application_memory_histograms\""));
EXPECT_TRUE(OutputContains("report_type: INT_RANGE_HISTOGRAM"));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("set metric power_usage"));
EXPECT_TRUE(OutputContains("Metric set."));
EXPECT_TRUE(test_app_->ProcessCommandLine("show config"));
EXPECT_TRUE(OutputContains("metric_name: \"power_usage\""));
EXPECT_TRUE(OutputContains("metric_type: INT_HISTOGRAM"));
EXPECT_TRUE(OutputContains("report_name: \"power_usage_histograms\""));
EXPECT_TRUE(OutputContains("report_type: INT_RANGE_HISTOGRAM"));
ClearOutput();
}
// Tests processing a bad log command line.
TEST_F(TestAppTest, ProcessCommandLineEncodeBad) {
EXPECT_TRUE(test_app_->ProcessCommandLine("log"));
EXPECT_TRUE(OutputContains("Malformed log command."));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("log foo"));
EXPECT_TRUE(OutputContains("Expected non-negative integer instead of foo."));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("log -1"));
EXPECT_TRUE(OutputContains("Expected non-negative integer instead of -1."));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("log 0"));
EXPECT_TRUE(OutputContains("Malformed log command. <num> must be positive: 0"));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("log 3.14 bar"));
EXPECT_TRUE(OutputContains("Expected non-negative integer instead of 3.14."));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("log 100"));
EXPECT_TRUE(
OutputContains("Malformed log command. Expected log method to be specified "
"after <num>."));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("log 100 foo"));
EXPECT_TRUE(OutputContains("Unrecognized log method specified: foo"));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("log 100 event"));
EXPECT_TRUE(
OutputContains("Malformed log event command. Expected one more "
"argument for <event_code>."));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("log 100 event foo bar baz"));
EXPECT_TRUE(OutputContains("Malformed log event command: too many arguments."));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("log 100 event_count"));
EXPECT_TRUE(
OutputContains("Malformed log event_count command: missing at least one "
"required argument."));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("log 100 event_count foo bar baz two three four"));
EXPECT_TRUE(OutputContains("Malformed log event_count command: too many arguments."));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("log 100 event foo"));
EXPECT_TRUE(OutputContains("Expected non-negative integer instead of foo."));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("set metric update_duration"));
EXPECT_TRUE(OutputContains("Metric set."));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("log 100 elapsed_time foo bar"));
EXPECT_TRUE(
OutputContains("Malformed log elapsed_time command. Expected 3 "
"additional parameters."));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("set metric game_frame_rate"));
EXPECT_TRUE(OutputContains("Metric set."));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("log 100 frame_rate foo bar"));
EXPECT_TRUE(
OutputContains("Malformed log frame_rate command. Expected 3 "
"additional parameters."));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("set metric application_memory"));
EXPECT_TRUE(OutputContains("Metric set."));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("log 100 memory_usage foo bar"));
EXPECT_TRUE(
OutputContains("Malformed log memory_usage command. Expected 3 "
"additional parameters."));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("set metric power_usage"));
EXPECT_TRUE(OutputContains("Metric set."));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("log 100 int_histogram foo bar"));
EXPECT_TRUE(
OutputContains("Malformed log int_histogram command. Expected 4 "
"additional parameters."));
}
// Tests processing of valid generate command lines.
TEST_F(TestAppTest, ProcessCommandLineGenerate) {
EXPECT_TRUE(test_app_->ProcessCommandLine("generate"));
EXPECT_TRUE(OutputContains("Generated"));
EXPECT_TRUE(OutputContains("locally aggregated observations for day index"));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("generate day=today"));
EXPECT_TRUE(OutputContains("Generated"));
EXPECT_TRUE(OutputContains("locally aggregated observations for day index"));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("generate day=today-5"));
EXPECT_TRUE(OutputContains("Generated"));
EXPECT_TRUE(OutputContains("locally aggregated observations for day index"));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("generate day=today+5"));
EXPECT_TRUE(OutputContains("Generated"));
EXPECT_TRUE(OutputContains("locally aggregated observations for day index"));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("generate day=150000"));
EXPECT_TRUE(OutputContains("Generated"));
EXPECT_TRUE(OutputContains("locally aggregated observations for day index 150000"));
ClearOutput();
}
// Tests processing a bad generate command line.
TEST_F(TestAppTest, ProcessCommandLineGenerateBad) {
// generate takes at most 1 argument.
EXPECT_TRUE(test_app_->ProcessCommandLine("generate foo bar"));
EXPECT_TRUE(OutputContains("Malformed generate command: too many arguments."));
ClearOutput();
}
// Tests processing of a valid reset-aggregation command line.
TEST_F(TestAppTest, ProcessCommandLineResetAggregation) {
EXPECT_TRUE(test_app_->ProcessCommandLine("reset-aggregation"));
EXPECT_TRUE(OutputContains("Reset local aggregation."));
ClearOutput();
}
// Tests processing a bad send command line.
TEST_F(TestAppTest, ProcessCommandLineSendBad) {
EXPECT_TRUE(test_app_->ProcessCommandLine("send foo"));
EXPECT_TRUE(OutputContains("The send command doesn't take any arguments."));
}
// Tests some minimal behavior related to local aggregation:
// (1) The response to a valid generate command should include the number of
// generated observations and the day index
// (2) generate should not produce observations twice for a given day index
// unless reset-aggregation is run before the second attempt
TEST_F(TestAppTest, GenerateAndReset) {
EXPECT_TRUE(test_app_->ProcessCommandLine("generate day=15000"));
std::ostringstream stream;
stream << "Generated " << kNumAggregatedObservations
<< " locally aggregated observations for day index 15000";
EXPECT_TRUE(OutputContains(stream.str()));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("generate day=15000"));
EXPECT_TRUE(OutputContains("Generated 0 locally aggregated observations for day index 15000"));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("generate day=14999"));
EXPECT_TRUE(OutputContains("Generated 0 locally aggregated observations for day index 14999"));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("reset-aggregation"));
EXPECT_TRUE(OutputContains("Reset local aggregation."));
ClearOutput();
EXPECT_TRUE(test_app_->ProcessCommandLine("generate day=15000"));
EXPECT_TRUE(OutputContains(stream.str()));
ClearOutput();
}
} // namespace cobalt