Skip to content

Commit

Permalink
Merge branch 'developer'
Browse files Browse the repository at this point in the history
  • Loading branch information
abainczyk committed Sep 18, 2018
2 parents 38aadc9 + bc75326 commit 2a3369c
Show file tree
Hide file tree
Showing 398 changed files with 17,217 additions and 10,612 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@ main/src/main/webapp/restdocs
main/uploads

frontend/src/main/javascript/npm-debug\.log
frontend/src/main/javascript/package-lock\.json

backend/debug.log
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ before_cache:
install: true # skip mvn install, because we essentially run the same command in the script routine

script:
- mvn clean package
- mvn clean package -Pbootstrap

branches:
only:
Expand Down
29 changes: 29 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,32 @@
# ALEX 1.6.0

## Breaking Changes

* Symbols have to be migrated to the new version.
Please use the migration script `src/main/resources/migration/1.6.0/migrate-symbols-1.5.0-to-1.6.0.js` via:

`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`

* Tests have to be migrated to the new version.
Please use the migration script `src/main/resources/migration/1.6.0/migrate-tests-1.5.0-to-1.6.0.js` via:

`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`

## Features

* Symbols can be composed of other symbols.
* Symbols can be parameterized in learning experiments.
* Connect ALEX to a MySQL database.
See the README for instructions.
* Generate test suites from discrimination tree based learners (TTT, Discrimination Tree).
* Use test cases in test suites as equivalence oracle.
* Added support for Internet Explorer
* Execute JavaScript asynchronously
* Symbol parameters can be *public* or *private*.
If a parameter is public, its value can be set by the user while configuring a testing or learning process.
If it is private, its value cannot be set manually, but is resolved by the value in the global data context.


# ALEX 1.5.1

This release only contains some bug fixes.
Expand Down
26 changes: 24 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Make sure you have Java 8 installed on your system.
We advise to use a modern web browser like Google Chrome, Mozilla Firefox or Microsoft Edge with JavaScript enabled.

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

