Skip to content

Commit

Permalink
Merge e8f32bc into ec843da
Browse files Browse the repository at this point in the history
  • Loading branch information
kraenhansen committed Feb 19, 2024
2 parents ec843da + e8f32bc commit b19542e
Show file tree
Hide file tree
Showing 40 changed files with 460 additions and 465 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/pr-coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ jobs:
timeout-minutes: 60
run: npm run ci:coverage --workspace @realm/integration-tests -- --reporter mocha-github-actions-reporter --timeout ${{ env.MOCHA_TIMEOUT }}
env:
CONTEXT: syncLogLevel=warn,longTimeout=${{ env.LONG_TIMEOUT }},realmBaseUrl=${{ steps.baas.outputs.baas-url }}
CONTEXT: syncLogLevel=warn,longTimeout=${{ env.LONG_TIMEOUT }},baseUrl=${{ steps.baas.outputs.baas-url }}

- name: Coveralls
uses: coverallsapp/github-action@v2
2 changes: 1 addition & 1 deletion .github/workflows/pr-realm-js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ jobs:

- name: Create Mocha Remote Context
id: mocha-env
run: echo "context=syncLogLevel=warn,longTimeout=${{ env.LONG_TIMEOUT }},realmBaseUrl=${{ steps.baas.outputs.baas-url }}" >> $GITHUB_OUTPUT
run: echo "context=syncLogLevel=warn,longTimeout=${{ env.LONG_TIMEOUT }},baseUrl=${{ steps.baas.outputs.baas-url }}" >> $GITHUB_OUTPUT

- name: Run ${{matrix.variant.target}} (${{ matrix.variant.os}} / ${{ matrix.variant.environment }})
if: ${{ matrix.variant.os != 'android' && matrix.variant.os != 'ios' }}
Expand Down
2 changes: 1 addition & 1 deletion integration-tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ Examples of context variables used:
- `defaultLogLevel=all`: Set the default log level to help debugging realm core issues.
- `syncLogLevel=all`: Set the sync client log level to help debugging sync client issues.
- `reuseApp=true`: Instructs the app importer to reuse and reconfigure a single app. Defaults to `false`.
- `realmBaseUrl=https://localhost:9090`: Set the base URL used when connecting the the server.
- `baseUrl=https://localhost:9090`: Set the base URL used when connecting the the server.
- `mongodbClusterName=Cluster0`: Set the name of the cluster, used when setting up the "mongodb-atlas" service on imported apps.
- `mongodbServiceType`: Set the type of mongodb service, used when importing. Defaults to `mongodb` or `mongodb-atlas` if `mongodbClusterName` is set.

