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

goblint / GobPie / 9678427073

26 Jun 2024 10:58AM UTC coverage: 58.518%. First build
9678427073

push

github

web-flow
Merge pull request #72 from AnetteTaivere/master

Add functional tests

123 of 233 branches covered (52.79%)

Branch coverage included in aggregate %.

128 of 160 new or added lines in 20 files covered. (80.0%)

406 of 671 relevant lines covered (60.51%)

2.74 hits per line

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

73.81
/src/main/java/goblintserver/GoblintServer.java
1
package goblintserver;
2

3
import gobpie.GobPieConfiguration;
4
import gobpie.GobPieException;
5
import magpiebridge.core.MagpieServer;
6
import org.apache.logging.log4j.LogManager;
7
import org.apache.logging.log4j.Logger;
8
import org.eclipse.lsp4j.MessageParams;
9
import org.eclipse.lsp4j.MessageType;
10
import org.zeroturnaround.exec.InvalidExitValueException;
11
import org.zeroturnaround.exec.ProcessExecutor;
12
import org.zeroturnaround.exec.StartedProcess;
13
import org.zeroturnaround.exec.listener.ProcessListener;
14
import org.zeroturnaround.process.UnixProcess;
15

16
import java.io.ByteArrayOutputStream;
17
import java.io.File;
18
import java.io.IOException;
19
import java.util.Arrays;
20
import java.util.List;
21
import java.util.Collections;
22
import java.util.concurrent.TimeoutException;
23

24
import static gobpie.GobPieExceptionType.GOBLINT_EXCEPTION;
25

26
/**
27
 * The Class GoblintServer.
28
 * <p>
29
 * Reads the configuration for GobPie extension, including Goblint configuration file name.
30
 * Starts Goblint Server and waits for the unix socket to be created.
31
 *
32
 * @author Karoliine Holter
33
 * @author Juhan Oskar Hennoste
34
 * @since 0.0.2
35
 */
36

