Kaynağa Gözat

SONAR-9718 Fail with a clear message when sonar.projectDate is empty

tags/6.6-RC1
Julien HENRY 6 yıl önce
ebeveyn
işleme
f76f82c6ef

+ 11
- 9
server/sonar-server/src/main/java/org/sonar/server/issue/IssueQueryFactory.java Dosyayı Görüntüle

@@ -25,6 +25,9 @@ import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import java.time.Clock;
import java.time.OffsetDateTime;
import java.time.Period;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -40,12 +43,9 @@ import java.util.stream.Collectors;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.apache.commons.lang.BooleanUtils;
import org.joda.time.DateTime;
import org.joda.time.format.ISOPeriodFormat;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.server.ServerSide;
import org.sonar.api.utils.System2;
import org.sonar.api.web.UserRole;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
@@ -90,12 +90,12 @@ public class IssueQueryFactory {
private static final ComponentDto UNKNOWN_COMPONENT = new ComponentDto().setUuid(UNKNOWN).setProjectUuid(UNKNOWN);

private final DbClient dbClient;
private final System2 system;
private final Clock clock;
private final UserSession userSession;

public IssueQueryFactory(DbClient dbClient, System2 system, UserSession userSession) {
public IssueQueryFactory(DbClient dbClient, Clock clock, UserSession userSession) {
this.dbClient = dbClient;
this.system = system;
this.clock = clock;
this.userSession = userSession;
}

@@ -138,8 +138,10 @@ public class IssueQueryFactory {

Date actualCreatedAfter = createdAfter;
if (createdInLast != null) {
actualCreatedAfter = new DateTime(system.now()).minus(
ISOPeriodFormat.standard().parsePeriod("P" + createdInLast.toUpperCase(Locale.ENGLISH))).toDate();
actualCreatedAfter = Date.from(
OffsetDateTime.now(clock)
.minus(Period.parse("P" + createdInLast.toUpperCase(Locale.ENGLISH)))
.toInstant());
}
return actualCreatedAfter;
}
@@ -392,7 +394,7 @@ public class IssueQueryFactory {
return mainBranchProjectUuid == null ? componentDto.projectUuid() : mainBranchProjectUuid;
}

private static void setBranch(IssueQuery.Builder builder, ComponentDto component, @Nullable String branch){
private static void setBranch(IssueQuery.Builder builder, ComponentDto component, @Nullable String branch) {
builder.branchUuid(branch == null ? null : component.projectUuid());
builder.mainBranch(branch == null || !branch.equals(component.getBranch()));
}

+ 2
- 0
server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel1.java Dosyayı Görüntüle

@@ -19,6 +19,7 @@
*/
package org.sonar.server.platform.platformlevel;

import java.time.Clock;
import java.util.Properties;
import javax.annotation.Nullable;
import org.sonar.NetworkUtils;
@@ -101,6 +102,7 @@ public class PlatformLevel1 extends PlatformLevel {
TempFolderCleaner.class,
new TempFolderProvider(),
System2.INSTANCE,
Clock.systemDefaultZone(),

// user session
ThreadLocalUserSession.class,

+ 32
- 10
server/sonar-server/src/test/java/org/sonar/server/issue/IssueQueryFactoryTest.java Dosyayı Görüntüle

@@ -19,6 +19,8 @@
*/
package org.sonar.server.issue;

import java.time.Clock;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Date;
import org.junit.Rule;
@@ -27,7 +29,6 @@ import org.junit.rules.ExpectedException;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.System2;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.SnapshotDto;
@@ -59,8 +60,8 @@ public class IssueQueryFactoryTest {
@Rule
public DbTester db = DbTester.create();

private System2 system = mock(System2.class);
private IssueQueryFactory underTest = new IssueQueryFactory(db.getDbClient(), system, userSession);
private Clock clock = mock(Clock.class);
private IssueQueryFactory underTest = new IssueQueryFactory(db.getDbClient(), clock, userSession);

@Test
public void create_from_parameters() {
@@ -126,6 +127,26 @@ public class IssueQueryFactoryTest {
assertThat(query.createdBefore()).isEqualTo(DateUtils.parseDate("2013-04-18"));
}

@Test
public void creation_date_support_localdate() {
SearchWsRequest request = new SearchWsRequest()
.setCreatedAt("2013-04-16");

IssueQuery query = underTest.create(request);

assertThat(query.createdAt()).isEqualTo(DateUtils.parseDate("2013-04-16"));
}

@Test
public void creation_date_support_zoneddatetime() {
SearchWsRequest request = new SearchWsRequest()
.setCreatedAt("2013-04-16T09:08:24+0200");

IssueQuery query = underTest.create(request);

assertThat(query.createdAt()).isEqualTo(DateUtils.parseDateTime("2013-04-16T09:08:24+0200"));
}

@Test
public void add_unknown_when_no_component_found() {
SearchWsRequest request = new SearchWsRequest()
@@ -403,8 +424,8 @@ public class IssueQueryFactoryTest {
.setComponentKeys(singletonList(file.getKey()))
.setBranch(branch.getBranch())
.setOnComponentOnly(true)))
.extracting(IssueQuery::branchUuid, query -> new ArrayList<>(query.componentUuids()), IssueQuery::isMainBranch)
.containsOnly(branch.uuid(), singletonList(file.uuid()), false);
.extracting(IssueQuery::branchUuid, query -> new ArrayList<>(query.componentUuids()), IssueQuery::isMainBranch)
.containsOnly(branch.uuid(), singletonList(file.uuid()), false);
}

@Test
@@ -415,13 +436,13 @@ public class IssueQueryFactoryTest {
assertThat(underTest.create(new SearchWsRequest()
.setProjectKeys(singletonList(project.getKey()))
.setBranch("master")))
.extracting(IssueQuery::branchUuid, query -> new ArrayList<>(query.projectUuids()), IssueQuery::isMainBranch)
.containsOnly(project.uuid(), singletonList(project.uuid()), true);
.extracting(IssueQuery::branchUuid, query -> new ArrayList<>(query.projectUuids()), IssueQuery::isMainBranch)
.containsOnly(project.uuid(), singletonList(project.uuid()), true);
assertThat(underTest.create(new SearchWsRequest()
.setComponentKeys(singletonList(project.getKey()))
.setBranch("master")))
.extracting(IssueQuery::branchUuid, query -> new ArrayList<>(query.projectUuids()), IssueQuery::isMainBranch)
.containsOnly(project.uuid(), singletonList(project.uuid()), true);
.extracting(IssueQuery::branchUuid, query -> new ArrayList<>(query.projectUuids()), IssueQuery::isMainBranch)
.containsOnly(project.uuid(), singletonList(project.uuid()), true);
}

@Test
@@ -441,7 +462,8 @@ public class IssueQueryFactoryTest {
@Test
public void set_created_after_from_created_since() {
Date now = DateUtils.parseDateTime("2013-07-25T07:35:00+0100");
when(system.now()).thenReturn(now.getTime());
when(clock.instant()).thenReturn(now.toInstant());
when(clock.getZone()).thenReturn(ZoneOffset.UTC);
SearchWsRequest request = new SearchWsRequest()
.setCreatedInLast("1y2m3w4d");
assertThat(underTest.create(request).createdAfter()).isEqualTo(DateUtils.parseDateTime("2012-04-30T07:35:00+0100"));

+ 2
- 1
server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionComponentsTest.java Dosyayı Görüntüle

@@ -20,6 +20,7 @@
package org.sonar.server.issue.ws;

import java.io.IOException;
import java.time.Clock;
import java.util.Arrays;
import java.util.Date;
import org.junit.Rule;
@@ -93,7 +94,7 @@ public class SearchActionComponentsTest {
private IssueIndex issueIndex = new IssueIndex(es.client(), System2.INSTANCE, userSession, new AuthorizationTypeSupport(userSession));
private IssueIndexer issueIndexer = new IssueIndexer(es.client(), dbClient, new IssueIteratorFactory(dbClient));
private ViewIndexer viewIndexer = new ViewIndexer(dbClient, es.client());
private IssueQueryFactory issueQueryFactory = new IssueQueryFactory(dbClient, System2.INSTANCE, userSession);
private IssueQueryFactory issueQueryFactory = new IssueQueryFactory(dbClient, Clock.systemUTC(), userSession);
private IssueFieldsSetter issueFieldsSetter = new IssueFieldsSetter();
private IssueWorkflow issueWorkflow = new IssueWorkflow(new FunctionExecutor(issueFieldsSetter), issueFieldsSetter);
private SearchResponseLoader searchResponseLoader = new SearchResponseLoader(userSession, dbClient, new ActionFinder(userSession),

+ 4
- 2
server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionTest.java Dosyayı Görüntüle

@@ -19,6 +19,7 @@
*/
package org.sonar.server.issue.ws;

import java.time.Clock;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -95,10 +96,11 @@ public class SearchActionTest {
private DbSession session = db.getSession();
private IssueIndex issueIndex = new IssueIndex(es.client(), System2.INSTANCE, userSessionRule, new AuthorizationTypeSupport(userSessionRule));
private IssueIndexer issueIndexer = new IssueIndexer(es.client(), dbClient, new IssueIteratorFactory(dbClient));
private IssueQueryFactory issueQueryFactory = new IssueQueryFactory(dbClient, System2.INSTANCE, userSessionRule);
private IssueQueryFactory issueQueryFactory = new IssueQueryFactory(dbClient, Clock.systemUTC(), userSessionRule);
private IssueFieldsSetter issueFieldsSetter = new IssueFieldsSetter();
private IssueWorkflow issueWorkflow = new IssueWorkflow(new FunctionExecutor(issueFieldsSetter), issueFieldsSetter);
private SearchResponseLoader searchResponseLoader = new SearchResponseLoader(userSessionRule, dbClient, new ActionFinder(userSessionRule), new TransitionService(userSessionRule, issueWorkflow));
private SearchResponseLoader searchResponseLoader = new SearchResponseLoader(userSessionRule, dbClient, new ActionFinder(userSessionRule),
new TransitionService(userSessionRule, issueWorkflow));
private Languages languages = new Languages();
private SearchResponseFormat searchResponseFormat = new SearchResponseFormat(new Durations(), new WsResponseCommonFormat(languages), languages, new AvatarResolverImpl());
private WsActionTester ws = new WsActionTester(new SearchAction(userSessionRule, issueIndex, issueQueryFactory, searchResponseLoader, searchResponseFormat));

+ 1
- 2
server/sonar-server/src/test/java/org/sonar/server/util/RubyUtilsTest.java Dosyayı Görüntüle

@@ -24,7 +24,6 @@ import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.SonarException;

import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;
@@ -132,7 +131,7 @@ public class RubyUtilsTest {

@Test
public void toDate_bad_format() {
throwable.expect(SonarException.class);
throwable.expect(RuntimeException.class);

RubyUtils.toDate("01/02/2013");
}

+ 1
- 2
sonar-plugin-api/src/main/java/org/sonar/api/server/ws/Request.java Dosyayı Görüntüle

@@ -32,7 +32,6 @@ import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.SonarException;

import static com.google.common.base.Preconditions.checkArgument;
import static java.lang.String.format;
@@ -246,7 +245,7 @@ public abstract class Request {

try {
return DateUtils.parseDate(s);
} catch (SonarException notDateException) {
} catch (RuntimeException notDateException) {
throw new IllegalArgumentException(notDateException);
}
}

+ 109
- 77
sonar-plugin-api/src/main/java/org/sonar/api/utils/DateUtils.java Dosyayı Görüntüle

@@ -19,15 +19,13 @@
*/
package org.sonar.api.utils;

import java.io.NotSerializableException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.text.DateFormat;
import java.text.FieldPosition;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
@@ -44,26 +42,44 @@ public final class DateUtils {
public static final String DATE_FORMAT = "yyyy-MM-dd";
public static final String DATETIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ssZ";

private static final ThreadSafeDateFormat THREAD_SAFE_DATE_FORMAT = new ThreadSafeDateFormat(DATE_FORMAT);
private static final ThreadSafeDateFormat THREAD_SAFE_DATETIME_FORMAT = new ThreadSafeDateFormat(DATETIME_FORMAT);
private static final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern(DATETIME_FORMAT);

private DateUtils() {
}

/**
* Warning: relies on default timezone!
*/
public static String formatDate(Date d) {
return THREAD_SAFE_DATE_FORMAT.format(d);
return d.toInstant().atZone(ZoneId.systemDefault()).toLocalDate().toString();
}

/**
* Warning: relies on default timezone!
*/
public static String formatDateTime(Date d) {
return THREAD_SAFE_DATETIME_FORMAT.format(d);
return formatDateTime(OffsetDateTime.ofInstant(d.toInstant(), ZoneId.systemDefault()));
}

/**
* Warning: relies on default timezone!
*/
public static String formatDateTime(long ms) {
return THREAD_SAFE_DATETIME_FORMAT.format(new Date(ms));
return formatDateTime(OffsetDateTime.ofInstant(Instant.ofEpochMilli(ms), ZoneId.systemDefault()));
}

/**
* @since 6.6
*/
public static String formatDateTime(OffsetDateTime dt) {
return DATETIME_FORMATTER.format(dt);
}

/**
* Warning: relies on default timezone!
*/
public static String formatDateTimeNullSafe(@Nullable Date date) {
return date == null ? "" : THREAD_SAFE_DATETIME_FORMAT.format(date);
return date == null ? "" : formatDateTime(date);
}

@CheckForNull
@@ -77,16 +93,12 @@ public final class DateUtils {
}

/**
* Return a date at the start of day.
* @param s string in format {@link #DATE_FORMAT}
* @throws SonarException when string cannot be parsed
*/
public static Date parseDate(String s) {
ParsePosition pos = new ParsePosition(0);
Date result = THREAD_SAFE_DATE_FORMAT.parse(s, pos);
if (pos.getIndex() != s.length()) {
throw new SonarException("The date '" + s + "' does not respect format '" + DATE_FORMAT + "'");
}
return result;
return Date.from(parseLocalDate(s).atStartOfDay(ZoneId.systemDefault()).toInstant());
}

/**
@@ -110,18 +122,57 @@ public final class DateUtils {
return date;
}

/**
* @since 6.6
*/
public static LocalDate parseLocalDate(String s) {
try {
return LocalDate.parse(s);
} catch (DateTimeParseException e) {
throw MessageException.of("The date '" + s + "' does not respect format '" + DATE_FORMAT + "'", e);
}
}

/**
* Parse format {@link #DATE_FORMAT}. This method never throws exception.
*
* @param s any string
* @return the date, {@code null} if parsing error or if parameter is {@code null}
* @since 6.6
*/
@CheckForNull
public static LocalDate parseLocalDateQuietly(@Nullable String s) {
LocalDate date = null;
if (s != null) {
try {
date = parseLocalDate(s);
} catch (RuntimeException e) {
// ignore
}

}
return date;
}

/**
* @param s string in format {@link #DATETIME_FORMAT}
* @throws SonarException when string cannot be parsed
*/

public static Date parseDateTime(String s) {
ParsePosition pos = new ParsePosition(0);
Date result = THREAD_SAFE_DATETIME_FORMAT.parse(s, pos);
if (pos.getIndex() != s.length()) {
throw new SonarException("The date '" + s + "' does not respect format '" + DATETIME_FORMAT + "'");
return Date.from(parseOffsetDateTime(s).toInstant());
}

/**
* @param s string in format {@link #DATETIME_FORMAT}
* @throws SonarException when string cannot be parsed
* @since 6.6
*/
public static OffsetDateTime parseOffsetDateTime(String s) {
try {
return OffsetDateTime.parse(s, DATETIME_FORMATTER);
} catch (DateTimeParseException e) {
throw MessageException.of("The date '" + s + "' does not respect format '" + DATETIME_FORMAT + "'", e);
}
return result;
}

/**
@@ -145,6 +196,28 @@ public final class DateUtils {
}

/**
* Parse format {@link #DATETIME_FORMAT}. This method never throws exception.
*
* @param s any string
* @return the datetime, {@code null} if parsing error or if parameter is {@code null}
* @since 6.6
*/
@CheckForNull
public static OffsetDateTime parseOffsetDateTimeQuietly(@Nullable String s) {
OffsetDateTime datetime = null;
if (s != null) {
try {
datetime = parseOffsetDateTime(s);
} catch (RuntimeException e) {
// ignore
}

}
return datetime;
}

/**
* Warning: may rely on default timezone!
* @throws IllegalArgumentException if stringDate is not a correctly formed date or datetime
* @return the datetime, {@code null} if stringDate is null
* @since 6.1
@@ -155,18 +228,19 @@ public final class DateUtils {
return null;
}

Date date = parseDateTimeQuietly(stringDate);
if (date != null) {
return date;
OffsetDateTime odt = parseOffsetDateTimeQuietly(stringDate);
if (odt != null) {
return Date.from(odt.toInstant());
}

date = parseDateQuietly(stringDate);
checkArgument(date != null, "Date '%s' cannot be parsed as either a date or date+time", stringDate);
LocalDate ld = parseLocalDateQuietly(stringDate);
checkArgument(ld != null, "Date '%s' cannot be parsed as either a date or date+time", stringDate);

return date;
return Date.from(ld.atStartOfDay(ZoneId.systemDefault()).toInstant());
}

/**
* Warning: may rely on default timezone!
* @see #parseDateOrDateTime(String)
*/
@CheckForNull
@@ -176,7 +250,7 @@ public final class DateUtils {

/**
* Return the datetime if @param stringDate is a datetime, date + 1 day if stringDate is a date.
* So '2016-09-01' would return a date equivalent to '2016-09-02T00:00:00+0000' in GMT
* So '2016-09-01' would return a date equivalent to '2016-09-02T00:00:00+0000' in GMT (Warning: relies on default timezone!)
* @see #parseDateOrDateTime(String)
* @throws IllegalArgumentException if stringDate is not a correctly formed date or datetime
* @return the datetime, {@code null} if stringDate is null
@@ -208,49 +282,7 @@ public final class DateUtils {
* @return the new date object with the amount added
*/
public static Date addDays(Date date, int numberOfDays) {
return org.apache.commons.lang.time.DateUtils.addDays(date, numberOfDays);
return Date.from(date.toInstant().plus(numberOfDays, ChronoUnit.DAYS));
}

static class ThreadSafeDateFormat extends DateFormat {
private final String format;
private final ThreadLocal<Reference<DateFormat>> cache = new ThreadLocal<Reference<DateFormat>>() {
@Override
public Reference<DateFormat> get() {
Reference<DateFormat> softRef = super.get();
if (softRef == null || softRef.get() == null) {
SimpleDateFormat sdf = new SimpleDateFormat(format);
sdf.setLenient(false);
softRef = new SoftReference<>(sdf);
super.set(softRef);
}
return softRef;
}
};

ThreadSafeDateFormat(String format) {
this.format = format;
}

private DateFormat getDateFormat() {
return cache.get().get();
}

@Override
public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) {
return getDateFormat().format(date, toAppendTo, fieldPosition);
}

@Override
public Date parse(String source, ParsePosition pos) {
return getDateFormat().parse(source, pos);
}

private void readObject(ObjectInputStream ois) throws NotSerializableException {
throw new NotSerializableException();
}

private void writeObject(ObjectOutputStream ois) throws NotSerializableException {
throw new NotSerializableException();
}
}
}

+ 3
- 0
sonar-plugin-api/src/main/java/org/sonar/api/utils/System2.java Dosyayı Görüntüle

@@ -20,6 +20,7 @@
package org.sonar.api.utils;

import java.net.URL;
import java.time.Clock;
import java.util.Date;
import java.util.Map;
import java.util.Properties;
@@ -72,7 +73,9 @@ public class System2 {

/**
* Shortcut for {@link System#currentTimeMillis()}
* @deprecated since 6.6 use {@link Clock} that is available in pico.
*/
@Deprecated
public long now() {
return System.currentTimeMillis();
}

+ 6
- 85
sonar-plugin-api/src/test/java/org/sonar/api/utils/DateUtilsTest.java Dosyayı Görüntüle

@@ -22,16 +22,13 @@ package org.sonar.api.utils;
import com.tngtech.java.junit.dataprovider.DataProvider;
import com.tngtech.java.junit.dataprovider.DataProviderRunner;
import com.tngtech.java.junit.dataprovider.UseDataProvider;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Fail.fail;
import static org.sonar.api.utils.DateUtils.parseDate;
import static org.sonar.api.utils.DateUtils.parseDateOrDateTime;
import static org.sonar.api.utils.DateUtils.parseDateTime;
@@ -52,13 +49,13 @@ public class DateUtilsTest {

@Test
public void parseDate_not_valid_format() {
expectedException.expect(SonarException.class);
expectedException.expect(MessageException.class);
DateUtils.parseDate("2010/05/18");
}

@Test
public void parseDate_not_lenient() {
expectedException.expect(SonarException.class);
expectedException.expect(MessageException.class);
DateUtils.parseDate("2010-13-18");
}

@@ -71,7 +68,7 @@ public class DateUtilsTest {

@Test
public void parseDate_fail_if_additional_characters() {
expectedException.expect(SonarException.class);
expectedException.expect(MessageException.class);
DateUtils.parseDate("1986-12-04foo");
}

@@ -83,13 +80,13 @@ public class DateUtilsTest {

@Test
public void parseDateTime_not_valid_format() {
expectedException.expect(SonarException.class);
expectedException.expect(MessageException.class);
DateUtils.parseDate("2010/05/18 10:55");
}

@Test
public void parseDateTime_fail_if_additional_characters() {
expectedException.expect(SonarException.class);
expectedException.expect(MessageException.class);
DateUtils.parseDateTime("1986-12-04T01:02:03+0300foo");
}

@@ -103,7 +100,7 @@ public class DateUtilsTest {
@Test
public void shouldFormatDate() {
assertThat(DateUtils.formatDate(new Date())).startsWith("20");
assertThat(DateUtils.formatDate(new Date()).length()).isEqualTo(10);
assertThat(DateUtils.formatDate(new Date())).hasSize(10);
}

@Test
@@ -194,80 +191,4 @@ public class DateUtilsTest {
parseEndingDateOrDateTime("polop");
}

/**
* Cordially copied from XStream unit test
* See http://koders.com/java/fid8A231D75F2C6E6909FB26BCA11C12D08AD05FB50.aspx?s=ThreadSafeDateFormatTest
*/
@Test
public void shouldBeThreadSafe() throws Exception {
final DateUtils.ThreadSafeDateFormat format = new DateUtils.ThreadSafeDateFormat("yyyy-MM-dd'T'HH:mm:ss,S z");
final Date now = new Date();
final List<Throwable> throwables = new ArrayList<>();

final ThreadGroup tg = new ThreadGroup("shouldBeThreadSafe") {
@Override
public void uncaughtException(Thread t, Throwable e) {
throwables.add(e);
super.uncaughtException(t, e);
}
};

final int[] counter = new int[1];
counter[0] = 0;
final Thread[] threads = new Thread[10];
for (int i = 0; i < threads.length; ++i) {
threads[i] = new Thread(tg, "JUnit Thread " + i) {

@Override
public void run() {
int i = 0;
try {
synchronized (this) {
notifyAll();
wait();
}
while (i < 1000 && !interrupted()) {
String formatted = format.format(now);
Thread.yield();
assertThat(now).isEqualTo(format.parse(formatted));
++i;
}
} catch (Exception e) {
fail("Unexpected exception: " + e);
}
synchronized (counter) {
counter[0] += i;
}
}

};
}

for (int i = 0; i < threads.length; ++i) {
synchronized (threads[i]) {
threads[i].start();
threads[i].wait();
}
}

for (int i = 0; i < threads.length; ++i) {
synchronized (threads[i]) {
threads[i].notifyAll();
}
}

Thread.sleep(1000);

for (int i = 0; i < threads.length; ++i) {
threads[i].interrupt();
}
for (int i = 0; i < threads.length; ++i) {
synchronized (threads[i]) {
threads[i].join();
}
}

assertThat(throwables).isEmpty();
assertThat(counter[0]).isGreaterThanOrEqualTo(threads.length);
}
}

+ 11
- 9
sonar-scanner-engine/src/main/java/org/sonar/scanner/ProjectAnalysisInfo.java Dosyayı Görüntüle

@@ -19,16 +19,14 @@
*/
package org.sonar.scanner;

import java.time.Clock;
import java.util.Date;
import java.util.Optional;

import org.picocontainer.Startable;
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.ScannerSide;
import org.sonar.api.config.Configuration;
import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.SonarException;
import org.sonar.api.utils.System2;

/**
* @since 6.3
@@ -37,15 +35,15 @@ import org.sonar.api.utils.System2;
*/
@ScannerSide
public class ProjectAnalysisInfo implements Startable {
private final System2 system2;
private final Clock clock;
private Configuration settings;

private Date analysisDate;
private String analysisVersion;

public ProjectAnalysisInfo(Configuration settings, System2 system2) {
public ProjectAnalysisInfo(Configuration settings, Clock clock) {
this.settings = settings;
this.system2 = system2;
this.clock = clock;
}

public Date analysisDate() {
@@ -59,15 +57,19 @@ public class ProjectAnalysisInfo implements Startable {
private Date loadAnalysisDate() {
Optional<String> value = settings.get(CoreProperties.PROJECT_DATE_PROPERTY);
if (!value.isPresent()) {
return new Date(system2.now());
return Date.from(clock.instant());
}
Date date;
try {
// sonar.projectDate may have been specified as a time
return DateUtils.parseDateTime(value.get());
} catch (SonarException e) {
} catch (RuntimeException e) {
// this is probably just a date
}
try {
// sonar.projectDate may have been specified as a date
return DateUtils.parseDate(value.get());
} catch (RuntimeException e) {
throw new IllegalArgumentException("Illegal value for '" + CoreProperties.PROJECT_DATE_PROPERTY + "'", e);
}
}


+ 2
- 0
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/GlobalContainer.java Dosyayı Görüntüle

@@ -19,6 +19,7 @@
*/
package org.sonar.scanner.bootstrap;

import java.time.Clock;
import java.util.List;
import java.util.Map;
import org.sonar.api.Plugin;
@@ -94,6 +95,7 @@ public class GlobalContainer extends ComponentContainer {
UriReader.class,
new FileCacheProvider(),
System2.INSTANCE,
Clock.systemDefaultZone(),
new MetricsRepositoryProvider(),
UuidFactoryImpl.INSTANCE);
addIfMissing(ScannerPluginInstaller.class, PluginInstaller.class);

+ 38
- 5
sonar-scanner-engine/src/test/java/org/sonar/scanner/ProjectAnalysisInfoTest.java Dosyayı Görüntüle

@@ -19,29 +19,62 @@
*/
package org.sonar.scanner;

import java.time.Clock;
import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.Date;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.CoreProperties;
import org.sonar.api.config.internal.MapSettings;
import org.sonar.api.utils.System2;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;

public class ProjectAnalysisInfoTest {

@Rule
public ExpectedException thrown = ExpectedException.none();

@Test
public void testSimpleDateTime() {
MapSettings settings = new MapSettings();
settings.appendProperty(CoreProperties.PROJECT_DATE_PROPERTY, "2017-01-01T12:13:14+0200");
settings.appendProperty(CoreProperties.PROJECT_VERSION_PROPERTY, "version");
Clock clock = mock(Clock.class);
ProjectAnalysisInfo info = new ProjectAnalysisInfo(settings.asConfig(), clock);
info.start();
OffsetDateTime date = OffsetDateTime.of(2017, 1, 1, 12, 13, 14, 0, ZoneOffset.ofHours(2));

assertThat(info.analysisDate()).isEqualTo(Date.from(date.toInstant()));
assertThat(info.analysisVersion()).isEqualTo("version");
}

@Test
public void testSimpleDate() {
MapSettings settings = new MapSettings();
settings.appendProperty(CoreProperties.PROJECT_DATE_PROPERTY, "2017-01-01");
settings.appendProperty(CoreProperties.PROJECT_VERSION_PROPERTY, "version");
System2 system = mock(System2.class);
ProjectAnalysisInfo info = new ProjectAnalysisInfo(settings.asConfig(), system);
Clock clock = mock(Clock.class);
ProjectAnalysisInfo info = new ProjectAnalysisInfo(settings.asConfig(), clock);
info.start();
LocalDate date = LocalDate.of(2017, 1, 1);

assertThat(info.analysisDate()).isEqualTo(Date.from(date.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()));
assertThat(info.analysisVersion()).isEqualTo("version");
}

@Test
public void emptyDate() {
MapSettings settings = new MapSettings();
settings.appendProperty(CoreProperties.PROJECT_DATE_PROPERTY, "");
settings.appendProperty(CoreProperties.PROJECT_VERSION_PROPERTY, "version");
Clock clock = mock(Clock.class);
ProjectAnalysisInfo info = new ProjectAnalysisInfo(settings.asConfig(), clock);

thrown.expect(RuntimeException.class);

info.start();
}
}

+ 3
- 1
sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/QualityProfileProviderTest.java Dosyayı Görüntüle

@@ -21,6 +21,7 @@ package org.sonar.scanner.repository;

import com.google.common.collect.ImmutableMap;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.junit.Before;
import org.junit.Rule;
@@ -28,6 +29,7 @@ import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.sonar.api.batch.bootstrap.ProjectKey;
import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.log.LogTester;
import org.sonar.api.utils.log.LoggerLevel;
import org.sonar.scanner.analysis.AnalysisProperties;
@@ -69,7 +71,7 @@ public class QualityProfileProviderTest {
when(projectRepo.exists()).thenReturn(true);

response = new ArrayList<>(1);
response.add(QualityProfile.newBuilder().setKey("profile").setName("profile").setLanguage("lang").build());
response.add(QualityProfile.newBuilder().setKey("profile").setName("profile").setLanguage("lang").setRulesUpdatedAt(DateUtils.formatDateTime(new Date())).build());
}

@Test

+ 3
- 1
sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/ActiveRulesProviderTest.java Dosyayı Görüntüle

@@ -20,6 +20,7 @@
package org.sonar.scanner.rule;

import com.google.common.collect.ImmutableList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import org.junit.Before;
@@ -28,6 +29,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.sonar.api.batch.rule.ActiveRules;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.utils.DateUtils;
import org.sonarqube.ws.QualityProfiles.SearchWsResponse.QualityProfile;

import static org.assertj.core.api.Assertions.assertThat;
@@ -79,7 +81,7 @@ public class ActiveRulesProviderTest {
List<QualityProfile> profiles = new LinkedList<>();

for (String k : keys) {
QualityProfile p = QualityProfile.newBuilder().setKey(k).setLanguage(k).build();
QualityProfile p = QualityProfile.newBuilder().setKey(k).setLanguage(k).setRulesUpdatedAt(DateUtils.formatDateTime(new Date())).build();
profiles.add(p);
}


Loading…
İptal
Kaydet