001package ca.uhn.fhir.util; 002 003/* 004 * #%L 005 * HAPI FHIR - Core Library 006 * %% 007 * Copyright (C) 2014 - 2022 Smile CDR, Inc. 008 * %% 009 * Licensed under the Apache License, Version 2.0 (the "License"); 010 * you may not use this file except in compliance with the License. 011 * You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, software 016 * distributed under the License is distributed on an "AS IS" BASIS, 017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 018 * See the License for the specific language governing permissions and 019 * limitations under the License. 020 * #L% 021 */ 022 023import ca.uhn.fhir.i18n.HapiLocalizer; 024 025import java.util.Locale; 026import java.util.TimeZone; 027import java.util.concurrent.Callable; 028import java.util.concurrent.atomic.AtomicInteger; 029 030import static org.apache.commons.lang3.StringUtils.defaultString; 031 032public class TestUtil { 033 private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TestUtil.class); 034 private static boolean ourShouldRandomizeTimezones = true; 035 036 public static void setShouldRandomizeTimezones(boolean theShouldRandomizeTimezones) { 037 ourShouldRandomizeTimezones = theShouldRandomizeTimezones; 038 } 039 040 /** 041 * <b>THIS IS FOR UNIT TESTS ONLY - DO NOT CALL THIS METHOD FROM USER CODE</b> 042 * <p> 043 * When we run the unit tests in cobertura, JUnit doesn't seem to clean up static fields which leads to 044 * tons of memory being used by the end and the JVM crashes in Travis. Manually clearing all of the 045 * static fields seems to solve this. 046 */ 047 public static void randomizeLocaleAndTimezone() { 048 HapiLocalizer.setOurFailOnMissingMessage(true); 049 050 doRandomizeLocaleAndTimezone(); 051 } 052 053 /** 054 * Set some system properties randomly after each test.. this is kind of hackish, 055 * but it helps us make sure we don't have any tests that depend on a particular 056 * environment 057 */ 058 public static void doRandomizeLocaleAndTimezone() { 059// Locale[] availableLocales = {Locale.CANADA, Locale.GERMANY, Locale.TAIWAN}; 060 Locale[] availableLocales = {Locale.US}; 061 Locale.setDefault(availableLocales[(int) (Math.random() * availableLocales.length)]); 062 ourLog.info("Tests are running in locale: " + Locale.getDefault().getDisplayName()); 063 if (Math.random() < 0.5) { 064 ourLog.info("Tests are using WINDOWS line endings and ISO-8851-1"); 065 System.setProperty("file.encoding", "ISO-8859-1"); 066 System.setProperty("line.separator", "\r\n"); 067 } else { 068 ourLog.info("Tests are using UNIX line endings and UTF-8"); 069 System.setProperty("file.encoding", "UTF-8"); 070 System.setProperty("line.separator", "\n"); 071 } 072 073 if (ourShouldRandomizeTimezones) { 074 String availableTimeZones[] = {"GMT+08:00", "GMT-05:00", "GMT+00:00", "GMT+03:30"}; 075 String timeZone = availableTimeZones[(int) (Math.random() * availableTimeZones.length)]; 076 TimeZone.setDefault(TimeZone.getTimeZone(timeZone)); 077 } 078 079 ourLog.info("Tests are using time zone: {}", TimeZone.getDefault().getID()); 080 } 081 082 083 /** 084 * <b>THIS IS FOR UNIT TESTS ONLY - DO NOT CALL THIS METHOD FROM USER CODE</b> 085 * <p> 086 * Wait for an atomicinteger to hit a given site and fail if it never does 087 */ 088 public static void waitForSize(int theTarget, AtomicInteger theInteger) { 089 long start = System.currentTimeMillis(); 090 while (theInteger.get() != theTarget && (System.currentTimeMillis() - start) <= 15000) { 091 try { 092 Thread.sleep(50); 093 } catch (InterruptedException theE) { 094 throw new Error(theE); 095 } 096 } 097 if ((System.currentTimeMillis() - start) >= 15000) { 098 throw new IllegalStateException("Size " + theInteger.get() + " is != target " + theTarget); 099 } 100 } 101 102 /** 103 * <b>THIS IS FOR UNIT TESTS ONLY - DO NOT CALL THIS METHOD FROM USER CODE</b> 104 * <p> 105 * Wait for an atomicinteger to hit a given site and fail if it never does 106 */ 107 public static void waitForSize(int theTarget, Callable<Integer> theSource) throws Exception { 108 long start = System.currentTimeMillis(); 109 while (theSource.call() != theTarget && (System.currentTimeMillis() - start) <= 15000) { 110 try { 111 Thread.sleep(50); 112 } catch (InterruptedException theE) { 113 throw new Error(theE); 114 } 115 } 116 if ((System.currentTimeMillis() - start) >= 15000) { 117 throw new IllegalStateException("Size " + theSource.call() + " is != target " + theTarget); 118 } 119 } 120 121 /** 122 * <b>THIS IS FOR UNIT TESTS ONLY - DO NOT CALL THIS METHOD FROM USER CODE</b> 123 * <p> 124 * Strip \r chars from a string to account for line ending platform differences 125 */ 126 public static String stripReturns(String theString) { 127 return defaultString(theString).replace("\r", ""); 128 } 129 130 /** 131 * <b>THIS IS FOR UNIT TESTS ONLY - DO NOT CALL THIS METHOD FROM USER CODE</b> 132 * <p> 133 * Strip \r chars from a string to account for line ending platform differences 134 */ 135 public static String stripWhitespace(String theString) { 136 return stripReturns(theString).replace(" ", ""); 137 } 138 139 public static void sleepAtLeast(long theMillis) { 140 sleepAtLeast(theMillis, true); 141 } 142 143 144 @SuppressWarnings("BusyWait") 145 public static void sleepAtLeast(long theMillis, boolean theLogProgress) { 146 long start = System.currentTimeMillis(); 147 while (System.currentTimeMillis() <= start + theMillis) { 148 try { 149 long timeSinceStarted = System.currentTimeMillis() - start; 150 long timeToSleep = Math.max(0, theMillis - timeSinceStarted); 151 if (theLogProgress) { 152 ourLog.info("Sleeping for {}ms", timeToSleep); 153 } 154 Thread.sleep(timeToSleep); 155 } catch (InterruptedException e) { 156 Thread.currentThread().interrupt(); 157 ourLog.error("Interrupted", e); 158 } 159 } 160 } 161}