Skip to content

Commit

Permalink
Merge pull request #76 from CodeKaio/58-make-settings-persistent
Browse files Browse the repository at this point in the history
🔧 : make settings persistent
  • Loading branch information
cdubuisson authored Jul 26, 2019
2 parents e2b0265 + 276d7c8 commit dddc112
Show file tree
Hide file tree
Showing 8 changed files with 293 additions and 8 deletions.
25 changes: 19 additions & 6 deletions src/main/java/io/codeka/gaia/bo/Settings.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package io.codeka.gaia.bo;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

Expand All @@ -18,18 +17,16 @@ public class Settings {
/**
* Gaia's external url (used to allow runners to speak to Gaia)
*/
@Value("${:http://localhost:${server.port:8080}}")
private String externalUrl;

/**
* Environment variables for the runner
*/
private List<EnvVar> envVars = Collections.emptyList();
private List<EnvVar> envVars = new ArrayList<>();

/**
* The docker daemon url used by Gaia to spawn its runners
*/
@Value(("${:unix:///var/run/docker.sock}"))
private String dockerDaemonUrl;

public String getExternalUrl() {
Expand Down Expand Up @@ -62,7 +59,23 @@ public void setDockerDaemonUrl(String dockerDaemonUrl) {
this.dockerDaemonUrl = dockerDaemonUrl;
}

static class EnvVar{
/**
* Merging two settings objets
* @param saved the settings to merge
*/
public void merge(Settings saved) {
if (saved.externalUrl != null) {
this.externalUrl = saved.externalUrl;
}
if (saved.dockerDaemonUrl != null) {
this.dockerDaemonUrl = saved.dockerDaemonUrl;
}
if (saved.envVars != null) {
this.envVars.addAll(saved.envVars);
}
}

public static class EnvVar{
String name;
String value;

Expand Down
10 changes: 8 additions & 2 deletions src/main/java/io/codeka/gaia/controller/SettingsController.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.codeka.gaia.controller;

import io.codeka.gaia.bo.Settings;
import io.codeka.gaia.repository.SettingsRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Controller;
Expand All @@ -18,9 +19,12 @@ public class SettingsController {

private Settings settings;

private SettingsRepository settingsRepository;

@Autowired
public SettingsController(Settings settings) {
public SettingsController(Settings settings, SettingsRepository settingsRepository) {
this.settings = settings;
this.settingsRepository = settingsRepository;
}

@GetMapping("/settings")
Expand All @@ -31,10 +35,12 @@ public String settings(Model model){
}

@PutMapping("/settings")
public void saveModule(@RequestBody Settings settings){
public void saveSettings(@RequestBody Settings settings){
// update global settings bean
this.settings.setExternalUrl( settings.getExternalUrl() );
this.settings.setEnvVars(settings.getEnvVars());
// saving the data
this.settingsRepository.save();
}

}
47 changes: 47 additions & 0 deletions src/main/java/io/codeka/gaia/repository/SettingsRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package io.codeka.gaia.repository;

import io.codeka.gaia.bo.Settings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Repository;

import javax.annotation.PostConstruct;


@Repository
public class SettingsRepository {

private MongoTemplate mongoTemplate;

private Settings settings;

@Autowired
public SettingsRepository(MongoTemplate mongoTemplate, Settings settings) {
this.mongoTemplate = mongoTemplate;
this.settings = settings;
}

/**
* loading settings that are saved in database, and merging into current settings (that are injected)
*/
@PostConstruct
void postConstruct(){
var savedSettings = mongoTemplate.findAll(Settings.class).stream()
.findFirst().orElse(null);

if(savedSettings != null) {
// if settings are found in database, merging them in the current settings
settings.merge(savedSettings);
}
}

/**
* Saving settings
* We don't need any parameter as settings are already in-memory
*/
public void save(){
mongoTemplate.remove(Settings.class).all();
mongoTemplate.save(settings);
}

}
3 changes: 3 additions & 0 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,8 @@ spring.data.mongodb.uri=${gaia.mongodb.uri}

gaia.mongodb.uri=mongodb://localhost/gaia

gaia.externalUrl=http://localhost:${server.port:8080}
gaia.dockerDaemonUrl=unix:///var/run/docker.sock

terraform.releases.url=https://releases.hashicorp.com/terraform/
terraform.releases.version.min=0.11.13
30 changes: 30 additions & 0 deletions src/test/java/io/codeka/gaia/bo/SettingsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.TestPropertySource;

import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest(classes = Settings.class)
Expand Down Expand Up @@ -41,4 +45,30 @@ void envVars_shouldBeConfigurableViaProperty(){
assertEquals("value", settings.getEnvVars().get(0).value);
}

@Test
@DirtiesContext // this test changes the settings objet
void settings_shouldBeMergedWithSavedSettings(){
var savedSettings = new Settings();
savedSettings.setExternalUrl("https://gaia.io");

var testVar = new Settings.EnvVar();
testVar.setName("name");
testVar.setValue("value");

var otherTestVar = new Settings.EnvVar();
otherTestVar.setName("anotherName");
otherTestVar.setValue("anotherValue");

var existingEnvVar = this.settings.getEnvVars().get(0);

savedSettings.setEnvVars(List.of(testVar, otherTestVar));

settings.merge(savedSettings);

assertEquals("https://gaia.io", settings.getExternalUrl());
assertEquals("unix:///var/run/docker.sock", settings.getDockerDaemonUrl());
assertThat(settings.getEnvVars()).hasSize(3)
.containsExactlyInAnyOrder(existingEnvVar, testVar, otherTestVar);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package io.codeka.gaia.controller;

import io.codeka.gaia.bo.Settings;
import io.codeka.gaia.repository.SettingsRepository;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import java.util.List;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;

@ExtendWith(MockitoExtension.class)
class SettingsControllerTest {

@Mock
private Settings settings;

@Mock
private SettingsRepository settingsRepository;

@InjectMocks
private SettingsController settingsController;

@Test
void put_shouldSaveUpdatedSettings(){
// given
var editedSettings = new Settings();
editedSettings.setExternalUrl("edited");

var envVar = new Settings.EnvVar();
envVar.setName("test");
envVar.setValue("value");
editedSettings.setEnvVars(List.of(envVar));

// when
settingsController.saveSettings(editedSettings);

// then
verify(settings).setExternalUrl("edited");
verify(settings).setEnvVars(anyList());

verify(settingsRepository).save();
}

}
59 changes: 59 additions & 0 deletions src/test/java/io/codeka/gaia/repository/SettingsRepositoryIT.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package io.codeka.gaia.repository;

import io.codeka.gaia.bo.Settings;
import io.codeka.gaia.test.MongoContainer;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.test.context.TestPropertySource;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
@Testcontainers
@TestPropertySource(properties = {"gaia.externalUrl=http://gaia.io", "gaia.dockerDaemonUrl=unix:///var/run/docker.sock"})
class SettingsRepositoryIT {

@Container
private static MongoContainer mongoContainer = new MongoContainer();

@Autowired
private MongoTemplate mongoTemplate;

@Autowired
private SettingsRepository settingsRepository;

@Autowired
private Settings settings;

@Test
void itShouldSaveSettings(){
// given

// when
settingsRepository.save();

// then
var saved = mongoTemplate.findAll(Settings.class).get(0);
assertEquals("http://gaia.io", saved.getExternalUrl());
assertEquals("unix:///var/run/docker.sock", saved.getDockerDaemonUrl());
}

@Test
void settings_shouldOnlyExistOnceInDatabase(){
// given

// when
settingsRepository.save();
settingsRepository.save();

// then
assertThat( mongoTemplate.findAll(Settings.class) ).hasSize(1);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package io.codeka.gaia.repository;

import io.codeka.gaia.bo.Settings;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.data.mongodb.core.MongoTemplate;

import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
class SettingsRepositoryTest {

@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private MongoTemplate mongoTemplate;

private Settings settings;

private SettingsRepository settingsRepository;

@BeforeEach
void setUp() {
settings = new Settings();
settings.setExternalUrl("externalUrl");
settings.setDockerDaemonUrl("dockerDaemonUrl");

settingsRepository = new SettingsRepository(mongoTemplate, settings);
}

@Test
void settings_shouldBeLoadedFromDatabase(){
var savedSettings = new Settings();
savedSettings.setExternalUrl("savedExternalUrl");
savedSettings.setDockerDaemonUrl("savedDockerDaemonUrl");

when(mongoTemplate.findAll(Settings.class)).thenReturn(List.of(savedSettings));

//when
settingsRepository.postConstruct();

//then
assertEquals("savedExternalUrl", settings.getExternalUrl());
assertEquals("savedDockerDaemonUrl", settings.getDockerDaemonUrl());

verify(mongoTemplate).findAll(Settings.class);
verifyNoMoreInteractions(mongoTemplate);
}

@Test
void nothingShouldHappen_whenSettingsDoesntExistInDatabase(){
//when
settingsRepository.postConstruct();

//then
verify(mongoTemplate).findAll(Settings.class);
verifyNoMoreInteractions(mongoTemplate);
}

@Test
void save_shouldSaveSettingsInDatabase(){
//when
settingsRepository.save();

//then
verify(mongoTemplate).remove(Settings.class);
verify(mongoTemplate).save(settings);
verifyNoMoreInteractions(mongoTemplate);
}

}

0 comments on commit dddc112

Please sign in to comment.