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