134e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar/*
234e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar * Copyright (C) 2017 The Android Open Source Project
334e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar *
434e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License");
534e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar * you may not use this file except in compliance with the License.
634e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar * You may obtain a copy of the License at
734e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar *
834e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar *      http://www.apache.org/licenses/LICENSE-2.0
934e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar *
1034e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar * Unless required by applicable law or agreed to in writing, software
1134e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS,
1234e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1334e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar * See the License for the specific language governing permissions and
1434e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar * limitations under the License.
1534e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar */
1634e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar
17ba069d50913c3fb250bb60ec310439db36895337Alan Viverettepackage androidx.room.integration.testapp.test;
1834e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar
192ec1285ef79d4849069efe95cfbac2307d291a47Yuichi Arakiimport static org.hamcrest.CoreMatchers.hasItem;
20d2cdfecb16af89f7b6a92d95f8854b261d2c6c0cYigit Boyarimport static org.hamcrest.CoreMatchers.nullValue;
2134e5031083f735db3a395b0f6aa430880b072d71Yigit Boyarimport static org.hamcrest.MatcherAssert.assertThat;
222ec1285ef79d4849069efe95cfbac2307d291a47Yuichi Arakiimport static org.hamcrest.collection.IsCollectionWithSize.hasSize;
2334e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar
242ec1285ef79d4849069efe95cfbac2307d291a47Yuichi Arakiimport android.content.Context;
252ec1285ef79d4849069efe95cfbac2307d291a47Yuichi Arakiimport android.support.test.InstrumentationRegistry;
262ec1285ef79d4849069efe95cfbac2307d291a47Yuichi Arakiimport android.support.test.filters.SmallTest;
272ec1285ef79d4849069efe95cfbac2307d291a47Yuichi Arakiimport android.support.test.runner.AndroidJUnit4;
2834e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar
29ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.annotation.NonNull;
30ddee2b5170ae257a7b2494f8aaa8459ebed806dcAurimas Liutikasimport androidx.arch.core.executor.testing.CountingTaskExecutorRule;
31ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.room.InvalidationTracker;
32ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.room.Room;
33ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.room.integration.testapp.TestDatabase;
34ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.room.integration.testapp.dao.UserDao;
35ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.room.integration.testapp.vo.User;
36ba069d50913c3fb250bb60ec310439db36895337Alan Viverette
37abd1282bf69658247b310982d529aa48a9466cf4Yigit Boyarimport org.junit.After;
3834e5031083f735db3a395b0f6aa430880b072d71Yigit Boyarimport org.junit.Before;
39d2cdfecb16af89f7b6a92d95f8854b261d2c6c0cYigit Boyarimport org.junit.Rule;
4034e5031083f735db3a395b0f6aa430880b072d71Yigit Boyarimport org.junit.Test;
4134e5031083f735db3a395b0f6aa430880b072d71Yigit Boyarimport org.junit.runner.RunWith;
4234e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar
432ec1285ef79d4849069efe95cfbac2307d291a47Yuichi Arakiimport java.util.Set;
4434e5031083f735db3a395b0f6aa430880b072d71Yigit Boyarimport java.util.concurrent.TimeUnit;
45d2cdfecb16af89f7b6a92d95f8854b261d2c6c0cYigit Boyarimport java.util.concurrent.TimeoutException;
4634e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar
4734e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar/**
4834e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar * Tests invalidation tracking.
4934e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar */
5034e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar@SmallTest
5134e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar@RunWith(AndroidJUnit4.class)
5234e5031083f735db3a395b0f6aa430880b072d71Yigit Boyarpublic class InvalidationTest {
53d2cdfecb16af89f7b6a92d95f8854b261d2c6c0cYigit Boyar    @Rule
54d2cdfecb16af89f7b6a92d95f8854b261d2c6c0cYigit Boyar    public CountingTaskExecutorRule executorRule = new CountingTaskExecutorRule();
5534e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    private UserDao mUserDao;
5634e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    private TestDatabase mDb;
5734e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar
5834e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    @Before
59d2cdfecb16af89f7b6a92d95f8854b261d2c6c0cYigit Boyar    public void createDb() throws TimeoutException, InterruptedException {
6034e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        Context context = InstrumentationRegistry.getTargetContext();
6134e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        mDb = Room.inMemoryDatabaseBuilder(context, TestDatabase.class).build();
6234e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        mUserDao = mDb.getUserDao();
63d2cdfecb16af89f7b6a92d95f8854b261d2c6c0cYigit Boyar        drain();
64abd1282bf69658247b310982d529aa48a9466cf4Yigit Boyar    }
65abd1282bf69658247b310982d529aa48a9466cf4Yigit Boyar
66abd1282bf69658247b310982d529aa48a9466cf4Yigit Boyar    @After
67d2cdfecb16af89f7b6a92d95f8854b261d2c6c0cYigit Boyar    public void closeDb() throws TimeoutException, InterruptedException {
68d2cdfecb16af89f7b6a92d95f8854b261d2c6c0cYigit Boyar        mDb.close();
69d2cdfecb16af89f7b6a92d95f8854b261d2c6c0cYigit Boyar        drain();
70abd1282bf69658247b310982d529aa48a9466cf4Yigit Boyar    }
71abd1282bf69658247b310982d529aa48a9466cf4Yigit Boyar
72d2cdfecb16af89f7b6a92d95f8854b261d2c6c0cYigit Boyar    private void drain() throws TimeoutException, InterruptedException {
73d2cdfecb16af89f7b6a92d95f8854b261d2c6c0cYigit Boyar        executorRule.drainTasks(1, TimeUnit.MINUTES);
7434e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    }
7534e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar
7634e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    @Test
77d2cdfecb16af89f7b6a92d95f8854b261d2c6c0cYigit Boyar    public void testInvalidationOnUpdate() throws InterruptedException, TimeoutException {
7834e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        User user = TestUtil.createUser(3);
7934e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        mUserDao.insert(user);
80d2cdfecb16af89f7b6a92d95f8854b261d2c6c0cYigit Boyar        LoggingObserver observer = new LoggingObserver("User");
8134e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        mDb.getInvalidationTracker().addObserver(observer);
82d2cdfecb16af89f7b6a92d95f8854b261d2c6c0cYigit Boyar        drain();
8334e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        mUserDao.updateById(3, "foo2");
84d2cdfecb16af89f7b6a92d95f8854b261d2c6c0cYigit Boyar        drain();
852ec1285ef79d4849069efe95cfbac2307d291a47Yuichi Araki        assertThat(observer.getInvalidatedTables(), hasSize(1));
862ec1285ef79d4849069efe95cfbac2307d291a47Yuichi Araki        assertThat(observer.getInvalidatedTables(), hasItem("User"));
8734e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    }
8834e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar
8934e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    @Test
90d2cdfecb16af89f7b6a92d95f8854b261d2c6c0cYigit Boyar    public void testInvalidationOnDelete() throws InterruptedException, TimeoutException {
9134e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        User user = TestUtil.createUser(3);
9234e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        mUserDao.insert(user);
93d2cdfecb16af89f7b6a92d95f8854b261d2c6c0cYigit Boyar        LoggingObserver observer = new LoggingObserver("User");
9434e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        mDb.getInvalidationTracker().addObserver(observer);
95d2cdfecb16af89f7b6a92d95f8854b261d2c6c0cYigit Boyar        drain();
9634e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        mUserDao.delete(user);
97d2cdfecb16af89f7b6a92d95f8854b261d2c6c0cYigit Boyar        drain();
982ec1285ef79d4849069efe95cfbac2307d291a47Yuichi Araki        assertThat(observer.getInvalidatedTables(), hasSize(1));
992ec1285ef79d4849069efe95cfbac2307d291a47Yuichi Araki        assertThat(observer.getInvalidatedTables(), hasItem("User"));
10034e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    }
10134e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar
10234e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    @Test
103d2cdfecb16af89f7b6a92d95f8854b261d2c6c0cYigit Boyar    public void testInvalidationOnInsert() throws InterruptedException, TimeoutException {
104d2cdfecb16af89f7b6a92d95f8854b261d2c6c0cYigit Boyar        LoggingObserver observer = new LoggingObserver("User");
10534e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        mDb.getInvalidationTracker().addObserver(observer);
106d2cdfecb16af89f7b6a92d95f8854b261d2c6c0cYigit Boyar        drain();
10734e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        mUserDao.insert(TestUtil.createUser(3));
108d2cdfecb16af89f7b6a92d95f8854b261d2c6c0cYigit Boyar        drain();
1092ec1285ef79d4849069efe95cfbac2307d291a47Yuichi Araki        assertThat(observer.getInvalidatedTables(), hasSize(1));
1102ec1285ef79d4849069efe95cfbac2307d291a47Yuichi Araki        assertThat(observer.getInvalidatedTables(), hasItem("User"));
11134e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    }
11234e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar
11334e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    @Test
114d2cdfecb16af89f7b6a92d95f8854b261d2c6c0cYigit Boyar    public void testDontInvalidateOnLateInsert() throws InterruptedException, TimeoutException {
115d2cdfecb16af89f7b6a92d95f8854b261d2c6c0cYigit Boyar        LoggingObserver observer = new LoggingObserver("User");
11634e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        mUserDao.insert(TestUtil.createUser(3));
117d2cdfecb16af89f7b6a92d95f8854b261d2c6c0cYigit Boyar        drain();
11834e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        mDb.getInvalidationTracker().addObserver(observer);
119d2cdfecb16af89f7b6a92d95f8854b261d2c6c0cYigit Boyar        drain();
120d2cdfecb16af89f7b6a92d95f8854b261d2c6c0cYigit Boyar        assertThat(observer.getInvalidatedTables(), nullValue());
12134e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    }
12234e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar
12308385cfa2c450904f437f8361ec3d3553834989bYuichi Araki    @Test
124d2cdfecb16af89f7b6a92d95f8854b261d2c6c0cYigit Boyar    public void testMultipleTables() throws InterruptedException, TimeoutException {
125d2cdfecb16af89f7b6a92d95f8854b261d2c6c0cYigit Boyar        LoggingObserver observer = new LoggingObserver("User", "Pet");
12608385cfa2c450904f437f8361ec3d3553834989bYuichi Araki        mDb.getInvalidationTracker().addObserver(observer);
127d2cdfecb16af89f7b6a92d95f8854b261d2c6c0cYigit Boyar        drain();
12808385cfa2c450904f437f8361ec3d3553834989bYuichi Araki        mUserDao.insert(TestUtil.createUser(3));
129d2cdfecb16af89f7b6a92d95f8854b261d2c6c0cYigit Boyar        drain();
13008385cfa2c450904f437f8361ec3d3553834989bYuichi Araki        assertThat(observer.getInvalidatedTables(), hasSize(1));
13108385cfa2c450904f437f8361ec3d3553834989bYuichi Araki        assertThat(observer.getInvalidatedTables(), hasItem("User"));
13208385cfa2c450904f437f8361ec3d3553834989bYuichi Araki    }
13308385cfa2c450904f437f8361ec3d3553834989bYuichi Araki
134d2cdfecb16af89f7b6a92d95f8854b261d2c6c0cYigit Boyar    private static class LoggingObserver extends InvalidationTracker.Observer {
1352ec1285ef79d4849069efe95cfbac2307d291a47Yuichi Araki        private Set<String> mInvalidatedTables;
1362ec1285ef79d4849069efe95cfbac2307d291a47Yuichi Araki
137d2cdfecb16af89f7b6a92d95f8854b261d2c6c0cYigit Boyar        LoggingObserver(String... tables) {
13834e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar            super(tables);
13934e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        }
14034e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar
14134e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        @Override
1422ec1285ef79d4849069efe95cfbac2307d291a47Yuichi Araki        public void onInvalidated(@NonNull Set<String> tables) {
1432ec1285ef79d4849069efe95cfbac2307d291a47Yuichi Araki            mInvalidatedTables = tables;
14434e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        }
1452ec1285ef79d4849069efe95cfbac2307d291a47Yuichi Araki
1462ec1285ef79d4849069efe95cfbac2307d291a47Yuichi Araki        Set<String> getInvalidatedTables() {
1472ec1285ef79d4849069efe95cfbac2307d291a47Yuichi Araki            return mInvalidatedTables;
1482ec1285ef79d4849069efe95cfbac2307d291a47Yuichi Araki        }
14934e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    }
15034e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar}
151