Skip to content
Merged
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
2 changes: 2 additions & 0 deletions .circleci/cluster.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pack.enabled=true
pack.zookeeper.address=zoo1:2181
44 changes: 44 additions & 0 deletions .circleci/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
version: '2'
services:
stardog1:
command: ["--port", "5821", "--home", "/var/opt/stardog"]
depends_on:
- zoo1
environment:
STARDOG_SERVER_JAVA_ARGS: -Xms2g -Xmx2g -XX:MaxDirectMemorySize=1g
THIS_HOST: stardog1
THIS_PORT: 5821
ZK_HOST_PORT: zoo1:2181
image: stardog/stardog:latest
ports:
- 5821:5821
restart: always
privileged: true
volumes:
- ../stardog-license-key.bin:/var/opt/stardog/stardog-license-key.bin
- ./cluster.properties:/var/opt/stardog/stardog.properties
stardog2:
command: ["--port", "5822", "--home", "/var/opt/stardog"]
depends_on:
- zoo1
environment:
STARDOG_SERVER_JAVA_ARGS: -Xms2g -Xmx2g -XX:MaxDirectMemorySize=1g
THIS_HOST: stardog2
THIS_PORT: 5822
ZK_HOST_PORT: zoo1:2181
image: stardog/stardog:latest
ports:
- 5822:5822
restart: always
privileged: true
volumes:
- ../stardog-license-key.bin:/var/opt/stardog/stardog-license-key.bin
- ./cluster.properties:/var/opt/stardog/stardog.properties
zoo1:
environment:
ZOO_MY_ID: 1
ZOO_SERVERS: server.1=zoo1:2888:3888
image: zookeeper:3.4.14
ports:
- 2181
restart: always
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ node_modules/
dist/**
.vscode/
.rpt2_cache/

stardog-license-key.bin
33 changes: 33 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,18 @@ In order to contribute changes, all test cases must pass. With the Stardog serve
npm test
```

To test the cluster commands you will need to first start a Stardog cluster then run the cluster suite. The easiest way to do this is to run docker-compose to start a cluster:

```bash
docker-compose -f .circleci/docker-compose.yml up
```

Then run the cluster test suite in `test/cluster`:

```bash
npm run test:cluster
```

### Contributing

Fork, clone and develop, write or amend tests, and then open a PR. All PRs go against "master". This project uses [prettier](https://github.com/prettier/prettier) on file commit, so don't worry about style as it'll just get rewritten when you commit your changes.
Expand Down Expand Up @@ -2095,3 +2107,24 @@ Expects the following parameters:

Returns [`Promise<HTTP.Body>`](#body)

## <a name="cluster">cluster</a>

#### <a name="shutdown">`cluster.info(conn)`</a>

Retrieves basic information about a Stardog cluster.

Expects the following parameters:

- conn ([`Connection`](#connection))

Returns [`Promise<HTTP.Body>`](#body)

#### <a name="status">`cluster.status(conn)`</a>

Retrieves detailed status information about a Stardog cluster.

Expects the following parameters:

- conn ([`Connection`](#connection))

Returns [`Promise<HTTP.Body>`](#body)
23 changes: 23 additions & 0 deletions lib/cluster.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const { fetch } = require('./fetch');
const { httpBody } = require('./response-transforms');

const info = conn => {
const headers = conn.headers();
headers.set('Accept', 'application/json');
return fetch(conn.request('admin', 'cluster'), {
headers,
}).then(httpBody);
};

const status = conn => {
const headers = conn.headers();
headers.set('Accept', 'application/json');
return fetch(conn.request('admin', 'cluster', 'status'), {
headers,
}).then(httpBody);
};

module.exports = {
info,
status,
};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, but a few general (somewhat nitpicky) comments here:

  1. Instead of requiring Fetch and doing Fetch.fetch, the convention in stardog.js is to do const { fetch } = require('./fetch'). Arguably, the former is cleaner because it doesn't shadow the fetch global variable in the browser and makes it explicit that you are calling a different fetch, but this is a small matter and I'd prefer sticking to convention for now.

  2. You can leave out the params parameter when it's not being used. Here, the stardog.js codebase is simply inconsistent right now -- sometimes the params parameter is included when it's not being used, and sometimes it isn't -- but we're trying to move toward "only include it when it's actually being used."

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed the import to make it possible to mock the fetch function. Since it needs an Object to spyOn, couldn't get it to work with a direct import. But I'm working on getting the cluster to run with docker compose and then I can change the tests to a full integration instead of mocks to address this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was able to get a simple cluster to run and have updated the tests to use the cluster nodes for the connection without mocking fetch. This should address the code style issues.

17 changes: 17 additions & 0 deletions lib/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1340,6 +1340,23 @@ declare namespace Stardog {
*/
function getAll(conn: Connection, params?: object): Promise<HTTP.Body>
}

