diff --git a/pom.xml b/pom.xml
index bb6d9b8a..f30e7d03 100644
--- a/pom.xml
+++ b/pom.xml
@@ -63,6 +63,11 @@
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 3.2.5
+
diff --git a/src/main/java/hse/java/lectures/lesson7/dau/DauServiceImpl.java b/src/main/java/hse/java/lectures/lesson7/dau/DauServiceImpl.java
new file mode 100644
index 00000000..60e8d564
--- /dev/null
+++ b/src/main/java/hse/java/lectures/lesson7/dau/DauServiceImpl.java
@@ -0,0 +1,52 @@
+package hse.java.lectures.lesson7.dau;
+
+import java.time.LocalDate;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class DauServiceImpl implements DauService {
+
+ private Map> yesterday = new HashMap<>();
+ private Map> today = new HashMap<>();
+ private LocalDate currentDate = LocalDate.now();
+
+ @Override
+ public synchronized void postEvent(Event event) {
+ valiDate();
+ today.computeIfAbsent(event.authorId(), id -> new HashSet<>())
+ .add(event.userId());
+ }
+
+ @Override
+ public synchronized Map getDauStatistics(List authorIds) {
+ valiDate();
+ Map result = new HashMap<>();
+ for (int authorId : authorIds) {
+ result.put(authorId, getAuthorDauStatistics(authorId));
+ }
+ return result;
+ }
+
+ @Override
+ public synchronized Long getAuthorDauStatistics(int authorId) {
+ valiDate();
+ Set users = yesterday.get(authorId);
+ return users == null ? 0L : (long) users.size();
+ }
+ void nextDay() {
+ yesterday = today;
+ today = new HashMap<>();
+ }
+
+ private void valiDate() {
+ LocalDate now = LocalDate.now();
+ if (now.isAfter(currentDate)) {
+ yesterday = today;
+ today = new HashMap<>();
+ currentDate = now;
+ }
+ }
+}
diff --git a/src/test/java/hse/java/lectures/lesson7/dau/DauServiceTest.java b/src/test/java/hse/java/lectures/lesson7/dau/DauServiceTest.java
new file mode 100644
index 00000000..c1800d16
--- /dev/null
+++ b/src/test/java/hse/java/lectures/lesson7/dau/DauServiceTest.java
@@ -0,0 +1,73 @@
+package hse.java.lectures.lesson7.dau;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+@Tag("dau")
+class DauServiceTest {
+
+ private DauServiceImpl service;
+
+ @BeforeEach
+ void setUp() {
+ service = new DauServiceImpl();
+ service.postEvent(new Event(1, 10));
+ service.postEvent(new Event(2, 10));
+ service.postEvent(new Event(3, 20));
+ service.nextDay();
+ }
+
+ @Test
+ void sameUserClickedTwice_countedOnce() {
+ service.postEvent(new Event(5, 10));
+ service.postEvent(new Event(5, 10));
+ service.nextDay();
+
+ assertEquals(1L, service.getAuthorDauStatistics(10));
+ }
+
+ @Test
+ void twoUniqueUsers_countedCorrectly() {
+ assertEquals(2L, service.getAuthorDauStatistics(10));
+ }
+
+ @Test
+ void authorWithNoClicks_returnsZero() {
+ assertEquals(0L, service.getAuthorDauStatistics(99));
+ }
+
+ @Test
+ void differentAuthors_countedIndependently() {
+ Map stats = service.getDauStatistics(List.of(10, 20));
+ assertEquals(2L, stats.get(10));
+ assertEquals(1L, stats.get(20));
+ }
+
+ @Test
+ void getDauStatistics_unknownAuthorReturnsZero() {
+ Map stats = service.getDauStatistics(List.of(999));
+ assertEquals(0L, stats.get(999));
+ }
+
+ @Test
+ void eventsPostedToday_notVisibleUntilTomorrow() {
+ service.postEvent(new Event(100, 10));
+ assertEquals(2L, service.getAuthorDauStatistics(10));
+ }
+
+ @Test
+ void afterNewDay_previousDataReplaced() {
+ service.postEvent(new Event(7, 10));
+ service.postEvent(new Event(8, 10));
+ service.postEvent(new Event(9, 10));
+ service.nextDay();
+
+ assertEquals(3L, service.getAuthorDauStatistics(10));
+ }
+}