LoggingActionQueue.java

1
package com.renomad.minum.logging;
2
3
import com.renomad.minum.queue.AbstractActionQueue;
4
import com.renomad.minum.queue.ActionQueue;
5
import com.renomad.minum.state.Constants;
6
import com.renomad.minum.utils.*;
7
8
import java.util.Map;
9
import java.util.concurrent.*;
10
11
import static com.renomad.minum.logging.Logger.showWhiteSpace;
12
import static com.renomad.minum.utils.TimeUtils.getTimestampIsoInstant;
13
14
/**
15
 * This class is very similar to {@link ActionQueue} but is
16
 * focused on Logging.
17
 * <p>
18
 *     It is necessary to create independent classes for logging to avoid circular dependencies
19
 * </p>
20
 */
21
final class LoggingActionQueue implements AbstractActionQueue {
22
    private final String name;
23
    private final ExecutorService executorService;
24
    private final LinkedBlockingQueue<RunnableWithDescription> queue;
25
    private Thread queueThread;
26
    private boolean stop = false;
27
    private boolean isStoppedStatus = false;
28
    private final Map<LoggingLevel, Boolean> enabledLogLevels;
29
30
    LoggingActionQueue(String name, ExecutorService executorService, Constants constants) {
31
        this.name = name;
32
        this.executorService = executorService;
33
        this.queue = new LinkedBlockingQueue<>();
34
        this.enabledLogLevels = Logger.convertToMap(constants.logLevels);
35
    }
36
37
    // Regarding the InfiniteLoopStatement - indeed, we expect that the while loop
38
    // below is an infinite loop unless there's an exception thrown, that is what it is.
39
    @Override
40
    @SuppressWarnings("InfiniteLoopStatement")
41
    public AbstractActionQueue initialize() {
42
        Runnable centralLoop = () -> {
43
            Thread.currentThread().setName(name);
44
            this.queueThread = Thread.currentThread();
45
            try {
46
                while (true) {
47
                    runAction(queue);
48
                }
49
            } catch (InterruptedException ex) {
50
                /*
51
                this is what we expect to happen.
52
                once this happens, we just continue on.
53
                this only gets called when we are trying to shut everything
54
                down cleanly
55
                 */
56
                Logger.logHelper(() -> String.format("%s LoggingActionQueue for %s is stopped.%n", TimeUtils.getTimestampIsoInstant(), name), LoggingLevel.DEBUG, enabledLogLevels, this);
57
                Thread.currentThread().interrupt();
58
            }
59
        };
60
        executorService.submit(centralLoop);
61 1 1. initialize : replaced return value with null for com/renomad/minum/logging/LoggingActionQueue::initialize → KILLED
        return this;
62
    }
63
64
    /**
65
     * Runs the action that renders to a string for logging.
66
     * @return true if we successfully ran the action or false if there was an error
67
     */
68
    static boolean runAction(LinkedBlockingQueue<RunnableWithDescription> queue) throws InterruptedException {
69
        RunnableWithDescription action = queue.take();
70
        try {
71 1 1. runAction : removed call to com/renomad/minum/utils/RunnableWithDescription::run → KILLED
            action.run();
72 1 1. runAction : replaced boolean return with false for com/renomad/minum/logging/LoggingActionQueue::runAction → KILLED
            return true;
73
        } catch (Throwable e) {
74
            System.out.println(getTimestampIsoInstant() + " LOGGER_ERROR: " + showWhiteSpace(StacktraceUtils.stackTraceToString(e)));
75 1 1. runAction : replaced boolean return with true for com/renomad/minum/logging/LoggingActionQueue::runAction → KILLED
            return false;
76
        }
77
    }
78
79
    /**
80
     * Adds something to the queue to be processed.
81
     */
82
    @Override
83
    public void enqueue(String description, ThrowingRunnable action) {
84 1 1. enqueue : negated conditional → KILLED
        if (! stop) {
85
            queue.add(new RunnableWithDescription(action, description));
86
        }
87
    }
88
89
    /**
90
     * Stops the action queue
91
     * @param count how many loops to wait before we crash it closed
92
     * @param sleepTime how long to wait in milliseconds between loops
93
     */
94
    @Override
95
    public void stop(int count, int sleepTime) {
96
        Logger.logHelper(() -> String.format("%s Stopping queue %s%n", TimeUtils.getTimestampIsoInstant(), this), LoggingLevel.DEBUG, enabledLogLevels, this);
97
        stop = true;
98 2 1. stop : changed conditional boundary → KILLED
2. stop : negated conditional → KILLED
        for (int i = 0; i < count; i++) {
99 1 1. stop : negated conditional → TIMED_OUT
            if (queue.isEmpty()) return;
100
            Logger.logHelper(() -> String.format("%s Queue not yet empty, has %d elements. waiting...%n", TimeUtils.getTimestampIsoInstant(), queue.size()), LoggingLevel.DEBUG, enabledLogLevels, this);
101
            MyThread.sleep(sleepTime);
102
        }
103
        isStoppedStatus = true;
104
        Logger.logHelper(() -> String.format("%s Queue %s has %d elements left but we're done waiting.  Queue toString: %s",TimeUtils.getTimestampIsoInstant(), this, queue.size(), queue), LoggingLevel.DEBUG, enabledLogLevels, this);
105
    }
106
107
    /**
108
     * This will prevent any new actions being
109
     * queued (by setting the stop flag to true and thus
110
     * causing an exception to be thrown
111
     * when a call is made to [enqueue]) and will
112
     * block until the queue is empty.
113
     */
114
    @Override
115
    public void stop() {
116
        stop(5, 20);
117
    }
118
119
    public Thread getQueueThread() {
120 1 1. getQueueThread : replaced return value with null for com/renomad/minum/logging/LoggingActionQueue::getQueueThread → KILLED
        return queueThread;
121
    }
122
123
    @Override
124
    public LinkedBlockingQueue<RunnableWithDescription> getQueue() {
125 1 1. getQueue : replaced return value with null for com/renomad/minum/logging/LoggingActionQueue::getQueue → KILLED
        return queue;
126
    }
127
128
    @Override
129
    public String toString() {
130 1 1. toString : replaced return value with "" for com/renomad/minum/logging/LoggingActionQueue::toString → KILLED
        return this.name;
131
    }
132
133
    @Override
134
    public boolean isStopped() {
135 2 1. isStopped : replaced boolean return with false for com/renomad/minum/logging/LoggingActionQueue::isStopped → KILLED
2. isStopped : replaced boolean return with true for com/renomad/minum/logging/LoggingActionQueue::isStopped → KILLED
        return isStoppedStatus;
136
    }
137
}

