DataSourceFactoryTest.java revision ddee2b5170ae257a7b2494f8aaa8459ebed806dc
1/* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package androidx.room.integration.testapp.paging; 18 19import static org.hamcrest.CoreMatchers.is; 20import static org.hamcrest.CoreMatchers.notNullValue; 21import static org.hamcrest.CoreMatchers.nullValue; 22import static org.hamcrest.MatcherAssert.assertThat; 23import static org.junit.Assert.assertNotNull; 24 25import android.support.test.filters.LargeTest; 26import android.support.test.runner.AndroidJUnit4; 27 28import androidx.annotation.Nullable; 29import androidx.arch.core.executor.ArchTaskExecutor; 30import androidx.arch.core.executor.testing.CountingTaskExecutorRule; 31import androidx.lifecycle.Lifecycle; 32import androidx.lifecycle.LifecycleOwner; 33import androidx.lifecycle.LifecycleRegistry; 34import androidx.lifecycle.LiveData; 35import androidx.lifecycle.Observer; 36import androidx.paging.DataSource; 37import androidx.paging.LivePagedListBuilder; 38import androidx.paging.PagedList; 39import androidx.room.integration.testapp.test.TestDatabaseTest; 40import androidx.room.integration.testapp.test.TestUtil; 41import androidx.room.integration.testapp.vo.Pet; 42import androidx.room.integration.testapp.vo.User; 43import androidx.room.integration.testapp.vo.UserAndAllPets; 44import androidx.sqlite.db.SimpleSQLiteQuery; 45 46import org.junit.Rule; 47import org.junit.Test; 48import org.junit.runner.RunWith; 49 50import java.util.Arrays; 51import java.util.Collections; 52import java.util.concurrent.ExecutionException; 53import java.util.concurrent.FutureTask; 54import java.util.concurrent.TimeUnit; 55import java.util.concurrent.TimeoutException; 56 57@LargeTest 58@RunWith(AndroidJUnit4.class) 59public class DataSourceFactoryTest extends TestDatabaseTest { 60 @Rule 61 public CountingTaskExecutorRule mExecutorRule = new CountingTaskExecutorRule(); 62 63 private interface LivePagedListFactory { 64 LiveData<PagedList<User>> create(); 65 } 66 67 @Test 68 public void getUsersAsPagedList() 69 throws InterruptedException, ExecutionException, TimeoutException { 70 validateUsersAsPagedList(() -> new LivePagedListBuilder<>( 71 mUserDao.loadPagedByAge(3), 72 new PagedList.Config.Builder() 73 .setPageSize(10) 74 .setPrefetchDistance(1) 75 .setInitialLoadSizeHint(10).build()) 76 .build()); 77 } 78 79 @Test 80 public void getUsersAsPagedList_ViaRawQuery_WithObservable() 81 throws InterruptedException, ExecutionException, TimeoutException { 82 SimpleSQLiteQuery query = new SimpleSQLiteQuery( 83 "SELECT * FROM user where mAge > ?", 84 new Object[]{3}); 85 validateUsersAsPagedList(() -> new LivePagedListBuilder<>( 86 mUserDao.loadPagedByAgeWithObserver(query), 87 new PagedList.Config.Builder() 88 .setPageSize(10) 89 .setPrefetchDistance(1) 90 .setInitialLoadSizeHint(10).build()) 91 .build()); 92 } 93 94 private void validateUsersAsPagedList( 95 LivePagedListFactory factory) 96 throws InterruptedException, ExecutionException, TimeoutException { 97 mDatabase.beginTransaction(); 98 try { 99 for (int i = 0; i < 100; i++) { 100 final User user = TestUtil.createUser(i + 1); 101 user.setAge(i); 102 mUserDao.insert(user); 103 } 104 mDatabase.setTransactionSuccessful(); 105 } finally { 106 mDatabase.endTransaction(); 107 } 108 assertThat(mUserDao.count(), is(100)); 109 110 final LiveData<PagedList<User>> livePagedUsers = factory.create(); 111 112 final TestLifecycleOwner testOwner = new TestLifecycleOwner(); 113 testOwner.handleEvent(Lifecycle.Event.ON_CREATE); 114 drain(); 115 PagedListObserver<User> observer = new PagedListObserver<>(); 116 117 observe(livePagedUsers, testOwner, observer); 118 assertThat(observer.get(), nullValue()); 119 observer.reset(); 120 121 testOwner.handleEvent(Lifecycle.Event.ON_START); 122 drain(); 123 124 PagedList<User> pagedList1 = observer.get(); 125 assertThat(pagedList1, is(notNullValue())); 126 127 assertThat(pagedList1.size(), is(96)); 128 assertThat(getAndLoad(pagedList1, 20), is(nullValue())); 129 drain(); 130 assertThat(getAndLoad(pagedList1, 31), nullValue()); 131 assertThat(getAndLoad(pagedList1, 20), notNullValue()); 132 assertThat(getAndLoad(pagedList1, 16), notNullValue()); 133 134 drain(); 135 assertThat(getAndLoad(pagedList1, 31), notNullValue()); 136 assertThat(getAndLoad(pagedList1, 50), nullValue()); 137 drain(); 138 assertThat(getAndLoad(pagedList1, 50), notNullValue()); 139 observer.reset(); 140 // now invalidate the database but don't get the new paged list 141 mUserDao.updateById(50, "foo"); 142 assertThat(getAndLoad(pagedList1, 70), nullValue()); 143 drain(); 144 assertThat(getAndLoad(pagedList1, 70), nullValue()); 145 PagedList<User> pagedList = observer.get(); 146 assertThat(getAndLoad(pagedList, 70), notNullValue()); 147 } 148 149 private <T> T getAndLoad(PagedList<T> list, int pos) { 150 T result = list.get(pos); 151 list.loadAround(pos); 152 return result; 153 } 154 155 private void drain() throws InterruptedException, TimeoutException { 156 mExecutorRule.drainTasks(60, TimeUnit.SECONDS); 157 } 158 159 private void observe(final LiveData liveData, final LifecycleOwner provider, 160 final Observer observer) throws ExecutionException, InterruptedException { 161 FutureTask<Void> futureTask = new FutureTask<>(() -> { 162 //noinspection unchecked 163 liveData.observe(provider, observer); 164 return null; 165 }); 166 ArchTaskExecutor.getInstance().executeOnMainThread(futureTask); 167 futureTask.get(); 168 } 169 170 @Test 171 public void withRelation() throws ExecutionException, InterruptedException, TimeoutException { 172 // verify DataSourceFactory can be created from a multi table join 173 DataSource.Factory<Integer, UserAndAllPets> factory = 174 mUserPetDao.dataSourceFactoryMultiTable(); 175 LiveData<PagedList<UserAndAllPets>> liveData = 176 new LivePagedListBuilder<>(mUserPetDao.dataSourceFactoryMultiTable(), 10).build(); 177 assertNotNull(factory.create()); 178 179 PagedListObserver<UserAndAllPets> observer = new PagedListObserver<>(); 180 final TestLifecycleOwner lifecycleOwner = new TestLifecycleOwner(); 181 lifecycleOwner.handleEvent(Lifecycle.Event.ON_START); 182 observe(liveData, lifecycleOwner, observer); 183 drain(); 184 assertThat(observer.get(), is(Collections.emptyList())); 185 186 observer.reset(); 187 User user = TestUtil.createUser(3); 188 mUserDao.insert(user); 189 drain(); 190 final UserAndAllPets noPets = observer.get().get(0); 191 assertThat(noPets.user, is(user)); 192 193 observer.reset(); 194 Pet[] pets = TestUtil.createPetsForUser(3, 1, 2); 195 mPetDao.insertAll(pets); 196 197 drain(); 198 final UserAndAllPets withPets = observer.get().get(0); 199 assertThat(withPets.user, is(user)); 200 assertThat(withPets.pets, is(Arrays.asList(pets))); 201 } 202 203 static class TestLifecycleOwner implements LifecycleOwner { 204 205 private LifecycleRegistry mLifecycle; 206 207 TestLifecycleOwner() { 208 mLifecycle = new LifecycleRegistry(this); 209 } 210 211 @Override 212 public Lifecycle getLifecycle() { 213 return mLifecycle; 214 } 215 216 void handleEvent(Lifecycle.Event event) { 217 mLifecycle.handleLifecycleEvent(event); 218 } 219 } 220 221 private static class PagedListObserver<T> implements Observer<PagedList<T>> { 222 private PagedList<T> mList; 223 224 void reset() { 225 mList = null; 226 } 227 228 public PagedList<T> get() { 229 return mList; 230 } 231 232 @Override 233 public void onChanged(@Nullable PagedList<T> pagedList) { 234 mList = pagedList; 235 } 236 } 237} 238