1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.commons.id.uuid.clock;
19
20 import junit.framework.TestCase;
21
22 import java.util.Arrays;
23
24 /**
25 * Unit tests for {@link SystemClockImplTest}.
26 *
27 * @author Commons-Id team
28 * @version $Revision: 480488 $ $Date: 2006-11-29 08:57:26 +0000 (Wed, 29 Nov 2006) $
29 */
30 public class ThreadClockImplTest extends TestCase {
31
32 /** Constant for System.property os.name */
33 public static final String SYS_OS_NAME_PROPERTY = "os.name";
34
35 /** Constant for Windows */
36 public static final String SYS_OS_WINDOWS = "Windows";
37
38 /** Indicates if the OS is windows */
39 private static boolean isWindows = false;
40
41 protected void setUp() throws Exception {
42 super.setUp();
43 if (System.getProperty(SYS_OS_NAME_PROPERTY).indexOf(SYS_OS_WINDOWS) > -1) {
44 isWindows = true;
45 }
46 }
47
48 /**
49 * Make sure that time stamps generated by concurrent threads
50 * are unique.
51 *
52 * @throws Exception a testing exception.
53 */
54 public void testUnique() throws Exception {
55 //Return if this is not Windows OS
56 if (!isWindows) {
57 return;
58 }
59
60 /*
61 * Number of timestamps to generate on each client
62 */
63 int iterations = 11000;
64
65 /*
66 * Number of client threads
67 */
68 int threadCount = 4;
69
70 // Launch threadCount client threads and set them
71 // off generating time stamps
72 long[][] threadTimes = new long[threadCount][iterations];
73 Thread[] clockClients = new Thread[threadCount];
74
75 for (int i = 0; i < threadCount; i++) {
76 clockClients[i] = new ClockClient(threadTimes[i], iterations);
77 clockClients[i].start();
78 }
79
80 // Wait until all the threads are done
81 boolean working = true;
82 while (working) {
83 working = false;
84 for (int i = 0; i < threadCount; i++) {
85 if (clockClients[i].isAlive()) {
86 working = true;
87 }
88 }
89 }
90
91 // Check for duplicates within each client
92 // Ridiculously inefficient, but effective -- sort and walk
93 for (int j = 0; j < threadTimes.length; j++) {
94 Arrays.sort(threadTimes[j]);
95 for (int i = 0; i < threadTimes.length - 1; i++) {
96 if (threadTimes[j][i] == threadTimes[j][i + 1]) {
97 fail( "Duplicate time stamps generated: " + threadTimes[j][i] + " " + i);
98 }
99 }
100 }
101 }
102
103 /**
104 * Make sure that generated time stamps are within expected ranges.
105 * Tolerance is now 1 seconds
106 *
107 * @throws Exception any test Exception.
108 */
109 public void testRange() throws Exception {
110 if (!isWindows) {
111 return;
112 }
113 long time = 0;
114 long baseTime = 0;
115 Clock c = new ThreadClockImpl();
116 for (int i = 0; i < 100; i++) {
117 Thread.currentThread().sleep(10);
118 for (int j = 0; j < 100; j++) {
119 try {
120 baseTime = System.currentTimeMillis();
121 time = c.getUUIDTime();
122 assertTrue( "Generated timestamp too large", time < ((baseTime + Clock.GREGORIAN_CHANGE_OFFSET + 1000)
123 * Clock.INTERVALS_PER_MILLI));
124
125 assertTrue("Generated timestamp too small", time > ((baseTime + Clock.GREGORIAN_CHANGE_OFFSET - 1000)
126 * Clock.INTERVALS_PER_MILLI));
127 } catch (OverClockedException oce) {
128 //Nothing to do
129 }
130 }
131 }
132 }
133
134 //--------------------------------------------------------------------------
135 /**
136 * Clock client thread
137 */
138 protected static class ClockClient extends Thread {
139 /** Counter for the number of over clockings */
140 private static int overClocks;
141
142 /** The clock instance to use */
143 private Clock c = new ThreadClockImpl();
144
145 /**
146 * Generated time stamps
147 */
148 protected long[] times;
149
150 /**
151 * Number of time stamps to generate on this thread
152 */
153 protected int iterations;
154
155 /**
156 * Constructor for the ClockClient thread.
157 *
158 * @param timez an array of times generated.
159 * @param iterationz the number of time stamps the generate.
160 */
161 ClockClient(long[] timez, int iterationz) {
162 super();
163 this.times = timez;
164 this.iterations = iterationz;
165 }
166
167 /**
168 * Run method of this thread generates n-iterations timestamps.
169 */
170 public void run() {
171 for (int i = 0; i < iterations;) {
172 try {
173 times[i] = c.getUUIDTime();
174 i++;
175 } catch (OverClockedException oce) {
176 overClocks++;
177 }
178 }
179 System.out.println("At End of this thread - Overclocks currently at: " + overClocks);
180 }
181 }
182 }