Mutations

61

1.1
Location : initialize
Killed by : com.renomad.minum.web.RequestTests.test_Request_ToString(com.renomad.minum.web.RequestTests)
replaced return value with null for com/renomad/minum/logging/LoggingActionQueue::initialize → KILLED

71

1.1
Location : runAction
Killed by : com.renomad.minum.logging.LoggingActionQueueTests.testGetQueue(com.renomad.minum.logging.LoggingActionQueueTests)
removed call to com/renomad/minum/utils/RunnableWithDescription::run → KILLED

72

1.1
Location : runAction
Killed by : com.renomad.minum.logging.LoggingActionQueueTests.testHappyPathWhileRunningAction(com.renomad.minum.logging.LoggingActionQueueTests)
replaced boolean return with false for com/renomad/minum/logging/LoggingActionQueue::runAction → KILLED

75

1.1
Location : runAction
Killed by : com.renomad.minum.logging.LoggingActionQueueTests.testErrorWhileRunningAction(com.renomad.minum.logging.LoggingActionQueueTests)
replaced boolean return with true for com/renomad/minum/logging/LoggingActionQueue::runAction → KILLED

84

1.1
Location : enqueue
Killed by : com.renomad.minum.logging.LoggingActionQueueTests.testGetQueue(com.renomad.minum.logging.LoggingActionQueueTests)
negated conditional → KILLED

98

1.1
Location : stop
Killed by : com.renomad.minum.database.DbTests.test_Locking(com.renomad.minum.database.DbTests)
changed conditional boundary → KILLED

2.2
Location : stop
Killed by : com.renomad.minum.utils.ActionQueueKillerTests.test_KillAllQueues_NeedingInterruption(com.renomad.minum.utils.ActionQueueKillerTests)
negated conditional → KILLED

99

1.1
Location : stop
Killed by : none
negated conditional → TIMED_OUT

120

1.1
Location : getQueueThread
Killed by : com.renomad.minum.logging.LoggingActionQueueTests.testGetQueueThread(com.renomad.minum.logging.LoggingActionQueueTests)
replaced return value with null for com/renomad/minum/logging/LoggingActionQueue::getQueueThread → KILLED

125

1.1
Location : getQueue
Killed by : com.renomad.minum.logging.LoggingActionQueueTests.testGetQueue(com.renomad.minum.logging.LoggingActionQueueTests)
replaced return value with null for com/renomad/minum/logging/LoggingActionQueue::getQueue → KILLED

130

1.1
Location : toString
Killed by : com.renomad.minum.web.RequestTests.test_Request_ToString(com.renomad.minum.web.RequestTests)
replaced return value with "" for com/renomad/minum/logging/LoggingActionQueue::toString → KILLED

135

1.1
Location : isStopped
Killed by : com.renomad.minum.web.FullSystemTests.testFullSystem_EdgeCase_InstantlyClosed(com.renomad.minum.web.FullSystemTests)
replaced boolean return with false for com/renomad/minum/logging/LoggingActionQueue::isStopped → KILLED

2.2
Location : isStopped
Killed by : com.renomad.minum.web.FullSystemTests.testFullSystem_EdgeCase_InstantlyClosed(com.renomad.minum.web.FullSystemTests)
replaced boolean return with true for com/renomad/minum/logging/LoggingActionQueue::isStopped → KILLED

Active mutators

Tests examined


Report generated by PIT 1.17.0