1
0
mirror of https://git.cloudron.io/cloudron/syncthing-app synced 2026-06-17 11:35:49 +00:00

Compare commits

..

16 Commits

Author SHA1 Message Date
Package Updates 32094b5108 Update package version to 1.34.0 2026-05-12 10:26:08 +00:00
Girish Ramakrishnan 8cf30550e3 fix tests 2026-05-12 12:14:49 +02:00
Renovate Bot a6a2bf218a chore(deps): update dependency syncthing/syncthing to v2.1.0
| datasource      | package             | from   | to    |
| --------------- | ------------------- | ------ | ----- |
| github-releases | syncthing/syncthing | 2.0.16 | 2.1.0 |
2026-05-12 08:46:59 +00:00
Girish Ramakrishnan ebc099e986 test: simplify clearCache, drop logout helpers, simplify button selectors
- Drop `await clearCache()` from login/auth helpers; clearing cache before
  every login is no longer necessary now that charlie isolates sessions.
- Replace `logout` helpers with `clearCache` directly in `it()` calls; the
  helpers were either thin wrappers around `clearCache()` or did real
  navigation that is no longer worth the maintenance.
- Simplify `xpath=//button[text()=...]` / `[contains(., ...)]` button text
  selectors to charlie's bare-string (or RegExp for OR-clauses) form.
2026-05-01 10:42:22 +02:00
Girish Ramakrishnan 3695f39ab6 test file cleanups 2026-04-30 10:25:54 +02:00
Girish Ramakrishnan ad17c38599 test: pass full Mocha test to takeScreenshot for unique screenshot names 2026-04-29 17:12:03 +02:00
Girish Ramakrishnan f861f076e4 test: drop 'text=' prefix from charlie locators
charlie now treats bare strings as exact-match (was substring) and
RegExp as the explicit fuzzy escape hatch. The 'text=' prefix has
been removed and now throws a migration error from charlie.

Made-with: Cursor
2026-04-27 17:03:24 +02:00
Girish Ramakrishnan b3297ccc87 test: port to charlie
Made-with: Cursor
2026-04-24 20:04:51 +02:00
Girish Ramakrishnan efe0db3947 test: remove package.json and package-lock.json, charlie provides all deps
Made-with: Cursor
2026-04-16 10:44:36 +02:00
Girish Ramakrishnan b8c7faa37a test: remove chromedriver dependency
Selenium Manager auto-detects the system ChromeDriver, making the
chromedriver npm package unnecessary.

Made-with: Cursor
2026-04-15 17:19:43 +02:00
Girish Ramakrishnan 7c3f77d272 test: convert test to ESM
Replace CommonJS require() with ESM imports, add "type": "module"
to test/package.json, remove 'use strict' and jshint directives,
replace __dirname with import.meta.dirname.

Made-with: Cursor
2026-04-15 16:17:02 +02:00
Girish Ramakrishnan 653e6a11bb Replace expect.js with node:assert/strict
expect.js is unmaintained and unnecessary — Node's built-in assert
module covers all our assertion patterns. This also removes expect.js
from package.json dependencies.

