1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/drive/drive_app_registry.h"
6
7#include "base/files/file_path.h"
8#include "base/macros.h"
9#include "base/run_loop.h"
10#include "base/values.h"
11#include "chrome/browser/drive/drive_app_registry_observer.h"
12#include "chrome/browser/drive/fake_drive_service.h"
13#include "content/public/test/test_browser_thread_bundle.h"
14#include "google_apis/drive/drive_api_parser.h"
15#include "google_apis/drive/gdata_wapi_parser.h"
16#include "google_apis/drive/test_util.h"
17#include "testing/gtest/include/gtest/gtest.h"
18
19namespace drive {
20
21class TestDriveAppRegistryObserver : public DriveAppRegistryObserver {
22 public:
23  explicit TestDriveAppRegistryObserver(DriveAppRegistry* registry)
24      : registry_(registry),
25        update_count_(0) {
26    registry_->AddObserver(this);
27  }
28  virtual ~TestDriveAppRegistryObserver() {
29    registry_->RemoveObserver(this);
30  }
31
32  int update_count() const { return update_count_; }
33
34 private:
35  // DriveAppRegistryObserver overrides:
36  virtual void OnDriveAppRegistryUpdated() OVERRIDE { ++update_count_; }
37
38  DriveAppRegistry* registry_;
39  int update_count_;
40  DISALLOW_COPY_AND_ASSIGN(TestDriveAppRegistryObserver);
41};
42
43class DriveAppRegistryTest : public testing::Test {
44 protected:
45  virtual void SetUp() OVERRIDE {
46    fake_drive_service_.reset(new FakeDriveService);
47    fake_drive_service_->LoadAppListForDriveApi("drive/applist.json");
48
49    apps_registry_.reset(new DriveAppRegistry(fake_drive_service_.get()));
50  }
51
52  bool VerifyApp(const std::vector<DriveAppInfo>& list,
53                 const std::string& app_id,
54                 const std::string& app_name) {
55    bool found = false;
56    for (size_t i = 0; i < list.size(); ++i) {
57      const DriveAppInfo& app = list[i];
58      if (app_id == app.app_id) {
59        EXPECT_EQ(app_name, app.app_name);
60        found = true;
61        break;
62      }
63    }
64    EXPECT_TRUE(found) << "Unable to find app with app_id " << app_id;
65    return found;
66  }
67
68  content::TestBrowserThreadBundle thread_bundle_;
69  scoped_ptr<FakeDriveService> fake_drive_service_;
70  scoped_ptr<DriveAppRegistry> apps_registry_;
71};
72
73TEST_F(DriveAppRegistryTest, BasicParse) {
74  TestDriveAppRegistryObserver observer(apps_registry_.get());
75
76  apps_registry_->Update();
77  base::RunLoop().RunUntilIdle();
78  EXPECT_EQ(1, observer.update_count());
79
80  std::vector<DriveAppInfo> apps;
81  apps_registry_->GetAppList(&apps);
82
83  ASSERT_EQ(2u, apps.size());
84  EXPECT_EQ("123456788192", apps[0].app_id);
85  EXPECT_EQ("Drive app 1", apps[0].app_name);
86  EXPECT_EQ("https://www.example.com/createForApp1",
87            apps[0].create_url.spec());
88  EXPECT_EQ("abcdefghabcdefghabcdefghabcdefgh", apps[0].product_id);
89  EXPECT_TRUE(apps[0].is_removable);
90}
91
92TEST_F(DriveAppRegistryTest, LoadAndFindDriveApps) {
93  TestDriveAppRegistryObserver observer(apps_registry_.get());
94
95  apps_registry_->Update();
96  base::RunLoop().RunUntilIdle();
97  EXPECT_EQ(1, observer.update_count());
98
99  // Find by primary extension 'exe'.
100  std::vector<DriveAppInfo> ext_results;
101  base::FilePath ext_file(FILE_PATH_LITERAL("drive/file.exe"));
102  apps_registry_->GetAppsForFile(ext_file.Extension(), "", &ext_results);
103  ASSERT_EQ(1U, ext_results.size());
104  VerifyApp(ext_results, "123456788192", "Drive app 1");
105
106  // Find by primary MIME type.
107  std::vector<DriveAppInfo> primary_app;
108  apps_registry_->GetAppsForFile(base::FilePath::StringType(),
109      "application/vnd.google-apps.drive-sdk.123456788192", &primary_app);
110  ASSERT_EQ(1U, primary_app.size());
111  VerifyApp(primary_app, "123456788192", "Drive app 1");
112
113  // Find by secondary MIME type.
114  std::vector<DriveAppInfo> secondary_app;
115  apps_registry_->GetAppsForFile(
116      base::FilePath::StringType(), "text/html", &secondary_app);
117  ASSERT_EQ(1U, secondary_app.size());
118  VerifyApp(secondary_app, "123456788192", "Drive app 1");
119}
120
121TEST_F(DriveAppRegistryTest, UpdateFromAppList) {
122  scoped_ptr<base::Value> app_info_value =
123      google_apis::test_util::LoadJSONFile("drive/applist.json");
124  scoped_ptr<google_apis::AppList> app_list(
125      google_apis::AppList::CreateFrom(*app_info_value));
126
127  TestDriveAppRegistryObserver observer(apps_registry_.get());
128  apps_registry_->UpdateFromAppList(*app_list);
129  EXPECT_EQ(1, observer.update_count());
130
131  // Confirm that something was loaded from applist.json.
132  std::vector<DriveAppInfo> ext_results;
133  base::FilePath ext_file(FILE_PATH_LITERAL("drive/file.exe"));
134  apps_registry_->GetAppsForFile(ext_file.Extension(), "", &ext_results);
135  ASSERT_EQ(1U, ext_results.size());
136}
137
138TEST_F(DriveAppRegistryTest, MultipleUpdate) {
139  TestDriveAppRegistryObserver observer(apps_registry_.get());
140
141  // Call Update().
142  apps_registry_->Update();
143  EXPECT_EQ(0, observer.update_count());
144
145  // Call Update() again.
146  // This call should be ignored because there is already an ongoing update.
147  apps_registry_->Update();
148  EXPECT_EQ(0, observer.update_count());
149
150  // The app list should be loaded only once.
151  base::RunLoop().RunUntilIdle();
152  EXPECT_EQ(1, fake_drive_service_->app_list_load_count());
153  EXPECT_EQ(1, observer.update_count());
154}
155
156TEST(DriveAppRegistryUtilTest, FindPreferredIcon_Empty) {
157  DriveAppInfo::IconList icons;
158  EXPECT_EQ("",
159            util::FindPreferredIcon(icons, util::kPreferredIconSize).spec());
160}
161
162TEST(DriveAppRegistryUtilTest, FindPreferredIcon_) {
163  const char kSmallerIconUrl[] = "http://example.com/smaller.png";
164  const char kMediumIconUrl[] = "http://example.com/medium.png";
165  const char kBiggerIconUrl[] = "http://example.com/bigger.png";
166  const int kMediumSize = 16;
167
168  DriveAppInfo::IconList icons;
169  // The icons are not sorted by the size.
170  icons.push_back(std::make_pair(kMediumSize,
171                                 GURL(kMediumIconUrl)));
172  icons.push_back(std::make_pair(kMediumSize + 2,
173                                 GURL(kBiggerIconUrl)));
174  icons.push_back(std::make_pair(kMediumSize - 2,
175                                 GURL(kSmallerIconUrl)));
176
177  // Exact match.
178  EXPECT_EQ(kMediumIconUrl,
179            util::FindPreferredIcon(icons, kMediumSize).spec());
180  // The requested size is in-between of smaller.png and
181  // medium.png. medium.png should be returned.
182  EXPECT_EQ(kMediumIconUrl,
183            util::FindPreferredIcon(icons, kMediumSize - 1).spec());
184  // The requested size is smaller than the smallest icon. The smallest icon
185  // should be returned.
186  EXPECT_EQ(kSmallerIconUrl,
187            util::FindPreferredIcon(icons, kMediumSize - 3).spec());
188  // The requested size is larger than the largest icon. The largest icon
189  // should be returned.
190  EXPECT_EQ(kBiggerIconUrl,
191            util::FindPreferredIcon(icons, kMediumSize + 3).spec());
192}
193
194TEST_F(DriveAppRegistryTest, UninstallDriveApp) {
195  apps_registry_->Update();
196  base::RunLoop().RunUntilIdle();
197
198  std::vector<DriveAppInfo> apps;
199  apps_registry_->GetAppList(&apps);
200  size_t original_count = apps.size();
201
202  // Uninstall an existing app.
203  google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
204  apps_registry_->UninstallApp(
205      "123456788192",
206      google_apis::test_util::CreateCopyResultCallback(&error));
207  base::RunLoop().RunUntilIdle();
208  EXPECT_EQ(error, google_apis::HTTP_NO_CONTENT);
209
210  // Check that the number of apps is decreased by one.
211  apps_registry_->GetAppList(&apps);
212  EXPECT_EQ(original_count - 1, apps.size());
213
214  // Try to uninstall a non-existing app.
215  error = google_apis::GDATA_OTHER_ERROR;
216  apps_registry_->UninstallApp(
217      "non-existing-app-id",
218      google_apis::test_util::CreateCopyResultCallback(&error));
219  base::RunLoop().RunUntilIdle();
220  EXPECT_EQ(error, google_apis::HTTP_NOT_FOUND);
221
222  // Check that the number is not changed this time.
223  apps_registry_->GetAppList(&apps);
224  EXPECT_EQ(original_count - 1, apps.size());
225}
226
227}  // namespace drive
228