Expand Down
2 changes: 1 addition & 1 deletion integration-tests/environments/react-native/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ export class App extends Component {
global.path = require("path-browserify");
global.environment = {
// Default to the host machine when running on Android
realmBaseUrl: Platform.OS === "android" ? "http://10.0.2.2:9090" : undefined,
baseUrl: Platform.OS === "android" ? "http://10.0.2.2:9090" : undefined,
...context,
reactNative: Platform.OS,
android: Platform.OS === "android",
Expand Down
99 changes: 93 additions & 6 deletions integration-tests/tests/src/hooks/import-app-before.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,27 @@
//
////////////////////////////////////////////////////////////////////////////

import Realm, { AppConfiguration } from "realm";
import Realm from "realm";

import { importApp } from "../utils/import-app";
import { AppConfig } from "@realm/app-importer";
import { AppConfig, AppImporter, Credentials } from "@realm/app-importer";
import { mongodbServiceType } from "../utils/ExtendedAppConfigBuilder";

const REALM_LOG_LEVELS = ["all", "trace", "debug", "detail", "info", "warn", "error", "fatal", "off"];

const { syncLogLevel = "warn" } = environment;
const {
syncLogLevel = "warn",
baseUrl = "http://localhost:9090",
reuseApp = false,
username = "unique_user@domain.com",
password = "password",
publicKey,
privateKey,
missingServer,
} = environment;

export { baseUrl };

const allowSkippingServerTests = typeof environment.baseUrl === "undefined" && missingServer !== false;

export type AppConfigurationRelaxed = {
id?: string;
Expand All @@ -34,20 +46,95 @@ export type AppConfigurationRelaxed = {
baseFilePath?: string;
};

function getCredentials(): Credentials {
if (typeof publicKey === "string" && typeof privateKey === "string") {
return {
kind: "api-key",
publicKey,
privateKey,
};
} else {
return {
kind: "username-password",
username,
password,
};
}
}

const credentials = getCredentials();

const importer = new AppImporter({
baseUrl,
credentials,
reuseApp,
});

function isConnectionRefused(err: unknown) {
return (
err instanceof Error &&
err.cause instanceof AggregateError &&
"code" in err.cause &&
err.cause.code === "ECONNREFUSED"
);
}

function printWarningBox(...lines: string[]) {
const contentWidth = Math.max(...lines.map((line) => line.length));
const bar = "━".repeat(contentWidth + 2);
console.warn(`┏${bar}┓`);
for (const line of lines) {
const padding = " ".repeat(contentWidth - line.length);
console.warn(`┃ ${line}${padding} ┃`);
}
console.warn(`┗${bar}┛`);
}

/** Ensure we'll only ever install a single after hook with this warning */
let skippedAppImportAfterHookInstalled = false;
function ensureSkippedAppImportAfterHook() {
if (!skippedAppImportAfterHookInstalled) {
skippedAppImportAfterHookInstalled = true;
after(function (this: Mocha.Context) {
printWarningBox(
"Connection got refused while importing an app - skipping tests",
"Run this with `MOCHA_REMOTE_CONTEXT=missingServer` to silence this warning",
);
});
}
}

/**
* Imports an app before the suite runs and stores an `App` instance on the test context (accessible via `this.app` of a test).
* If the `missingServer` context is set the suite will be skipped.
* If the import fails due to a connection refusal, the suite will be skipped and a warning printed at the end of the test run.
*/
export function importAppBefore(config: AppConfig | { config: AppConfig }, sdkConfig?: AppConfigurationRelaxed): void {
// Unwrap when passed a builder directly
if ("config" in config) {
return importAppBefore(config.config, sdkConfig);
}

before(importAppBefore.name, async function (this: AppContext & Mocha.Context) {
if (missingServer) {
this.skip();
}
// Importing an app might take up to 5 minutes when the app has a MongoDB Atlas service enabled.
this.longTimeout();
if (this.app) {
throw new Error("Unexpected app on context, use only one importAppBefore per test");
} else {
const { appId, baseUrl } = await importApp(config);
this.app = new Realm.App({ id: appId, baseUrl, ...sdkConfig });
try {
const { appId } = await importer.importApp(config);
this.app = new Realm.App({ id: appId, baseUrl, ...sdkConfig });
} catch (err) {
if (isConnectionRefused(err) && allowSkippingServerTests) {
ensureSkippedAppImportAfterHook();
this.skip();
} else {
throw err;
}
}

// Extract the sync database name from the config
const databaseNames: (string | undefined)[] = config.services
Expand Down
7 changes: 3 additions & 4 deletions integration-tests/tests/src/hooks/open-realm-before.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,6 @@ export function openRealmHook(config: OpenRealmConfiguration = {}) {
if (this.realm) {
throw new Error("Unexpected realm on context, use only one openRealmBefore per test");
} else {
this.closeRealm = async () => {
console.warn("🤷 Skipped closing a Realm that failed to open");
};
const { realm, config: actualConfig } = await openRealm(config, this.user as unknown as User);
this.realm = realm;
this.closeRealm = async ({
Expand Down Expand Up @@ -70,7 +67,9 @@ export function openRealmHook(config: OpenRealmConfiguration = {}) {
* @param this Mocha `this` context
*/
export function closeThisRealm(this: RealmContext & Mocha.Context): void {
this.closeRealm({ clearTestState: true, deleteFile: true });
if (this.closeRealm) {
this.closeRealm({ clearTestState: true, deleteFile: true });
}
// Clearing the test state to ensure the sync session gets completely reset and nothing is cached between tests
Realm.clearTestState();
}
Expand Down
1 change: 0 additions & 1 deletion integration-tests/tests/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ afterEach(() => {
}
});

import "./utils/import-app.test.ts";
import "./utils/chai-plugin.test.ts";
import "./utils/listener-stub.test.ts";
import "./utils/promise-handle.test.ts";
Expand Down
5 changes: 2 additions & 3 deletions integration-tests/tests/src/node/node-fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,14 @@
//
////////////////////////////////////////////////////////////////////////////

import { expect } from "chai";
import nodeFetch from "node-fetch";
import Realm from "realm";

import { importAppBefore } from "../hooks";
import { buildAppConfig } from "../utils/build-app-config";
import { baseUrl } from "../utils/import-app";
import { baseUrl } from "../hooks/import-app-before";

describe.skipIf(environment.missingServer, "passing node-fetch to AppConfiguration", () => {
describe("passing node-fetch to AppConfiguration", () => {
importAppBefore(buildAppConfig().anonAuth());

it("is supported", async function (this: AppContext) {
Expand Down
78 changes: 37 additions & 41 deletions integration-tests/tests/src/node/path.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ describe("path configuration (local)", function () {
});
});

describe.skipIf(environment.missingServer, `app configuration of root directory (flexible sync)`, async function () {
describe("app configuration of root directory (flexible sync)", async function () {
// describe.only(`app configuration of root directory (flexible sync)`, async function () {
this.timeout(60_000);
const tmpdir = getAbsolutePath();
Expand All @@ -85,7 +85,7 @@ describe.skipIf(environment.missingServer, `app configuration of root directory
});
});

describe.skipIf(environment.missingServer, "path configuration (partition based sync)", function () {
describe("path configuration (partition based sync)", function () {
importAppBefore(buildAppConfig("with-pbs").anonAuth().partitionBasedSync());
authenticateUserBefore();

Expand Down Expand Up @@ -123,46 +123,42 @@ describe.skipIf(environment.missingServer, "path configuration (partition based
});
});

describe.skipIf(
environment.skipFlexibleSync || environment.missingServer,
"path configuration (flexible sync)",
function () {
importAppBefore(buildAppConfig("with-flx").anonAuth().flexibleSync());
authenticateUserBefore();
describe.skipIf(environment.skipFlexibleSync, "path configuration (flexible sync)", function () {
importAppBefore(buildAppConfig("with-flx").anonAuth().flexibleSync());
authenticateUserBefore();

it("absolute path", async function () {
this.longTimeout();
const filename = getAbsolutePath();
const realm = await Realm.open({
path: filename,
schema: [schema],
sync: {
flexible: true,
user: this.user,
},
});
expect(realm.path).to.equal(filename);
expect(Realm.exists({ path: filename })).to.be.true;
realm.close();
Realm.deleteFile({ path: filename });
it("absolute path", async function () {
this.longTimeout();
const filename = getAbsolutePath();
const realm = await Realm.open({
path: filename,
schema: [schema],
sync: {
flexible: true,
user: this.user,
},
});
expect(realm.path).to.equal(filename);
expect(Realm.exists({ path: filename })).to.be.true;
realm.close();
Realm.deleteFile({ path: filename });
});

it("relative path", async function () {
this.longTimeout();
const filename = getRelativePath();
const realm = await Realm.open({
path: filename,
schema: [schema],
sync: {
flexible: true,
user: this.user,
},
});
// Realm Core will add a ".realm" suffix and url encode the path, if path is relative and sync is configured
const realmPath = realm.path;
expect(Realm.exists({ path: realmPath })).to.be.true;
realm.close();
Realm.deleteFile({ path: realmPath });
it("relative path", async function () {
this.longTimeout();
const filename = getRelativePath();
const realm = await Realm.open({
path: filename,
schema: [schema],
sync: {
flexible: true,
user: this.user,
},
});
},
);
// Realm Core will add a ".realm" suffix and url encode the path, if path is relative and sync is configured
const realmPath = realm.path;
expect(Realm.exists({ path: realmPath })).to.be.true;
realm.close();
Realm.deleteFile({ path: realmPath });
});
});
4 changes: 2 additions & 2 deletions integration-tests/tests/src/node/ssl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@ import { buildAppConfig } from "../utils/build-app-config";
import { closeRealm } from "../utils/close-realm";
import { createPromiseHandle } from "../utils/promise-handle";
import { importAppBefore } from "../hooks";
import { baseUrl } from "../utils/import-app";
import { baseUrl } from "../hooks/import-app-before";

// IMPORTANT:
// * Can only run on non-Apple machines, otherwise tests will await forever.
// * Can only run if the baseUrl points to a server using TLS / HTTPs.
const missingTLS = baseUrl.startsWith("http://");
describe.skipIf(platform() === "darwin" || environment.missingServer || missingTLS, "SSL Configuration", function () {
describe.skipIf(platform() === "darwin" || missingTLS, "SSL Configuration", function () {
this.longTimeout();
importAppBefore(buildAppConfig("with-flx").anonAuth().flexibleSync());

Expand Down
2 changes: 1 addition & 1 deletion integration-tests/tests/src/node/sync-proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ function getSyncConfiguration(user: Realm.User, partition: string, addProxyConfi
return realmConfig;
}

describe.skipIf(environment.missingServer, "Proxy support", function () {
describe("Proxy support", function () {
let proxyServer: http.Server;
let nCalls = 0;

Expand Down
1 change: 1 addition & 0 deletions integration-tests/tests/src/tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import "./tests/sync/dictionary";
import "./tests/sync/encryption";
import "./tests/sync/flexible";
import "./tests/sync/geospatial";
import "./tests/sync/logging";
import "./tests/sync/mixed";
import "./tests/sync/mongo-db-client";
import "./tests/sync/open-behavior";
Expand Down
2 changes: 1 addition & 1 deletion integration-tests/tests/src/tests/credentials/anonymous.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { Credentials, User } from "realm";
import { importAppBefore } from "../../hooks";
import { buildAppConfig } from "../../utils/build-app-config";

describe.skipIf(environment.missingServer, "anonymous credentials", () => {
describe("anonymous credentials", () => {
importAppBefore(buildAppConfig("with-anon").anonAuth());

it("authenticates", async function (this: AppContext) {
Expand Down
2 changes: 1 addition & 1 deletion integration-tests/tests/src/tests/credentials/api-key.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { importAppBefore } from "../../hooks";
import { buildAppConfig } from "../../utils/build-app-config";

//These tests are adopted from api-key-auth.test.ts in the realm-web-integration-tests directory.
describe.skipIf(environment.missingServer, "api-key credentials", () => {
describe("api-key credentials", () => {
importAppBefore(buildAppConfig("with-api-key").apiKeyAuth().emailPasswordAuth());

it("lists, creates, gets, enables, authenticates, disables and deletes api keys", async function (this: AppContext) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { importAppBefore } from "../../hooks";
import { buildAppConfig } from "../../utils/build-app-config";

//These tests are adopted from email-password-auth.test.ts in the realm-web-integration-tests directory.
describe.skipIf(environment.missingServer, "email-password credentials", () => {
describe("email-password credentials", () => {
importAppBefore(buildAppConfig("with-email-password").emailPasswordAuth());

it("authenticates", async function (this: AppContext) {
Expand Down
2 changes: 1 addition & 1 deletion integration-tests/tests/src/tests/credentials/jwt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import { buildAppConfig } from "../../utils/build-app-config";

const privateKey = "2k66QfKeTRk3MdZ5vpDYgZCu2k66QfKeTRk3MdZ5vpDYgZCu";

describe.skipIf(environment.missingServer, "jwt credentials", () => {
describe("jwt credentials", () => {
importAppBefore(
buildAppConfig("with-custom-token").customTokenAuth({
privateKey,
Expand Down
Loading

0 comments on commit b19542e

Please sign in to comment.