diff --git a/src/main/java/org/olat/course/editor/PublishProcess.java b/src/main/java/org/olat/course/editor/PublishProcess.java
index 2f0828c8a11b12bb13dc328b215c414767a59c16..6cfc601475b727df3293e31cf361df95ec6e701a 100644
--- a/src/main/java/org/olat/course/editor/PublishProcess.java
+++ b/src/main/java/org/olat/course/editor/PublishProcess.java
@@ -40,6 +40,8 @@ import org.olat.core.gui.translator.Translator;
 import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.logging.AssertException;
+import org.olat.core.logging.OLog;
+import org.olat.core.logging.Tracing;
 import org.olat.core.util.ObjectCloner;
 import org.olat.core.util.Util;
 import org.olat.core.util.ValidationStatus;
@@ -80,6 +82,8 @@ import org.olat.user.UserManager;
  */
 public class PublishProcess {
 	
+	private static final OLog log = Tracing.createLoggerFor(PublishProcess.class);
+	
 	private static final String PACKAGE = Util.getPackageName(PublishProcess.class);
 	private static Translator translator;
 	
@@ -407,7 +411,7 @@ public class PublishProcess {
 					if (!(cn.getIdent().equals(oldCn.getIdent()))) { throw new AssertException("deleted cn.getIdent != oldCn.getIdent"); }
 				}
 				cetn.removeFromParent();
-				if (!cetn.isNewnode()) {
+				if (!cetn.isNewnode() && oldCn != null) {
 					// only clean up and archive of nodes which were already in run
 					// save data, remove references
 					deleteRefs(oldCn);
@@ -513,9 +517,9 @@ public class PublishProcess {
 	 */
 	private void deleteRefs(CourseNode courseNode) {
 		ReferenceManager refM = ReferenceManager.getInstance();
-		List courseRefs = refM.getReferences(course);
-		for (Iterator iter = courseRefs.iterator(); iter.hasNext();) {
-			ReferenceImpl ref = (ReferenceImpl) iter.next();
+		List<ReferenceImpl> courseRefs = refM.getReferences(course);
+		for (Iterator<ReferenceImpl> iter = courseRefs.iterator(); iter.hasNext();) {
+			ReferenceImpl ref = iter.next();
 			if (!ref.getUserdata().equals(courseNode.getIdent())) continue;
 			refM.delete(ref);
 			break;
@@ -677,7 +681,7 @@ public class PublishProcess {
 		private CourseEditorTreeNode root;
 		private Structure existingRun;
 		private List<String> publishNodeIds;
-		private List skippableNodes;
+		private List<CourseEditorTreeNode> skippableNodes;
 
 		private NodePublishVisitor(CourseEditorTreeNode root, List<String> userSelectedNodeIdsToPublish, Structure existingRun) {
 			/*
@@ -691,7 +695,7 @@ public class PublishProcess {
 			this.existingRun = existingRun;
 			this.publishNodeIds = userSelectedNodeIdsToPublish;
 			// internal use
-			this.skippableNodes = new ArrayList();
+			this.skippableNodes = new ArrayList<CourseEditorTreeNode>();
 		}
 
 		public void visit(INode node) {
@@ -746,22 +750,25 @@ public class PublishProcess {
 					// new node and its former parent is deleted.
 					addNodeTo(resultingCourseRun, cetn);
 					editorModelModifiedNodes.add(cetn);
-				} else if (cetn.isNewnode() && cetn.isDeleted()) {
+				} else if (cetn.isDeleted()) {
 					// publish deletion of a new node
 					editorModelDeletedNodes.add(cetn);
-					List getsAlsoDeleted = new ArrayList();
+					List<CourseEditorTreeNode> getsAlsoDeleted = new ArrayList<CourseEditorTreeNode>();
 					collectSubTreeNodesStartingFrom(cetn, getsAlsoDeleted);
 					// whole subtree added, marked as being deleted
 					editorModelDeletedNodes.addAll(getsAlsoDeleted);
-					return;
-				} else if (cetn.isNewnode() && !cetn.isDeleted()) {
+					if(!cetn.isNewnode()) {
+						log.warn("try to publish node [" + cetn.getTitle() + " " + cetn.getIdent() + "]which says it is not new (but deleted )but also not in the runstructure (OO-249 delete it).");
+					}
+				} else if (!cetn.isDeleted()) {
 					// publish new node
 					addNodeTo(resultingCourseRun, cetn);
 					editorModelInsertedNodes.add(cetn);
-					return;
+					if(!cetn.isNewnode()) {
+						log.warn("try to publish node [" + cetn.getTitle() + " " + cetn.getIdent() + "] which says it is not new but also not in the runstructure (OO-249 publish it).");
+					}
 				} else {
-					// ...!cetn.isNewnode() && cetn.isDeleted()
-					// this state is not possible
+					// this state is really not possible
 					throw new AssertException("try to publish node [" + cetn.getTitle() + " " + cetn.getIdent()
 							+ "]which says it is not new but also not in the runstructure.");
 				}
@@ -770,29 +777,34 @@ public class PublishProcess {
 					// publish modified node
 					addNodeTo(resultingCourseRun, cetn);
 					editorModelModifiedNodes.add(cetn);
-					return;
-				} else if (!cetn.isNewnode() && cetn.isDeleted()) {
+				} else if (cetn.isDeleted()) {
 					// publish deletion of a node
 					editorModelDeletedNodes.add(cetn);
-					List getsAlsoDeleted = new ArrayList();
+					List<CourseEditorTreeNode> getsAlsoDeleted = new ArrayList<CourseEditorTreeNode>();
 					collectSubTreeNodesStartingFrom(cetn, getsAlsoDeleted);
 					// whole subtree added, marked as being deleted
 					editorModelDeletedNodes.addAll(getsAlsoDeleted);
-					return;
+					if(cetn.isNewnode()) {
+						log.warn(cetn.getTitle() + " - try to publish node which says it is new and deleted but also exists in the runstructure (OO-249 delete it).");
+					}
 				} else if (cetn.isNewnode() && !cetn.isDeleted()) {
-					// this state is not possible
-					throw new AssertException(cetn.getTitle() + " - try to publish node which says it is new but also exists in the runstructure.");
+					// this state is not possible but appears somewhat
+					addNodeTo(resultingCourseRun, cetn);
+					editorModelModifiedNodes.add(cetn);
+					log.warn(cetn.getTitle() + " - try to publish node which says it is new but also exists in the runstructure (OO-249: publish the node).");
+				} else if (!cetn.isNewnode() && !cetn.isDeleted()) {
+					//not new, not deleted, not changed
+					log.warn(cetn.getTitle() + " - try to publish node which says it is not new, not deleted, not changed (OO-249: publish do nothing).");
 				} else {
-					// ...cetn.isNewnode() && cetn.isDeleted()
-					// this state is not possible
-					throw new AssertException(cetn.getTitle() + " - try to publish node which says it is new but also exists in the runstructure.");
+					log.error(cetn.getTitle() + " - try to publish node which is in an unkown state (OO-249: publish do nothing).");
 				}
 			} else {
 				// ...(!publishNode && !alreadyInRun){
 				// check condition, and add all subnodes to be skipped
 				if (!cetn.isNewnode()) { 
-					throw new AssertException(cetn.getTitle()+" - node is not to publish and not in run -> hence it should be isNewnode() == true, but it is not!!"); }
-				List skippable = new ArrayList();
+					log.warn(cetn.getTitle()+" - node is not to publish and not in run -> hence it should be isNewnode() == true, but it is not (OO-249: ignore it until explicitly published)!!");
+				}
+				List<CourseEditorTreeNode> skippable = new ArrayList<CourseEditorTreeNode>();
 				collectSubTreeNodesStartingFrom(cetn, skippable);
 				// remember this new node with its subtree as not being published
 				// there may float a dirty node in the subtree, which got there by
@@ -838,10 +850,11 @@ public class PublishProcess {
 		 * @param root
 		 * @param rootNodeWithSubtree
 		 */
-		private void collectSubTreeNodesStartingFrom(CourseEditorTreeNode root, List rootNodeWithSubtree) {
+		private void collectSubTreeNodesStartingFrom(CourseEditorTreeNode root, List<CourseEditorTreeNode> rootNodeWithSubtree) {
 			for (int i = 0; i < root.getChildCount(); i++) {
-				rootNodeWithSubtree.add(root.getChildAt(i));
-				collectSubTreeNodesStartingFrom((CourseEditorTreeNode) root.getChildAt(i), rootNodeWithSubtree);
+				CourseEditorTreeNode node = (CourseEditorTreeNode)root.getChildAt(i);
+				rootNodeWithSubtree.add(node);
+				collectSubTreeNodesStartingFrom(node, rootNodeWithSubtree);
 			}
 		}
 	}// end nested class
diff --git a/src/main/java/org/olat/restapi/system/MonitoringModule.java b/src/main/java/org/olat/restapi/system/MonitoringModule.java
index 3a015e083912eafb3f4945e3fac2ebd0c5cccc22..29985ae6cc8bcc60813d1bdf1688c9e2e472651b 100644
--- a/src/main/java/org/olat/restapi/system/MonitoringModule.java
+++ b/src/main/java/org/olat/restapi/system/MonitoringModule.java
@@ -50,7 +50,7 @@ public class MonitoringModule extends AbstractOLATModule implements ConfigOnOff
 	@Override
 	protected void initDefaultProperties() {
 		enabled = getBooleanConfigParameter(ENABLED, true);
-		monitoredProbes = getStringConfigParameter(MONITORED_PROBES, "Environnment,Release", false);
+		monitoredProbes = getStringConfigParameter(MONITORED_PROBES, "Environment,Release", false);
 		server = getStringConfigParameter(SERVER, "local", false);
 		description = getStringConfigParameter(DESCRIPTION, "Dummy description", false);
 	}
diff --git a/src/main/java/org/olat/restapi/system/vo/Examples.java b/src/main/java/org/olat/restapi/system/vo/Examples.java
index 223b5e690bfa0ac6e77915325c1e1f3b603a1494..dbb17b80d6730c988291ec1ea7392a77190b8f06 100644
--- a/src/main/java/org/olat/restapi/system/vo/Examples.java
+++ b/src/main/java/org/olat/restapi/system/vo/Examples.java
@@ -119,7 +119,7 @@ public class Examples {
 		
 		SAMPLE_MONITORINGCONFIGVO.setDescription("this is an OpenOLAT instance");
 		SAMPLE_MONITORINGCONFIGVO.setType("openolat");
-		SAMPLE_MONITORINGCONFIGVO.setProbes(new String[]{"Environnment", "System", "Runtime", "Memory"});
+		SAMPLE_MONITORINGCONFIGVO.setProbes(new String[]{"Environment", "System", "Runtime", "Memory"});
 		
 		MonitoringDependencyVO dep1 = new MonitoringDependencyVO();
 		dep1.setType("openfire");
diff --git a/src/main/java/org/olat/restapi/system/vo/SystemInfosVO.java b/src/main/java/org/olat/restapi/system/vo/SystemInfosVO.java
index f0a46b18eb1d48f806e4b4b5c8d1fb1cd0ff2dc3..4fd1ce33a8551805a4a967b827dfae396b2bac1d 100644
--- a/src/main/java/org/olat/restapi/system/vo/SystemInfosVO.java
+++ b/src/main/java/org/olat/restapi/system/vo/SystemInfosVO.java
@@ -29,18 +29,18 @@ import javax.xml.bind.annotation.XmlRootElement;
 public class SystemInfosVO {
 	
 	private ReleaseInfosVO openolatRelease;
-	private EnvironmentInformationsVO environnment;
+	private EnvironmentInformationsVO environment;
 	
 	public SystemInfosVO() {
 		//make JAXB happy
 	}
 
-	public EnvironmentInformationsVO getEnvironnment() {
-		return environnment;
+	public EnvironmentInformationsVO getEnvironment() {
+		return environment;
 	}
 
-	public void setEnvironnment(EnvironmentInformationsVO environnment) {
-		this.environnment = environnment;
+	public void setEnvironment(EnvironmentInformationsVO environment) {
+		this.environment = environment;
 	}
 
 	public ReleaseInfosVO getOpenolatRelease() {
diff --git a/src/main/resources/serviceconfig/olat.properties b/src/main/resources/serviceconfig/olat.properties
index e6657abeecd5878435e157e881db1006058a8ba4..2b0b98b721cd5165f6ec59d4548bcd05b3484376 100644
--- a/src/main/resources/serviceconfig/olat.properties
+++ b/src/main/resources/serviceconfig/olat.properties
@@ -794,7 +794,7 @@ vc.vitero.deleteVmsUserOnUserDelete=true
 ########################################
 monitoring.enabled=true
 monitoring.instance.description=OpenOLAT instance
-monitored.probes=Runtime,System,Database,Memory,OpenOLAT,Release,Environnment
+monitored.probes=Runtime,System,Database,Memory,OpenOLAT,Release,Environment
 monitoring.dependency.server=myserver
 
 
diff --git a/src/test/java/org/olat/course/editor/PublishProcessTest.java b/src/test/java/org/olat/course/editor/PublishProcessTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..20399d67b19c5597e35d2171ec5e58e400bb4ef2
--- /dev/null
+++ b/src/test/java/org/olat/course/editor/PublishProcessTest.java
@@ -0,0 +1,290 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.course.editor;
+
+import java.io.File;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import java.util.UUID;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.olat.core.id.Identity;
+import org.olat.core.util.nodes.INode;
+import org.olat.course.CourseFactory;
+import org.olat.course.ICourse;
+import org.olat.course.nodes.CourseNode;
+import org.olat.course.tree.CourseEditorTreeModel;
+import org.olat.course.tree.CourseEditorTreeNode;
+import org.olat.repository.RepositoryEntry;
+import org.olat.test.JunitTestHelper;
+import org.olat.test.OlatTestCase;
+
+
+/**
+ * These unit tests are related to OO-249. the main goal is to make the
+ * publish process robust against the different AssertException and to
+ * handle to possible corruption without triggering a red screen which
+ * make the course corrupt, uneditable, lost.
+ * 
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class PublishProcessTest extends OlatTestCase {
+	
+	private static final Locale locale = Locale.GERMAN;
+	
+	/**
+	 * Publish process without error
+	 * @throws URISyntaxException
+	 */
+	@Test
+	public void testPublishProcess() throws URISyntaxException {
+		Identity author = JunitTestHelper.createAndPersistIdentityAsAdmin("publisher-" + UUID.randomUUID().toString());
+		RepositoryEntry re = deployTestCourse(author, "simple_course.zip");
+
+		//change node 1
+		ICourse course = CourseFactory.openCourseEditSession(re.getOlatResource().getResourceableId());
+		CourseEditorTreeModel cetm = course.getEditorTreeModel();
+		CourseEditorTreeNode node1 = (CourseEditorTreeNode)cetm.getRootNode().getChildAt(0);
+		node1.getCourseNode().setShortTitle("Node 1 prime");
+		cetm.nodeConfigChanged(node1);				
+		CourseFactory.saveCourseEditorTreeModel(course.getResourceableId());
+		CourseFactory.closeCourseEditSession(course.getResourceableId(), true);	
+		
+		//publish the course
+		List<String> nodeIds = Collections.singletonList(node1.getIdent());
+		publishCourse(nodeIds, re, author);
+		
+		//check the change
+		ICourse reloadedCourse = CourseFactory.loadCourse(re.getOlatResource().getResourceableId());
+		Assert.assertEquals(3, reloadedCourse.getRunStructure().getRootNode().getChildCount());
+		INode runNode1 = reloadedCourse.getRunStructure().getRootNode().getChildAt(0);
+		Assert.assertNotNull(runNode1);
+		CourseNode runNode1Impl = (CourseNode)runNode1;
+		Assert.assertEquals("Node 1 prime", runNode1Impl.getShortTitle());
+	}
+	
+	/**
+	 * Publish an unchanged course. We try to publish a node which
+	 * was not changed nor deleted.
+	 * 
+	 * @throws URISyntaxException
+	 */
+	@Test
+	public void testPublishANotPublishedNode()
+	throws URISyntaxException {
+		Identity author = JunitTestHelper.createAndPersistIdentityAsAdmin("publisher-" + UUID.randomUUID().toString());
+		RepositoryEntry re = deployTestCourse(author, "simple_course.zip");
+		
+		//change node 1
+		ICourse course = CourseFactory.loadCourse(re.getOlatResource().getResourceableId());
+		CourseEditorTreeModel cetm = course.getEditorTreeModel();
+		CourseEditorTreeNode node1 = (CourseEditorTreeNode)cetm.getRootNode().getChildAt(0);
+
+		//publish the course and must survive this without exception
+		//as the course has no changes but we try to publish it
+		List<String> nodeIds = Collections.singletonList(node1.getIdent());
+		publishCourse(nodeIds, re, author);
+	}
+	
+	/**
+	 * Publish a course with a node marked as new but the node
+	 * exists already in the run structure.
+	 * 
+	 * @throws URISyntaxException
+	 */
+	@Test
+	public void testPublishANotReallyNewNode()
+	throws URISyntaxException {
+		Identity author = JunitTestHelper.createAndPersistIdentityAsAdmin("publisher-" + UUID.randomUUID().toString());
+		RepositoryEntry re = deployTestCourse(author, "simple_course_err1_new.zip");
+		
+		//change node 1
+		ICourse course = CourseFactory.loadCourse(re.getOlatResource().getResourceableId());
+		CourseEditorTreeModel cetm = course.getEditorTreeModel();
+		CourseEditorTreeNode node1 = (CourseEditorTreeNode)cetm.getRootNode().getChildAt(0);
+
+		//publish the course and must survive this without exception
+		//as the course has no changes but we try to publish it
+		List<String> nodeIds = Collections.singletonList(node1.getIdent());
+		publishCourse(nodeIds, re, author);
+
+		//check the change
+		ICourse reloadedCourse = CourseFactory.loadCourse(re.getOlatResource().getResourceableId());
+		Assert.assertEquals(3, reloadedCourse.getRunStructure().getRootNode().getChildCount());
+		INode runNode1 = reloadedCourse.getRunStructure().getRootNode().getChildAt(0);
+		Assert.assertNotNull(runNode1);
+		CourseNode runNode1Impl = (CourseNode)runNode1;
+		Assert.assertEquals("Node 1 not really new", runNode1Impl.getShortTitle());
+	}
+	
+	/**
+	 * Publish a course with a node marked as new and deleted but the
+	 * node exists already in the run structure.
+	 * 
+	 * @throws URISyntaxException
+	 */
+	@Test
+	public void testPublishANotReallyNewNodeButDeleted()
+	throws URISyntaxException {
+		Identity author = JunitTestHelper.createAndPersistIdentityAsAdmin("publisher-" + UUID.randomUUID().toString());
+		RepositoryEntry re = deployTestCourse(author, "simple_course_err2_new_deleted.zip");
+		
+		//change node 1
+		ICourse course = CourseFactory.loadCourse(re.getOlatResource().getResourceableId());
+		CourseEditorTreeModel cetm = course.getEditorTreeModel();
+		CourseEditorTreeNode node1 = (CourseEditorTreeNode)cetm.getRootNode().getChildAt(0);
+
+		//publish the course and must survive this without exception
+		//as the course has no changes but we try to publish it
+		List<String> nodeIds = Collections.singletonList(node1.getIdent());
+		publishCourse(nodeIds, re, author);
+
+		//check the change
+		ICourse reloadedCourse = CourseFactory.loadCourse(re.getOlatResource().getResourceableId());
+		Assert.assertEquals(2, reloadedCourse.getRunStructure().getRootNode().getChildCount());
+		INode runNode2 = reloadedCourse.getRunStructure().getRootNode().getChildAt(0);
+		Assert.assertNotNull(runNode2);
+		CourseNode runNode2Impl = (CourseNode)runNode2;
+		Assert.assertEquals("Node 2", runNode2Impl.getShortTitle());
+	}
+	
+	/**
+	 * Publish a course with a node marked as not new but the
+	 * node dosn't exist in the run structure.
+	 * 
+	 * @throws URISyntaxException
+	 */
+	@Test
+	public void testPublishNewNodeButNotMarkedAsSuch()
+	throws URISyntaxException {
+		Identity author = JunitTestHelper.createAndPersistIdentityAsAdmin("publisher-" + UUID.randomUUID().toString());
+		RepositoryEntry re = deployTestCourse(author, "simple_course_err3_not_new.zip");
+		
+		//change node 1
+		ICourse course = CourseFactory.loadCourse(re.getOlatResource().getResourceableId());
+		CourseEditorTreeModel cetm = course.getEditorTreeModel();
+		CourseEditorTreeNode node1 = (CourseEditorTreeNode)cetm.getRootNode().getChildAt(0);
+
+		//publish the course and must survive this without exception
+		//as the course has no changes but we try to publish it
+		List<String> nodeIds = Collections.singletonList(node1.getIdent());
+		publishCourse(nodeIds, re, author);
+
+		//check the change
+		ICourse reloadedCourse = CourseFactory.loadCourse(re.getOlatResource().getResourceableId());
+		Assert.assertEquals(3, reloadedCourse.getRunStructure().getRootNode().getChildCount());
+		INode runNode1 = reloadedCourse.getRunStructure().getRootNode().getChildAt(0);
+		Assert.assertNotNull(runNode1);
+		CourseNode runNode1Impl = (CourseNode)runNode1;
+		Assert.assertEquals("Node 1 from hell", runNode1Impl.getShortTitle());
+	}
+	
+	/**
+	 * Publish a course with a node marked as not new and deleted but
+	 * the node doesn't exist in the run structure.
+	 * 
+	 * @throws URISyntaxException
+	 */
+	@Test
+	public void testPublishNewNodeButNotMarkedAsSuchAndDeleted()
+	throws URISyntaxException {
+		Identity author = JunitTestHelper.createAndPersistIdentityAsAdmin("publisher-" + UUID.randomUUID().toString());
+		RepositoryEntry re = deployTestCourse(author, "simple_course_err4_not_new_deleted.zip");
+		
+		//change node 1
+		ICourse course = CourseFactory.loadCourse(re.getOlatResource().getResourceableId());
+		CourseEditorTreeModel cetm = course.getEditorTreeModel();
+		CourseEditorTreeNode node1 = (CourseEditorTreeNode)cetm.getRootNode().getChildAt(0);
+
+		//publish the course and must survive this without exception
+		//as the course has no changes but we try to publish it
+		List<String> nodeIds = Collections.singletonList(node1.getIdent());
+		publishCourse(nodeIds, re, author);
+
+		//check the change
+		ICourse reloadedCourse = CourseFactory.loadCourse(re.getOlatResource().getResourceableId());
+		Assert.assertEquals(2, reloadedCourse.getRunStructure().getRootNode().getChildCount());
+		INode runNode1 = reloadedCourse.getRunStructure().getRootNode().getChildAt(0);
+		Assert.assertNotNull(runNode1);
+		CourseNode runNode1Impl = (CourseNode)runNode1;
+		Assert.assertEquals("Node 2", runNode1Impl.getShortTitle());
+	}
+	
+	/**
+	 * Publish a course with a node marked as not new but
+	 * the node doesn't exist in the run structure. The node
+	 * itself is not published.
+	 * 
+	 * @throws URISyntaxException
+	 */
+	@Test
+	public void testPublishNewNodeNotMarkedAsSuchAndNotPublished()
+	throws URISyntaxException {
+		Identity author = JunitTestHelper.createAndPersistIdentityAsAdmin("publisher-" + UUID.randomUUID().toString());
+		RepositoryEntry re = deployTestCourse(author, "simple_course_err5_not_new_or_published.zip");
+		
+		//change node 1
+		ICourse course = CourseFactory.loadCourse(re.getOlatResource().getResourceableId());
+		CourseEditorTreeModel cetm = course.getEditorTreeModel();
+
+		//publish the course and must survive this without exception
+		//as the course has no changes but we try to publish it
+		List<String> nodeIds = Collections.singletonList(cetm.getRootNode().getIdent());
+		publishCourse(nodeIds, re, author);
+
+		//check the change
+		ICourse reloadedCourse = CourseFactory.loadCourse(re.getOlatResource().getResourceableId());
+		Assert.assertEquals(2, reloadedCourse.getRunStructure().getRootNode().getChildCount());
+		INode runNode1 = reloadedCourse.getRunStructure().getRootNode().getChildAt(0);
+		Assert.assertNotNull(runNode1);
+		CourseNode runNode1Impl = (CourseNode)runNode1;
+		Assert.assertEquals("Node 2", runNode1Impl.getShortTitle());
+	}
+	
+	private void publishCourse(List<String> nodeIds, RepositoryEntry re, Identity author) {
+		ICourse course = CourseFactory.openCourseEditSession(re.getOlatResource().getResourceableId());
+		CourseEditorTreeModel cetm = course.getEditorTreeModel();
+		PublishProcess pp = PublishProcess.getInstance(course, cetm, locale);
+		// create publish node list
+		pp.createPublishSetFor(nodeIds);
+		StatusDescription[] sds = pp.testPublishSet(locale);
+		Assert.assertNotNull(sds);
+		Assert.assertEquals(0, sds.length);
+		pp.applyPublishSet(author, locale);
+		CourseFactory.closeCourseEditSession(course.getResourceableId(), true);
+	}
+	
+	private RepositoryEntry deployTestCourse(Identity author, String filename)
+	throws URISyntaxException {
+		URL courseUrl = PublishProcessTest.class.getResource(filename);
+		Assert.assertNotNull(courseUrl);
+		File courseFile = new File(courseUrl.toURI());
+		
+		//deploy a course
+		String softKey = UUID.randomUUID().toString().replace("-", "").substring(0, 30);
+		RepositoryEntry re = CourseFactory.deployCourseFromZIP(courseFile, author.getName(), softKey, 1);
+		Assert.assertNotNull(re);
+		return re;
+	}
+}
diff --git a/src/test/java/org/olat/course/editor/simple_course.zip b/src/test/java/org/olat/course/editor/simple_course.zip
new file mode 100644
index 0000000000000000000000000000000000000000..138e4788a2890c257dcc8601023f6dc0190723b1
Binary files /dev/null and b/src/test/java/org/olat/course/editor/simple_course.zip differ
diff --git a/src/test/java/org/olat/course/editor/simple_course_err1_new.zip b/src/test/java/org/olat/course/editor/simple_course_err1_new.zip
new file mode 100644
index 0000000000000000000000000000000000000000..2f6cbb5a0deed33faa07e3538b957dc25ad22c61
Binary files /dev/null and b/src/test/java/org/olat/course/editor/simple_course_err1_new.zip differ
diff --git a/src/test/java/org/olat/course/editor/simple_course_err2_new_deleted.zip b/src/test/java/org/olat/course/editor/simple_course_err2_new_deleted.zip
new file mode 100644
index 0000000000000000000000000000000000000000..144c008bd01fdbb768b82569dfd121c39f240d72
Binary files /dev/null and b/src/test/java/org/olat/course/editor/simple_course_err2_new_deleted.zip differ
diff --git a/src/test/java/org/olat/course/editor/simple_course_err3_not_new.zip b/src/test/java/org/olat/course/editor/simple_course_err3_not_new.zip
new file mode 100644
index 0000000000000000000000000000000000000000..6d2a00ff3086e7ef7e90d026314532c2aad90ce1
Binary files /dev/null and b/src/test/java/org/olat/course/editor/simple_course_err3_not_new.zip differ
diff --git a/src/test/java/org/olat/course/editor/simple_course_err4_not_new_deleted.zip b/src/test/java/org/olat/course/editor/simple_course_err4_not_new_deleted.zip
new file mode 100644
index 0000000000000000000000000000000000000000..5fd95acd9665fee87ffacecf821d50bbf6f1fb13
Binary files /dev/null and b/src/test/java/org/olat/course/editor/simple_course_err4_not_new_deleted.zip differ
diff --git a/src/test/java/org/olat/course/editor/simple_course_err5_not_new_or_published.zip b/src/test/java/org/olat/course/editor/simple_course_err5_not_new_or_published.zip
new file mode 100644
index 0000000000000000000000000000000000000000..dbd83b6026de7a6d301553cd131bb8c027d811a0
Binary files /dev/null and b/src/test/java/org/olat/course/editor/simple_course_err5_not_new_or_published.zip differ
diff --git a/src/test/java/org/olat/test/AllTestsJunit4.java b/src/test/java/org/olat/test/AllTestsJunit4.java
index 721719745ebfe27436fd8fd60ee49b07f4420b50..e3e08fa4383ad6612bca000ac1e4cb8800f96b31 100644
--- a/src/test/java/org/olat/test/AllTestsJunit4.java
+++ b/src/test/java/org/olat/test/AllTestsJunit4.java
@@ -93,6 +93,7 @@ import org.junit.runners.Suite;
 	org.olat.course.assessment.AssessmentManagerTest.class,//ok
 	org.olat.course.config.CourseConfigManagerImplTest.class,//ok
 	org.olat.course.groupsandrights.CourseGroupManagementTest.class,//ok
+	org.olat.course.editor.PublishProcessTest.class,//ok
 	org.olat.modules.fo.ForumManagerTest.class,//fail
 	org.olat.modules.wiki.WikiUnitTest.class,//ok
 	org.olat.modules.wiki.versioning.diff.CookbookDiffTest.class,//ok