/** Stardog HTTP cluster actions. */
export namespace cluster {
/**
* Retrieves basic information about a Stardog cluster.
*
* @param {Connection} conn the Stardog server connection
*/
function info(conn: Connection): Promise<HTTP.Body>;

/**
* Retrieves detailed status information about a Stardog cluster.
*
* @param {Connection} conn the Stardog server connection
*/
function status(conn: Connection): Promise<HTTP.Body>;
}
}

// No idea why I need this, but this is what removes the extra level of nesting
Expand Down
1 change: 1 addition & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const Stardog = {
query: require('./query'),
user: require('./user'),
server: require('./server'),
cluster: require('./cluster'),
virtualGraphs: require('./virtualGraphs'),
storedFunctions: require('./storedFunctions'),
};
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@
"build": "node scripts/build",
"docs": "node scripts/docs",
"test": "eslint '{lib,test}/**/*.js' --fix && jest test/*.spec.js --verbose -i",
"test:cluster": "jest test/cluster/*.spec.js --verbose -i",
"precommit": "lint-staged",
"format": "prettier '{lib,test}/**/*.js' --single-quote --trailing-comma es5 --write",
"version": "mdchangelog --remote stardog-union/stardog.js --no-prologue --order-milestones semver --order-issues closed_at --overwrite --no-orphan-issues && npm run docs && git add README.md CHANGELOG.md",
Expand Down
38 changes: 38 additions & 0 deletions test/cluster/clusterInfo.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/* eslint-env jest */

const { cluster } = require('../../lib');
const { ConnectionFactory } = require('../setup-database');

describe('cluster.info()', () => {
const coordinatorPort = 5821;
const participantPort = 5822;
const expectedNodeCount = 2;

it('should retrieve a JS object containing cluster information', () => {
const coordinatorConnection = ConnectionFactory(coordinatorPort);

return cluster.info(coordinatorConnection).then(res => {
const { nodes } = res.body;
const coordinator = nodes.find(node => node.includes(coordinatorPort));
const participant = nodes.find(node => node.includes(participantPort));

expect(nodes).toHaveLength(expectedNodeCount);
expect(coordinator).not.toBeUndefined();
expect(participant).not.toBeUndefined();
});
});

it('should respond correctly from both nodes', () => {
const participantConnection = ConnectionFactory(participantPort);

return cluster.info(participantConnection).then(res => {
const { nodes } = res.body;
const coordinator = nodes.find(node => node.includes(coordinatorPort));
const participant = nodes.find(node => node.includes(participantPort));

expect(nodes).toHaveLength(expectedNodeCount);
expect(coordinator).not.toBeUndefined();
expect(participant).not.toBeUndefined();
});
});
});
54 changes: 54 additions & 0 deletions test/cluster/clusterStatus.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/* eslint-env jest */

const { cluster } = require('../../lib');
const { ConnectionFactory } = require('../setup-database');

describe('cluster.status()', () => {
const coordinatorPort = 5821;
const participantPort = 5822;
const expectedNodeCount = 2;

it('should retrieve a JS object containing cluster status', () => {
const coordinatorConnection = ConnectionFactory(coordinatorPort);

return cluster.status(coordinatorConnection).then(res => {
const { nodes } = res.body;
const coordinator = nodes.find(node =>
node.address.includes(coordinatorPort)
);
const participant = nodes.find(node =>
node.address.includes(participantPort)
);

expect(nodes).toHaveLength(expectedNodeCount);
expect(coordinator).not.toBeUndefined();
expect(coordinator.metadata).not.toBeUndefined();
expect(coordinator.type).toEqual('FULL');
expect(participant).not.toBeUndefined();
expect(participant.metadata).not.toBeUndefined();
expect(participant.type).toEqual('FULL');
});
});

it('should respond correctly from both nodes', () => {
const participantConnection = ConnectionFactory(participantPort);

return cluster.status(participantConnection).then(res => {
const { nodes } = res.body;
const coordinator = nodes.find(node =>
node.address.includes(coordinatorPort)
);
const participant = nodes.find(node =>
node.address.includes(participantPort)
);

expect(nodes).toHaveLength(expectedNodeCount);
expect(coordinator).not.toBeUndefined();
expect(coordinator.metadata).not.toBeUndefined();
expect(coordinator.type).toEqual('FULL');
expect(participant).not.toBeUndefined();
expect(participant.metadata).not.toBeUndefined();
expect(participant.type).toEqual('FULL');
});
});
});
5 changes: 2 additions & 3 deletions test/setup-database.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,9 @@ exports.generateRandomString = () =>
charset: 'alphabetic',
});

exports.ConnectionFactory = () =>
exports.ConnectionFactory = (port = 5820) =>
new Connection({
username: 'admin',
password: 'admin',
endpoint: 'http://localhost:5820',
// endpoint: 'http://localhost:61941',
endpoint: `http://localhost:${port}`,
});