1 // Copyright (c) 2012 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/history/android/sqlite_cursor.h" 6 7 #include <jni.h> 8 9 #include "base/android/jni_android.h" 10 #include "base/android/jni_array.h" 11 #include "base/android/jni_string.h" 12 #include "base/strings/utf_string_conversions.h" 13 #include "base/time/time.h" 14 #include "chrome/browser/bookmarks/bookmark_test_helpers.h" 15 #include "chrome/browser/history/android/android_history_provider_service.h" 16 #include "chrome/browser/history/android/android_history_types.h" 17 #include "chrome/browser/history/android/android_time.h" 18 #include "chrome/browser/history/history_service.h" 19 #include "chrome/browser/history/history_service_factory.h" 20 #include "chrome/common/chrome_constants.h" 21 #include "chrome/test/base/testing_browser_process.h" 22 #include "chrome/test/base/testing_profile.h" 23 #include "chrome/test/base/testing_profile_manager.h" 24 #include "content/public/browser/browser_thread.h" 25 #include "content/public/test/test_browser_thread.h" 26 #include "content/public/test/test_utils.h" 27 #include "testing/gtest/include/gtest/gtest.h" 28 29 namespace { 30 31 using base::Bind; 32 using base::Time; 33 using content::BrowserThread; 34 using history::AndroidStatement; 35 using history::HistoryAndBookmarkRow; 36 using history::SearchRow; 37 38 // The test cases in this file don't test the JNI interface which will be 39 // covered in Java tests. 40 class SQLiteCursorTest : public testing::Test, 41 public SQLiteCursor::TestObserver { 42 public: 43 SQLiteCursorTest() 44 : profile_manager_( 45 TestingBrowserProcess::GetGlobal()), 46 ui_thread_(BrowserThread::UI, &message_loop_), 47 file_thread_(BrowserThread::FILE, &message_loop_) { 48 } 49 virtual ~SQLiteCursorTest() { 50 } 51 52 protected: 53 virtual void SetUp() OVERRIDE { 54 // Setup the testing profile, so the bookmark_model_sql_handler could 55 // get the bookmark model from it. 56 ASSERT_TRUE(profile_manager_.SetUp()); 57 // It seems that the name has to be chrome::kInitialProfile, so it 58 // could be found by ProfileManager::GetLastUsedProfile(). 59 testing_profile_ = profile_manager_.CreateTestingProfile( 60 chrome::kInitialProfile); 61 62 testing_profile_->CreateBookmarkModel(true); 63 test::WaitForBookmarkModelToLoad(testing_profile_); 64 65 testing_profile_->CreateFaviconService(); 66 ASSERT_TRUE(testing_profile_->CreateHistoryService(true, false)); 67 service_.reset(new AndroidHistoryProviderService(testing_profile_)); 68 hs_ = HistoryServiceFactory::GetForProfile(testing_profile_, 69 Profile::EXPLICIT_ACCESS); 70 } 71 72 virtual void TearDown() OVERRIDE { 73 testing_profile_->DestroyHistoryService(); 74 profile_manager_.DeleteTestingProfile(chrome::kInitialProfile); 75 testing_profile_ = NULL; 76 } 77 78 // Override SQLiteCursor::TestObserver. 79 virtual void OnPostMoveToTask() OVERRIDE { 80 base::MessageLoop::current()->Run(); 81 } 82 83 virtual void OnGetMoveToResult() OVERRIDE { 84 base::MessageLoop::current()->Quit(); 85 } 86 87 virtual void OnPostGetFaviconTask() OVERRIDE { 88 base::MessageLoop::current()->Run(); 89 } 90 91 virtual void OnGetFaviconResult() OVERRIDE { 92 base::MessageLoop::current()->Quit(); 93 } 94 95 protected: 96 TestingProfileManager profile_manager_; 97 base::MessageLoop message_loop_; 98 content::TestBrowserThread ui_thread_; 99 content::TestBrowserThread file_thread_; 100 scoped_ptr<AndroidHistoryProviderService> service_; 101 CancelableRequestConsumer cancelable_consumer_; 102 TestingProfile* testing_profile_; 103 HistoryService* hs_; 104 105 106 private: 107 DISALLOW_COPY_AND_ASSIGN(SQLiteCursorTest); 108 }; 109 110 class CallbackHelper : public base::RefCountedThreadSafe<CallbackHelper> { 111 public: 112 CallbackHelper() 113 : success_(false), 114 statement_(NULL) { 115 } 116 117 bool success() const { 118 return success_; 119 } 120 121 AndroidStatement* statement() const { 122 return statement_; 123 } 124 125 void OnInserted(AndroidHistoryProviderService::Handle handle, 126 bool success, 127 int64 id) { 128 success_ = success; 129 base::MessageLoop::current()->Quit(); 130 } 131 132 void OnQueryResult(AndroidHistoryProviderService::Handle handle, 133 bool success, 134 AndroidStatement* statement) { 135 success_ = success; 136 statement_ = statement; 137 base::MessageLoop::current()->Quit(); 138 } 139 140 private: 141 friend class base::RefCountedThreadSafe<CallbackHelper>; 142 ~CallbackHelper() { 143 } 144 145 bool success_; 146 AndroidStatement* statement_; 147 148 DISALLOW_COPY_AND_ASSIGN(CallbackHelper); 149 }; 150 151 } // namespace 152 153 TEST_F(SQLiteCursorTest, Run) { 154 HistoryAndBookmarkRow row; 155 row.set_raw_url("http://www.google.com/"); 156 row.set_url(GURL("http://www.google.com/")); 157 std::vector<unsigned char> favicon_data; 158 favicon_data.push_back(1); 159 base::RefCountedBytes *data_bytes = 160 base::RefCountedBytes::TakeVector(&favicon_data); 161 row.set_favicon(data_bytes); 162 row.set_last_visit_time(Time::Now()); 163 row.set_visit_count(2); 164 row.set_title(UTF8ToUTF16("cnn")); 165 scoped_refptr<CallbackHelper> callback(new CallbackHelper()); 166 167 // Insert a row and verify it succeeded. 168 service_->InsertHistoryAndBookmark(row, &cancelable_consumer_, 169 Bind(&CallbackHelper::OnInserted, callback.get())); 170 171 base::MessageLoop::current()->Run(); 172 EXPECT_TRUE(callback->success()); 173 174 std::vector<HistoryAndBookmarkRow::ColumnID> projections; 175 projections.push_back(HistoryAndBookmarkRow::URL); 176 projections.push_back(HistoryAndBookmarkRow::LAST_VISIT_TIME); 177 projections.push_back(HistoryAndBookmarkRow::VISIT_COUNT); 178 projections.push_back(HistoryAndBookmarkRow::FAVICON); 179 180 // Query the inserted row. 181 service_->QueryHistoryAndBookmarks(projections, std::string(), 182 std::vector<base::string16>(), std::string(), &cancelable_consumer_, 183 Bind(&CallbackHelper::OnQueryResult, callback.get())); 184 base::MessageLoop::current()->Run(); 185 ASSERT_TRUE(callback->success()); 186 187 AndroidStatement* statement = callback->statement(); 188 std::vector<std::string> column_names; 189 column_names.push_back( 190 HistoryAndBookmarkRow::GetAndroidName(HistoryAndBookmarkRow::URL)); 191 column_names.push_back(HistoryAndBookmarkRow::GetAndroidName( 192 HistoryAndBookmarkRow::LAST_VISIT_TIME)); 193 column_names.push_back(HistoryAndBookmarkRow::GetAndroidName( 194 HistoryAndBookmarkRow::VISIT_COUNT)); 195 column_names.push_back(HistoryAndBookmarkRow::GetAndroidName( 196 HistoryAndBookmarkRow::FAVICON)); 197 198 FaviconService* favicon_service = new FaviconService(testing_profile_); 199 200 SQLiteCursor* cursor = new SQLiteCursor(column_names, statement, 201 service_.get(), favicon_service); 202 cursor->set_test_observer(this); 203 JNIEnv* env = base::android::AttachCurrentThread(); 204 EXPECT_EQ(1, cursor->GetCount(env, NULL)); 205 EXPECT_EQ(0, cursor->MoveTo(env, NULL, 0)); 206 EXPECT_EQ(row.url().spec(), base::android::ConvertJavaStringToUTF8( 207 cursor->GetString(env, NULL, 0)).c_str()); 208 EXPECT_EQ(history::ToDatabaseTime(row.last_visit_time()), 209 cursor->GetLong(env, NULL, 1)); 210 EXPECT_EQ(row.visit_count(), cursor->GetInt(env, NULL, 2)); 211 base::android::ScopedJavaLocalRef<jbyteArray> data = 212 cursor->GetBlob(env, NULL, 3); 213 std::vector<uint8> out; 214 base::android::JavaByteArrayToByteVector(env, data.obj(), &out); 215 EXPECT_EQ(data_bytes->data().size(), out.size()); 216 EXPECT_EQ(data_bytes->data()[0], out[0]); 217 cursor->Destroy(env, NULL); 218 // Cursor::Destroy posts the task in UI thread, run Message loop to release 219 // the statement, delete SQLiteCursor itself etc. 220 content::RunAllPendingInMessageLoop(); 221 } 222