Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,29 @@ export default defineConfig({
})
```

## Getting the server log

The server's `data` directory is mounted as a tmpfs and the container is removed after the run,
so `data/nextcloud.log` is gone once the tests have finished.
To keep it, save it while the container still exists — either by passing `saveLogTo` to `stopNextcloud`,
or by setting the `NEXTCLOUD_E2E_LOG_FILE` environment variable (both take a path on your machine, relative paths are resolved from the current working directory):

```js
import { stopNextcloud } from '@nextcloud/e2e-test-server'

// Writes `data/nextcloud.log` to `cypress/logs/nextcloud.log`, then removes the container
await stopNextcloud({ saveLogTo: 'cypress/logs/nextcloud.log' })
```

If you need the log during a run — e.g. to attach it to a failing test — use `getNextcloudLog()`,
which resolves with the log contents, or `saveNextcloudLog(path)` to write it out.

```js
import { getNextcloudLog } from '@nextcloud/e2e-test-server'

const log = await getNextcloudLog()
```

## Cypress commands

You can import individual commands or all at once
Expand Down
3 changes: 2 additions & 1 deletion cypress.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ export default defineConfig({

// Remove container after run
on('after:run', async () => {
await stopNextcloud()
// The data directory is a tmpfs, so grab the server log before the container goes away
await stopNextcloud({ saveLogTo: 'cypress/logs/nextcloud.log' })
await docker.getVolume('apps_writable').remove()
})

Expand Down
83 changes: 80 additions & 3 deletions lib/docker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ import type { Stream } from 'stream'

import Docker from 'dockerode'
import { XMLParser } from 'fast-xml-parser'
import { existsSync, readFileSync } from 'fs'
import { basename, join, resolve, sep } from 'path'
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs'
import { basename, dirname, join, resolve, sep } from 'path'
import { PassThrough } from 'stream'
import { pipeline } from 'stream/promises'
import tarStreamer from 'tar-stream'
import waitOn from 'wait-on'
import { User } from './User.ts'
Expand All @@ -23,6 +24,9 @@ const COMPOSER_PHAR = '/tmp/composer.phar'
/** `COMPOSER_HOME` used inside the server container, must be writable by `www-data` */
const COMPOSER_HOME = '/tmp/composer-home'

/** Path of the server log inside the container, it lives on the tmpfs mounted data directory */
const NEXTCLOUD_LOG = '/var/www/html/data/nextcloud.log'

export const docker = new Docker({ socketPath: process.env.DOCKER_SOCKET ?? '/var/run/docker.sock' })

// Store the container name, different names are used to prevent conflicts when testing multiple apps locally
Expand Down Expand Up @@ -418,12 +422,85 @@ export async function restoreSnapshot(snapshot = 'init', container?: Container)
console.log('└─ Done')
}

/**
* Read the server log (`data/nextcloud.log`) from the container.
*
* The data directory is a tmpfs and the container is removed after the run,
* so the log has to be fetched while the container still exists.
*
* @param container Optional server container to use (defaults to current container)
* @return The log contents, or an empty string if the server has not written a log
*/
export async function getNextcloudLog(container?: Container): Promise<string> {
container = container ?? getContainer()

let archive: NodeJS.ReadableStream
try {
archive = await container.getArchive({ path: NEXTCLOUD_LOG })
} catch {
// No log written (yet), or the container is already gone
return ''
}

// `getArchive` always answers with a tar stream, containing the single log entry
const extract = tarStreamer.extract()
const chunks: Buffer[] = []
extract.on('entry', (_header, stream, next) => {
stream.on('data', (chunk: Buffer) => chunks.push(chunk))
stream.on('end', next)
})
await pipeline(archive, extract)

return Buffer.concat(chunks).toString('utf8')
}

/**
* Save the server log (`data/nextcloud.log`) from the container to a local file.
*
* Must be called before {@link stopNextcloud}, the log is lost with the container.
*
* @param targetPath Local path to write the log to (default 'nextcloud.log' in the current directory)
* @param container Optional server container to use (defaults to current container)
* @return Whether a log was found and written
*/
export async function saveNextcloudLog(targetPath = 'nextcloud.log', container?: Container): Promise<boolean> {
const log = await getNextcloudLog(container)
if (log === '') {
console.log('└─ No server log found in the container')
return false
}

const target = resolve(targetPath)
mkdirSync(dirname(target), { recursive: true })
writeFileSync(target, log)
console.log(`└─ Server log saved to ${target} 📝`)
return true
}

interface StopOptions {
/**
* Local path to save the server log (`data/nextcloud.log`) to before the container is removed.
*
* @default process.env.NEXTCLOUD_E2E_LOG_FILE (disabled if unset)
*/
saveLogTo?: string
}

/**
* Force stop the testing container
*
* @param options Optional parameters to configure the container removal
*/
export async function stopNextcloud() {
export async function stopNextcloud(options: StopOptions = {}) {
try {
const container = getContainer()

const logTarget = options.saveLogTo ?? process.env.NEXTCLOUD_E2E_LOG_FILE
if (logTarget) {
console.log('\nSaving Nextcloud server log…')
await saveNextcloudLog(logTarget, container)
}

console.log('Stopping Nextcloud container…')
await container.remove({ force: true })
console.log('└─ Nextcloud container removed 🥀')
Expand Down
2 changes: 1 addition & 1 deletion playwright/start-nextcloud-server.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ function getBranch() {
await start()
// Listen for process to exit (tests done) and shut down the docker container
process.on('beforeExit', async () => {
await stopNextcloud()
await stopNextcloud({ saveLogTo: 'playwright-report/nextcloud.log' })
await docker.getVolume('apps_writable').remove()
})

Expand Down
Loading