diff --git a/vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/controller/UploadController.java b/vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/controller/UploadController.java
index 370018f8593cd1a0f0a89f27dfd9a974c68755f0..ea2cab9e2724a37ec05388327cfeaef8e3b6b1f1 100644
--- a/vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/controller/UploadController.java
+++ b/vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/controller/UploadController.java
@@ -64,7 +64,11 @@ public class UploadController extends BaseController {
     public CompletableFuture<String> prepareForDownload(String parentPath, String fileName) {
 
         return CompletableFuture.supplyAsync(() -> {
-            String nodeUri = "vos://" + authority + parentPath + "/" + fileName;
+            String nodeUri = "vos://" + authority + parentPath;
+            if (!nodeUri.endsWith("/")) {
+                nodeUri += "/";
+            }
+            nodeUri += fileName;
 
             createDataNode(nodeUri, getUser().getName());
 
diff --git a/vospace-ui-backend/src/test/java/it/inaf/ia2/vospace/ui/controller/UploadControllerTest.java b/vospace-ui-backend/src/test/java/it/inaf/ia2/vospace/ui/controller/UploadControllerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..18e8fdc415235326d5d637153daff2c03bb5be90
--- /dev/null
+++ b/vospace-ui-backend/src/test/java/it/inaf/ia2/vospace/ui/controller/UploadControllerTest.java
@@ -0,0 +1,99 @@
+/*
+ * This file is part of vospace-ui
+ * Copyright (C) 2021 Istituto Nazionale di Astrofisica
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+package it.inaf.ia2.vospace.ui.controller;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import it.inaf.ia2.aa.data.User;
+import it.inaf.ia2.vospace.ui.client.VOSpaceClient;
+import it.inaf.ia2.vospace.ui.data.UploadFilesData;
+import java.util.List;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import static org.mockito.ArgumentMatchers.any;
+import org.mockito.Mock;
+import static org.mockito.Mockito.when;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.MediaType;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.web.servlet.MockMvc;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@SpringBootTest
+@AutoConfigureMockMvc
+@TestPropertySource(properties = {"vospace-authority=example.com!vospace"})
+public class UploadControllerTest {
+
+    private static final ObjectMapper MAPPER = new ObjectMapper();
+
+    @MockBean
+    private VOSpaceClient client;
+
+    @Autowired
+    private MockMvc mockMvc;
+
+    @Mock
+    private User user;
+
+    @BeforeEach
+    public void setUp() {
+        when(user.getName()).thenReturn("user_id");
+    }
+
+    @Test
+    public void testPreUpload() throws Exception {
+
+        UploadFilesData data = new UploadFilesData();
+        data.setParentPath("/mynode");
+        data.setFiles(List.of("test.txt"));
+
+        when(client.getFileServiceEndpoint(any())).thenReturn("http://files/mynode/test.txt");
+
+        mockMvc.perform(post("/preupload")
+                .sessionAttr("user_data", user)
+                .contentType(MediaType.APPLICATION_JSON)
+                .content(MAPPER.writeValueAsString(data)))
+                .andDo(print())
+                .andExpect(status().isOk())
+                .andExpect(jsonPath("$[0]").value("http://files/mynode/test.txt"));
+    }
+
+    @Test
+    public void testPreUploadRoot() throws Exception {
+
+        UploadFilesData data = new UploadFilesData();
+        data.setParentPath("/");
+        data.setFiles(List.of("test.txt"));
+
+        when(client.getFileServiceEndpoint(any())).thenReturn("http://files/test.txt");
+
+        mockMvc.perform(post("/preupload")
+                .sessionAttr("user_data", user)
+                .contentType(MediaType.APPLICATION_JSON)
+                .content(MAPPER.writeValueAsString(data)))
+                .andDo(print())
+                .andExpect(status().isOk())
+                .andExpect(jsonPath("$[0]").value("http://files/test.txt"));
+    }
+
+    @Test
+    public void testUploadNotAllowedToAnonymous() throws Exception {
+
+        UploadFilesData data = new UploadFilesData();
+        data.setParentPath("/");
+        data.setFiles(List.of("test.txt"));
+
+        mockMvc.perform(post("/preupload")
+                .contentType(MediaType.APPLICATION_JSON)
+                .content(MAPPER.writeValueAsString(data)))
+                .andExpect(status().isForbidden());
+    }
+}