37
public class GoblintServer {
38

39
    private static final String GOBLINT_SOCKET = "goblint.sock";
40
    private static final int SIGINT = 2;
41
    private final MagpieServer magpieServer;
42
    private final GobPieConfiguration configuration;
43
    private StartedProcess goblintRunProcess;
44

45
    private final Logger log = LogManager.getLogger(GoblintServer.class);
4✔
46

47

48
    public GoblintServer(MagpieServer magpieServer, GobPieConfiguration configuration) {
2✔
49
        this.magpieServer = magpieServer;
3✔
50
        this.configuration = configuration;
3✔
51
    }
1✔
52

53
    /**
54
     * Aborts the previous running analysis by sending a SIGINT signal to Goblint.
55
     */
56
    public void abortAnalysis() throws IOException {
NEW
57
        Process goblintProcess = goblintRunProcess.getProcess();
×
NEW
58
        int pid = Math.toIntExact(goblintProcess.pid());
×
NEW
59
        UnixProcess unixProcess = new UnixProcess(pid);
×
NEW
60
        unixProcess.kill(SIGINT);
×
61
    }
×
62

63

64
    /**
65
     * The method that is triggered before each analysis.
66
     * <p>
67
     * preAnalyzeCommand is read from the GobPie configuration file.
68
     * Can be used for automating the compilation database generation.
69
     */
70
    public void preAnalyse() {
71
        List<String> preAnalyzeCommand = configuration.preAnalyzeCommand();
4✔
72
        if ((preAnalyzeCommand != null) && (!preAnalyzeCommand.isEmpty())) {
5✔
73
            try {
74
                log.info("PreAnalysis command ran: '" + preAnalyzeCommand + "'");
5✔
75
                ProcessListener processListener = new ProcessListener() {
11✔
76
                };
77
                StartedProcess preAnalysisProcess = runCommand(new File(System.getProperty("user.dir")), preAnalyzeCommand, processListener);
10✔
78
                switch (preAnalysisProcess.getProcess().waitFor()) {
4!
79
                    case 0 -> log.info("PreAnalysis command finished.");
5✔
80
                    default -> {
NEW
81
                        log.warn("Running preAnalysis command failed. (code: " + preAnalysisProcess.getProcess().exitValue() + ")");
×
NEW
82
                        magpieServer.forwardMessageToClient(new MessageParams(MessageType.Warning, "Running preAnalysis command failed."));
×
83
                    }
84
                }
85
            } catch (IOException | InvalidExitValueException | InterruptedException | TimeoutException e) {
1✔
86
                log.warn("Running preAnalysis command failed. " + e.getMessage());
6✔
87
                this.magpieServer.forwardMessageToClient(new MessageParams(MessageType.Warning, "Running preAnalysis command failed. " + e.getMessage()));
10✔
88
            }
1✔
89
        }
90
    }
1✔
91

92

93
    public String getGoblintSocket() {
94
        return GOBLINT_SOCKET;
2✔
95
    }
96

97

98
    /**
99
     * Method for constructing the command to run Goblint server.
100
     * Files to analyse must be defined in goblint conf.
101
     */
102
    public List<String> constructGoblintRunCommand() {
103
        List<String> command = new java.util.ArrayList<>(List.of(
11✔
104
                configuration.goblintExecutable(),
43✔
105
                "--enable", "server.enabled",
106
                "--enable", "server.reparse",
107
                "--set", "server.mode", "unix",
108
                "--set", "server.unix-socket", new File(getGoblintSocket()).getAbsolutePath()
4✔
109
        ));
110
        if (configuration.abstractDebugging()) {
5!
111
            Collections.addAll(command, "--enable", "exp.arg.enabled");
13✔
112
        }
113
        return command;
2✔
114
    }
115

116

117
    private String[] constructGoblintVersionCheckCommand() {
118
        return new String[]{
7✔
119
                configuration.goblintExecutable(),
6✔
120
                "--version"
121
        };
122
    }
123

124

125
    /**
126
     * Method to start the Goblint server.
127
     *
128
     * @throws GobPieException when running Goblint fails.
129
     */
130
    public void startGoblintServer() {
131
        try {
132
            // run command to start Goblint
133
            ProcessListener listener = new ProcessListener() {
11✔
134
                public void afterStop(Process process) {
NEW
135
                    switch (process.exitValue()) {
×
NEW
136
                        case 0 -> log.info("Goblint server has stopped.");
×
137
                        case 143 -> {
NEW
138
                            log.info("Goblint server has been killed.");
×
NEW
139
                            magpieServer.forwardMessageToClient(new MessageParams(MessageType.Error, "Goblint server has been killed. Please check the output terminal of GobPie extension for more information."));
×
NEW
140
                        }
×
141
                        default -> {
NEW
142
                            log.error("Goblint server exited due to an error (code: " + process.exitValue() + "). Please fix the issue reported above and rerun the analysis to restart the extension.");
×
NEW
143
                            magpieServer.forwardMessageToClient(new MessageParams(MessageType.Error, "Goblint server exited due to an error. Please check the output terminal of GobPie extension for more information."));
×
144
                        }
145
                    }
NEW
146
                    magpieServer.cleanUp();
×
147
                    // TODO: throw an exception? where (and how) can it be caught to be handled though?
NEW
148
                }
×
149
            };
150
            List<String> goblintRunCommand = constructGoblintRunCommand();
3✔
151
            log.info("Goblint run with command: " + String.join(" ", goblintRunCommand));
7✔
152
            goblintRunProcess = runCommand(new File(System.getProperty("user.dir")), goblintRunCommand, listener);
11✔
153
        } catch (IOException | InvalidExitValueException | InterruptedException | TimeoutException e) {
1✔
154
            throw new GobPieException("Running Goblint failed.", e, GOBLINT_EXCEPTION);
7✔
155
        }
1✔
156
    }
1✔
157

158
    public boolean isAlive() {
NEW
159
        return goblintRunProcess.getProcess().isAlive();
×
160
    }
161

162

163
    /**
164
     * Checks Goblint command reported version.
165
     *
166
     * @throws GobPieException when running Goblint fails.
167
     */
168
    public String checkGoblintVersion() {
169
        File dirPath = new File(System.getProperty("user.dir"));
6✔
170
        String[] command = constructGoblintVersionCheckCommand();
3✔
171

172
        ByteArrayOutputStream output = new ByteArrayOutputStream();
4✔
173

174
        try {
175
            log.debug("Waiting for command: " + Arrays.toString(command) + " to run...");
6✔
176
            new ProcessExecutor()
4✔
177
                    .directory(dirPath)
2✔
178
                    .command(command)
2✔
179
                    .redirectOutput(output)
2✔
180
                    .redirectError(output)
1✔
181
                    .execute();
2✔
182
        } catch (IOException | InterruptedException | TimeoutException e) {
1✔
183
            throw new GobPieException("Checking version failed.", e, GOBLINT_EXCEPTION);
7✔
184
        }
1✔
185

186
        return output.toString();
3✔
187
    }
188

189

190
    /**
191
     * Method for running a command.
192
     *
193
     * @param dirPath The directory in which the command will run.
194
     * @param command The command to run.
195
     * @return An object that represents a process that has started. It may or may not have finished.
196
     */
197
    private StartedProcess runCommand(File dirPath, List<String> command, ProcessListener listener) throws IOException, InterruptedException, TimeoutException {
198
        log.debug("Waiting for command: " + command + " to run...");
5✔
199
        return new ProcessExecutor()
5✔
200
                .directory(dirPath)
2✔
201
                .command(command)
2✔
202
                .redirectOutput(System.err)
2✔
203
                .redirectError(System.err)
2✔
204
                .addListener(listener)
1✔
205
                .start();
1✔
206
    }
207

208
}
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