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

leeonky / test-charm-java / 227

21 Apr 2025 03:32PM UTC coverage: 71.06% (-3.0%) from 74.052%
227

push

circleci

leeonky
Refactor UI test

6 of 15 new or added lines in 5 files covered. (40.0%)

42 existing lines in 11 files now uncovered.

6858 of 9651 relevant lines covered (71.06%)

0.71 hits per line

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

92.7
/DAL-extension-inspector/src/main/java/com/github/leeonky/dal/extensions/inspector/Inspector.java
1
package com.github.leeonky.dal.extensions.inspector;
2

3
import com.github.leeonky.dal.DAL;
4
import com.github.leeonky.dal.ast.node.DALNode;
5
import com.github.leeonky.dal.runtime.Data;
6
import com.github.leeonky.dal.runtime.RuntimeContextBuilder.DALRuntimeContext;
7
import com.github.leeonky.interpreter.InterpreterException;
8
import com.github.leeonky.util.Sneaky;
9
import io.javalin.Javalin;
10
import io.javalin.http.Context;
11
import io.javalin.http.staticfiles.Location;
12
import io.javalin.websocket.WsContext;
13
import org.apache.tika.Tika;
14

15
import java.io.ByteArrayOutputStream;
16
import java.io.InputStream;
17
import java.net.InetAddress;
18
import java.net.NetworkInterface;
19
import java.time.Duration;
20
import java.time.Instant;
21
import java.util.*;
22
import java.util.concurrent.ConcurrentHashMap;
23
import java.util.concurrent.CountDownLatch;
24
import java.util.function.Supplier;
25
import java.util.stream.Collectors;
26

27
import static com.github.leeonky.util.function.Extension.getFirstPresent;
28
import static java.lang.Long.parseLong;
29
import static java.util.Objects.requireNonNull;
30
import static java.util.Optional.ofNullable;
31

