1cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla/*
2ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas * Copyright 2018 The Android Open Source Project
3cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla *
4ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas * Licensed under the Apache License, Version 2.0 (the "License");
5ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas * you may not use this file except in compliance with the License.
6ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas * You may obtain a copy of the License at
7cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla *
8cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla *      http://www.apache.org/licenses/LICENSE-2.0
9cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla *
10ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas * Unless required by applicable law or agreed to in writing, software
11ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas * distributed under the License is distributed on an "AS IS" BASIS,
12ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas * See the License for the specific language governing permissions and
14ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas * limitations under the License.
15cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla */
16cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla
17ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.collection;
18cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla
19cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shuklaimport static org.junit.Assert.fail;
20cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla
21cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shuklaimport org.junit.Test;
22cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla
23cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shuklaimport java.util.ConcurrentModificationException;
244328b29e10111ed2f6325a740a777ed5c0eb23aaAurimas Liutikasimport java.util.Locale;
25cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla
26cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla/**
27cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla * Unit tests for SimpleArrayMap
28cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla */
29cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shuklapublic class SimpleArrayMapTest {
30cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla    SimpleArrayMap<String, String> map = new SimpleArrayMap<>();
31a4f98193a1efa5a2de25451f59af4b91547974c2Suprabh Shukla    private boolean mDone;
32cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla
33cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla    /**
34cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla     * Attempt to generate a ConcurrentModificationException in ArrayMap.
35cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla     */
36cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla    @Test
37cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla    public void testConcurrentModificationException() throws Exception {
38cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla        final int TEST_LEN_MS = 5000;
39df3c42068dd979a9738c3dad87fa3165b61bb8a3Jake Wharton        System.out.println("Starting SimpleArrayMap concurrency test");
40a4f98193a1efa5a2de25451f59af4b91547974c2Suprabh Shukla        mDone = false;
41cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla        new Thread(new Runnable() {
42cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla            @Override
43cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla            public void run() {
44cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla                int i = 0;
45a4f98193a1efa5a2de25451f59af4b91547974c2Suprabh Shukla                while (!mDone) {
46cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla                    try {
474328b29e10111ed2f6325a740a777ed5c0eb23aaAurimas Liutikas                        map.put(String.format(Locale.US, "key %d", i++), "B_DONT_DO_THAT");
48cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla                    } catch (ArrayIndexOutOfBoundsException e) {
49cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla                        // SimpleArrayMap is not thread safe, so lots of concurrent modifications
50cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla                        // can still cause data corruption
51df3c42068dd979a9738c3dad87fa3165b61bb8a3Jake Wharton                        System.err.println("concurrent modification uncaught, causing indexing failure");
52df3c42068dd979a9738c3dad87fa3165b61bb8a3Jake Wharton                        e.printStackTrace();
53cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla                    } catch (ClassCastException e) {
54cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla                        // cache corruption should not occur as it is hard to trace and one thread
55cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla                        // may corrupt the pool for all threads in the same process.
56df3c42068dd979a9738c3dad87fa3165b61bb8a3Jake Wharton                        System.err.println("concurrent modification uncaught, causing cache corruption");
57df3c42068dd979a9738c3dad87fa3165b61bb8a3Jake Wharton                        e.printStackTrace();
58cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla                        fail();
59cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla                    } catch (ConcurrentModificationException e) {
60cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla                    }
61cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla                }
62cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla            }
63cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla        }).start();
64cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla        for (int i = 0; i < (TEST_LEN_MS / 100); i++) {
65cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla            try {
66cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla                Thread.sleep(100);
67cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla                map.clear();
68cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla            } catch (InterruptedException e) {
69cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla            } catch (ArrayIndexOutOfBoundsException e) {
70df3c42068dd979a9738c3dad87fa3165b61bb8a3Jake Wharton                System.err.println("concurrent modification uncaught, causing indexing failure");
71cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla            } catch (ClassCastException e) {
72df3c42068dd979a9738c3dad87fa3165b61bb8a3Jake Wharton                System.err.println("concurrent modification uncaught, causing cache corruption");
73cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla                fail();
74cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla            } catch (ConcurrentModificationException e) {
75cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla            }
76cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla        }
77a4f98193a1efa5a2de25451f59af4b91547974c2Suprabh Shukla        mDone = true;
78cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla    }
79cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla
80cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla    /**
81cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla     * Check to make sure the same operations behave as expected in a single thread.
82cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla     */
83cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla    @Test
84cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla    public void testNonConcurrentAccesses() throws Exception {
85cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla        for (int i = 0; i < 100000; i++) {
86cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla            try {
874328b29e10111ed2f6325a740a777ed5c0eb23aaAurimas Liutikas                map.put(String.format(Locale.US, "key %d", i++), "B_DONT_DO_THAT");
88cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla                if (i % 500 == 0) {
89cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla                    map.clear();
90cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla                }
91cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla            } catch (ConcurrentModificationException e) {
92df3c42068dd979a9738c3dad87fa3165b61bb8a3Jake Wharton                System.err.println("Concurrent modification caught on single thread");
93df3c42068dd979a9738c3dad87fa3165b61bb8a3Jake Wharton                e.printStackTrace();
94cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla                fail();
95cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla            }
96cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla        }
97cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla    }
98cde1e1ab92ed386095d847fcb6d04b699e60ff8dSuprabh Shukla}
99