SimpleArrayMapTest.java revision a4f98193a1efa5a2de25451f59af4b91547974c2
1869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen/*
2869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen * Copyright (C) 2017 The Android Open Source Project
3869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen *
4869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen * except in compliance with the License. You may obtain a copy of the License at
6869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen *
7869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen *      http://www.apache.org/licenses/LICENSE-2.0
8869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen *
9869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen * Unless required by applicable law or agreed to in writing, software distributed under the
10869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen * KIND, either express or implied. See the License for the specific language governing
12869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen * permissions and limitations under the License.
13869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen */
14869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen
15869868be653cb8eedd338e8347dfee1520d38cecPaul Jensenpackage android.support.v4.util;
16869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen
17869868be653cb8eedd338e8347dfee1520d38cecPaul Jensenimport static org.junit.Assert.fail;
18869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen
19869868be653cb8eedd338e8347dfee1520d38cecPaul Jensenimport android.support.test.filters.SmallTest;
2088eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensenimport android.support.test.runner.AndroidJUnit4;
2188eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensenimport android.util.Log;
22869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen
23869868be653cb8eedd338e8347dfee1520d38cecPaul Jensenimport org.junit.Test;
2449e3edff5156f471819e4ea2a88994bca70bd870Paul Jensenimport org.junit.runner.RunWith;
25869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen
268df099df1516d23c113be3121635dcd34984a4a0Paul Jensenimport java.util.ConcurrentModificationException;
27869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen
288df099df1516d23c113be3121635dcd34984a4a0Paul Jensen/**
293a222974e9cdbb120d22c439580401a5d63b51b2Hugo Benichi * Unit tests for SimpleArrayMap
308df099df1516d23c113be3121635dcd34984a4a0Paul Jensen */
3188eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen@RunWith(AndroidJUnit4.class)
3288eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen@SmallTest
33fc8022f8cfffded3d94baef3ba5e5ce936799b06Paul Jensenpublic class SimpleArrayMapTest {
3412df465997c1be51c6802acad2dcf20f010c3576Hugo Benichi    private static final String TAG = "SimpleArrayMapTest";
35869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen    SimpleArrayMap<String, String> map = new SimpleArrayMap<>();
36869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen    private boolean mDone;
3794bc48f7bbff4772de967bcfc3effd4f710503c2Chalard Jean
3888eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen    /**
3988eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen     * Attempt to generate a ConcurrentModificationException in ArrayMap.
4065636fb23c86e546dc4ce584481fa58bf72e4945Paul Jensen     */
4104d78601ab0bbf7deee9ef97526fd9d45587aec1Hugo Benichi    @Test
42869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen    public void testConcurrentModificationException() throws Exception {
43869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen        final int TEST_LEN_MS = 5000;
44a206649a6f66f16cc56db2f4e32b846d9b03501cHugo Benichi        Log.d(TAG, "Starting SimpleArrayMap concurrency test");
45c3c95bab8ec7f3ef4e7649b5d24ea6525a407c44Lorenzo Colitti        mDone = false;
46fc8022f8cfffded3d94baef3ba5e5ce936799b06Paul Jensen        new Thread(new Runnable() {
47869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen            @Override
48869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen            public void run() {
49869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen                int i = 0;
5004d78601ab0bbf7deee9ef97526fd9d45587aec1Hugo Benichi                while (!mDone) {
51869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen                    try {
528f333f19222ac9415152e31f10e0df2b571b0b77Paul Jensen                        map.put(String.format("key %d", i++), "B_DONT_DO_THAT");
535344a4abdf239a19485a9c858b6cc3be96002eacPaul Jensen                    } catch (ArrayIndexOutOfBoundsException e) {
54869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen                        // SimpleArrayMap is not thread safe, so lots of concurrent modifications
559e8ab43ab22555acff9fefca2ed433425c92fb87Hugo Benichi                        // can still cause data corruption
569e8ab43ab22555acff9fefca2ed433425c92fb87Hugo Benichi                        Log.w(TAG, "concurrent modification uncaught, causing indexing failure", e);
579e8ab43ab22555acff9fefca2ed433425c92fb87Hugo Benichi                    } catch (ClassCastException e) {
58869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen                        // cache corruption should not occur as it is hard to trace and one thread
59869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen                        // may corrupt the pool for all threads in the same process.
60869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen                        Log.e(TAG, "concurrent modification uncaught, causing cache corruption", e);
61869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen                        fail();
62869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen                    } catch (ConcurrentModificationException e) {
6388eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen                    }
6488eb0fa8eec7da1b7a3bd39f9d9844909911bc64Paul Jensen                }
6512df465997c1be51c6802acad2dcf20f010c3576Hugo Benichi            }
6665636fb23c86e546dc4ce584481fa58bf72e4945Paul Jensen        }).start();
67a173a63a6cf9c94c511d14d75648f55525ce7006Hugo Benichi        for (int i = 0; i < (TEST_LEN_MS / 100); i++) {
68869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen            try {
69869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen                Thread.sleep(100);
707f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi                map.clear();
717f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi            } catch (InterruptedException e) {
7260d5f46d89038a6a46c38ac0e57d0762a67732cbHugo Benichi            } catch (ArrayIndexOutOfBoundsException e) {
737f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi                Log.w(TAG, "concurrent modification uncaught, causing indexing failure");
74869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen            } catch (ClassCastException e) {
75869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen                Log.e(TAG, "concurrent modification uncaught, causing cache corruption");
769e8ab43ab22555acff9fefca2ed433425c92fb87Hugo Benichi                fail();
779e8ab43ab22555acff9fefca2ed433425c92fb87Hugo Benichi            } catch (ConcurrentModificationException e) {
789e8ab43ab22555acff9fefca2ed433425c92fb87Hugo Benichi            }
799e8ab43ab22555acff9fefca2ed433425c92fb87Hugo Benichi        }
809e8ab43ab22555acff9fefca2ed433425c92fb87Hugo Benichi        mDone = true;
819e8ab43ab22555acff9fefca2ed433425c92fb87Hugo Benichi    }
829e8ab43ab22555acff9fefca2ed433425c92fb87Hugo Benichi
839e8ab43ab22555acff9fefca2ed433425c92fb87Hugo Benichi    /**
84869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen     * Check to make sure the same operations behave as expected in a single thread.
857f086e162b9000fd471f3450ae53fe1261f58993Hugo Benichi     */
862c02197bdd12378c7b2f8ee4bcaa625b2c564edeHugo Benichi    @Test
8725a217c0fbda9bbaf58ec08b91115e99f73b727fPaul Jensen    public void testNonConcurrentAccesses() throws Exception {
8849e3edff5156f471819e4ea2a88994bca70bd870Paul Jensen        for (int i = 0; i < 100000; i++) {
898df099df1516d23c113be3121635dcd34984a4a0Paul Jensen            try {
9025a217c0fbda9bbaf58ec08b91115e99f73b727fPaul Jensen                map.put(String.format("key %d", i++), "B_DONT_DO_THAT");
9165636fb23c86e546dc4ce584481fa58bf72e4945Paul Jensen                if (i % 500 == 0) {
92e836b6847af968460f36a4e6649b8cb6f6da18dbPaul Jensen                    map.clear();
9394bc48f7bbff4772de967bcfc3effd4f710503c2Chalard Jean                }
94a173a63a6cf9c94c511d14d75648f55525ce7006Hugo Benichi            } catch (ConcurrentModificationException e) {
95a173a63a6cf9c94c511d14d75648f55525ce7006Hugo Benichi                Log.e(TAG, "concurrent modification caught on single thread", e);
96869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen                fail();
97869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen            }
98869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen        }
99869868be653cb8eedd338e8347dfee1520d38cecPaul Jensen    }
1009e8ab43ab22555acff9fefca2ed433425c92fb87Hugo Benichi}
1019e8ab43ab22555acff9fefca2ed433425c92fb87Hugo Benichi