• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

sonus21 / rqueue / 25600722838

09 May 2026 12:06PM UTC coverage: 83.396% (-5.3%) from 88.677%
25600722838

push

github

web-flow
Nats v2 web (#295)

* ci: compile main sources in coverage_report job

The coverage_report job was producing an effectively empty
jacocoTestReport.xml (3.4KB vs ~1.1MB locally) because no .class files
existed when coverageReportOnly ran — the job checked out source code
and downloaded .exec artifacts, but never compiled. JaCoCo's report
generator skips packages/classes it cannot resolve, so the merged XML
ended up with only <sessioninfo> entries and no <package> elements.

That made coverallsJacoco silently no-op via the
"source file set empty, skipping" branch in CoverallsReporter, so
"Push coverage to Coveralls" reported success without uploading.

Verified by downloading the coverage-report artifact from a recent run
and comparing its XML structure against a local build's report.

Assisted-By: Claude Code

* nats-web: implement pause / soft-delete admin ops and capability-aware Q-detail

Replace the all-stub `NatsRqueueUtilityService` with real impls for the operations
JetStream can model: `pauseUnpauseQueue` persists the `paused` flag on `QueueConfig`
in the queue-config KV bucket and notifies the local listener container so the poller
stops dispatching; `deleteMessage` is a soft delete via `MessageMetadataService`
(stream message persists, dashboard hides via the metadata flag); `getDataType`
reports `STREAM`. `moveMessage`, `enqueueMessage`, and `makeEmpty` deliberately
remain "not supported" — there is no JetStream primitive for those.

Update `RqueueQDetailServiceImpl.getRunningTasks` / `getScheduledTasks` to return
header-only tables when the broker capabilities suppress those sections, instead of
emitting zero rows or 501s on NATS.

20 new unit tests cover the pause/delete paths and lock in the still-unsupported
operations. Updates `nats-task.md` / `nats-task-v2.md` to reflect what landed.

Assisted-By: Claude Code

* nats-web: capability-aware nav / charts and stream-based peek

End-to-end browser-tested the NATS dashboard and shipped the t... (continued)

2566 of 3407 branches covered (75.32%)

Branch coverage included in aggregate %.

795 of 1072 new or added lines in 22 files covered. (74.16%)

312 existing lines in 38 files now uncovered.

7715 of 8921 relevant lines covered (86.48%)

0.86 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.68
/rqueue-core/src/main/java/com/github/sonus21/rqueue/utils/DateTimeUtils.java
1
/*
2
 * Copyright (c) 2020-2026 Sonu Kumar
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * You may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     https://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and limitations under the License.
14
 *
15
 */
16

17
package com.github.sonus21.rqueue.utils;
18

19
import java.time.Instant;
20
import java.time.LocalDate;
21
import java.time.LocalDateTime;
22
import java.time.ZoneId;
23
import java.time.ZonedDateTime;
24
import java.time.format.DateTimeFormatter;
25
import java.util.Locale;
26
import lombok.AccessLevel;
27
import lombok.NoArgsConstructor;
28

29
@NoArgsConstructor(access = AccessLevel.PRIVATE)
30
public final class DateTimeUtils {
31

32
  private static final DateTimeFormatter dateTimeFormatter =
1✔
33
      DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
1✔
34
  private static final DateTimeFormatter dateTimeFormatterWithSecond =
1✔
35
      DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
1✔
36
  private static final DateTimeFormatter readableDateTimeFormatter =
1✔
37
      DateTimeFormatter.ofPattern("dd MMM, yyyy 'at' hh:mm a", Locale.ENGLISH);
1✔
38

39
  private static String hourString(long hour) {
40
    if (hour > 1) {
1✔
41
      return hour + " Hours";
1✔
42
    }
43
    return hour + " Hour";
1✔
44
  }
45

46
  private static String minuteString(long minutes) {
47
    if (minutes > 1) {
1✔
48
      return minutes + " Minutes";
1✔
49
    }
50
    return minutes + " Minute";
1✔
51
  }
52

53
  private static String secondString(long seconds) {
54
    if (seconds > 1) {
1✔
55
      return seconds + " Seconds";
1✔
56
    }
57
    return seconds + " Second";
1✔
58
  }
59

60
  private static String dayString(long days) {
61
    if (days > 1) {
1✔
62
      return days + " Days";
1✔
63
    }
64
    return days + " Day";
1✔
65
  }
66

67
  private static String formatDay(long days, long hours, long minutes, long seconds) {
68
    if (hours == 0 && minutes == 0 && seconds == 0) {
1!
69
      return dayString(days);
1✔
70
    }
71
    if (minutes == 0 && seconds == 0) {
1!
72
      return String.format("%s, %s", dayString(days), hourString(hours));
1✔
73
    }
74
    if (seconds == 0) {
1✔
75
      return String.format("%s, %s, %s", dayString(days), hourString(hours), minuteString(minutes));
1✔
76
    }
77
    return String.format(
1✔
78
        "%s, %s, %s, %s",
79
        dayString(days), hourString(hours), minuteString(minutes), secondString(seconds));
1✔
80
  }
81

82
  private static String formatHour(long hours, long minutes, long seconds) {
83
    if (minutes == 0 && seconds == 0) {
1!
84
      return hourString(hours);
1✔
85
    }
86
    if (seconds == 0) {
1✔
87
      return String.format("%s, %s", hourString(hours), minuteString(minutes));
1✔
88
    }
89
    return String.format(
1✔
90
        "%s, %s, %s", hourString(hours), minuteString(minutes), secondString(seconds));
1✔
91
  }
92

93
  public static String milliToHumanRepresentation(long millisecond) {
94
    long millis = millisecond;
1✔
95
    String prefix = "";
1✔
96
    if (millis < 0) {
1✔
97
      prefix = "- ";
1✔
98
      millis = -1 * millis;
1✔
99
    }
100
    long seconds = millis / Constants.ONE_MILLI;
1✔
101
    long minutes = seconds / Constants.SECONDS_IN_A_MINUTE;
1✔
102
    seconds = seconds % Constants.SECONDS_IN_A_MINUTE; // remaining seconds
1✔
103
    long hours = minutes / Constants.MINUTES_IN_AN_HOUR;
1✔
104
    minutes = minutes % Constants.MINUTES_IN_AN_HOUR; // remaining minutes
1✔
105
    long days = hours / Constants.HOURS_IN_A_DAY;
1✔
106
    hours = hours % Constants.HOURS_IN_A_DAY; // remaining hours
1✔
107
    if (days != 0) {
1✔
108
      return prefix + formatDay(days, hours, minutes, seconds);
1✔
109
    }
110
    if (hours != 0) {
1✔
111
      return prefix + formatHour(hours, minutes, seconds);
1✔
112
    }
113
    if (minutes != 0) {
1✔
114
      if (seconds == 0) {
1✔
115
        return prefix + minuteString(minutes);
1✔
116
      }
117
      return prefix + String.format("%s, %s", minuteString(minutes), secondString(seconds));
1✔
118
    }
119
    return prefix + secondString(seconds);
1✔
120
  }
121

122
  public static String formatMilliToString(Long milli) {
123
    if (milli == null) {
1✔
124
      return "";
1✔
125
    }
126
    Instant instant = Instant.ofEpochMilli(milli);
1✔
127
    ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(instant, ZoneId.systemDefault());
1✔
128
    return zonedDateTime.format(dateTimeFormatter);
1✔
129
  }
130

131
  public static String formatMilliToReadableString(Long milli) {
132
    if (milli == null) {
1✔
133
      return "";
1✔
134
    }
135
    Instant instant = Instant.ofEpochMilli(milli);
1✔
136
    ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(instant, ZoneId.systemDefault());
1✔
137
    return zonedDateTime.format(readableDateTimeFormatter);
1✔
138
  }
139

140
  public static String formatMilliToCompactDuration(Long milli) {
141
    if (milli == null) {
1✔
142
      return "";
1✔
143
    }
144
    long millis = milli;
1✔
145
    long absMillis = Math.abs(millis);
1✔
146
    String prefix = millis < 0 ? "- " : "";
1✔
147
    if (absMillis < Constants.ONE_MILLI) {
1✔
148
      return prefix + absMillis + " ms";
1✔
149
    }
150
    if (absMillis < 2L * Constants.SECONDS_IN_A_MINUTE * Constants.ONE_MILLI) {
1✔
151
      long seconds = absMillis / Constants.ONE_MILLI;
1✔
152
      return prefix + seconds + " sec";
1✔
153
    }
154
    if (absMillis
1!
155
            < Constants.MINUTES_IN_AN_HOUR * Constants.SECONDS_IN_A_MINUTE * Constants.ONE_MILLI
156
        && absMillis % (Constants.SECONDS_IN_A_MINUTE * Constants.ONE_MILLI) == 0) {
157
      long minutes = absMillis / (Constants.SECONDS_IN_A_MINUTE * Constants.ONE_MILLI);
1✔
158
      return prefix + minutes + " min";
1✔
159
    }
160
    if (absMillis
1!
161
            < Constants.HOURS_IN_A_DAY
162
                * Constants.MINUTES_IN_AN_HOUR
163
                * Constants.SECONDS_IN_A_MINUTE
164
                * Constants.ONE_MILLI
165
        && absMillis
166
                % (Constants.MINUTES_IN_AN_HOUR
167
                    * Constants.SECONDS_IN_A_MINUTE
168
                    * Constants.ONE_MILLI)
169
            == 0) {
170
      long hours = absMillis
1✔
171
          / (Constants.MINUTES_IN_AN_HOUR * Constants.SECONDS_IN_A_MINUTE * Constants.ONE_MILLI);
172
      return prefix + hours + " hr";
1✔
173
    }
174
    long totalSeconds = absMillis / Constants.ONE_MILLI;
1✔
175
    long hours = totalSeconds / (Constants.MINUTES_IN_AN_HOUR * Constants.SECONDS_IN_A_MINUTE);
1✔
176
    long minutes = (totalSeconds % (Constants.MINUTES_IN_AN_HOUR * Constants.SECONDS_IN_A_MINUTE))
1✔
177
        / Constants.SECONDS_IN_A_MINUTE;
178
    long seconds = totalSeconds % Constants.SECONDS_IN_A_MINUTE;
1✔
179
    if (hours > 0) {
1!
180
      if (minutes > 0) {
1!
181
        return prefix + hours + " hr " + minutes + " min";
1✔
182
      }
UNCOV
183
      return prefix + hours + " hr";
×
184
    }
UNCOV
185
    if (minutes > 0) {
×
UNCOV
186
      if (seconds > 0) {
×
UNCOV
187
        return prefix + minutes + " min " + seconds + " sec";
×
188
      }
UNCOV
189
      return prefix + minutes + " min";
×
190
    }
UNCOV
191
    return prefix + totalSeconds + " sec";
×
192
  }
193

194
  public static LocalDate localDateFromMilli(long millis) {
195
    return Instant.ofEpochMilli(millis).atZone(ZoneId.systemDefault()).toLocalDate();
1✔
196
  }
197

198
  public static LocalDate today() {
199
    return LocalDate.now();
1✔
200
  }
201

202
  public static String currentTimeFormatted() {
203
    return LocalDateTime.now().format(dateTimeFormatterWithSecond);
1✔
204
  }
205
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc