Skip to content

Commit 2a3369c

Browse files
committed
Merge branch 'developer'
2 parents 38aadc9 + bc75326 commit 2a3369c

File tree

398 files changed

+17217
-10612
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

398 files changed

+17217
-10612
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,6 @@ main/src/main/webapp/restdocs
2222
main/uploads
2323

2424
frontend/src/main/javascript/npm-debug\.log
25+
frontend/src/main/javascript/package-lock\.json
2526

2627
backend/debug.log

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ before_cache:
2727
install: true # skip mvn install, because we essentially run the same command in the script routine
2828

2929
script:
30-
- mvn clean package
30+
- mvn clean package -Pbootstrap
3131

3232
branches:
3333
only:

CHANGELOG.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,32 @@
1+
# ALEX 1.6.0
2+
3+
## Breaking Changes
4+
5+
* Symbols have to be migrated to the new version.
6+
Please use the migration script `src/main/resources/migration/1.6.0/migrate-symbols-1.5.0-to-1.6.0.js` via:
7+
8+
`node migrate-symbols-1.5.0-to-1.6.0.js -i ./symbols-from-1.5.0.json -o ./symbols-for-1.6.0.json`
9+
10+
* Tests have to be migrated to the new version.
11+
Please use the migration script `src/main/resources/migration/1.6.0/migrate-tests-1.5.0-to-1.6.0.js` via:
12+
13+
`node migrate-tests-1.5.0-to-1.6.0.js -i ./tests-from-1.5.0.json -o ./tests-for-1.6.0.json`
14+
15+
## Features
16+
17+
* Symbols can be composed of other symbols.
18+
* Symbols can be parameterized in learning experiments.
19+
* Connect ALEX to a MySQL database.
20+
See the README for instructions.
21+
* Generate test suites from discrimination tree based learners (TTT, Discrimination Tree).
22+
* Use test cases in test suites as equivalence oracle.
23+
* Added support for Internet Explorer
24+
* Execute JavaScript asynchronously
25+
* Symbol parameters can be *public* or *private*.
26+
If a parameter is public, its value can be set by the user while configuring a testing or learning process.
27+
If it is private, its value cannot be set manually, but is resolved by the value in the global data context.
28+
29+
130
# ALEX 1.5.1
231

332
This release only contains some bug fixes.

README.md

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Make sure you have Java 8 installed on your system.
1818
We advise to use a modern web browser like Google Chrome, Mozilla Firefox or Microsoft Edge with JavaScript enabled.
1919

