Adding instrumentation to locate the source of jankiness
[chromium-blink-merge.git] / chrome / browser / media_galleries / fileapi / itunes_data_provider_browsertest.cc
blobd71ff0c356fe9537f1fb25943f3a7b02bb856432
1 // Copyright 2013 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.
5 #include <string>
6 #include <vector>
8 #include "base/bind.h"
9 #include "base/files/file_path.h"
10 #include "base/files/file_util.h"
11 #include "base/files/scoped_temp_dir.h"
12 #include "base/format_macros.h"
13 #include "base/logging.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/message_loop/message_loop.h"
16 #include "base/run_loop.h"
17 #include "base/strings/stringprintf.h"
18 #include "chrome/browser/media_galleries/fileapi/itunes_data_provider.h"
19 #include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h"
20 #include "chrome/browser/media_galleries/imported_media_gallery_registry.h"
21 #include "chrome/test/base/in_process_browser_test.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "url/gurl.h"
25 namespace itunes {
27 namespace {
29 struct LibraryEntry {
30 LibraryEntry(const std::string& artist, const std::string& album,
31 const base::FilePath& location)
32 : artist(artist),
33 album(album),
34 location(location) {
36 std::string artist;
37 std::string album;
38 base::FilePath location;
41 // 'c' with combinding cedilla.
42 const char kDeNormalizedName[] = {
43 'c', static_cast<unsigned char>(0xCC), static_cast<unsigned char>(0xA7), 0};
44 // 'c' with cedilla.
45 const char kNormalizedName[] = {
46 static_cast<unsigned char>(0xC3), static_cast<unsigned char>(0xA7), 0};
48 } // namespace
50 class TestITunesDataProvider : public ITunesDataProvider {
51 public:
52 TestITunesDataProvider(const base::FilePath& xml_library_path,
53 const base::Closure& callback)
54 : ITunesDataProvider(xml_library_path),
55 callback_(callback) {
57 virtual ~TestITunesDataProvider() {}
59 private:
60 virtual void OnLibraryChanged(const base::FilePath& path,
61 bool error) override {
62 ITunesDataProvider::OnLibraryChanged(path, error);
63 callback_.Run();
66 base::Closure callback_;
68 DISALLOW_COPY_AND_ASSIGN(TestITunesDataProvider);
71 class ITunesDataProviderTest : public InProcessBrowserTest {
72 public:
73 ITunesDataProviderTest() {}
74 virtual ~ITunesDataProviderTest() {}
76 protected:
77 virtual void SetUp() override {
78 ASSERT_TRUE(library_dir_.CreateUniqueTempDir());
79 WriteLibraryInternal(SetUpLibrary());
80 // The ImportedMediaGalleryRegistry is created on which ever thread calls
81 // GetInstance() first. It shouldn't matter what thread creates, however
82 // in practice it is always created on the UI thread, so this calls
83 // GetInstance here to mirror those real conditions.
84 ImportedMediaGalleryRegistry::GetInstance();
85 InProcessBrowserTest::SetUp();
88 void RunTest() {
89 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
90 base::RunLoop loop;
91 quit_closure_ = loop.QuitClosure();
92 MediaFileSystemBackend::MediaTaskRunner()->PostTask(
93 FROM_HERE,
94 base::Bind(&ITunesDataProviderTest::StartTestOnMediaTaskRunner,
95 base::Unretained(this)));
96 loop.Run();
99 void WriteLibrary(const std::vector<LibraryEntry>& entries,
100 const base::Closure& callback) {
101 SetLibraryChangeCallback(callback);
102 WriteLibraryInternal(entries);
105 void SetLibraryChangeCallback(const base::Closure& callback) {
106 EXPECT_TRUE(library_changed_callback_.is_null());
107 library_changed_callback_ = callback;
110 ITunesDataProvider* data_provider() const {
111 return ImportedMediaGalleryRegistry::ITunesDataProvider();
114 const base::FilePath& library_dir() const {
115 return library_dir_.path();
118 base::FilePath XmlFile() const {
119 return library_dir_.path().AppendASCII("library.xml");
122 void ExpectTrackLocation(const std::string& artist, const std::string& album,
123 const std::string& track_name) {
124 base::FilePath track =
125 library_dir().AppendASCII(track_name).NormalizePathSeparators();
126 EXPECT_EQ(track.value(),
127 data_provider()->GetTrackLocation(
128 artist, album, track_name).NormalizePathSeparators().value());
131 void ExpectNoTrack(const std::string& artist, const std::string& album,
132 const std::string& track_name) {
133 EXPECT_TRUE(data_provider()->GetTrackLocation(
134 artist, album, track_name).empty()) << track_name;
138 // Get the initial set of library entries, called by SetUp. If no entries
139 // are returned the xml file is not created.
140 virtual std::vector<LibraryEntry> SetUpLibrary() {
141 return std::vector<LibraryEntry>();
144 // Start the test. The data provider is refreshed before calling StartTest
145 // and the result of the refresh is passed in.
146 virtual void StartTest(bool parse_success) = 0;
148 void TestDone() {
149 DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
150 ImportedMediaGalleryRegistry* imported_registry =
151 ImportedMediaGalleryRegistry::GetInstance();
152 imported_registry->itunes_data_provider_.reset();
153 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
154 quit_closure_);
157 private:
158 void StartTestOnMediaTaskRunner() {
159 DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
160 ImportedMediaGalleryRegistry* imported_registry =
161 ImportedMediaGalleryRegistry::GetInstance();
162 imported_registry->itunes_data_provider_.reset(
163 new TestITunesDataProvider(
164 XmlFile(),
165 base::Bind(&ITunesDataProviderTest::OnLibraryChanged,
166 base::Unretained(this))));
167 data_provider()->RefreshData(base::Bind(&ITunesDataProviderTest::StartTest,
168 base::Unretained(this)));
171 void OnLibraryChanged() {
172 DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
173 if (!library_changed_callback_.is_null()) {
174 library_changed_callback_.Run();
175 library_changed_callback_.Reset();
179 void WriteLibraryInternal(const std::vector<LibraryEntry>& entries) {
180 if (!entries.size())
181 return;
182 std::string xml = "<plist><dict><key>Tracks</key><dict>\n";
183 for (size_t i = 0; i < entries.size(); ++i) {
184 std::string separator;
185 #if defined(OS_WIN)
186 separator = "/";
187 #endif
188 GURL location("file://localhost" + separator +
189 entries[i].location.AsUTF8Unsafe());
190 std::string entry_string = base::StringPrintf(
191 "<key>%" PRIuS "</key><dict>\n"
192 " <key>Track ID</key><integer>%" PRIuS "</integer>\n"
193 " <key>Location</key><string>%s</string>\n"
194 " <key>Artist</key><string>%s</string>\n"
195 " <key>Album</key><string>%s</string>\n"
196 "</dict>\n",
197 i + 1, i + 1, location.spec().c_str(), entries[i].artist.c_str(),
198 entries[i].album.c_str());
199 xml += entry_string;
201 xml += "</dict></dict></plist>\n";
202 ASSERT_EQ(static_cast<int>(xml.size()),
203 base::WriteFile(XmlFile(), xml.c_str(), xml.size()));
206 base::ScopedTempDir library_dir_;
208 base::Closure library_changed_callback_;
210 base::Closure quit_closure_;
212 DISALLOW_COPY_AND_ASSIGN(ITunesDataProviderTest);
215 class ITunesDataProviderBasicTest : public ITunesDataProviderTest {
216 public:
217 ITunesDataProviderBasicTest() {}
218 virtual ~ITunesDataProviderBasicTest() {}
220 virtual std::vector<LibraryEntry> SetUpLibrary() override {
221 base::FilePath track = library_dir().AppendASCII("Track.mp3");
222 std::vector<LibraryEntry> entries;
223 entries.push_back(LibraryEntry("Artist", "Album", track));
224 return entries;
227 virtual void StartTest(bool parse_success) override {
228 EXPECT_TRUE(parse_success);
230 // KnownArtist
231 EXPECT_TRUE(data_provider()->KnownArtist("Artist"));
232 EXPECT_FALSE(data_provider()->KnownArtist("Artist2"));
234 // KnownAlbum
235 EXPECT_TRUE(data_provider()->KnownAlbum("Artist", "Album"));
236 EXPECT_FALSE(data_provider()->KnownAlbum("Artist", "Album2"));
237 EXPECT_FALSE(data_provider()->KnownAlbum("Artist2", "Album"));
239 // GetTrackLocation
240 ExpectTrackLocation("Artist", "Album", "Track.mp3");
241 ExpectNoTrack("Artist", "Album", "Track2.mp3");
242 ExpectNoTrack("Artist", "Album2", "Track.mp3");
243 ExpectNoTrack("Artist2", "Album", "Track.mp3");
245 // GetArtistNames
246 std::set<ITunesDataProvider::ArtistName> artists =
247 data_provider()->GetArtistNames();
248 ASSERT_EQ(1U, artists.size());
249 EXPECT_EQ("Artist", *artists.begin());
251 // GetAlbumNames
252 std::set<ITunesDataProvider::AlbumName> albums =
253 data_provider()->GetAlbumNames("Artist");
254 ASSERT_EQ(1U, albums.size());
255 EXPECT_EQ("Album", *albums.begin());
257 albums = data_provider()->GetAlbumNames("Artist2");
258 EXPECT_EQ(0U, albums.size());
260 // GetAlbum
261 base::FilePath track =
262 library_dir().AppendASCII("Track.mp3").NormalizePathSeparators();
263 ITunesDataProvider::Album album =
264 data_provider()->GetAlbum("Artist", "Album");
265 ASSERT_EQ(1U, album.size());
266 EXPECT_EQ(track.BaseName().AsUTF8Unsafe(), album.begin()->first);
267 EXPECT_EQ(track.value(),
268 album.begin()->second.NormalizePathSeparators().value());
270 album = data_provider()->GetAlbum("Artist", "Album2");
271 EXPECT_EQ(0U, album.size());
273 album = data_provider()->GetAlbum("Artist2", "Album");
274 EXPECT_EQ(0U, album.size());
276 TestDone();
279 private:
280 DISALLOW_COPY_AND_ASSIGN(ITunesDataProviderBasicTest);
283 class ITunesDataProviderRefreshTest : public ITunesDataProviderTest {
284 public:
285 ITunesDataProviderRefreshTest() {}
286 virtual ~ITunesDataProviderRefreshTest() {}
288 virtual std::vector<LibraryEntry> SetUpLibrary() override {
289 base::FilePath track = library_dir().AppendASCII("Track.mp3");
290 std::vector<LibraryEntry> entries;
291 entries.push_back(LibraryEntry("Artist", "Album", track));
292 return entries;
295 virtual void StartTest(bool parse_success) override {
296 EXPECT_TRUE(parse_success);
298 // Initial contents.
299 ExpectTrackLocation("Artist", "Album", "Track.mp3");
300 ExpectNoTrack("Artist2", "Album2", "Track2.mp3");
302 // New file.
303 base::FilePath track2 = library_dir().AppendASCII("Track2.mp3");
304 std::vector<LibraryEntry> entries;
305 entries.push_back(LibraryEntry("Artist2", "Album2", track2));
306 WriteLibrary(entries,
307 base::Bind(&ITunesDataProviderRefreshTest::CheckAfterWrite,
308 base::Unretained(this)));
311 void CheckAfterWrite() {
312 // Content the same.
313 ExpectTrackLocation("Artist", "Album", "Track.mp3");
314 ExpectNoTrack("Artist2", "Album2", "Track2.mp3");
316 data_provider()->RefreshData(
317 base::Bind(&ITunesDataProviderRefreshTest::CheckRefresh,
318 base::Unretained(this)));
321 void CheckRefresh(bool is_valid) {
322 EXPECT_TRUE(is_valid);
324 ExpectTrackLocation("Artist2", "Album2", "Track2.mp3");
325 ExpectNoTrack("Artist", "Album", "Track.mp3");
326 TestDone();
329 private:
330 DISALLOW_COPY_AND_ASSIGN(ITunesDataProviderRefreshTest);
333 class ITunesDataProviderInvalidTest : public ITunesDataProviderTest {
334 public:
335 ITunesDataProviderInvalidTest() {}
336 virtual ~ITunesDataProviderInvalidTest() {}
338 virtual std::vector<LibraryEntry> SetUpLibrary() override {
339 base::FilePath track = library_dir().AppendASCII("Track.mp3");
340 std::vector<LibraryEntry> entries;
341 entries.push_back(LibraryEntry("Artist", "Album", track));
342 return entries;
345 virtual void StartTest(bool parse_success) override {
346 EXPECT_TRUE(parse_success);
348 SetLibraryChangeCallback(
349 base::Bind(&ITunesDataProvider::RefreshData,
350 base::Unretained(data_provider()),
351 base::Bind(&ITunesDataProviderInvalidTest::CheckInvalid,
352 base::Unretained(this))));
353 ASSERT_EQ(1L, base::WriteFile(XmlFile(), " ", 1));
356 void CheckInvalid(bool is_valid) {
357 EXPECT_FALSE(is_valid);
358 TestDone();
361 private:
362 DISALLOW_COPY_AND_ASSIGN(ITunesDataProviderInvalidTest);
365 class ITunesDataProviderUniqueNameTest : public ITunesDataProviderTest {
366 public:
367 ITunesDataProviderUniqueNameTest() {}
368 virtual ~ITunesDataProviderUniqueNameTest() {}
370 virtual std::vector<LibraryEntry> SetUpLibrary() override {
371 base::FilePath track = library_dir().AppendASCII("Track.mp3");
372 std::vector<LibraryEntry> entries;
373 // Dupe album names should get uniquified with the track id, which in the
374 // test framework is the vector index.
375 entries.push_back(LibraryEntry("Artist", "Album", track));
376 entries.push_back(LibraryEntry("Artist", "Album", track));
377 entries.push_back(LibraryEntry("Artist", "Album2", track));
378 return entries;
381 virtual void StartTest(bool parse_success) override {
382 EXPECT_TRUE(parse_success);
384 base::FilePath track =
385 library_dir().AppendASCII("Track.mp3").NormalizePathSeparators();
386 EXPECT_EQ(track.value(),
387 data_provider()->GetTrackLocation(
388 "Artist", "Album",
389 "Track (1).mp3").NormalizePathSeparators().value());
390 EXPECT_EQ(track.value(),
391 data_provider()->GetTrackLocation(
392 "Artist", "Album",
393 "Track (2).mp3").NormalizePathSeparators().value());
394 EXPECT_EQ(track.value(),
395 data_provider()->GetTrackLocation(
396 "Artist", "Album2",
397 "Track.mp3").NormalizePathSeparators().value());
399 TestDone();
402 private:
403 DISALLOW_COPY_AND_ASSIGN(ITunesDataProviderUniqueNameTest);
406 class ITunesDataProviderEscapeTest : public ITunesDataProviderTest {
407 // Albums and tracks that aren't the same, but become the same after
408 // replacing bad characters are not handled properly, but that case should
409 // never happen in practice.
410 public:
411 ITunesDataProviderEscapeTest() {}
412 virtual ~ITunesDataProviderEscapeTest() {}
414 virtual std::vector<LibraryEntry> SetUpLibrary() override {
415 base::FilePath track = library_dir().AppendASCII("Track:1.mp3");
416 std::vector<LibraryEntry> entries;
417 entries.push_back(LibraryEntry("Artist:/name", "Album:name/", track));
418 entries.push_back(LibraryEntry("Artist/name", "Album:name", track));
419 entries.push_back(LibraryEntry("Artist/name", "Album:name", track));
420 entries.push_back(LibraryEntry(kDeNormalizedName, kNormalizedName, track));
421 return entries;
424 virtual void StartTest(bool parse_success) override {
425 EXPECT_TRUE(parse_success);
427 base::FilePath track =
428 library_dir().AppendASCII("Track:1.mp3").NormalizePathSeparators();
429 EXPECT_EQ(track.value(),
430 data_provider()->GetTrackLocation(
431 "Artist__name", "Album_name_",
432 "Track_1.mp3").NormalizePathSeparators().value());
433 EXPECT_EQ(track.value(),
434 data_provider()->GetTrackLocation(
435 "Artist_name", "Album_name",
436 "Track_1 (2).mp3").NormalizePathSeparators().value());
437 EXPECT_EQ(track.value(),
438 data_provider()->GetTrackLocation(
439 "Artist_name", "Album_name",
440 "Track_1 (3).mp3").NormalizePathSeparators().value());
441 EXPECT_EQ(track.value(),
442 data_provider()->GetTrackLocation(
443 kNormalizedName, kNormalizedName,
444 "Track_1.mp3").NormalizePathSeparators().value());
446 TestDone();
449 private:
450 DISALLOW_COPY_AND_ASSIGN(ITunesDataProviderEscapeTest);
453 IN_PROC_BROWSER_TEST_F(ITunesDataProviderBasicTest, BasicTest) {
454 RunTest();
457 IN_PROC_BROWSER_TEST_F(ITunesDataProviderRefreshTest, RefreshTest) {
458 RunTest();
461 IN_PROC_BROWSER_TEST_F(ITunesDataProviderInvalidTest, InvalidTest) {
462 RunTest();
465 IN_PROC_BROWSER_TEST_F(ITunesDataProviderUniqueNameTest, UniqueNameTest) {
466 RunTest();
469 IN_PROC_BROWSER_TEST_F(ITunesDataProviderEscapeTest, EscapeTest) {
470 RunTest();
473 } // namespace itunes