1 | // License: GPL. For details, see LICENSE file.
|
---|
2 | package org.openstreetmap.josm.actions.upload;
|
---|
3 |
|
---|
4 | import static org.junit.jupiter.api.Assertions.assertAll;
|
---|
5 | import static org.junit.jupiter.api.Assertions.assertFalse;
|
---|
6 | import static org.junit.jupiter.api.Assertions.assertTrue;
|
---|
7 |
|
---|
8 | import java.time.Instant;
|
---|
9 | import java.util.ArrayList;
|
---|
10 | import java.util.Collection;
|
---|
11 | import java.util.Collections;
|
---|
12 | import java.util.concurrent.ExecutionException;
|
---|
13 | import java.util.concurrent.TimeUnit;
|
---|
14 | import java.util.stream.Collectors;
|
---|
15 | import java.util.stream.Stream;
|
---|
16 |
|
---|
17 | import org.junit.jupiter.params.ParameterizedTest;
|
---|
18 | import org.junit.jupiter.params.provider.Arguments;
|
---|
19 | import org.junit.jupiter.params.provider.MethodSource;
|
---|
20 | import org.openstreetmap.josm.TestUtils;
|
---|
21 | import org.openstreetmap.josm.data.coor.LatLon;
|
---|
22 | import org.openstreetmap.josm.data.notes.Note;
|
---|
23 | import org.openstreetmap.josm.data.notes.NoteComment;
|
---|
24 | import org.openstreetmap.josm.data.osm.NoteData;
|
---|
25 | import org.openstreetmap.josm.data.osm.User;
|
---|
26 | import org.openstreetmap.josm.gui.MainApplication;
|
---|
27 | import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
|
---|
28 | import org.openstreetmap.josm.gui.progress.ProgressMonitor;
|
---|
29 | import org.openstreetmap.josm.gui.util.GuiHelper;
|
---|
30 | import org.openstreetmap.josm.io.OsmTransferException;
|
---|
31 | import org.openstreetmap.josm.testutils.FakeOsmApi;
|
---|
32 | import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
|
---|
33 | import org.openstreetmap.josm.testutils.annotations.OsmApi;
|
---|
34 | import org.openstreetmap.josm.tools.Logging;
|
---|
35 |
|
---|
36 | import mockit.Mock;
|
---|
37 | import mockit.MockUp;
|
---|
38 |
|
---|
39 | /**
|
---|
40 | * Test class for {@link UploadNotesTask}
|
---|
41 | * @author Taylor Smock
|
---|
42 | */
|
---|
43 | @BasicPreferences
|
---|
44 | @OsmApi(OsmApi.APIType.FAKE)
|
---|
45 | class UploadNotesTaskTest {
|
---|
46 | static Stream<Arguments> testUpload() {
|
---|
47 | final NoteData commonData = new NoteData();
|
---|
48 | for (int i = 0; i < 12; i++) {
|
---|
49 | for (Note.State state : Note.State.values()) {
|
---|
50 | final Note note1 = new Note(LatLon.ZERO);
|
---|
51 | note1.setId((state.ordinal() + 1) * (i + 1));
|
---|
52 | note1.setCreatedAt(Instant.ofEpochSecond(TimeUnit.DAYS.toSeconds(365) * i));
|
---|
53 | note1.setState(state);
|
---|
54 | if (i > 2) {
|
---|
55 | note1.addComment(new NoteComment(note1.getCreatedAt().plusSeconds(60),
|
---|
56 | User.getAnonymous(), state.toString() + i, NoteComment.Action.OPENED, false));
|
---|
57 | }
|
---|
58 | if (i > 4) {
|
---|
59 | note1.addComment(new NoteComment(note1.getCreatedAt().plusSeconds(120),
|
---|
60 | User.getAnonymous(), state.toString() + i, NoteComment.Action.COMMENTED, false));
|
---|
61 | }
|
---|
62 | if (i > 6) {
|
---|
63 | Instant closedAt = note1.getCreatedAt().plusSeconds(180);
|
---|
64 | note1.addComment(new NoteComment(closedAt,
|
---|
65 | User.getAnonymous(), state.toString() + i, NoteComment.Action.CLOSED, false));
|
---|
66 | note1.setClosedAt(closedAt);
|
---|
67 | note1.setState(Note.State.CLOSED);
|
---|
68 | }
|
---|
69 | if (i > 8) {
|
---|
70 | note1.addComment(new NoteComment(note1.getCreatedAt().plusSeconds(240),
|
---|
71 | User.getAnonymous(), state.toString() + i, NoteComment.Action.REOPENED, false));
|
---|
72 | note1.setClosedAt(null);
|
---|
73 | note1.setState(Note.State.OPEN);
|
---|
74 | }
|
---|
75 | if (i > 10) {
|
---|
76 | note1.addComment(new NoteComment(note1.getCreatedAt().plusSeconds(300),
|
---|
77 | User.getAnonymous(), state.toString() + i, NoteComment.Action.HIDDEN, false));
|
---|
78 | }
|
---|
79 | commonData.addNotes(Collections.singleton(note1));
|
---|
80 | }
|
---|
81 | }
|
---|
82 | return Stream.of(
|
---|
83 | Arguments.of(new NoteData(commonData.getNotes()), Collections.singleton(generateNote(1, null, null,
|
---|
84 | new NoteComment.Action[] {NoteComment.Action.OPENED}, new boolean[] {true}))),
|
---|
85 | Arguments.of(new NoteData(commonData.getNotes()), Collections.singleton(generateNote(2, Instant.now(), null,
|
---|
86 | new NoteComment.Action[] {NoteComment.Action.OPENED, NoteComment.Action.COMMENTED}, new boolean[] {false, true}))),
|
---|
87 | Arguments.of(new NoteData(commonData.getNotes()), Collections.singleton(generateNote(3, Instant.now(),
|
---|
88 | Instant.now().plusSeconds(60), new NoteComment.Action[] {NoteComment.Action.OPENED,
|
---|
89 | NoteComment.Action.COMMENTED, NoteComment.Action.CLOSED}, new boolean[] {false, false, true}))),
|
---|
90 | Arguments.of(new NoteData(commonData.getNotes()), Collections.singleton(generateNote(4, Instant.now(),
|
---|
91 | Instant.now().plusSeconds(60), new NoteComment.Action[] {NoteComment.Action.OPENED,
|
---|
92 | NoteComment.Action.COMMENTED, NoteComment.Action.CLOSED, NoteComment.Action.REOPENED},
|
---|
93 | new boolean[] {false, false, false, true})))
|
---|
94 | );
|
---|
95 | }
|
---|
96 |
|
---|
97 | private static Note generateNote(int id, Instant openedAt, Instant closedAt, NoteComment.Action[] actions, boolean[] isNew) {
|
---|
98 | final Note newNote = new Note(LatLon.ZERO);
|
---|
99 | newNote.setId(id);
|
---|
100 | if (openedAt != null) {
|
---|
101 | newNote.setState(Note.State.OPEN);
|
---|
102 | newNote.setCreatedAt(openedAt);
|
---|
103 | } else {
|
---|
104 | openedAt = Instant.now();
|
---|
105 | }
|
---|
106 | if (closedAt != null) {
|
---|
107 | newNote.setState(Note.State.CLOSED);
|
---|
108 | newNote.setClosedAt(closedAt);
|
---|
109 | }
|
---|
110 |
|
---|
111 | for (int i = 0; i < actions.length; i++) {
|
---|
112 | NoteComment.Action action = actions[i];
|
---|
113 | newNote.addComment(new NoteComment(openedAt.plusSeconds(30L * i), User.getAnonymous(),
|
---|
114 | action.toString() + i, action, isNew[i]));
|
---|
115 | }
|
---|
116 |
|
---|
117 | return newNote;
|
---|
118 | }
|
---|
119 |
|
---|
120 | @ParameterizedTest
|
---|
121 | @MethodSource
|
---|
122 | void testUpload(final NoteData noteData, final Collection<Note> shouldBeUploaded)
|
---|
123 | throws ExecutionException, InterruptedException {
|
---|
124 | TestUtils.assumeWorkingJMockit();
|
---|
125 | Logging.clearLastErrorAndWarnings();
|
---|
126 | FakeOsmApiMocker fakeOsmApiMocker = new FakeOsmApiMocker();
|
---|
127 | noteData.addNotes(shouldBeUploaded);
|
---|
128 | new UploadNotesTask().uploadNotes(noteData, NullProgressMonitor.INSTANCE);
|
---|
129 | // Sync both threads.
|
---|
130 | MainApplication.worker.submit(() -> { /* Sync worker thread */ }).get();
|
---|
131 | GuiHelper.runInEDTAndWait(() -> { /* Sync UI thread */ });
|
---|
132 | assertTrue(noteData.getNotes().containsAll(shouldBeUploaded));
|
---|
133 | for (Note note : noteData.getNotes()) {
|
---|
134 | for (NoteComment comment : note.getComments().stream().filter(NoteComment::isNew).collect(Collectors.toList())) {
|
---|
135 | assertTrue(shouldBeUploaded.contains(note));
|
---|
136 | NoteComment.Action action = comment.getNoteAction();
|
---|
137 | if (action == NoteComment.Action.CLOSED) {
|
---|
138 | assertTrue(fakeOsmApiMocker.closed.contains(note));
|
---|
139 | } else if (action == NoteComment.Action.COMMENTED) {
|
---|
140 | assertTrue(fakeOsmApiMocker.commented.contains(note));
|
---|
141 | } else if (action == NoteComment.Action.REOPENED) {
|
---|
142 | assertTrue(fakeOsmApiMocker.reopened.contains(note));
|
---|
143 | } else if (action == NoteComment.Action.OPENED) {
|
---|
144 | assertTrue(fakeOsmApiMocker.created.stream().anyMatch(n -> n.getFirstComment().getText().equals(comment.getText())));
|
---|
145 | }
|
---|
146 | }
|
---|
147 | if (!shouldBeUploaded.contains(note)) {
|
---|
148 | assertAll("All comments should not be new", note.getComments().stream().map(comment -> () -> assertFalse(comment.isNew())));
|
---|
149 | assertAll("All comments should not be uploaded",
|
---|
150 | () -> assertFalse(fakeOsmApiMocker.closed.contains(note)),
|
---|
151 | () -> assertFalse(fakeOsmApiMocker.commented.contains(note)),
|
---|
152 | () -> assertFalse(fakeOsmApiMocker.created.contains(note)),
|
---|
153 | () -> assertFalse(fakeOsmApiMocker.reopened.contains(note)));
|
---|
154 | }
|
---|
155 | }
|
---|
156 | assertTrue(Logging.getLastErrorAndWarnings().isEmpty());
|
---|
157 | }
|
---|
158 |
|
---|
159 | private static class FakeOsmApiMocker extends MockUp<FakeOsmApi> {
|
---|
160 | Collection<Note> closed = new ArrayList<>();
|
---|
161 | Collection<Note> commented = new ArrayList<>();
|
---|
162 | Collection<Note> created = new ArrayList<>();
|
---|
163 | Collection<Note> reopened = new ArrayList<>();
|
---|
164 | @Mock
|
---|
165 | public Note createNote(LatLon latlon, String text, ProgressMonitor monitor) throws OsmTransferException {
|
---|
166 | final Note newNote = new Note(latlon);
|
---|
167 | this.created.add(newNote);
|
---|
168 | newNote.setId(Instant.now().toEpochMilli());
|
---|
169 | newNote.setClosedAt(Instant.now());
|
---|
170 | newNote.addComment(new NoteComment(Instant.now(), User.getAnonymous(), text, NoteComment.Action.OPENED, false));
|
---|
171 | return newNote;
|
---|
172 | }
|
---|
173 |
|
---|
174 | @Mock
|
---|
175 | public Note addCommentToNote(Note note, String comment, ProgressMonitor monitor) throws OsmTransferException {
|
---|
176 | this.commented.add(note);
|
---|
177 | return note;
|
---|
178 | }
|
---|
179 |
|
---|
180 | @Mock
|
---|
181 | public Note closeNote(Note note, String closeMessage, ProgressMonitor monitor) throws OsmTransferException {
|
---|
182 | this.closed.add(note);
|
---|
183 | return note;
|
---|
184 | }
|
---|
185 |
|
---|
186 | @Mock
|
---|
187 | public Note reopenNote(Note note, String reactivateMessage, ProgressMonitor monitor) throws OsmTransferException {
|
---|
188 | this.reopened.add(note);
|
---|
189 | return note;
|
---|
190 | }
|
---|
191 | }
|
---|
192 | }
|
---|