blob: 0eb5e882994c181436d9c46f42d085f212711911 [file] [log] [blame]
// Copyright 2017 The Chromium 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 "chrome/browser/chromeos/printing/external_printers.h"
#include <string>
#include <vector>
#include "base/bind.h"
#include "base/strings/stringprintf.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/scoped_task_environment.h"
#include "chrome/common/chrome_features.h"
#include "chromeos/printing/printer_configuration.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace chromeos {
namespace {
// The number of printers in BulkPolicyContentsJson.
constexpr size_t kNumPrinters = 3;
// An example bulk printer configuration file.
constexpr char kBulkPolicyContentsJson[] = R"json(
[
{
"id": "First",
"display_name": "LexaPrint",
"description": "Laser on the test shelf",
"manufacturer": "LexaPrint, Inc.",
"model": "MS610de",
"uri": "ipp://192.168.1.5",
"ppd_resource": {
"effective_model": "MS610de"
}
}, {
"id": "Second",
"display_name": "Color Laser",
"description": "The printer next to the water cooler.",
"manufacturer": "Printer Manufacturer",
"model":"Color Laser 2004",
"uri":"ipps://print-server.intranet.example.com:443/ipp/cl2k4",
"uuid":"1c395fdb-5d93-4904-b246-b2c046e79d12",
"ppd_resource":{
"effective_manufacturer": "MakesPrinters",
"effective_model": "ColorLaser2k4"
}
}, {
"id": "Third",
"display_name": "YaLP",
"description": "Fancy Fancy Fancy",
"manufacturer": "LexaPrint, Inc.",
"model": "MS610de",
"uri": "ipp://192.168.1.8",
"ppd_resource": {
"effective_manufacturer": "LexaPrint",
"effective_model": "MS610de"
}
}
])json";
// A different bulk printer configuration file.
constexpr char kMoreContentsJson[] = R"json(
[
{
"id": "ThirdPrime",
"display_name": "Printy McPrinter",
"description": "Laser on the test shelf",
"manufacturer": "CrosInc.",
"model": "MS610de",
"uri": "ipp://192.168.1.5",
"ppd_resource": {
"effective_model": "MS610de"
}
}
])json";
// Observer that counts the number of times it has been called.
class TestObserver : public ExternalPrinters::Observer {
public:
void OnPrintersChanged(
bool valid,
const std::map<const std::string, const Printer>& /* printers */)
override {
last_valid = valid;
called++;
}
// Counts the number of times the observer is invoked.
int called = 0;
// Holds the most recent value of valid.
bool last_valid = false;
};
class ExternalPrintersTest : public testing::Test {
public:
ExternalPrintersTest() : scoped_task_environment_() {
scoped_feature_list_.InitAndEnableFeature(
base::Feature(features::kBulkPrinters));
external_printers_ = ExternalPrinters::Create();
}
~ExternalPrintersTest() override {
// Delete the printer before the task environment.
external_printers_.reset();
}
protected:
std::unique_ptr<ExternalPrinters> external_printers_;
base::test::ScopedTaskEnvironment scoped_task_environment_;
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
// Verify that we're initiall unset and empty.
TEST_F(ExternalPrintersTest, InitialConditions) {
EXPECT_FALSE(external_printers_->IsPolicySet());
EXPECT_TRUE(external_printers_->GetPrinters().empty());
}
// Verify that the object can be destroyed while parsing is in progress.
TEST_F(ExternalPrintersTest, DestructionIsSafe) {
{
std::unique_ptr<ExternalPrinters> printers = ExternalPrinters::Create();
printers->SetAccessMode(ExternalPrinters::BLACKLIST_ONLY);
printers->SetBlacklist({"Third"});
printers->SetData(std::make_unique<std::string>(kBulkPolicyContentsJson));
// Data is valid. Computation is proceeding.
}
// printers is out of scope. Destructor has run. Pump the message queue to
// see if anything strange happens.
scoped_task_environment_.RunUntilIdle();
}
// Verifies that all IsPolicySet returns false until all necessary data is set.
TEST_F(ExternalPrintersTest, PolicyUnsetWithMissingData) {
auto data = std::make_unique<std::string>(kBulkPolicyContentsJson);
external_printers_->ClearData();
external_printers_->SetData(std::move(data));
// Waiting for AccessMode.
scoped_task_environment_.RunUntilIdle();
EXPECT_FALSE(external_printers_->IsPolicySet());
external_printers_->SetAccessMode(ExternalPrinters::AccessMode::ALL_ACCESS);
scoped_task_environment_.RunUntilIdle();
EXPECT_TRUE(external_printers_->IsPolicySet());
external_printers_->SetAccessMode(
ExternalPrinters::AccessMode::WHITELIST_ONLY);
scoped_task_environment_.RunUntilIdle();
EXPECT_FALSE(external_printers_->IsPolicySet()); // Waiting for Whitelist.
std::vector<std::string> whitelist = {"First", "Third"};
external_printers_->SetWhitelist(whitelist);
scoped_task_environment_.RunUntilIdle();
EXPECT_TRUE(external_printers_->IsPolicySet()); // Everything is set.
external_printers_->SetAccessMode(
ExternalPrinters::AccessMode::BLACKLIST_ONLY);
scoped_task_environment_.RunUntilIdle();
EXPECT_FALSE(external_printers_->IsPolicySet()); // Blacklist needed now.
std::vector<std::string> blacklist = {"Second"};
external_printers_->SetBlacklist(blacklist);
scoped_task_environment_.RunUntilIdle();
EXPECT_TRUE(
external_printers_->IsPolicySet()); // Blacklist was set. Ready again.
}
// Verify printer list after all attributes have been set.
TEST_F(ExternalPrintersTest, AllPoliciesResultInPrinters) {
auto data = std::make_unique<std::string>(kBulkPolicyContentsJson);
external_printers_->SetAccessMode(ExternalPrinters::AccessMode::ALL_ACCESS);
external_printers_->SetData(std::move(data));
scoped_task_environment_.RunUntilIdle();
const auto& printers = external_printers_->GetPrinters();
EXPECT_TRUE(external_printers_->IsPolicySet());
EXPECT_EQ(kNumPrinters, printers.size());
EXPECT_EQ("LexaPrint", printers.at("First").display_name());
EXPECT_EQ("Color Laser", printers.at("Second").display_name());
EXPECT_EQ("YaLP", printers.at("Third").display_name());
}
// The external policy was cleared, results should be invalidated.
TEST_F(ExternalPrintersTest, PolicyClearedNowUnset) {
auto data = std::make_unique<std::string>(kBulkPolicyContentsJson);
external_printers_->SetAccessMode(ExternalPrinters::AccessMode::ALL_ACCESS);
external_printers_->ClearData();
external_printers_->SetData(std::move(data));
scoped_task_environment_.RunUntilIdle();
ASSERT_TRUE(external_printers_->IsPolicySet());
external_printers_->ClearData();
scoped_task_environment_.RunUntilIdle();
EXPECT_FALSE(external_printers_->IsPolicySet());
EXPECT_TRUE(external_printers_->GetPrinters().empty());
}
// Verify that the blacklist policy is applied correctly. Printers in the
// blacklist policy should not be available. Printers not in the blackslist
// should be available.
TEST_F(ExternalPrintersTest, BlacklistPolicySet) {
auto data = std::make_unique<std::string>(kBulkPolicyContentsJson);
external_printers_->ClearData();
external_printers_->SetData(std::move(data));
external_printers_->SetAccessMode(ExternalPrinters::BLACKLIST_ONLY);
scoped_task_environment_.RunUntilIdle();
EXPECT_FALSE(external_printers_->IsPolicySet());
external_printers_->SetBlacklist({"Second", "Third"});
scoped_task_environment_.RunUntilIdle();
EXPECT_TRUE(external_printers_->IsPolicySet());
scoped_task_environment_.RunUntilIdle();
const auto& printers = external_printers_->GetPrinters();
EXPECT_EQ(1U, printers.size());
EXPECT_EQ("LexaPrint", printers.at("First").display_name());
}
// Verify that the whitelist policy is correctly applied. Only printers
// available in the whitelist are available.
TEST_F(ExternalPrintersTest, WhitelistPolicySet) {
auto data = std::make_unique<std::string>(kBulkPolicyContentsJson);
external_printers_->ClearData();
external_printers_->SetData(std::move(data));
external_printers_->SetAccessMode(ExternalPrinters::WHITELIST_ONLY);
scoped_task_environment_.RunUntilIdle();
EXPECT_FALSE(external_printers_->IsPolicySet());
external_printers_->SetWhitelist({"First"});
scoped_task_environment_.RunUntilIdle();
EXPECT_TRUE(external_printers_->IsPolicySet());
const auto& printers = external_printers_->GetPrinters();
EXPECT_EQ(1U, printers.size());
EXPECT_EQ("LexaPrint", printers.at("First").display_name());
}
// Verify that switching from whitelist to blacklist behaves correctly.
TEST_F(ExternalPrintersTest, BlacklistToWhitelistSwap) {
auto data = std::make_unique<std::string>(kBulkPolicyContentsJson);
external_printers_->ClearData();
external_printers_->SetData(std::move(data));
external_printers_->SetAccessMode(ExternalPrinters::BLACKLIST_ONLY);
external_printers_->SetWhitelist({"First"});
external_printers_->SetBlacklist({"First"});
// This should result in 2 printers. But we're switching the mode anyway.
external_printers_->SetAccessMode(ExternalPrinters::WHITELIST_ONLY);
scoped_task_environment_.RunUntilIdle();
EXPECT_TRUE(external_printers_->IsPolicySet());
const auto& printers = external_printers_->GetPrinters();
EXPECT_EQ(1U, printers.size());
EXPECT_EQ("LexaPrint", printers.at("First").display_name());
}
// Verify that updated configurations are handled properly.
TEST_F(ExternalPrintersTest, MultipleUpdates) {
auto data = std::make_unique<std::string>(kBulkPolicyContentsJson);
external_printers_->ClearData();
external_printers_->SetData(std::move(data));
external_printers_->SetAccessMode(ExternalPrinters::ALL_ACCESS);
// There will be 3 printers here. But we don't want to wait for compuation to
// complete to verify the final value gets used.
auto new_data = std::make_unique<std::string>(kMoreContentsJson);
external_printers_->SetData(std::move(new_data));
scoped_task_environment_.RunUntilIdle();
const auto& printers = external_printers_->GetPrinters();
ASSERT_EQ(1U, printers.size());
EXPECT_EQ("ThirdPrime", printers.at("ThirdPrime").id());
}
// Verifies that the observer is called at the expected times.
TEST_F(ExternalPrintersTest, ObserverTest) {
TestObserver obs;
external_printers_->AddObserver(&obs);
external_printers_->SetAccessMode(ExternalPrinters::ALL_ACCESS);
external_printers_->SetWhitelist(std::vector<std::string>());
external_printers_->SetBlacklist(std::vector<std::string>());
external_printers_->ClearData();
scoped_task_environment_.RunUntilIdle();
EXPECT_EQ(0, obs.called);
external_printers_->SetData(
std::make_unique<std::string>(kBulkPolicyContentsJson));
scoped_task_environment_.RunUntilIdle();
EXPECT_TRUE(external_printers_->IsPolicySet());
EXPECT_EQ(1, obs.called);
EXPECT_TRUE(obs.last_valid); // ready now
// Printer list is correct after notification.
EXPECT_EQ(kNumPrinters, external_printers_->GetPrinters().size());
external_printers_->SetAccessMode(ExternalPrinters::WHITELIST_ONLY);
scoped_task_environment_.RunUntilIdle();
EXPECT_EQ(2, obs.called); // effective list changed. Notified.
EXPECT_TRUE(obs.last_valid);
external_printers_->SetAccessMode(ExternalPrinters::BLACKLIST_ONLY);
scoped_task_environment_.RunUntilIdle();
EXPECT_EQ(3, obs.called); // effective list changed. Notified.
EXPECT_TRUE(obs.last_valid);
external_printers_->ClearData();
scoped_task_environment_.RunUntilIdle();
EXPECT_EQ(4, obs.called); // Called for transition to invalid policy.
EXPECT_FALSE(obs.last_valid);
EXPECT_TRUE(external_printers_->GetPrinters().empty());
// cleanup
external_printers_->RemoveObserver(&obs);
}
} // namespace
} // namespace chromeos