32
public class Inspector {
33
    private static Inspector inspector = null;
1✔
34
    private static Mode mode = null;
1✔
35
    private final Javalin javalin;
36
    private final CountDownLatch serverReadyLatch = new CountDownLatch(1);
1✔
37
    private final Set<DAL> instances = new LinkedHashSet<>();
1✔
38
    //   TODO refactor
39
    private final Map<String, WsContext> clientConnections = new ConcurrentHashMap<>();
1✔
40
    private final Map<String, Set<String>> clientMonitors = new ConcurrentHashMap<>();
1✔
41
    private final Map<String, DalInstance> dalInstances = new ConcurrentHashMap<>();
1✔
42
    private static Supplier<Object> defaultInput = () -> null;
1✔
43

44
    public Inspector() {
1✔
45
        DalInstance defaultInstance = new DalInstance(() -> defaultInput.get(), DAL.create("Try It!", InspectorExtension.class), "");
1✔
46
        defaultInstance.running = false;
1✔
47
        dalInstances.put("Try It!", defaultInstance);
1✔
48
        javalin = Javalin.create(config -> config.addStaticFiles("/public", Location.CLASSPATH))
1✔
49
                .events(event -> event.serverStarted(serverReadyLatch::countDown));
1✔
50
        requireNonNull(javalin.jettyServer()).setServerPort(getServerPort());
1✔
51
        javalin.get("/", ctx -> ctx.redirect("/index.html"));
1✔
52
        javalin.post("/api/execute", ctx -> ctx.html(execute(ctx.queryParam("name"), ctx.body())));
1✔
53
        javalin.post("/api/exchange", ctx -> exchange(ctx.queryParam("session"), ctx.body()));
1✔
54
        javalin.post("/api/pass", ctx -> pass(ctx.queryParam("name")));
1✔
55
        javalin.post("/api/release", ctx -> release(ctx.queryParam("name")));
1✔
56
        javalin.post("/api/release-all", ctx -> releaseAll());
1✔
57
        javalin.get("/api/request", ctx -> ctx.html(request(ctx.queryParam("name"))));
1✔
58
        javalin.get("/attachments", ctx -> responseAttachment(ctx.queryParam("name"), Integer.parseInt(ctx.queryParam("index")), ctx));
1✔
59
        javalin.ws("/ws/exchange", ws -> {
1✔
60
            ws.onConnect(ctx -> {
1✔
61
                clientConnections.put(ctx.getSessionId(), ctx);
1✔
62
                sendInstances(ctx);
1✔
63
            });
1✔
64
            ws.onClose(ctx -> clientConnections.remove(ctx.getSessionId()));
1✔
65
        });
1✔
66
        javalin.start();
1✔
67
    }
1✔
68

69
    private void responseAttachment(String name, int index, Context ctx) {
70
        DalInstance dalInstance = dalInstances.get(name);
1✔
71
        if (dalInstance != null) {
1✔
72
            Watch watch = dalInstance.watches.get(index);
1✔
73
            if (watch instanceof DalInstance.BinaryWatch) {
1✔
74

75
                DalInstance.BinaryWatch binaryWatch = (DalInstance.BinaryWatch) watch;
1✔
76
                String contentType = Sneaky.get(() -> new Tika().detect(binaryWatch.binary()));
1✔
77
                ctx.contentType(contentType == null ? "application/octet-stream" : contentType);
1✔
78
                ctx.result(binaryWatch.binary());
1✔
79
            }
80
        }
81
    }
1✔
82

83
    public static void watch(DAL dal, String property, Data value) {
84
        if (inspector != null)
1✔
85
            inspector.watchInner(dal, property, value);
1✔
86
    }
1✔
87

88
    private void watchInner(DAL dal, String property, Data value) {
89
        if (inspector.calledFromInspector())
1✔
90
            dalInstances.get(dal.getName()).watch(property, value);
1✔
91
    }
1✔
92

93
    private void pass(String name) {
94
        if (!name.equals("Try It!")) {
1✔
95
            DalInstance remove = dalInstances.remove(name);
1✔
96
            if (remove != null)
1✔
97
                remove.pass();
1✔
98
        }
99
    }
1✔
100

101
    private void waitForReady() {
102
        Sneaky.run(serverReadyLatch::await);
1✔
103
    }
1✔
104

105
    private static int getServerPort() {
106

107
        return getFirstPresent(() -> ofNullable(System.getenv("DAL_INSPECTOR_PORT")),
1✔
108
                () -> ofNullable(System.getProperty("dal.inspector.port")))
1✔
109
                .map(Integer::parseInt)
1✔
110
                .orElse(10082);
1✔
111
    }
112

113
    public static void ready() {
114
        inspector.waitForReady();
1✔
115
    }
1✔
116

117
    private void releaseAll() {
118
        for (String instanceName : new ArrayList<>(dalInstances.keySet()))
1✔
119
            release(instanceName);
1✔
120
    }
1✔
121

122
    private void release(String name) {
123
        if (!name.equals("Try It!")) {
1✔
124
            DalInstance remove = dalInstances.remove(name);
1✔
125
            if (remove != null)
1✔
126
                remove.release();
1✔
127
        }
128
    }
1✔
129

130
    public static void setDefaultMode(Mode mode) {
131
        Inspector.mode = mode;
1✔
132
    }
1✔
133

134
    private void exchange(String session, String body) {
135
        if (clientConnections.containsKey(session)) {
1✔
136
            clientMonitors.put(session, Arrays.stream(body.trim().split("\\n")).map(String::trim).filter(s -> !s.isEmpty()).collect(Collectors.toSet()));
1✔
137

138
            for (DalInstance dalInstance : dalInstances.values()) {
1✔
139
                if (dalInstance.running)
1✔
140
                    clientConnections.get(session).send(ObjectWriter.serialize(new HashMap<String, String>() {{
1✔
141
                        put("request", dalInstance.dal.getName());
1✔
142
                    }}));
1✔
143
            }
1✔
144
        }
145
    }
1✔
146

147
    public static class DalInstance {
148
        private final Supplier<Object> input;
149
        private boolean running = true;
1✔
150
        private boolean pass = false;
1✔
151
        private final DAL dal;
152
        private final String code;
153
        private final List<Watch> watches = new ArrayList<>();
1✔
154

155
        public DalInstance(Supplier<Object> input, DAL dal, String code) {
1✔
156
            this.input = input;
1✔
157
            this.dal = dal;
1✔
158
            this.code = code;
1✔
159
        }
1✔
160

161
        public DalInstance(Data<?> inputData, DAL dal, String code) {
1✔
162
            input = inputData::value;
1✔
163
            this.dal = dal;
1✔
164
            this.code = code;
1✔
165
        }
1✔
166

167
        public String execute(String code) {
168
            watches.clear();
1✔
169
            Map<String, Object> response = new HashMap<>();
1✔
170
            DALRuntimeContext runtimeContext = dal.getRuntimeContextBuilder().build(input::get, null);
1✔
171
            try {
172
                response.put("root", runtimeContext.getThis().dump());
1✔
173
                DALNode dalNode = dal.compileSingle(code, runtimeContext);
1✔
174
                response.put("inspect", dalNode.inspect());
1✔
175
                response.put("result", dalNode.evaluateData(runtimeContext).dump());
1✔
176
            } catch (InterpreterException e) {
1✔
177
                response.put("error", e.show(code) + "\n\n" + e.getMessage());
1✔
178
            }
1✔
179
            response.put("watches", watches.stream().map(Watch::collect).collect(Collectors.toList()));
1✔
180
            return ObjectWriter.serialize(response);
1✔
181
        }
182

183
        public boolean hold() {
184
            System.err.println("Waiting for DAL inspector release...");
1✔
185
            try {
186
                Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
1✔
187

188
                System.err.println("\tDal inspector running at:");
1✔
189

190
                while (interfaces.hasMoreElements()) {
1✔
191
                    Enumeration<InetAddress> inetAddresses = interfaces.nextElement().getInetAddresses();
1✔
192
                    while (inetAddresses.hasMoreElements()) {
1✔
193
                        InetAddress address = inetAddresses.nextElement();
1✔
194
                        System.err.printf("\t\thttp://%s:%d%n", address.getHostAddress(), getServerPort());
1✔
195
                    }
1✔
196
                }
1✔
UNCOV
197
            } catch (Exception ignore) {
×
198
            }
1✔
199
            //        TODO use sempahore to wait for the result
200
            Instant now = Instant.now();
1✔
201
            while (running && stillWaiting(now))
1✔
202
                Sneaky.run(() -> Thread.sleep(20));
1✔
203
//            TODO use logger
204
            System.err.println("DAL inspector released with pass: " + pass);
1✔
205
            return pass;
1✔
206
        }
207

208
        public void release() {
209
            running = false;
1✔
210
        }
1✔
211

212
        public void pass() {
213
            pass = true;
1✔
214
            release();
1✔
215
        }
1✔
216

217
        private byte[] getBytes(Data<?> data) {
218
            return getFirstPresent(
1✔
219
                    () -> data.cast(byte[].class),
1✔
220
                    () -> data.cast(InputStream.class).map(stream -> Sneaky.get(() -> {
1✔
UNCOV
221
                        try (ByteArrayOutputStream buffer = new ByteArrayOutputStream()) {
×
222
                            int size;
UNCOV
223
                            byte[] data1 = new byte[1024];
×
224
                            while ((size = stream.read(data1, 0, data1.length)) != -1)
×
UNCOV
225
                                buffer.write(data1, 0, size);
×
226
                            return buffer.toByteArray();
×
227
                        }
228
                    })),
229
                    () -> data.cast(Byte[].class).map(bytes -> {
1✔
UNCOV
230
                        ByteArrayOutputStream stream = new ByteArrayOutputStream();
×
UNCOV
231
                        for (Byte b : bytes)
×
UNCOV
232
                            stream.write(b);
×
233
                        return stream.toByteArray();
×
234
                    })
235
            ).orElse(null);
1✔
236
        }
237

238
        public void watch(String property, Data value) {
239
            byte[] bytes = getBytes(value);
1✔
240
            if (bytes != null) {
1✔
241
                watches.add(new BinaryWatch(property, bytes));
1✔
242
            } else
243
                watches.add(new DefaultWatch(property, value));
1✔
244
        }
1✔
245

246

247
        public class DefaultWatch implements Watch {
248
            private final String property;
249
            private final String value;
250

251
            public DefaultWatch(String property, Data value) {
1✔
252
                this.property = property;
1✔
253
                this.value = value.dump();
1✔
254
            }
1✔
255

256
            @Override
257
            public Map<String, Object> collect() {
258
                return new HashMap<String, Object>() {{
1✔
259
                    put("property", property);
1✔
260
                    put("type", "DEFAULT");
1✔
261
                    put("value", value);
1✔
262
                }};
1✔
263
            }
264
        }
265

266
        private class BinaryWatch implements Watch {
267
            private final String property;
268
            private final int index;
269
            private final byte[] binary;
270

271
            public BinaryWatch(String property, byte[] value) {
1✔
272
                this.property = property;
1✔
273
                index = watches.size();
1✔
274
                binary = new byte[value.length];
1✔
275
                System.arraycopy(value, 0, binary, 0, value.length);
1✔
276
            }
1✔
277

278
            public byte[] binary() {
279
                return binary;
1✔
280
            }
281

282
            @Override
283
            public Map<String, Object> collect() {
284
                return new HashMap<String, Object>() {{
1✔
285
                    put("property", property);
1✔
286
                    put("type", "BINARY");
1✔
287
                    put("url", "/attachments?name=" + dal.getName() + "&index=" + index + "&tm=" + Instant.now().getEpochSecond());
1✔
288
                }};
1✔
289
            }
290
        }
291
    }
292

293
    public boolean inspectInner(DAL dal, Data input, String code) {
294
        if (calledFromInspector())
1✔
UNCOV
295
            return false;
×
296
//        lock inspect by name
297
//        check mode
298
        if (currentMode() == Mode.FORCED) {
1✔
299
            DalInstance dalInstance = new DalInstance(input, dal, code);
1✔
300
            dalInstances.put(dal.getName(), dalInstance);
1✔
301

302
//            List<WsContext> monitored = clientMonitors.entrySet().stream().filter(e -> e.getValue().contains(dal.getName()))
303
//                    .map(o -> clientConnections.get(o.getKey()))
304
//                    .collect(Collectors.toList());
305
//            TODO check monitor flag
306
            for (WsContext wsContext : clientConnections.values()) {
1✔
307
                wsContext.send(ObjectWriter.serialize(new HashMap<String, String>() {{
1✔
308
                    put("request", dal.getName());
1✔
309
                }}));
1✔
310
            }
1✔
311

312
            return dalInstance.hold();
1✔
313

314
        } else {
315
//        TODO refactor
316
            List<WsContext> monitored = clientMonitors.entrySet().stream().filter(e -> e.getValue().contains(dal.getName()))
1✔
317
                    .map(o -> clientConnections.get(o.getKey()))
1✔
318
                    .collect(Collectors.toList());
1✔
319
            if (!monitored.isEmpty()) {
1✔
320
                DalInstance dalInstance = new DalInstance(input, dal, code);
1✔
321
                dalInstances.put(dal.getName(), dalInstance);
1✔
322
                for (WsContext wsContext : monitored) {
1✔
323
                    wsContext.send(ObjectWriter.serialize(new HashMap<String, String>() {{
1✔
324
                        put("request", dal.getName());
1✔
325
                    }}));
1✔
326
                }
1✔
UNCOV
327
                return dalInstance.hold();
×
328
            }
329
            return false;
1✔
330
        }
331
    }
332

333
    private static boolean stillWaiting(Instant now) {
334
        String waitingTime = System.getenv("DAL_INSPECTOR_WAITING_TIME");
1✔
335
        return (waitingTime == null ? 3600 * 1000 * 24 : parseLong(waitingTime))
1✔
336
                > Duration.between(now, Instant.now()).toMillis();
1✔
337
    }
338

339
    public static boolean inspect(DAL dal, Data input, String code) {
340
        if (currentMode() != Mode.DISABLED)
1✔
341
            return inspector.inspectInner(dal, input, code);
1✔
UNCOV
342
        return false;
×
343
    }
344

345
    private String request(String name) {
346
//       TODO reject other request
347
        return dalInstances.get(name).code;
1✔
348
    }
349

350
    private String execute(String name, String code) {
351
        return dalInstances.get(name).execute(code);
1✔
352
    }
353

354
    public static void register(DAL dal) {
355
        inspector.addInstance(dal);
1✔
356
    }
1✔
357

358
    private void addInstance(DAL dal) {
359
        instances.add(dal);
1✔
360
        for (WsContext ctx : clientConnections.values()) {
1✔
361
            sendInstances(ctx);
1✔
362
        }
1✔
363
    }
1✔
364

365
    private void sendInstances(WsContext ctx) {
366
        ctx.send(ObjectWriter.serialize(new HashMap<String, Object>() {{
1✔
367
            put("instances", instances.stream().map(DAL::getName).collect(Collectors.toSet()));
1✔
368
            put("session", ctx.getSessionId());
1✔
369
        }}));
1✔
370
    }
1✔
371

372
    private void stop() {
373
        javalin.close();
1✔
374
    }
1✔
375

376
    public static void launch() {
377
        if (inspector == null) {
1✔
378
            inspector = new Inspector();
1✔
379
        }
380
    }
1✔
381

382
    public static void shutdown() {
383
        if (inspector != null) {
1✔
384
            inspector.stop();
1✔
385
            inspector = null;
1✔
386
        }
387
    }
1✔
388

389
    public static void setDefaultInput(Supplier<Object> supplier) {
390
        defaultInput = supplier;
1✔
391
    }
1✔
392

393
    public static Mode currentMode() {
394
        return getFirstPresent(() -> ofNullable(mode),
1✔
UNCOV
395
                () -> ofNullable(System.getenv("DAL_INSPECTOR_MODE")).map(Mode::valueOf),
×
UNCOV
396
                () -> ofNullable(System.getProperty("dal.inspector.mode")).map(Mode::valueOf))
×
397
                .orElse(Mode.DISABLED);
1✔
398
    }
399

400
    public enum Mode {
1✔
401
        DISABLED, FORCED, AUTO
1✔
402
    }
403

404
    private boolean calledFromInspector() {
405
        for (StackTraceElement stack : Thread.currentThread().getStackTrace())
1✔
406
            if (DalInstance.class.getName().equals(stack.getClassName()))
1✔
407
                return true;
1✔
408
        return false;
1✔
409
    }
410

411
    public static void main(String[] args) {
UNCOV
412
        launch();
×
UNCOV
413
    }
×
414

415
    interface Watch {
416
        Map<String, Object> collect();
417
    }
418
}
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