Made-with: Cursor
2026-04-15 15:38:49 +02:00
Package Updates dfbe17a05f Update package version to 1.33.17 2026-04-08 08:44:29 +00:00
Renovate Bot 7f76c04f69 chore(deps): update dependency syncthing/syncthing to v2.0.16
| datasource      | package             | from   | to     |
| --------------- | ------------------- | ------ | ------ |
| github-releases | syncthing/syncthing | 2.0.15 | 2.0.16 |
2026-04-08 06:20:32 +00:00
Package Updates a3d4d57462 Update package version to 1.33.16 2026-03-03 12:34:54 +00:00
Renovate Bot a060d6e28b chore(deps): update dependency syncthing/syncthing to v2.0.15
| datasource      | package             | from   | to     |
| --------------- | ------------------- | ------ | ------ |
| github-releases | syncthing/syncthing | 2.0.14 | 2.0.15 |
2026-03-03 12:18:52 +00:00
6 changed files with 84 additions and 3293 deletions
+45
View File
@@ -795,3 +795,48 @@
* Update syncthing to 2.0.14
* [Full Changelog](https://github.com/syncthing/syncthing/releases/tag/v2.0.14)
[1.33.16]
* Update syncthing to 2.0.15
* [Full Changelog](https://github.com/syncthing/syncthing/releases/tag/v2.0.15)
* Database backend switched from LevelDB to SQLite. There is a migration on
* first launch which can be lengthy for larger setups. The new database is
* easier to understand and maintain and, hopefully, less buggy.
* The logging format has changed to use structured log entries (a message
* plus several key-value pairs). Additionally, we can now control the log
* level per package, and a new log level WARNING has been inserted between
* INFO and ERROR (which was previously known as WARNING...). The INFO level
* has become more verbose, indicating the sync actions taken by Syncthing. A
* new command line flag `--log-level` sets the default log level for all
* packages, and the `STTRACE` environment variable and GUI has been updated
* to set log levels per package. The `--verbose` and `--logflags` command
* line options have been removed and will be ignored if given.
* packages, and the `STTRACE` environment variable and GUI has been updated
[1.33.17]
* Update syncthing to 2.0.16
* [Full Changelog](https://github.com/syncthing/syncthing/releases/tag/v2.0.16)
* Database backend switched from LevelDB to SQLite. There is a migration on first launch which can be lengthy for larger setups. The new database is easier to understand and maintain and, hopefully, less buggy.
* The logging format has changed to use structured log entries (a message plus several key-value pairs). Additionally, we can now control the log level per package, and a new log level WARNING has been inserted between INFO and ERROR (which was previously known as WARNING...). The INFO level has become more verbose, indicating the sync actions taken by Syncthing. A new command line flag `--log-level` sets the default log level for all packages, and the `STTRACE` environment variable and GUI has been updated to set log levels per package. The `--verbose` and `--logflags` command line options have been removed and will be ignored if given.
* Deleted items are no longer kept forever in the database, instead they are forgotten after fifteen months. If your use case require deletes to take effect after more than a fifteen month delay, set the `--db-delete-retention-interval` command line option or corresponding environment variable to zero, or a longer time interval of your choosing.
* Modernised command line options parsing. Old single-dash long options are no longer supported, e.g. `-home` must be given as `--home`. Some options have been renamed, others have become subcommands. All serve options are now also accepted as environment variables. See `syncthing --help` and `syncthing serve --help` for details.
* Rolling hash detection of shifted data is no longer supported as this effectively never helped. Instead, scanning and syncing is faster and more efficient without it.
* A "default folder" is no longer created on first startup.
* Multiple connections are now used by default between v2 devices. The new default value is to use three connections: one for index metadata and two for data exchange.
* The following platforms unfortunately no longer get prebuilt binaries for download at syncthing.net and on GitHub, due to complexities related to cross compilation with SQLite:
* The handling of conflict resolution involving deleted files has changed. A delete can now be the winning outcome of conflict resolution, resulting in the deleted file being moved to a conflict copy.
* fix(protocol): verify compressed message length before decompression by [@​calmh](https://github.com/calmh) in [#​10595](https://github.com/syncthing/syncthing/pull/10595)
[1.34.0]
* Update syncthing to 2.1.0
* [Full Changelog](https://github.com/syncthing/syncthing/releases/tag/v2.1.0)
* fix(stdiscosrv): close file descriptor on flush error in write by [@cuiweixie](https://github.com/cuiweixie) in [#10615](https://github.com/syncthing/syncthing/pull/10615)
* fix(gui): disable autocomplete for folder password by [@bt90](https://github.com/bt90) in [#10342](https://github.com/syncthing/syncthing/pull/10342)
* fix(protocol): limit size of incoming request messages by [@calmh](https://github.com/calmh) in [#10629](https://github.com/syncthing/syncthing/pull/10629)
* fix(gui): don't show local device under remote devices (ref [#10563](https://github.com/syncthing/syncthing/issues/10563)) by [@maen-bn](https://github.com/maen-bn) in [#10631](https://github.com/syncthing/syncthing/pull/10631)
* fix(gui): order folders alphabetically and ensure local device stays hidden (ref [#10563](https://github.com/syncthing/syncthing/issues/10563), ref [#10631](https://github.com/syncthing/syncthing/issues/10631)) by [@maen-bn](https://github.com/maen-bn) in [#10637](https://github.com/syncthing/syncthing/pull/10637)
* fix(gui): fallback to folder ID when label is empty in remove dialog by [@RealCharlesChia](https://github.com/RealCharlesChia) in [#10657](https://github.com/syncthing/syncthing/pull/10657)
* fix(gui): fix tabs visually disabled but still clickable during ignore patterns setup (fixes [#10634](https://github.com/syncthing/syncthing/issues/10634)) by [@JRNitre](https://github.com/JRNitre) in [#10651](https://github.com/syncthing/syncthing/pull/10651)
* fix(strelaysrv): properly use bind address for outgoing requests (fixes [#10658](https://github.com/syncthing/syncthing/issues/10658)) by [@calmh](https://github.com/calmh) in [#10659](https://github.com/syncthing/syncthing/pull/10659)
* feat(gui, config): support simple folder grouping (fixes [#2070](https://github.com/syncthing/syncthing/issues/2070)) by [@maen-bn](https://github.com/maen-bn) in [#10563](https://github.com/syncthing/syncthing/pull/10563)
* feat(dialer): add HTTP/HTTPS proxy support via CONNECT by [@luizluca](https://github.com/luizluca) in [#10572](https://github.com/syncthing/syncthing/pull/10572)
+2 -2
View File
@@ -5,8 +5,8 @@
"description": "file://DESCRIPTION.md",
"changelog": "file://CHANGELOG",
"tagline": "Decentralized file synchronization",
"version": "1.33.15",
"upstreamVersion": "2.0.14",
"version": "1.34.0",
"upstreamVersion": "2.1.0",
"healthCheckPath": "/healthcheck",
"httpPort": 8000,
"addons": {
+1 -1
View File
@@ -4,7 +4,7 @@ RUN mkdir -p /app/code
WORKDIR /app/code
# renovate: datasource=github-releases depName=syncthing/syncthing versioning=semver extractVersion=^v(?<version>.+)$
ARG SYNCTHING_VERSION=2.0.14
ARG SYNCTHING_VERSION=2.1.0
RUN wget https://github.com/syncthing/syncthing/releases/download/v${SYNCTHING_VERSION}/syncthing-linux-amd64-v${SYNCTHING_VERSION}.tar.gz -O - | tar -xz -C /app/code --strip-components=1
-3134
View File
File diff suppressed because it is too large Load Diff
-17
View File
@@ -1,17 +0,0 @@
{
"name": "test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"chromedriver": "^145.0.0",
"expect.js": "^0.3.1",
"mocha": "^11.7.5",
"selenium-webdriver": "^4.40.0"
}
}
+36 -139
View File
@@ -1,195 +1,92 @@
#!/usr/bin/env node
/* jshint esversion: 8 */
/* global it, xit, describe, before, after, afterEach */
import { app, clearCache, click, cloudronCli, goto, password, sendKeys, setupBrowser, takeScreenshot, teardownBrowser, username, waitFor } from '@cloudron/charlie';
'use strict';
require('chromedriver');
const execSync = require('child_process').execSync,
expect = require('expect.js'),
fs = require('fs'),
path = require('path'),
timers = require('timers/promises'),
{ Builder, By, until } = require('selenium-webdriver'),
{ Options } = require('selenium-webdriver/chrome');
if (!process.env.USERNAME || !process.env.PASSWORD) {
console.log('USERNAME and PASSWORD env vars need to be set');
process.exit(1);
}
/* global it, describe, before, after, afterEach */
describe('Application life cycle test', function () {
this.timeout(0);
const LOCATION = process.env.LOCATION || 'test';
const TEST_TIMEOUT = 30000;
const FOLDER = 'xmf'; // keep this small. long folder names fail in automation, not sure why
const FOLDER = 'xmf'; // keep small; long folder names fail in automation
const SYNC_PORT = 22001;
const EXEC_ARGS = { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' };
const adminUsername = 'admin';
const adminPassword = 'changeme';
let browser, app;
const adminUsername = 'admin', adminPassword = 'changeme';
const username = process.env.USERNAME;
const password = process.env.PASSWORD;
before(function () {
const chromeOptions = new Options().windowSize({ width: 1280, height: 1024 });
if (process.env.CI) chromeOptions.addArguments('no-sandbox', 'disable-dev-shm-usage', 'headless');
browser = new Builder().forBrowser('chrome').setChromeOptions(chromeOptions).build();
if (!fs.existsSync('./screenshots')) fs.mkdirSync('./screenshots');
});
after(function () {
browser.quit();
});
before(setupBrowser);
after(teardownBrowser);
afterEach(async function () {
if (!process.env.CI || !app) return;
const currentUrl = await browser.getCurrentUrl();
if (!currentUrl.includes(app.domain)) return;
expect(this.currentTest.title).to.be.a('string');
const screenshotData = await browser.takeScreenshot();
fs.writeFileSync(`./screenshots/${new Date().getTime()}-${this.currentTest.title.replaceAll(' ', '_')}.png`, screenshotData, 'base64');
await takeScreenshot(this.currentTest);
});
function getAppInfo() {
const inspect = JSON.parse(execSync('cloudron inspect'));
app = inspect.apps.filter(function (a) { return a.location.indexOf(LOCATION) === 0; })[0];
expect(app).to.be.an('object');
}
async function waitForElement(elem) {
await browser.wait(until.elementLocated(elem), TEST_TIMEOUT);
await browser.wait(until.elementIsVisible(browser.findElement(elem)), TEST_TIMEOUT);
}
async function login(username, password) {
await browser.manage().deleteAllCookies();
await browser.get('https://' + app.fqdn);
await waitForElement(By.id('user'));
await browser.findElement(By.id('user')).sendKeys(username);
await browser.findElement(By.id('password')).sendKeys(password);
await browser.findElement(By.xpath('//button[@type="submit"]')).click();
await waitForElement(By.xpath('//span[text()="Actions"]'));
}
async function logout() {
await browser.get('https://' + app.fqdn);
await waitForElement(By.xpath('//span[text()="Actions"]'));
await browser.findElement(By.xpath('//span[text()="Actions"]')).click();
await browser.sleep(4000);
await waitForElement(By.xpath('//span[text()="Log Out"]'));
await browser.findElement(By.xpath('//span[text()="Log Out"]')).click();
await browser.sleep(4000);
await waitForElement(By.id('user'));
async function login(uname, pass) {
await goto(`https://${app.fqdn}`, 'label=User');
await sendKeys('label=User', uname);
await sendKeys('label=Password', pass);
await click('Log In');
await waitFor('Actions');
}
async function loadPage() {
await browser.get('https://' + app.fqdn);
await waitForElement(By.xpath('//span[text()="Actions"]'));
await goto(`https://${app.fqdn}`, 'Actions');
}
async function addFolder() {
await browser.get('https://' + app.fqdn);
await browser.findElement(By.css('[ng-click*=addFolder]')).click();
await browser.sleep(8000);
await waitForElement(By.id('folderPath'));
await browser.sleep(8000); // wait more, not sure why this is needed
await browser.findElement(By.id('folderLabel')).sendKeys(FOLDER);
await browser.findElement(By.id('folderPath')).sendKeys(`/app/data/${FOLDER}`);
await browser.sleep(8000); // without this sometimes only part of the folder name gets through
await browser.findElement(By.css('[ng-click*=saveFolder]')).click();
await browser.sleep(8000); // without this "stale element"
await waitForElement(By.xpath(`//span[contains(text(), '${FOLDER}')]`));
await browser.sleep(8000);
await goto(`https://${app.fqdn}`, /Add Folder/);
await click(/Add Folder/);
await sendKeys('label=Folder Label', FOLDER);
await sendKeys('label=Folder Path', `/app/data/${FOLDER}`);
await click(/Save/);
await waitFor(FOLDER);
}
async function checkFolder() {
await browser.get('https://' + app.fqdn);
await browser.sleep(5000);
await browser.get('https://' + app.fqdn);
await browser.wait(until.elementLocated(By.xpath(`//span[text()="${FOLDER}"]`)), TEST_TIMEOUT);
await goto(`https://${app.fqdn}`, FOLDER);
}
xit('build app', function () { execSync('cloudron build', EXEC_ARGS); });
// NO SSO
it('install app (NO SSO)', function () { execSync('cloudron install --no-sso --port-bindings SYNC_PORT=' + SYNC_PORT + ' --location ' + LOCATION, EXEC_ARGS); });
it('can get app information', getAppInfo);
it('install app (NO SSO)', () => cloudronCli.install({ noSso: true, tcpPortFlags: { SYNC_PORT } }));
it('can admin login', login.bind(null, adminUsername, adminPassword));
it('can load page', loadPage);
it('can add folder', addFolder);
it('can check folder', checkFolder);
it('uninstall app', async function () {
await browser.get('about:blank');
execSync('cloudron uninstall --app ' + app.id, EXEC_ARGS);
});
it('uninstall app', cloudronCli.uninstall);
// SSO
it('install app (SSO)', function () { execSync('cloudron install --port-bindings SYNC_PORT=' + SYNC_PORT + ' --location ' + LOCATION, EXEC_ARGS); });
it('can get app information', getAppInfo);
it('install app (SSO)', () => cloudronCli.install({ noSso: false, tcpPortFlags: { SYNC_PORT } }));
it('can login', login.bind(null, username, password));
it('can load page', loadPage);
it('can add folder', addFolder);
it('can logout', logout);
it('can logout', clearCache);
it('backup app', async function () { execSync('cloudron backup create --app ' + app.id, EXEC_ARGS); });
it('restore app', async function () {
await browser.get('about:blank');
execSync('cloudron restore --app ' + app.id, EXEC_ARGS);
await timers.setTimeout(5000);
});
it('backup app', cloudronCli.createBackup);
it('restore app', cloudronCli.restoreFromLatestBackup);
it('can login', login.bind(null, username, password));
it('can load page', loadPage);
it('can check folder', checkFolder);
it('can logout', logout);
it('can logout', clearCache);
it('move to different location', async function () {
await browser.get('about:blank');
execSync(`cloudron configure --location ${LOCATION}2 --app ${app.id}`, EXEC_ARGS);
await timers.setTimeout(5000);
});
it('can get app information', getAppInfo);
it('move to different location', cloudronCli.changeLocation);
it('can login', login.bind(null, username, password));
it('can load page', loadPage);
it('can check folder', checkFolder);
it('can logout', logout);
it('can logout', clearCache);
it('uninstall app', async function () {
await browser.get('about:blank');
execSync('cloudron uninstall --app ' + app.id, EXEC_ARGS);
});
it('uninstall app', cloudronCli.uninstall);
// test update
it('can install app', async function () {
execSync('cloudron install --port-bindings SYNC_PORT=' + SYNC_PORT + ' --appstore-id net.syncthing.cloudronapp2 --location ' + LOCATION, EXEC_ARGS);
await timers.setTimeout(30000);
});
it('can get app information', getAppInfo);
it('can install app for update', () => cloudronCli.appstoreInstall({ tcpPortFlags: { SYNC_PORT } }));
it('can login', login.bind(null, username, password));
it('can load page', loadPage);
it('can add folder', addFolder);
it('can logout', logout);
it('can logout', clearCache);
it('can update', async function () {
await browser.get('about:blank');
execSync('cloudron update --app ' + LOCATION, EXEC_ARGS);
await timers.setTimeout(30000);
});
it('can update', cloudronCli.update);
it('can login', login.bind(null, username, password));
it('can check folder', checkFolder);
it('uninstall app', async function () {
await browser.get('about:blank');
execSync('cloudron uninstall --app ' + app.id, EXEC_ARGS);
});
it('uninstall app', cloudronCli.uninstall);
});