001package ca.uhn.fhir.util; 002 003/* 004 * #%L 005 * HAPI FHIR - Core Library 006 * %% 007 * Copyright (C) 2014 - 2017 University Health Network 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 java.lang.reflect.Field; 024import java.lang.reflect.Modifier; 025import java.util.Arrays; 026import java.util.Locale; 027import java.util.TimeZone; 028 029import org.slf4j.LoggerFactory; 030 031import ca.uhn.fhir.context.FhirContext; 032import ca.uhn.fhir.i18n.HapiLocalizer; 033import ch.qos.logback.classic.Level; 034import ch.qos.logback.classic.Logger; 035import ch.qos.logback.classic.LoggerContext; 036 037public class TestUtil { 038 private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TestUtil.class); 039 040 /** 041 * <b>THIS IS FOR UNIT TESTS ONLY - DO NOT CALL THIS METHOD FROM USER CODE</b> 042 * 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 clearAllStaticFieldsForUnitTest() { 048 HapiLocalizer.setOurFailOnMissingMessage(true); 049 050 Class<?> theType; 051 try { 052 throw new Exception(); 053 } catch (Exception e) { 054 StackTraceElement[] st = e.getStackTrace(); 055 StackTraceElement elem = st[1]; 056 String clazzName = elem.getClassName(); 057 try { 058 theType = Class.forName(clazzName); 059 } catch (ClassNotFoundException e1) { 060 throw new Error(e); 061 } 062 } 063 064 for (Field next : Arrays.asList(theType.getDeclaredFields())) { 065 if (Modifier.isStatic(next.getModifiers())) { 066 if (!Modifier.isFinal(next.getModifiers()) && !next.getType().isPrimitive()) { 067 ourLog.info("Clearing value of field: {}", next.toString()); 068 try { 069 next.setAccessible(true); 070 next.set(theType, null); 071 } catch (Exception e) { 072 throw new Error(e); 073 } 074 } 075 if (Modifier.isFinal(next.getModifiers())) { 076 if (next.getType().equals(FhirContext.class)) { 077 throw new Error("Test has final field of type FhirContext: " + next); 078 } 079 } 080 } 081 082 } 083 084 randomizeLocale(); 085 086 /* 087 * If we're running a CI build, set all loggers to TRACE level to ensure coverage 088 * on trace blocks 089 */ 090 try { 091 if ("true".equals(System.getProperty("ci"))) { 092 for (Logger next : ((LoggerContext) LoggerFactory.getILoggerFactory()).getLoggerList()) { 093 next.setLevel(Level.TRACE); 094 } 095 } 096 } catch (NoClassDefFoundError e) { 097 // ignore 098 } 099 } 100 101 /** 102 * Set some system properties randomly after each test.. this is kind of hackish, 103 * but it helps us make sure we don't have any tests that depend on a particular 104 * environment 105 */ 106 public static void randomizeLocale() { 107 Locale[] availableLocales = { Locale.CANADA, Locale.GERMANY, Locale.TAIWAN }; 108 Locale.setDefault(availableLocales[(int) (Math.random() * availableLocales.length)]); 109 ourLog.info("Tests are running in locale: " + Locale.getDefault().getDisplayName()); 110 if (Math.random() < 0.5) { 111 ourLog.info("Tests are using WINDOWS line endings and ISO-8851-1"); 112 System.setProperty("file.encoding", "ISO-8859-1"); 113 System.setProperty("line.separator", "\r\n"); 114 } else { 115 ourLog.info("Tests are using UNIX line endings and UTF-8"); 116 System.setProperty("file.encoding", "UTF-8"); 117 System.setProperty("line.separator", "\n"); 118 } 119 String availableTimeZones[] = { "GMT+08:00", "GMT-05:00", "GMT+00:00", "GMT+03:30" }; 120 String timeZone = availableTimeZones[(int) (Math.random() * availableTimeZones.length)]; 121 TimeZone.setDefault(TimeZone.getTimeZone(timeZone)); 122 ourLog.info("Tests are using time zone: {}", TimeZone.getDefault().getID()); 123 } 124 125}