blob: 72f2107eb5d1ee5d829aba517311726657dc9d31 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors
//
// Licensed 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.
#import "tools/observation_querier/observation_querier.h"
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "analyzer/store/memory_store.h"
#include "analyzer/store/observation_store.h"
#include "gflags/gflags.h"
#include "glog/logging.h"
#include "third_party/googletest/googletest/include/gtest/gtest.h"
namespace cobalt {
using analyzer::store::DataStore;
using analyzer::store::MemoryStore;
using analyzer::store::ObservationStore;
namespace {
const uint32_t kCustomerId = 1;
const uint32_t kProjectId = 2;
const uint32_t kDayIndex = 3;
} // namespace
// Tests of ObservationQuerier.
class ObservationQuerierTest : public ::testing::Test {
public:
ObservationQuerierTest()
: data_store_(new MemoryStore()),
observation_store_(new ObservationStore(data_store_)),
querier_(kCustomerId, kProjectId, observation_store_, &output_stream_) {
}
protected:
// Clears the contents of the ObservationQuerier'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 ObservationQuerier's output stream contain
// the given text.
bool OutputContains(const std::string text) {
return std::string::npos != output_stream_.str().find(text);
}
// Is the ObservationQuerier's output stream curently empty?
bool NoOutput() { return output_stream_.str().empty(); }
// Writes an observation for the given |metric_id| into the ObservationStore.
// There will be |num_parts| parts named part0, part1, etc. Each part will
// have the same value given by |data|. If |forculus| is true all the
// parts will be Forculus observations otherwise all the parts will be
// Basic RAPPOR observations.
void WriteObservation(uint32_t metric_id, bool forculus, int num_parts,
std::string data) {
ObservationMetadata metadata;
metadata.set_customer_id(kCustomerId);
metadata.set_project_id(kProjectId);
metadata.set_metric_id(metric_id);
metadata.set_day_index(kDayIndex);
std::vector<Observation> observations;
observations.emplace_back();
Observation& observation = observations.back();
for (int i = 0; i < num_parts; i++) {
std::ostringstream stream;
stream << "part" << i;
std::string part_name = stream.str();
ObservationPart& part = (*observation.mutable_parts())[part_name];
if (forculus) {
part.mutable_forculus()->set_ciphertext(data);
} else {
part.mutable_basic_rappor()->set_data(data);
}
}
EXPECT_EQ(analyzer::store::kOK,
observation_store_->AddObservationBatch(metadata, observations));
}
// The output stream that the ObservationQuerier has been given.
std::ostringstream output_stream_;
std::shared_ptr<DataStore> data_store_;
std::shared_ptr<ObservationStore> observation_store_;
// The ObservationQuerier under test.
ObservationQuerier querier_;
};
// Tests processing a bad command line.
TEST_F(ObservationQuerierTest, ProcessCommandLineBad) {
EXPECT_TRUE(querier_.ProcessCommandLine("this is not a command"));
EXPECT_TRUE(OutputContains("Unrecognized command: this"));
}
// Tests processing the "help" command
TEST_F(ObservationQuerierTest, ProcessCommandLineHelp) {
EXPECT_TRUE(querier_.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."));
EXPECT_TRUE(OutputContains("Query up to <max_num> observations."));
}
// Tests processing a bad set command line.
TEST_F(ObservationQuerierTest, ProcessCommandLineSetBad) {
EXPECT_TRUE(querier_.ProcessCommandLine("set"));
EXPECT_TRUE(OutputContains("Malformed set command."));
ClearOutput();
EXPECT_TRUE(querier_.ProcessCommandLine("set a b c"));
EXPECT_TRUE(OutputContains("Malformed set command."));
ClearOutput();
EXPECT_TRUE(querier_.ProcessCommandLine("set a b"));
EXPECT_TRUE(OutputContains("a is not a settable parameter"));
ClearOutput();
EXPECT_TRUE(querier_.ProcessCommandLine("set metric b"));
EXPECT_TRUE(OutputContains("Expected positive integer instead of b."));
ClearOutput();
ClearOutput();
}
// Tests processing the set and ls commands
TEST_F(ObservationQuerierTest, ProcessCommandLineSetAndLs) {
EXPECT_TRUE(querier_.ProcessCommandLine("ls"));
EXPECT_TRUE(OutputContains("Metric ID: 1"));
ClearOutput();
EXPECT_TRUE(querier_.ProcessCommandLine("set metric 2"));
EXPECT_TRUE(NoOutput());
EXPECT_TRUE(querier_.ProcessCommandLine("ls"));
EXPECT_TRUE(OutputContains("Metric ID: 2"));
}
// Tests processing a bad query command
TEST_F(ObservationQuerierTest, ProcessCommandLineQueryBad) {
EXPECT_TRUE(querier_.ProcessCommandLine("query"));
EXPECT_TRUE(
OutputContains("Malformed query command. Expected query <max_num>"));
ClearOutput();
EXPECT_TRUE(querier_.ProcessCommandLine("query a b"));
EXPECT_TRUE(
OutputContains("Malformed query command. Expected query <max_num>"));
ClearOutput();
EXPECT_TRUE(querier_.ProcessCommandLine("query a"));
EXPECT_TRUE(OutputContains("Expected positive integer instead of a."));
ClearOutput();
}
// Tests processing the query command
TEST_F(ObservationQuerierTest, ProcessCommandLineQuery) {
// Query when there are no observations.
EXPECT_TRUE(querier_.ProcessCommandLine("query 3"));
EXPECT_TRUE(NoOutput());
// Add 3 Forculus observations for metric 1.
uint32_t metric_id = 1;
bool forculus = true;
WriteObservation(metric_id, forculus, 1, "hello");
WriteObservation(metric_id, forculus, 1, "goodbye");
WriteObservation(metric_id, forculus, 1, "peace");
// Add 2 basic RAPPOR observations for metric 2.
metric_id = 2;
forculus = false;
WriteObservation(metric_id, forculus, 1, "A");
WriteObservation(metric_id, forculus, 1, "B");
// Query 3 observations from metric 1.
EXPECT_TRUE(querier_.ProcessCommandLine("query 3"));
EXPECT_TRUE(
OutputContains("part0:forculus:ciphertext:aGVsbG8=::point_x:"));
EXPECT_TRUE(
OutputContains("part0:forculus:ciphertext:Z29vZGJ5ZQ==::point_x:"));
EXPECT_TRUE(
OutputContains("part0:forculus:ciphertext:cGVhY2U=::point_x:"));
ClearOutput();
// Query 3 observations from metric 2.
querier_.ProcessCommandLine("set metric 2");
EXPECT_TRUE(querier_.ProcessCommandLine("query 3"));
EXPECT_TRUE(
OutputContains("part0:basic_rappor:01000010"));
EXPECT_TRUE(
OutputContains("part0:basic_rappor:01000001"));
}
// Tests processing the "quit" command
TEST_F(ObservationQuerierTest, ProcessCommandLineQuit) {
EXPECT_FALSE(querier_.ProcessCommandLine("quit"));
EXPECT_TRUE(NoOutput());
}
} // namespace cobalt
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
google::ParseCommandLineFlags(&argc, &argv, true);
google::InitGoogleLogging(argv[0]);
return RUN_ALL_TESTS();
}