2020
1. [Download](https://github.com/LearnLib/alex/releases/latest) the latest version.
21-
2. Open a terminal and start ALEX via `java -jar alex-1.5.1.war [--alex.port=XXXX]`.
21+
2. Open a terminal and start ALEX via `java -jar alex-1.6.0.war [--server.port=XXXX]`.
2222
3. Wait until the command line prints something like `de.learnlib.alex.App - Started App in XX.XXX seconds`.
2323
3. Open *http://localhost:8000* in a web browser.
2424

@@ -48,7 +48,29 @@ cd alex
4848
mvn install package [-DskipTests]
4949
```
5050

51-
The bundle can then be found at `build/target/alex-build-1.5.1.war`.
51+
The bundle can then be found at `build/target/alex-build-1.6.0.war`.
52+
53+
## Connecting to a database
54+
55+
Per default, ALEX uses an embedded HSQL database which is stored in the *target/alex-database* directory.
56+
You can however also connect ALEX to a MySQL 5.7 database.
57+
Other databases have not been tested yet.
58+
59+
### MySQL
60+
61+
Create a file called *application.properties* and add the following contents (and change the values according to your setup):
62+
63+
```
64+
# application.properties
65+
spring.datasource.url=jdbc:mysql://localhost:3306/alex
66+
spring.datasource.username=root
67+
spring.datasource.password=root
68+
spring.jpa.hibernate.ddl-auto=update
69+
```
70+
71+
Then, start ALEX like this:
72+
73+
`java -jar alex-1.6.0.war "--spring.config.location=/path/to/your/application.properties"`
5274

5375
## Further reading
5476

backend/pom.xml

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
<parent>
2424
<groupId>de.learnlib.alex</groupId>
2525
<artifactId>alex-parent</artifactId>
26-
<version>1.5.1</version>
26+
<version>1.6.0</version>
2727
<relativePath>../pom.xml</relativePath>
2828
</parent>
2929

@@ -59,6 +59,7 @@
5959
<mockito.version>2.12.0</mockito.version>
6060
<powermock.version>1.7.3</powermock.version>
6161
<json-schema-validator.version>2.2.8</json-schema-validator.version>
62+
<mysql-connector.version>8.0.11</mysql-connector.version>
6263
</properties>
6364

6465
<!--===== dependencies ======-->
@@ -182,6 +183,12 @@
182183
<version>${json-path.version}</version>
183184
</dependency>
184185

186+
<dependency>
187+
<groupId>mysql</groupId>
188+
<artifactId>mysql-connector-java</artifactId>
189+
<version>${mysql-connector.version}</version>
190+
</dependency>
191+
185192
<!-- LearnLib -->
186193
<dependency>
187194
<groupId>de.learnlib</groupId>
@@ -423,11 +430,12 @@
423430
</plugins>
424431
</build>
425432

433+
426434
<profiles>
427435
<profile>
428436
<id>createRestDoc</id>
429437
<activation>
430-
<activeByDefault>true</activeByDefault>
438+
<activeByDefault>false</activeByDefault>
431439
</activation>
432440
<build>
433441
<plugins>

backend/src/main/java/de/learnlib/alex/ALEXApplication.java

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
import de.learnlib.alex.auth.rest.UserResource;
2323
import de.learnlib.alex.auth.security.AuthenticationFilter;
2424
import de.learnlib.alex.common.exceptions.NotFoundExceptionMapper;
25+
import de.learnlib.alex.common.exceptions.UnauthorizedExceptionMapper;
26+
import de.learnlib.alex.common.exceptions.ValidationExceptionMapper;
2527
import de.learnlib.alex.config.dao.SettingsDAO;
2628
import de.learnlib.alex.config.entities.DriverSettings;
2729
import de.learnlib.alex.config.entities.Settings;
@@ -111,6 +113,8 @@ public ALEXApplication() {
111113

112114
// Exceptions
113115
register(NotFoundExceptionMapper.class);
116+
register(UnauthorizedExceptionMapper.class);
117+
register(ValidationExceptionMapper.class);
114118

115119
// Other
116120
register(MultiPartFeature.class);
@@ -148,14 +152,13 @@ public void initSettings() {
148152
String chromeDriverPath = System.getProperty("webdriver.chrome.driver", "");
149153
String geckoDriverPath = System.getProperty("webdriver.gecko.driver", "");
150154
String edgeDriverPath = System.getProperty("webdriver.edge.driver", "");
155+
String ieDriverPath = System.getProperty("webdriver.ie.driver", "");
151156
String remoteDriverURL = System.getProperty("webdriver.remote.url", "");
152157

153-
final DriverSettings driverSettings = new DriverSettings(chromeDriverPath,
154-
geckoDriverPath,
155-
edgeDriverPath,
156-
remoteDriverURL);
157-
settings.setDriverSettings(driverSettings);
158+
final DriverSettings driverSettings = new DriverSettings(chromeDriverPath, geckoDriverPath,
159+
edgeDriverPath, remoteDriverURL, ieDriverPath);
158160

161+
settings.setDriverSettings(driverSettings);
159162
settingsDAO.create(settings);
160163
} catch (ValidationException e) {
161164
e.printStackTrace();
@@ -167,21 +170,26 @@ public void initSettings() {
167170
final String chromeDriver = env.getProperty("chromeDriver");
168171
final String geckoDriver = env.getProperty("geckoDriver");
169172
final String edgeDriver = env.getProperty("edgeDriver");
173+
final String ieDriver = env.getProperty("ieDriver");
170174
final String remoteDriver = env.getProperty("remoteDriver");
171175

172-
if (!env.getProperty("chromeDriver").equals("")) {
176+
if (!chromeDriver.isEmpty()) {
173177
settings.getDriverSettings().setChrome(chromeDriver);
174178
}
175179

176-
if (!env.getProperty("geckoDriver").equals("")) {
180+
if (!geckoDriver.isEmpty()) {
177181
settings.getDriverSettings().setFirefox(geckoDriver);
178182
}
179183

180-
if (!env.getProperty("edgeDriver").equals("")) {
184+
if (!edgeDriver.isEmpty()) {
181185
settings.getDriverSettings().setEdge(edgeDriver);
182186
}
183187

184-
if (!env.getProperty("remoteDriver").equals("")) {
188+
if (!ieDriver.isEmpty()) {
189+
settings.getDriverSettings().setIe(ieDriver);
190+
}
191+
192+
if (!remoteDriver.isEmpty()) {
185193
settings.getDriverSettings().setRemote(remoteDriver);
186194
}
187195

@@ -197,6 +205,7 @@ public void initSettings() {
197205
System.setProperty("webdriver.chrome.driver", settings.getDriverSettings().getChrome());
198206
System.setProperty("webdriver.gecko.driver", settings.getDriverSettings().getFirefox());
199207
System.setProperty("webdriver.edge.driver", settings.getDriverSettings().getEdge());
208+
System.setProperty("webdriver.ie.driver", settings.getDriverSettings().getIe());
200209
System.setProperty("webdriver.remote.url", settings.getDriverSettings().getRemote());
201210
}
202211

backend/src/main/java/de/learnlib/alex/auth/dao/UserDAOImpl.java

Lines changed: 43 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323
import de.learnlib.alex.common.utils.IdsList;
2424
import de.learnlib.alex.common.utils.ValidationExceptionHelper;
2525
import de.learnlib.alex.data.dao.FileDAO;
26+
import de.learnlib.alex.data.dao.ProjectDAO;
27+
import de.learnlib.alex.data.entities.Project;
28+
import de.learnlib.alex.data.repositories.ProjectRepository;
2629
import org.apache.logging.log4j.LogManager;
2730
import org.apache.logging.log4j.Logger;
2831
import org.springframework.dao.DataIntegrityViolationException;
@@ -45,21 +48,36 @@ public class UserDAOImpl implements UserDAO {
4548
private static final Logger LOGGER = LogManager.getLogger();
4649

4750
/** The UserRepository to use. Will be injected. */
48-
private UserRepository userRepository;
51+
private final UserRepository userRepository;
4952

5053
/** The FileDAO to use. Will be injected. */
51-
private FileDAO fileDAO;
54+
private final FileDAO fileDAO;
55+
56+
/** The DAO for project. */
57+
private final ProjectDAO projectDAO;
58+
59+
/** The repository for projects. */
60+
private final ProjectRepository projectRepository;
5261

5362
/**
5463
* Creates a new UserDAO.
5564
*
56-
* @param userRepository The UserRepository to use.
57-
* @param fileDAO The FileDAO to use.
65+
* @param userRepository
66+
* The UserRepository to use.
67+
* @param fileDAO
68+
* The FileDAO to use.
69+
* @param projectDAO
70+
* The ProjectDAO to use.
71+
* @param projectRepository
72+
* The repository for project.
5873
*/
5974
@Inject
60-
public UserDAOImpl(UserRepository userRepository, FileDAO fileDAO) {
75+
public UserDAOImpl(UserRepository userRepository, FileDAO fileDAO, ProjectDAO projectDAO,
76+
ProjectRepository projectRepository) {
6177
this.userRepository = userRepository;
6278
this.fileDAO = fileDAO;
79+
this.projectDAO = projectDAO;
80+
this.projectRepository = projectRepository;
6381
}
6482

6583
@Override
@@ -115,8 +133,23 @@ public void update(User user) throws ValidationException {
115133
@Override
116134
@Transactional
117135
public void delete(Long id) throws NotFoundException {
118-
User user = getById(id);
136+
delete(getById(id));
137+
}
138+
139+
@Override
140+
@Transactional
141+
public void delete(IdsList ids) throws NotFoundException {
142+
final List<User> users = userRepository.findAllByIdIn(ids);
143+
if (users.size() != ids.size()) {
144+
throw new NotFoundException("At least one user could not be found.");
145+
}
146+
147+
for (User user : users) {
148+
delete(user);
149+
}
150+
}
119151

152+
private void delete(User user) throws NotFoundException {
120153
// make sure there is at least one registered admin
121154
if (user.getRole().equals(UserRole.ADMIN)) {
122155
List<User> admins = userRepository.findByRole(UserRole.ADMIN);
@@ -126,6 +159,9 @@ public void delete(Long id) throws NotFoundException {
126159
}
127160
}
128161

162+
for (Project project : projectRepository.findAllByUser_Id(user.getId())) {
163+
projectDAO.delete(user, project.getId());
164+
}
129165
userRepository.delete(user);
130166

131167
// delete the user directory
@@ -136,19 +172,10 @@ public void delete(Long id) throws NotFoundException {
136172
}
137173
}
138174

139-
@Override
140-
@Transactional
141-
public void delete(IdsList ids) throws NotFoundException {
142-
for (Long id: ids) {
143-
User user = getById(id);
144-
userRepository.delete(user);
145-
}
146-
}
147-
148175
private void saveUser(User user) {
149176
try {
150177
userRepository.save(user);
151-
// error handling
178+
// error handling
152179
} catch (TransactionSystemException e) {
153180
LOGGER.info("Saving a user failed:", e);
154181
ConstraintViolationException cve = (ConstraintViolationException) e.getCause().getCause();

backend/src/main/java/de/learnlib/alex/auth/repositories/UserRepository.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,14 @@ public interface UserRepository extends JpaRepository<User, Long> {
5050
@Transactional(readOnly = true)
5151
User findOneByEmail(String email);
5252

53+
/**
54+
* Find multiple users by IDs.
55+
*
56+
* @param userIds
57+
* The IDs of the users to get.
58+
* @return The matching users.
59+
*/
60+
@Transactional(readOnly = true)
61+
List<User> findAllByIdIn(List<Long> userIds);
62+
5363
}

backend/src/main/java/de/learnlib/alex/auth/rest/UserResource.java

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,6 @@
3131
import de.learnlib.alex.webhooks.services.WebhookService;
3232
import org.apache.logging.log4j.LogManager;
3333
import org.apache.logging.log4j.Logger;
34-
import org.apache.logging.log4j.Marker;
35-
import org.apache.logging.log4j.MarkerManager;
3634
import org.apache.shiro.authz.UnauthorizedException;
3735
import org.hibernate.validator.internal.constraintvalidators.hv.EmailValidator;
3836
import org.jose4j.json.internal.json_simple.JSONObject;
@@ -68,11 +66,6 @@ public class UserResource {
6866

6967
private static final Logger LOGGER = LogManager.getLogger();
7068

71-
private static final Marker USER_MARKER = MarkerManager.getMarker("USER");
72-
private static final Marker REST_MARKER = MarkerManager.getMarker("REST");
73-
private static final Marker RESOURCE_MARKER = MarkerManager.getMarker("USER_RESOURCE")
74-
.setParents(USER_MARKER, REST_MARKER);
75-
7669
/** The UserDAO to user. */
7770
@Inject
7871
private UserDAO userDAO;
@@ -345,7 +338,7 @@ public Response promoteUser(@PathParam("id") Long userId) throws NotFoundExcepti
345338
User userToPromote = userDAO.getById(userId);
346339
userToPromote.setRole(UserRole.ADMIN);
347340
userDAO.update(userToPromote);
348-
LOGGER.info(RESOURCE_MARKER, "User {} promoted.", user);
341+
LOGGER.info("User {} promoted.", user);
349342

350343
LOGGER.traceExit(userToPromote);
351344
webhookService.fireEvent(user, new UserEvent.RoleUpdated(userToPromote));
@@ -461,14 +454,12 @@ public Response delete(@PathParam("ids") IdsList ids) throws NotFoundException {
461454
}
462455

463456
userDAO.delete(ids);
464-
465457
LOGGER.traceExit("User(s) {} deleted.", ids);
466458

467459
ids.forEach(id -> webhookService.fireEvent(new User(id), new UserEvent.Deleted(id)));
468460
return Response.status(Status.NO_CONTENT).build();
469461
}
470462

471-
472463
/**
473464
* Logs in a user by generating a unique JWT for him that needs to be send in every request.
474465
*
@@ -509,4 +500,21 @@ public Response login(User user) throws NotFoundException {
509500
}
510501
}
511502

503+
/**
504+
* Get the current logged in user.
505+
*
506+
* @return The user.
507+
* @throws NotFoundException
508+
* If the user could not be found.
509+
*/
510+
@GET
511+
@Produces(MediaType.APPLICATION_JSON)
512+
@Path("/myself")
513+
@RolesAllowed({"ADMIN", "REGISTERED"})
514+
public Response myself() throws NotFoundException {
515+
User user = ((UserPrincipal) securityContext.getUserPrincipal()).getUser();
516+
517+
final User myself = userDAO.getById(user.getId());
518+
return Response.ok(myself).build();
519+
}
512520
}

0 commit comments

Comments
 (0)