Expand Down Expand Up @@ -48,7 +48,29 @@ cd alex
mvn install package [-DskipTests]
```

The bundle can then be found at `build/target/alex-build-1.5.1.war`.
The bundle can then be found at `build/target/alex-build-1.6.0.war`.

## Connecting to a database

Per default, ALEX uses an embedded HSQL database which is stored in the *target/alex-database* directory.
You can however also connect ALEX to a MySQL 5.7 database.
Other databases have not been tested yet.

### MySQL

Create a file called *application.properties* and add the following contents (and change the values according to your setup):

```
# application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/alex
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.hibernate.ddl-auto=update
```

Then, start ALEX like this:

`java -jar alex-1.6.0.war "--spring.config.location=/path/to/your/application.properties"`

## Further reading

Expand Down
12 changes: 10 additions & 2 deletions backend/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<parent>
<groupId>de.learnlib.alex</groupId>
<artifactId>alex-parent</artifactId>
<version>1.5.1</version>
<version>1.6.0</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down Expand Up @@ -59,6 +59,7 @@
<mockito.version>2.12.0</mockito.version>
<powermock.version>1.7.3</powermock.version>
<json-schema-validator.version>2.2.8</json-schema-validator.version>
<mysql-connector.version>8.0.11</mysql-connector.version>
</properties>

<!--===== dependencies ======-->
Expand Down Expand Up @@ -182,6 +183,12 @@
<version>${json-path.version}</version>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-connector.version}</version>
</dependency>

<!-- LearnLib -->
<dependency>
<groupId>de.learnlib</groupId>
Expand Down Expand Up @@ -423,11 +430,12 @@
</plugins>
</build>


<profiles>
<profile>
<id>createRestDoc</id>
<activation>
<activeByDefault>true</activeByDefault>
<activeByDefault>false</activeByDefault>
</activation>
<build>
<plugins>
Expand Down
27 changes: 18 additions & 9 deletions backend/src/main/java/de/learnlib/alex/ALEXApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import de.learnlib.alex.auth.rest.UserResource;
import de.learnlib.alex.auth.security.AuthenticationFilter;
import de.learnlib.alex.common.exceptions.NotFoundExceptionMapper;
import de.learnlib.alex.common.exceptions.UnauthorizedExceptionMapper;
import de.learnlib.alex.common.exceptions.ValidationExceptionMapper;
import de.learnlib.alex.config.dao.SettingsDAO;
import de.learnlib.alex.config.entities.DriverSettings;
import de.learnlib.alex.config.entities.Settings;
Expand Down Expand Up @@ -111,6 +113,8 @@ public ALEXApplication() {

// Exceptions
register(NotFoundExceptionMapper.class);
register(UnauthorizedExceptionMapper.class);
register(ValidationExceptionMapper.class);

// Other
register(MultiPartFeature.class);
Expand Down Expand Up @@ -148,14 +152,13 @@ public void initSettings() {
String chromeDriverPath = System.getProperty("webdriver.chrome.driver", "");
String geckoDriverPath = System.getProperty("webdriver.gecko.driver", "");
String edgeDriverPath = System.getProperty("webdriver.edge.driver", "");
String ieDriverPath = System.getProperty("webdriver.ie.driver", "");
String remoteDriverURL = System.getProperty("webdriver.remote.url", "");

final DriverSettings driverSettings = new DriverSettings(chromeDriverPath,
geckoDriverPath,
edgeDriverPath,
remoteDriverURL);
settings.setDriverSettings(driverSettings);
final DriverSettings driverSettings = new DriverSettings(chromeDriverPath, geckoDriverPath,
edgeDriverPath, remoteDriverURL, ieDriverPath);

settings.setDriverSettings(driverSettings);
settingsDAO.create(settings);
} catch (ValidationException e) {
e.printStackTrace();
Expand All @@ -167,21 +170,26 @@ public void initSettings() {
final String chromeDriver = env.getProperty("chromeDriver");
final String geckoDriver = env.getProperty("geckoDriver");
final String edgeDriver = env.getProperty("edgeDriver");
final String ieDriver = env.getProperty("ieDriver");
final String remoteDriver = env.getProperty("remoteDriver");

if (!env.getProperty("chromeDriver").equals("")) {
if (!chromeDriver.isEmpty()) {
settings.getDriverSettings().setChrome(chromeDriver);
}

if (!env.getProperty("geckoDriver").equals("")) {
if (!geckoDriver.isEmpty()) {
settings.getDriverSettings().setFirefox(geckoDriver);
}

if (!env.getProperty("edgeDriver").equals("")) {
if (!edgeDriver.isEmpty()) {
settings.getDriverSettings().setEdge(edgeDriver);
}

if (!env.getProperty("remoteDriver").equals("")) {
if (!ieDriver.isEmpty()) {
settings.getDriverSettings().setIe(ieDriver);
}

if (!remoteDriver.isEmpty()) {
settings.getDriverSettings().setRemote(remoteDriver);
}

Expand All @@ -197,6 +205,7 @@ public void initSettings() {
System.setProperty("webdriver.chrome.driver", settings.getDriverSettings().getChrome());
System.setProperty("webdriver.gecko.driver", settings.getDriverSettings().getFirefox());
System.setProperty("webdriver.edge.driver", settings.getDriverSettings().getEdge());
System.setProperty("webdriver.ie.driver", settings.getDriverSettings().getIe());
System.setProperty("webdriver.remote.url", settings.getDriverSettings().getRemote());
}

Expand Down
59 changes: 43 additions & 16 deletions backend/src/main/java/de/learnlib/alex/auth/dao/UserDAOImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
import de.learnlib.alex.common.utils.IdsList;
import de.learnlib.alex.common.utils.ValidationExceptionHelper;
import de.learnlib.alex.data.dao.FileDAO;
import de.learnlib.alex.data.dao.ProjectDAO;
import de.learnlib.alex.data.entities.Project;
import de.learnlib.alex.data.repositories.ProjectRepository;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.dao.DataIntegrityViolationException;
Expand All @@ -45,21 +48,36 @@ public class UserDAOImpl implements UserDAO {
private static final Logger LOGGER = LogManager.getLogger();

/** The UserRepository to use. Will be injected. */
private UserRepository userRepository;
private final UserRepository userRepository;

/** The FileDAO to use. Will be injected. */
private FileDAO fileDAO;
private final FileDAO fileDAO;

/** The DAO for project. */
private final ProjectDAO projectDAO;

/** The repository for projects. */
private final ProjectRepository projectRepository;

/**
* Creates a new UserDAO.
*
* @param userRepository The UserRepository to use.
* @param fileDAO The FileDAO to use.
* @param userRepository
* The UserRepository to use.
* @param fileDAO
* The FileDAO to use.
* @param projectDAO
* The ProjectDAO to use.
* @param projectRepository
* The repository for project.
*/
@Inject
public UserDAOImpl(UserRepository userRepository, FileDAO fileDAO) {
public UserDAOImpl(UserRepository userRepository, FileDAO fileDAO, ProjectDAO projectDAO,
ProjectRepository projectRepository) {
this.userRepository = userRepository;
this.fileDAO = fileDAO;
this.projectDAO = projectDAO;
this.projectRepository = projectRepository;
}

@Override
Expand Down Expand Up @@ -115,8 +133,23 @@ public void update(User user) throws ValidationException {
@Override
@Transactional
public void delete(Long id) throws NotFoundException {
User user = getById(id);
delete(getById(id));
}

@Override
@Transactional
public void delete(IdsList ids) throws NotFoundException {
final List<User> users = userRepository.findAllByIdIn(ids);
if (users.size() != ids.size()) {
throw new NotFoundException("At least one user could not be found.");
}

for (User user : users) {
delete(user);
}
}

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

for (Project project : projectRepository.findAllByUser_Id(user.getId())) {
projectDAO.delete(user, project.getId());
}
userRepository.delete(user);

// delete the user directory
Expand All @@ -136,19 +172,10 @@ public void delete(Long id) throws NotFoundException {
}
}

@Override
@Transactional
public void delete(IdsList ids) throws NotFoundException {
for (Long id: ids) {
User user = getById(id);
userRepository.delete(user);
}
}

private void saveUser(User user) {
try {
userRepository.save(user);
// error handling
// error handling
} catch (TransactionSystemException e) {
LOGGER.info("Saving a user failed:", e);
ConstraintViolationException cve = (ConstraintViolationException) e.getCause().getCause();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,14 @@ public interface UserRepository extends JpaRepository<User, Long> {
@Transactional(readOnly = true)
User findOneByEmail(String email);

/**
* Find multiple users by IDs.
*
* @param userIds
* The IDs of the users to get.
* @return The matching users.
*/
@Transactional(readOnly = true)
List<User> findAllByIdIn(List<Long> userIds);

}
28 changes: 18 additions & 10 deletions backend/src/main/java/de/learnlib/alex/auth/rest/UserResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@
import de.learnlib.alex.webhooks.services.WebhookService;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.MarkerManager;
import org.apache.shiro.authz.UnauthorizedException;
import org.hibernate.validator.internal.constraintvalidators.hv.EmailValidator;
import org.jose4j.json.internal.json_simple.JSONObject;
Expand Down Expand Up @@ -68,11 +66,6 @@ public class UserResource {

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

private static final Marker USER_MARKER = MarkerManager.getMarker("USER");
private static final Marker REST_MARKER = MarkerManager.getMarker("REST");
private static final Marker RESOURCE_MARKER = MarkerManager.getMarker("USER_RESOURCE")
.setParents(USER_MARKER, REST_MARKER);

/** The UserDAO to user. */
@Inject
private UserDAO userDAO;
Expand Down Expand Up @@ -345,7 +338,7 @@ public Response promoteUser(@PathParam("id") Long userId) throws NotFoundExcepti
User userToPromote = userDAO.getById(userId);
userToPromote.setRole(UserRole.ADMIN);
userDAO.update(userToPromote);
LOGGER.info(RESOURCE_MARKER, "User {} promoted.", user);
LOGGER.info("User {} promoted.", user);

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

userDAO.delete(ids);

LOGGER.traceExit("User(s) {} deleted.", ids);

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


/**
* Logs in a user by generating a unique JWT for him that needs to be send in every request.
*
Expand Down Expand Up @@ -509,4 +500,21 @@ public Response login(User user) throws NotFoundException {
}
}

/**
* Get the current logged in user.
*
* @return The user.
* @throws NotFoundException
* If the user could not be found.
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/myself")
@RolesAllowed({"ADMIN", "REGISTERED"})
public Response myself() throws NotFoundException {
User user = ((UserPrincipal) securityContext.getUserPrincipal()).getUser();

final User myself = userDAO.getById(user.getId());
return Response.ok(myself).build();
}
}
Loading

0 comments on commit 2a3369c

Please sign in to comment.