Compare commits

..
76 Commits
Author SHA1 Message Date
Chris Troutner 6b00513db7 Merge pull request #78 from Permissionless-Software-Foundation/ct-unstable
Syncing with upstream ipfs-service-provider
2022-07-08 09:03:54 -07:00
Chris Troutner 4387c9a758 fix(production): Updating docker file 2022-07-08 09:01:04 -07:00
Chris Troutner 469f1e05e8 fix(startup): Fixing bug from merge with upstream 2022-07-08 08:51:16 -07:00
Chris Troutner 3b836a7a35 Fixing merge conflicts with upstream 2022-07-08 08:46:05 -07:00
Chris Troutner fd1b13a917 Minor edit to documentation 2022-07-08 08:35:26 -07:00
Chris Troutner e2c5821dbe Merge pull request #93 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord): Updating bootstrap nodes
2022-07-07 15:56:42 -07:00
Chris Troutner 9967d5145b fix(ipfs-coord): Updating bootstrap nodes 2022-07-07 15:55:33 -07:00
Chris Troutner 9d16291855 Merge pull request #92 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord): Updating to v8
2022-07-07 15:17:09 -07:00
Chris Troutner 1518d1a12b fix(ipfs-coord): Updating to v8 2022-07-07 15:16:03 -07:00
Chris Troutner b68a143071 Merge pull request #91 from Permissionless-Software-Foundation/ct-unstable
Added hooks for async startup
2022-06-27 11:33:50 -07:00
Chris Troutner 5c25ebeeca Renaming mock log 2022-06-27 11:32:25 -07:00
Chris Troutner 3b17ba8e8b fix(logapi): Fixing issues with unit tests 2022-06-27 11:29:27 -07:00
Chris Troutner 434a4d7bd6 Refactoring failing unit tests 2022-06-27 10:25:19 -07:00
Chris Troutner dd36ebc7a0 Got test coverage back to 100% 2022-06-27 10:15:35 -07:00
Chris Troutner f117fe15df fix(startup): Added hooks for async startup 2022-06-27 10:09:08 -07:00
Chris Troutner 0333f77f5a Fixing broken link in README 2022-06-20 07:30:10 -07:00
Chris Troutner 3c908d1a4d Merge pull request #90 from Permissionless-Software-Foundation/ct-unstable
Increasing test coverage to 100%
2022-06-20 07:22:10 -07:00
Chris Troutner eb46a4c130 fix(tests): Got to 100% test coverage for entire repo 2022-06-20 07:19:36 -07:00
Chris Troutner d0efdcfa07 fix(ipfs-coord): Increased unit test coverage to 100% 2022-06-20 07:01:43 -07:00
Chris Troutner 62a7fcb16d fix(tests): Got bin/server.js unit test coverage to 100% 2022-06-19 20:21:40 -07:00
Chris Troutner d8addd5b27 Trying to build unit tests for bin/server 2022-06-19 20:00:25 -07:00
Chris Troutner bf6f1cf62d Merge pull request #89 from Permissionless-Software-Foundation/ct-unstable
Updating dependencies
2022-06-19 13:25:07 -07:00
Chris Troutner b7df7c47a5 Updated ipfs 2022-06-19 13:23:52 -07:00
Chris Troutner ae260db4af Updated some dependencies 2022-06-19 13:19:31 -07:00
Chris Troutner 778098ca12 fix(ipfs-coord): Updating to v7.1.19 2022-05-28 09:29:31 -07:00
Chris Troutner 0c4bb9c4a1 fix(ipfs-coord): Updating to v7.1.18 2022-05-28 09:09:44 -07:00
Chris Troutner 9cb975656d Merge pull request #88 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord): Updating to v7.1.17
2022-05-28 08:00:57 -07:00
Chris Troutner 4f6564423e fix(ipfs-coord): Updating to v7.1.17 2022-05-28 07:59:47 -07:00
Chris Troutner 54e7e74ae5 Merge pull request #87 from Permissionless-Software-Foundation/ct-unstable
Subscribing to chat channel at startup
2022-05-26 09:14:50 -07:00
Chris Troutner 324c372119 fix(startup): Subscribing to chat pubsub channel at startup 2022-05-26 09:12:15 -07:00
Chris Troutner da62f1bbe3 linting 2022-05-26 08:24:45 -07:00
Chris Troutner 129047fe88 fix(startup): Announcing config settings at startup 2022-05-26 08:24:30 -07:00
Chris Troutner fb182ced58 Merge pull request #86 from Permissionless-Software-Foundation/ct-unstable
Updating docker-compose file
2022-05-16 12:33:03 -07:00
Chris Troutner bec7c11e46 Updating README 2022-05-16 12:31:53 -07:00
Chris Troutner fb10e10226 fix(production): Updating docker images 2022-05-16 12:30:58 -07:00
Chris Troutner 5b37e47747 Merge pull request #85 from Permissionless-Software-Foundation/ct-unstable
fix(bch-js): Updating to v6.4.1
2022-05-16 12:15:47 -07:00
Chris Troutner a3cea782ba fix(bch-js): Updating to v6.4.1 2022-05-16 12:14:20 -07:00
Chris Troutner 14ffdae194 Merge pull request #84 from Permissionless-Software-Foundation/dh-test-coverage
feat(coverage): Got ipfs-coord.js to 100% test coverage
2022-05-16 12:09:18 -07:00
Chris Troutner 79918f6376 Merge pull request #77 from Permissionless-Software-Foundation/ct-unstable
feat(getTokenData): Adding new endpoint for PS002 token data
2022-05-10 11:15:21 -07:00
Chris Troutner da5942b28f feat(getTokenData): Adding new endpoint for PS002 token data 2022-05-10 11:14:11 -07:00
Chris Troutner d54cd3889b Merge pull request #76 from Permissionless-Software-Foundation/ct-unstable
feat(utxoIsValid): Adding new bch endpoint
2022-05-10 10:16:15 -07:00
Chris Troutner 5df54feb5e feat(utxoIsValid): Adding new bch endpoint 2022-05-10 10:14:37 -07:00
Chris Troutner fb841df43e fix(bch-js): Updated to v6.3.4 2022-05-09 18:33:28 -07:00
Chris Troutner a763ec640f Merge pull request #75 from Permissionless-Software-Foundation/ct-unstable
fix(bch-js): Updating to v6.2.14
2022-05-05 16:48:00 -07:00
Chris Troutner e74e063b0d fix(bch-js): Updating to v6.2.14 2022-05-05 16:46:50 -07:00
Daniel Gonzalez 7e3ce1564d feat(coverage): Got ipfs-coord.js to 100% test coverage 2022-03-25 22:12:11 -04:00
Chris Troutner 8154dd96f9 Merge pull request #83 from Permissionless-Software-Foundation/ct-unstable
fix(deps): Updating bch-js
2022-03-20 07:48:42 -07:00
Chris Troutner e37223cc88 fix(deps): Updating bch-js 2022-03-20 07:46:08 -07:00
Chris Troutner 5002ef2b90 Merge pull request #82 from Permissionless-Software-Foundation/dh-test-coverage-ipfsjs
feat(test): Got ipfs.js to 100% test coverage
2022-03-18 11:27:32 -07:00
Chris Troutner 5d95109ad4 more linting 2022-03-18 11:24:15 -07:00
Chris Troutner 13b3150f62 minor linting 2022-03-18 11:24:04 -07:00
Daniel Gonzalez b3a4a7c1ab feat(test): Got ipfs.js to 100% test coverage 2022-03-15 18:58:55 -04:00
Chris Troutner 142cdb17a6 fix(production): Updating IPFS docker container from v11 to v12 2022-03-15 14:12:11 -07:00
Chris Troutner a129988538 Merge pull request #74 from Permissionless-Software-Foundation/ct-unstable
Ct unstable
2022-03-10 09:55:32 -08:00
Chris Troutner 6bf85b4639 Merge branch 'master' of https://github.com/Permissionless-Software-Foundation/ipfs-service-provider into ct-unstable 2022-03-10 09:53:17 -08:00
Chris Troutner 733e8fd405 Merge pull request #81 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord): Updating to v7.1.6
2022-03-10 09:29:32 -08:00
Chris Troutner baee72c1c6 fix(ipfs-coord): Updating to v7.1.6 2022-03-10 09:27:13 -08:00
Chris Troutner 5d12749043 Merge pull request #73 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord): Updating to v7.1.5
2022-03-10 08:46:47 -08:00
Chris Troutner 2ebd8b998f Merge branch 'master' of https://github.com/Permissionless-Software-Foundation/ipfs-service-provider into ct-unstable 2022-03-10 08:42:57 -08:00
Chris Troutner 11618a796f Merge pull request #80 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord): Updating to v7.1.5
2022-03-10 08:35:21 -08:00
Chris Troutner 025ae20704 fix(ipfs-coord): Updating to v7.1.5 2022-03-10 08:33:53 -08:00
Chris Troutner b9146bbff9 Merge pull request #72 from Permissionless-Software-Foundation/ct-unstable
Syncing with upstream ipfs-service-provider
2022-03-08 10:15:33 -08:00
Chris Troutner 47f1b84dd8 Merge branch 'master' of https://github.com/Permissionless-Software-Foundation/ipfs-service-provider into ct-unstable 2022-03-08 10:13:37 -08:00
Chris Troutner fdf73610eb Merge pull request #79 from Permissionless-Software-Foundation/ct-unstable
fix(tests): Updating tests for node.js v16
2022-03-08 09:42:42 -08:00
Chris Troutner b09e77c079 fix(tests): Updating tests for node.js v16 2022-03-08 09:39:54 -08:00
Chris Troutner 5050816052 Merge pull request #71 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord): Updating to v7.1.4
2022-03-05 14:26:18 -08:00
Chris Troutner 7193b9d048 Merge branch 'master' of https://github.com/Permissionless-Software-Foundation/ipfs-service-provider into ct-unstable 2022-03-05 14:23:22 -08:00
Chris Troutner c2977c5264 fix(production): Updating to node v16 for IPFS 2022-03-05 14:23:14 -08:00
Chris Troutner 68ad2561b1 Merge pull request #78 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord): Updating to v7.1.4
2022-03-05 14:22:25 -08:00
Chris Troutner 791d11e597 Merge branch 'master' into ct-unstable 2022-03-05 14:20:19 -08:00
Chris Troutner 5489e76f55 fix(ipfs-coord): Updating to v7.1.4 2022-03-05 14:20:13 -08:00
Chris Troutner 2ad10180d0 Merge pull request #70 from Permissionless-Software-Foundation/ct-upstream
fix(ipfs-coord): Updating to v7.1.3
2022-03-05 08:35:10 -08:00
Chris Troutner dd42f5da16 fix(upstream): Syncing with upstream. Updating ipfs-coord 2022-03-05 08:32:38 -08:00
Chris Troutner 496a1dd07c Merge pull request #77 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord): Updating to v7.1.3
2022-03-05 08:26:32 -08:00
Chris Troutner a7b8ca9ad5 linting 2022-03-05 08:24:50 -08:00
Chris Troutner 6eb16eb11a fix(ipfs-coord): Updating to v7.1.3 2022-03-05 08:24:36 -08:00
39 changed files with 10460 additions and 13357 deletions
+8
View File
@@ -0,0 +1,8 @@
[
{
"srcDir": "",
"destDir": "",
"files": "**/*.js",
"command": "npm run lint"
}
]
+4 -4
View File
@@ -54,13 +54,11 @@ cd shell-scripts
The [docker](./production/docker) directory contains a Dockerfile for building a production deployment.
```
docker-compose build --no-cache
docker-compose pull
docker-compose up -d
```
- Bring the containers up once, then take them back down with `docker-compose down`.
- Copy the [swarm.key](./swarm.key) file to `ipfs-service-provider/production/data/go-ipfs/data/swarm.key`.
- Bring the containers back up with `docker-compose up -d`.
You can bring the containers back up with `docker-compose up -d`.
### Operation Notes
@@ -90,6 +88,8 @@ API documentation is written inline and generated by [apidoc](http://apidocjs.co
Visit `http://localhost:5000/docs/` to view docs
There is additional developer documentation in the [dev-docs directory](./dev-docs).
## Dependencies
- [koa2](https://github.com/koajs/koa/tree/v2.x)
+40 -24
View File
@@ -24,31 +24,37 @@ const config = require('../config') // this first.
const AdminLib = require('../src/adapters/admin')
const errorMiddleware = require('../src/controllers/rest-api/middleware/error')
const { wlogger } = require('../src/adapters/wlogger')
const Controllers = require('../src/controllers')
class Server {
constructor () {
// Encapsulate dependencies
this.adminLib = new AdminLib()
this.controllers = new Controllers()
this.mongoose = mongoose
this.config = config
this.process = process
}
async startServer () {
try {
// Create a Koa instance.
const app = new Koa()
app.keys = [config.session]
app.keys = [this.config.session]
// Connect to the Mongo Database.
mongoose.Promise = global.Promise
mongoose.set('useCreateIndex', true) // Stop deprecation warning.
this.mongoose.Promise = global.Promise
this.mongoose.set('useCreateIndex', true) // Stop deprecation warning.
console.log(
`Connecting to MongoDB with this connection string: ${config.database}`
`Connecting to MongoDB with this connection string: ${this.config.database}`
)
await mongoose.connect(config.database, {
await this.mongoose.connect(this.config.database, {
useUnifiedTopology: true,
useNewUrlParser: true
})
console.log(`Starting environment: ${config.env}`)
console.log(`Debug level: ${config.debugLevel}`)
console.log(`Starting environment: ${this.config.env}`)
console.log(`Debug level: ${this.config.debugLevel}`)
// MIDDLEWARE START
@@ -73,20 +79,24 @@ class Server {
// Dev Note: This line must come BEFORE controllers.attachRESTControllers()
app.use(cors({ origin: '*' }))
// Attach REST API and JSON RPC controllers to the app.
const Controllers = require('../src/controllers')
const controllers = new Controllers()
await controllers.attachRESTControllers(app)
// Wait for any adapters to initialize.
await this.controllers.initAdapters()
app.controllers = controllers
// Wait for any use-libraries to initialize.
await this.controllers.initUseCases()
// Attach REST API and JSON RPC controllers to the app.
await this.controllers.attachRESTControllers(app)
app.controllers = this.controllers
// MIDDLEWARE END
console.log(`Running server in environment: ${config.env}`)
wlogger.info(`Running server in environment: ${config.env}`)
console.log(`Running server in environment: ${this.config.env}`)
wlogger.info(`Running server in environment: ${this.config.env}`)
await app.listen(config.port)
console.log(`Server started on ${config.port}`)
this.server = await app.listen(this.config.port)
console.log(`Server started on ${this.config.port}`)
// Create the system admin user.
try {
@@ -100,10 +110,16 @@ class Server {
// Attach the other IPFS controllers.
// Skip if this is a test environment.
if (config.env !== 'test') {
await controllers.attachControllers(app)
if (this.config.env !== 'test') {
await this.controllers.attachControllers(app)
}
// Display configuration settings
console.log('\nConfiguration:')
console.log(`Circuit Relay: ${this.config.isCircuitRelay}`)
console.log(`IPFS TCP port: ${this.config.ipfsTcpPort}`)
console.log(`IPFS WS port: ${this.config.ipfsWsPort}\n`)
return app
} catch (err) {
console.error('Could not start server. Error: ', err)
@@ -111,14 +127,14 @@ class Server {
console.log(
'Exiting after 5 seconds. Depending on process manager to restart.'
)
await sleep(5000)
process.exit(1)
await this.sleep(5000)
this.process.exit(1)
}
}
sleep (ms) {
return new Promise((resolve) => setTimeout(resolve, ms))
}
}
function sleep (ms) {
return new Promise((resolve) => setTimeout(resolve, ms))
}
module.exports = Server
+3 -1
View File
@@ -89,5 +89,7 @@ module.exports = {
ipfsHost: process.env.IPFS_HOST ? process.env.IPFS_HOST : 'localhost',
ipfsApiPort: process.env.IPFS_API_PORT
? parseInt(process.env.IPFS_API_PORT)
: 5001
: 5001,
chatPubSubChan: 'psf-ipfs-chat-001'
}
+10
View File
@@ -0,0 +1,10 @@
# Developer Documentation
This directory needs to be fleshed out with more information. The markdown files in this directory are intended to provide additional documentation for software developers that use this boilerplate to run their own forks.
## Startup
This software requires an IPFS node in order to operate the JSON RPC and ipfs-coord features. There are two ways to incorporate an IPFS node:
- js-ipfs is integrated into this repository. If you simply run `npm start`, then this app will default to the js-ipfs IPFS node. However, js-ipfs is not as full featured as go-ipfs. It has memory leaks and lags considerably behind go-ipfs in terms of features.
- go-ipfs is the preferred way to run a node. It can be run externally by following the guidence on the [IPFS homepage](https://ipfs.io). Once the IPFS node is running, this app can take control of it. Use the [local-external-ipfs-node.sh](../shell-scripts/local-external-ipfs-node.sh) shell script to start this app and attach it to the go-ipfs node.
+9505 -13203
View File
File diff suppressed because it is too large Load Diff
+10 -10
View File
@@ -24,12 +24,12 @@
},
"repository": "Permissionless-Software-Foundation/ipfs-bch-wallet-service",
"dependencies": {
"@psf/bch-js": "5.3.1",
"axios": "0.25.0",
"@psf/bch-js": "6.4.1",
"axios": "0.27.2",
"bcryptjs": "2.4.3",
"glob": "7.1.6",
"ipfs": "0.60.0",
"ipfs-coord": "6.8.12",
"ipfs": "0.62.3",
"ipfs-coord": "8.0.2",
"ipfs-http-client": "55.0.0",
"jsonrpc-lite": "2.2.0",
"jsonwebtoken": "8.5.1",
@@ -46,16 +46,16 @@
"koa-static": "5.0.0",
"koa2-ratelimit": "0.9.1",
"line-reader": "0.4.0",
"mongoose": "5.11.15",
"mongoose": "5.13.14",
"node-fetch": "npm:@achingbrain/node-fetch@2.6.7",
"nodemailer": "6.4.17",
"nodemailer": "6.7.5",
"passport-local": "1.0.0",
"public-ip": "4.0.4",
"winston": "3.3.3",
"winston-daily-rotate-file": "4.5.0"
},
"devDependencies": {
"apidoc": "0.26.0",
"apidoc": "0.51.1",
"chai": "4.3.0",
"coveralls": "3.1.0",
"eslint": "7.19.0",
@@ -65,10 +65,10 @@
"eslint-plugin-prettier": "3.3.1",
"eslint-plugin-standard": "4.0.0",
"husky": "4.3.8",
"lodash.clonedeep": "^4.5.0",
"mocha": "8.2.1",
"lodash.clonedeep": "4.5.0",
"mocha": "10.0.0",
"nyc": "15.1.0",
"semantic-release": "17.4.4",
"semantic-release": "19.0.3",
"sinon": "9.2.4",
"standard": "16.0.3",
"uuid": "8.3.2"
+2 -2
View File
@@ -10,7 +10,7 @@ RUN apt-get update
RUN apt-get install -y sudo git curl nano gnupg wget
#Install Node and NPM
RUN curl -sL https://deb.nodesource.com/setup_14.x -o nodesource_setup.sh
RUN curl -sL https://deb.nodesource.com/setup_16.x -o nodesource_setup.sh
RUN bash nodesource_setup.sh
RUN apt-get install -y nodejs build-essential
@@ -73,7 +73,7 @@ RUN mkdir /home/safeuser/.ipfsdata
EXPOSE 5010
# Start the application.
COPY start-production.sh start-production.sh
#COPY start-production.sh start-production.sh
CMD ["./start-production.sh"]
#CMD ["npm", "start"]
+3 -2
View File
@@ -14,7 +14,7 @@ services:
restart: always
ipfs-bch-wallet:
image: ipfs/go-ipfs:v0.11.0
image: ipfs/go-ipfs:v0.13.0
container_name: ipfs-bch-wallet
environment:
MY_ENV_VAR: 'placeholder'
@@ -30,7 +30,7 @@ services:
- 172.17.0.1:8080:8080
volumes:
- ../data/go-ipfs/data:/data/ipfs
- ../data/go-ipfs/export:/export
#- ../../swarm.key:/data/ipfs/swarm.key
# https://docs.docker.com/compose/compose-file/compose-file-v3/#command
# https://github.com/ipfs/go-ipfs/blob/91c52657166bcf86f2476926e4fe56694dc26562/Dockerfile#L115
command:
@@ -58,4 +58,5 @@ services:
- '5010:5010' # <host port>:<container port>
volumes:
- ../data/ipfsdata:/home/safeuser/ipfs-bch-wallet-service/.ipfsdata
- ./start-production.sh:/home/safeuser/ipfs-bch-wallet-service/start-production.sh
restart: always
+1 -1
View File
@@ -23,7 +23,7 @@ export DEBUG_LEVEL=2
# Change APISERVER to point to your own installation of bch-api
export APISERVER=https://api.fullstack.cash/v5/
# These settings are used to proxy a subscription to FullStack.cash.
export GET_JWT_AT_STARTUP=1
#export GET_JWT_AT_STARTUP=1
export AUTHSERVER=https://auth.fullstack.cash
export FULLSTACKLOGIN=demo@demo.com
export FULLSTACKPASS=demo
+34
View File
@@ -0,0 +1,34 @@
#!/bin/bash
# This script is an example for running a production environment, which is
# defined by running an external go-ipfs node.
# Ports
export PORT=5010 # REST API port
# The human-readible name that is used when displaying data about this node.
export COORD_NAME=ipfs-bch-service-generic
# This is used for end-to-end encryption (e2ee).
export MNEMONIC="churn aisle shield silver ladder swear hunt slim pen demand spoil veteran"
# 0 = less verbose. 3 = most verbose
export DEBUG_LEVEL=2
# Production settings that use external IPFS node.
# https://github.com/christroutner/docker-ipfs
export SVC_ENV=production
export IPFS_HOST=localhost
#export IPFS_HOST=172.17.0.1
export IPFS_API_PORT=5001
# Configure IPFS ports
export IPFS_TCP_PORT=4001
#export IPFS_WS_PORT=5269
# MongoDB connection string.
export DBURL=mongodb://localhost:27017/ipfs-service-dev
#export ENABLE_CIRCUIT_RELAY=true
npm start
+6 -1
View File
@@ -50,10 +50,15 @@ class Adapters {
this.bchjs = new BCHJS({ restURL: this.config.apiServer })
}
// Start the IPFS node.
// Do not start these adapters if this is an e2e test.
if (this.config.env !== 'test') {
// Start the IPFS node.
await this.ipfs.start({ bchjs: this.bchjs })
}
console.log('Async Adapters have been started.')
return true
} catch (err) {
console.error('Error in adapters/index.js/start()')
throw err
+4
View File
@@ -2,6 +2,7 @@
top-level IPFS library that combines the individual IPFS-based libraries.
*/
// Local libraries
const IpfsAdapter = require('./ipfs')
const IpfsCoordAdapter = require('./ipfs-coord')
@@ -44,6 +45,9 @@ class IPFS {
await this.ipfsCoordAdapter.start()
console.log('ipfs-coord is ready.')
// Subscribe to the chat pubsub channel
await this.ipfsCoordAdapter.subscribeToChat()
return true
} catch (err) {
console.error('Error in adapters/ipfs/index.js/start()')
+10 -1
View File
@@ -98,12 +98,21 @@ class IpfsCoordAdapter {
attachRPCRouter (router) {
try {
_this.ipfsCoord.privateLog = router
_this.ipfsCoord.adapters.orbit.privateLog = router
_this.ipfsCoord.adapters.pubsub.privateLog = router
} catch (err) {
console.error('Error in attachRPCRouter()')
throw err
}
}
// Subscribe to the chat pubsub channel
async subscribeToChat () {
await this.ipfsCoord.adapters.pubsub.subscribeToPubsubChannel(
this.config.chatPubSubChan,
console.log,
this.ipfsCoord.thisNode
)
}
}
module.exports = IpfsCoordAdapter
+18 -19
View File
@@ -102,10 +102,9 @@ class IpfsAdapter {
console.error('Error in ipfs.js/start()')
// If IPFS crashes because the /blocks directory is full, wipe the directory.
if (err.message.includes('No space left on device')) {
console.log('No space left in /blocks folder. Deleting blocks folder.')
this.rmBlocksDir()
}
// if (err.message.includes('No space left on device')) {
// this.rmBlocksDir()
// }
throw err
}
@@ -121,21 +120,21 @@ class IpfsAdapter {
// Dev Note: It's assumed this node is not pinning any data and that
// everything in this directory is transient. This folder will regularly
// fill up and prevent IPFS from starting.
rmBlocksDir () {
try {
const dir = `${IPFS_DIR}/blocks`
console.log(`Deleting ${dir} directory...`)
this.fs.rmdirSync(dir, { recursive: true })
console.log(`${dir} directory is deleted!`)
return true // Signal successful execution.
} catch (err) {
console.log('Error in rmBlocksDir()')
throw err
}
}
// rmBlocksDir () {
// try {
// const dir = `${IPFS_DIR}/blocks`
// console.log(`Deleting ${dir} directory...`)
//
// this.fs.rmdirSync(dir, { recursive: true })
//
// console.log(`${dir} directory is deleted!`)
//
// return true // Signal successful execution.
// } catch (err) {
// console.log('Error in rmBlocksDir()')
// throw err
// }
// }
}
module.exports = IpfsAdapter
+3 -1
View File
@@ -135,8 +135,10 @@ class LogsApi {
if (!filename || typeof filename !== 'string') {
throw new Error('filename must be a string')
}
// Throw an error if the file does not exist.
console.log('readLines() filename: ', filename)
// Throw an error if the file does not exist.
if (!_this.fs.existsSync(filename)) {
throw new Error('file does not exist')
}
+17 -3
View File
@@ -25,11 +25,14 @@ class Controllers {
this.useCases = new UseCases({ adapters: this.adapters })
}
async attachControllers (app) {
// Wait for any startup processes to complete for the Adapters libraries.
// Spin up any adapter libraries that have async startup needs.
async initAdapters () {
await this.adapters.start()
}
this.attachRPCControllers()
// Run any Use Cases to startup the app.
async initUseCases () {
await this.useCases.start()
}
// Top-level function for this library.
@@ -44,6 +47,17 @@ class Controllers {
restControllers.attachRESTControllers(app)
}
// Attach any other controllers other than REST API controllers.
async attachControllers (app) {
// Wait for any startup processes to complete for the Adapters libraries.
// await this.adapters.start()
// Attach the REST controllers to the Koa app.
// this.attachRESTControllers(app)
this.attachRPCControllers()
}
// Add the JSON RPC router to the ipfs-coord adapter.
attachRPCControllers () {
const jsonRpcController = new JSONRPC({
+5
View File
@@ -1,5 +1,8 @@
/*
This is the JSON RPC router for the users API
CT 3/5/22: This library can probably be deleted. Handling of the /about endpoint
is now directly controlled by the ipfs-coord library.
*/
// Public npm libraries
@@ -33,6 +36,8 @@ class AboutRPC {
// This is a bit different than other router libraries, because there is
// only one response, which is a string about this node.
async aboutRouter (rpcData) {
console.log('debugging: aboutRouter from ipfs-service-provider triggered')
return {
success: true,
status: 200,
+174 -3
View File
@@ -71,6 +71,14 @@ class BCHRPC {
case 'pubkey':
await this.rateLimit.limiter(rpcData.from)
return await this.pubKey(rpcData)
case 'utxoIsValid':
await this.rateLimit.limiter(rpcData.from)
return await this.utxoIsValid(rpcData)
case 'getTokenData':
await this.rateLimit.limiter(rpcData.from)
return await this.getTokenData(rpcData)
}
} catch (err) {
console.error('Error in BCHRPC/rpcRouter()')
@@ -529,7 +537,6 @@ class BCHRPC {
return retObj
} catch (err) {
console.error('Error in JSON RPC BCH txData()): ', err)
// throw err
// Return an error response
return {
@@ -577,7 +584,6 @@ class BCHRPC {
*
* }
*/
async pubKey (rpcData) {
try {
// console.log('createUser rpcData: ', rpcData)
@@ -598,11 +604,13 @@ class BCHRPC {
return retObj
} catch (err) {
console.error('Error in JSON RPC BCH pubKey()')
// throw err
// Handle different error formats.
let error = err
if (err.error && typeof err.error === 'string') {
error = new Error(err.error)
}
// Return an error response
return {
success: false,
@@ -612,6 +620,169 @@ class BCHRPC {
}
}
}
/**
* @api {JSON} /bch UtxoIsValid
* @apiPermission public
* @apiName UtxoIsValid
* @apiGroup JSON BCH
* @apiDescription Verify if UTXO is valid
* Given a UTXO object (txid and vout), a full node is queried to verify that
* the UTXO still exists in the mempool (true), or if it has been spent (false).
*
* - jsonrpc: "" - jsonrpc version
* - id: "" - jsonrpc id
* - result: {} - Result of the petition with the RPC information
* - success: - Request status
* - isValid: - Boolean: true or false
*
* @apiExample Example usage:
* {"jsonrpc":"2.0","id":"555","method":"bch","params":{ "endpoint": "utxoIsValid", "utxo": {"tx_hash": "17754221b29f189532d4fc2ae89fb467ad2dede30fdec4854eb2129b3ba90d7a", "tx_pos": 0}}}
*
* @apiSuccessExample {json} Success-Response:
* {
* "jsonrpc":"2.0",
* "id":"555",
* "result":{
* "method":"bch",
* "reciever":"QmU86vLVbUY1UhziKB6rak7GPKRA2QHWvzNm2AjEvXNsT6",
* "value":{
* "success": true,
* "status": 200,
* "endpoint": "utxoIsValid",
* "isValid": true
* }
* }
*
* }
*/
async utxoIsValid (rpcData) {
try {
// console.log('createUser rpcData: ', rpcData)
const utxo = rpcData.payload.params.utxo
// console.log('utxo: ', utxo)
const isValid = await this.bchjs.Utxo.isValid(utxo)
const retObj = {
success: true,
status: 200,
endpoint: 'utxoIsValid',
isValid
}
// retObj.status = 200
return retObj
} catch (err) {
console.error('Error in JSON RPC BCH utxoIsValid()')
// Handle different error formats.
let error = err
if (err.error && typeof err.error === 'string') {
error = new Error(err.error)
}
// Return an error response
return {
success: false,
status: 422,
message: error.message,
endpoint: 'utxoIsValid'
}
}
}
/**
* @api {JSON} /bch getTokenData
* @apiPermission public
* @apiName getTokenData
* @apiGroup JSON BCH
* @apiDescription Get data associated with a token
* Given a token ID, this endpoint will retrieve the IPFS CIDs associated with
* the tokens mutable and immutable data. This is extension of the PS002
* specification for mutable data for tokens:
* https://github.com/Permissionless-Software-Foundation/specifications/blob/master/ps002-slp-mutable-data.md
*
* - jsonrpc: "" - jsonrpc version
* - id: "" - jsonrpc id
* - result: {} - Result of the petition with the RPC information
* - success: - Request status
* - tokenData: - Address public key
*
* @apiExample Example usage:
* {"jsonrpc":"2.0","id":"555","method":"bch","params":{ "endpoint": "getTokenData", "tokenId": "c85042ab08a2099f27de880a30f9a42874202751d834c42717a20801a00aab0d" }}
*
* @apiSuccessExample {json} Success-Response:
* {
* "jsonrpc":"2.0",
* "id":"555",
* "result":{
* "method":"bch",
* "reciever":"QmU86vLVbUY1UhziKB6rak7GPKRA2QHWvzNm2AjEvXNsT6",
* "value":{
* "success": true,
* "status": 200,
* "endpoint": "getTokenData",
* "tokenData": {
* "genesisData": {
* "type": 1,
* "ticker": 'MT2',
* "name": 'Mutable Token',
* "tokenId": 'c85042ab08a2099f27de880a30f9a42874202751d834c42717a20801a00aab0d',
* "documentUri": 'ipfs://bafybeie7oxpsr7evcnlptecxfdhaqlot4732phukd2ekgvuzoir2frost4',
* "documentHash": '56ed1a5768076a318d02b5db64e125544dca57ab6b2cc7ca61dfa4645d244463',
* "decimals": 0,
* "mintBatonIsActive": true,
* "tokensInCirculationBN": '1000',
* "tokensInCirculationStr": '1000',
* "blockCreated": 739412,
* "totalBurned": '0',
* "totalMinted": '1000'
* },
* "immutableData": 'ipfs://bafybeie7oxpsr7evcnlptecxfdhaqlot4732phukd2ekgvuzoir2frost4',
* "mutableData": 'ipfs://bafybeigotuony53ley3n63hqwyxiqruqn5uamskmci6f645putnc46jju4'
* }
* }
* }
* }
*/
async getTokenData (rpcData) {
try {
// console.log('createUser rpcData: ', rpcData)
const tokenId = rpcData.payload.params.tokenId
// console.log('tokenId: ', tokenId)
const tokenData = await this.bchjs.PsfSlpIndexer.getTokenData(tokenId)
const retObj = {
success: true,
status: 200,
endpoint: 'getTokenData',
tokenData
}
// retObj.status = 200
return retObj
} catch (err) {
console.error('Error in JSON RPC BCH utxoIsValid()')
// Handle different error formats.
let error = err
if (err.error && typeof err.error === 'string') {
error = new Error(err.error)
}
// Return an error response
return {
success: false,
status: 422,
message: error.message,
endpoint: 'getTokenData'
}
}
}
}
module.exports = BCHRPC
+13
View File
@@ -21,6 +21,19 @@ class UseCases {
this.user = new UserUseCases(localConfig)
this.bch = new BCHUseCases(localConfig)
}
// Run any startup Use Cases at the start of the app.
async start () {
// try {
console.log('Async Use Cases have been started.')
return true
// } catch (err) {
// console.error('Error in use-cases/index.js/start()')
// // console.log(err)
// throw err
// }
}
}
module.exports = UseCases
+1
View File
@@ -7,6 +7,7 @@
// Public npm libraries
const assert = require('chai').assert
const axios = require('axios').default
// const sinon = require('sinon')
// Local support libraries
const config = require('../../../config')
@@ -0,0 +1,117 @@
/*
Integration tests for the endpoints in controllers/json-rpc/bch
*/
// Global npm libraries
const assert = require('chai').assert
// Local libraries
const BCHController = require('../../../../src/controllers/json-rpc/bch')
const Adapters = require('../../../../src/adapters')
const UseCases = require('../../../../src/use-cases')
describe('#BCH', () => {
let uut
before(async () => {
const adapters = new Adapters()
const useCases = new UseCases({ adapters })
// await adapters.start()
uut = new BCHController({ adapters, useCases })
})
describe('#utxoIsValid', () => {
it('should return true for valid UTXO with fullnode properties', async () => {
const rpcData = {
payload: {
params: {
utxo: {
txid: 'b94e1ff82eb5781f98296f0af2488ff06202f12ee92b0175963b8dba688d1b40',
vout: 0
}
}
}
}
const result = await uut.utxoIsValid(rpcData)
// console.log('result: ', result)
assert.equal(result.isValid, true)
})
it('should return true for valid UTXO with fulcrum properties', async () => {
const rpcData = {
payload: {
params: {
utxo: {
tx_hash: 'b94e1ff82eb5781f98296f0af2488ff06202f12ee92b0175963b8dba688d1b40',
tx_pos: 0
}
}
}
}
const result = await uut.utxoIsValid(rpcData)
// console.log('result: ', result)
assert.equal(result.isValid, true)
})
it('should return false for valid UTXO with fullnode properties', async () => {
const rpcData = {
payload: {
params: {
utxo: {
txid: '17754221b29f189532d4fc2ae89fb467ad2dede30fdec4854eb2129b3ba90d7a',
vout: 0
}
}
}
}
const result = await uut.utxoIsValid(rpcData)
// console.log('result: ', result)
assert.equal(result.isValid, false)
})
it('should return false for valid UTXO with fulcrum properties', async () => {
const rpcData = {
payload: {
params: {
utxo: {
tx_hash: '17754221b29f189532d4fc2ae89fb467ad2dede30fdec4854eb2129b3ba90d7a',
tx_pos: 0
}
}
}
}
const result = await uut.utxoIsValid(rpcData)
// console.log('result: ', result
assert.equal(result.isValid, false)
})
})
describe('#getTokenData', () => {
it('should return data for a token', async () => {
const rpcData = {
payload: {
params: {
tokenId: 'c85042ab08a2099f27de880a30f9a42874202751d834c42717a20801a00aab0d'
}
}
}
const result = await uut.getTokenData(rpcData)
console.log('result: ', result)
// assert.equal(result.isValid, true)
assert.property(result.tokenData, 'immutableData')
assert.property(result.tokenData, 'mutableData')
assert.equal(result.success, true)
})
})
})
@@ -14,7 +14,7 @@ describe('#BCH', () => {
before(async () => {
const adapters = new Adapters()
await adapters.start()
// await adapters.start()
uut = new BCHUseCases({ adapters })
})
+54
View File
@@ -0,0 +1,54 @@
/*
Unit tests for the adapters index.js library
*/
// Global npm libraries
const assert = require('chai').assert
const sinon = require('sinon')
// Local libraries
const Adapters = require('../../../src/adapters')
describe('#adapters', () => {
let uut, sandbox
beforeEach(() => {
uut = new Adapters()
sandbox = sinon.createSandbox()
})
afterEach(() => {
sandbox.restore()
})
describe('#start', () => {
it('should start the async adapters', async () => {
// Mock dependencies
uut.config.getJwtAtStartup = true
sandbox.stub(uut.fullStackJwt, 'getJWT').resolves()
sandbox.stub(uut.fullStackJwt, 'instanceBchjs').resolves()
sandbox.stub(uut.ipfs, 'start').resolves()
const result = await uut.start()
assert.equal(result, true)
})
it('should catch and throw an error', async () => {
try {
// Force an error
uut.config.getJwtAtStartup = false
uut.config.env = 'dev'
sandbox.stub(uut.ipfs, 'start').rejects(new Error('test error'))
await uut.start()
assert.fail('Unexpected result')
} catch (err) {
// console.log('err: ', err)
assert.include(err.message, 'test error')
}
})
})
})
+31 -3
View File
@@ -8,6 +8,7 @@ const sinon = require('sinon')
const IPFSCoordAdapter = require('../../../src/adapters/ipfs/ipfs-coord')
const IPFSMock = require('../mocks/ipfs-mock')
const IPFSCoordMock = require('../mocks/ipfs-coord-mock')
const config = require('../../../config')
describe('#IPFS', () => {
let uut
@@ -76,6 +77,16 @@ describe('#IPFS', () => {
assert.equal(result, true)
})
it('should return a promise that resolves into an instance of IPFS in production mode', async () => {
uut.config.isProduction = true
// Mock dependencies.
uut.IpfsCoord = IPFSCoordMock
const result = await uut.start()
// console.log('result: ', result)
assert.equal(result, true)
config.isProduction = false
})
})
describe('#attachRPCRouter', () => {
@@ -89,8 +100,9 @@ describe('#IPFS', () => {
}
},
adapters: {
orbit: {
privateLog: () => {}
pubsub: {
privateLog: () => {
}
}
}
}
@@ -111,8 +123,24 @@ describe('#IPFS', () => {
assert.fail('Unexpected code path')
} catch (err) {
assert.include(err.message, 'Cannot read property')
assert.include(err.message, 'Cannot read')
}
})
})
describe('#subscribeToChat', () => {
it('should subscribe to the chat channel', async () => {
// Mock dependencies
uut.ipfsCoord = {
adapters: {
pubsub: {
subscribeToPubsubChannel: async () => {
}
}
}
}
await uut.subscribeToChat()
})
})
})
+57 -23
View File
@@ -4,10 +4,11 @@
const assert = require('chai').assert
const sinon = require('sinon')
const IPFSLib = require('../../../src/adapters/ipfs/ipfs')
const IPFSMock = require('../mocks/ipfs-mock')
const config = require('../../../config')
// config.isProduction = true;
describe('#IPFS-adapter', () => {
let uut
let sandbox
@@ -18,7 +19,27 @@ describe('#IPFS-adapter', () => {
sandbox = sinon.createSandbox()
})
afterEach(() => sandbox.restore())
afterEach(() => {
sandbox.restore()
})
describe('#constructor', () => {
it('should instantiate IPFS Lib in dev mode.', async () => {
const _uut = new IPFSLib()
assert.exists(_uut)
assert.isFunction(_uut.start)
assert.isFunction(_uut.stop)
})
it('should instantiate dev IPFS Lib in production mode.', async () => {
config.isProduction = true
const _uut = new IPFSLib()
assert.exists(_uut)
assert.isFunction(_uut.start)
assert.isFunction(_uut.stop)
config.isProduction = false
})
})
describe('#start', () => {
it('should return a promise that resolves into an instance of IPFS.', async () => {
@@ -33,6 +54,18 @@ describe('#IPFS-adapter', () => {
assert.property(result, 'config')
})
it('should return a promise that resolves into an instance of IPFS in production mode.', async () => {
// Mock dependencies.
uut.IPFS = IPFSMock
uut.config.isProduction = true
const result = await uut.start()
// console.log('result: ', result)
assert.equal(uut.isReady, true)
assert.property(result, 'config')
})
it('should catch and throw an error', async () => {
try {
// Force an error
@@ -52,7 +85,8 @@ describe('#IPFS-adapter', () => {
it('should stop the IPFS node', async () => {
// Mock dependencies
uut.ipfs = {
stop: () => {}
stop: () => {
}
}
const result = await uut.stop()
@@ -61,24 +95,24 @@ describe('#IPFS-adapter', () => {
})
})
describe('#rmBlocksDir', () => {
it('should delete the /blocks directory', () => {
const result = uut.rmBlocksDir()
assert.equal(result, true)
})
it('should catch and throw an error', () => {
try {
// Force an error
sandbox.stub(uut.fs, 'rmdirSync').throws(new Error('test error'))
uut.rmBlocksDir()
assert.fail('Unexpected code path')
} catch (err) {
assert.equal(err.message, 'test error')
}
})
})
// describe('#rmBlocksDir', () => {
// it('should delete the /blocks directory', () => {
// const result = uut.rmBlocksDir()
//
// assert.equal(result, true)
// })
//
// it('should catch and throw an error', () => {
// try {
// // Force an error
// sandbox.stub(uut.fs, 'rmdirSync').throws(new Error('test error'))
//
// uut.rmBlocksDir()
//
// assert.fail('Unexpected code path')
// } catch (err) {
// assert.equal(err.message, 'test error')
// }
// })
// })
})
+25 -32
View File
@@ -32,19 +32,18 @@ describe('#LogsApiLib', () => {
})
it('should return log', async () => {
try {
const pass = 'test'
const result = await uut.getLogs(pass)
// console.log('result', result)
// Mock dependencies
sandbox.stub(uut, 'generateFileName').returns(`${__dirname.toString()}/../mocks/adapters/fake-log`)
assert.isTrue(result.success)
assert.isArray(result.data)
assert.property(result.data[0], 'message')
assert.property(result.data[0], 'level')
assert.property(result.data[0], 'timestamp')
} catch (err) {
assert(false, 'Unexpected result')
}
const pass = 'test'
const result = await uut.getLogs(pass)
// console.log('result', result)
assert.isTrue(result.success)
assert.isArray(result.data)
assert.property(result.data[0], 'message')
assert.property(result.data[0], 'level')
assert.property(result.data[0], 'timestamp')
})
it('should return false if files are not found!', async () => {
@@ -201,31 +200,25 @@ describe('#LogsApiLib', () => {
})
it('should ignore fileReader callback errors', async () => {
try {
// https://sinonjs.org/releases/latest/stubs/
// About yields
sandbox.stub(uut.lineReader, 'eachLine').yieldsRight({}, true)
// https://sinonjs.org/releases/latest/stubs/
// About yields
sandbox.stub(uut.lineReader, 'eachLine').yieldsRight({}, true)
const fileName = context.fileName
const result = await uut.readLines(fileName)
assert.isArray(result)
} catch (err) {
assert.fail('Unexpected result')
}
const fileName = `${__dirname.toString()}/../mocks/adapters/fake-log`
const result = await uut.readLines(fileName)
assert.isArray(result)
})
it('should return data', async () => {
try {
const fileName = context.fileName
const result = await uut.readLines(fileName)
const fileName = `${__dirname.toString()}/../mocks/adapters/fake-log`
assert.isArray(result)
assert.property(result[1], 'message')
assert.property(result[1], 'level')
assert.property(result[1], 'timestamp')
} catch (err) {
assert.fail('Unexpected result')
}
const result = await uut.readLines(fileName)
assert.isArray(result)
assert.property(result[1], 'message')
assert.property(result[1], 'level')
assert.property(result[1], 'timestamp')
})
})
})
+1 -1
View File
@@ -45,7 +45,7 @@ describe('#Controllers', () => {
it('should catch and throw errors', async () => {
try {
// Force an error
sandbox.stub(uut.adapters, 'start').rejects(new Error('test error'))
sandbox.stub(uut, 'attachRPCControllers').throws(new Error('test error'))
const app = {
use: () => {}
@@ -488,6 +488,7 @@ describe('#BCHRPC', () => {
assert.equal(response.message, 'No transaction history.')
assert.equal(response.endpoint, 'pubkey')
})
it('should return an error for invalid input', async () => {
// Force an error
sandbox
@@ -513,4 +514,128 @@ describe('#BCHRPC', () => {
assert.equal(response.endpoint, 'pubkey')
})
})
describe('#utxoIsValid', () => {
it('should return false if UTXO.isValid() returns false', async () => {
// Mock dependencies
sandbox
.stub(uut.bchjs.Utxo, 'isValid')
.resolves(false)
const rpcData = {
payload: {
params: {
utxo: {
txid: 'b94e1ff82eb5781f98296f0af2488ff06202f12ee92b0175963b8dba688d1b40',
vout: 0
}
}
}
}
const result = await uut.utxoIsValid(rpcData)
// console.log('result: ', result)
assert.equal(result.isValid, false)
assert.equal(result.success, true)
})
it('should return true if UTXO.isValid() returns true', async () => {
// Mock dependencies
sandbox
.stub(uut.bchjs.Utxo, 'isValid')
.resolves(true)
const rpcData = {
payload: {
params: {
utxo: {
txid: 'b94e1ff82eb5781f98296f0af2488ff06202f12ee92b0175963b8dba688d1b40',
vout: 0
}
}
}
}
const result = await uut.utxoIsValid(rpcData)
// console.log('result: ', result)
assert.equal(result.isValid, true)
assert.equal(result.success, true)
})
it('should catch and return errors', async () => {
// Mock dependencies
sandbox
.stub(uut.bchjs.Utxo, 'isValid')
.rejects(new Error('test error'))
const rpcData = {
payload: {
params: {
utxo: {
txid: 'b94e1ff82eb5781f98296f0af2488ff06202f12ee92b0175963b8dba688d1b40',
vout: 0
}
}
}
}
const result = await uut.utxoIsValid(rpcData)
// console.log('result: ', result)
assert.equal(result.success, false)
assert.equal(result.status, 422)
assert.equal(result.message, 'test error')
assert.equal(result.endpoint, 'utxoIsValid')
})
})
describe('#getTokenData', () => {
it('should return data from PsfSlpIndexer.getTokenData()', async () => {
// Mock dependencies
sandbox
.stub(uut.bchjs.PsfSlpIndexer, 'getTokenData')
.resolves({ a: 'b' })
const rpcData = {
payload: {
params: {
tokenId: 'c85042ab08a2099f27de880a30f9a42874202751d834c42717a20801a00aab0d'
}
}
}
const result = await uut.getTokenData(rpcData)
// console.log('result: ', result)
assert.equal(result.success, true)
assert.equal(result.status, 200)
assert.equal(result.endpoint, 'getTokenData')
assert.property(result, 'tokenData')
})
it('should catch and return errors', async () => {
// Mock dependencies
sandbox
.stub(uut.bchjs.PsfSlpIndexer, 'getTokenData')
.rejects(new Error('test error'))
const rpcData = {
payload: {
params: {
tokenId: 'c85042ab08a2099f27de880a30f9a42874202751d834c42717a20801a00aab0d'
}
}
}
const result = await uut.getTokenData(rpcData)
// console.log('result: ', result)
assert.equal(result.success, false)
assert.equal(result.status, 422)
assert.equal(result.message, 'test error')
assert.equal(result.endpoint, 'getTokenData')
})
})
})
@@ -333,7 +333,7 @@ describe('#UserRPC', () => {
assert.equal(result.endpoint, 'updateUser')
assert.equal(result.success, false)
assert.equal(result.status, 422)
assert.include(result.message, 'Cannot read property')
assert.include(result.message, 'Cannot read')
})
})
@@ -375,7 +375,7 @@ describe('#UserRPC', () => {
assert.equal(result.endpoint, 'getUser')
assert.equal(result.success, false)
assert.equal(result.status, 422)
assert.include(result.message, 'Cannot read property')
assert.include(result.message, 'Cannot read')
})
})
@@ -14,7 +14,8 @@ let ctx
const mockContext = require('../../../../unit/mocks/ctx-mock').context
describe('Contact', () => {
before(async () => {})
before(async () => {
})
beforeEach(() => {
uut = new ContactController()
@@ -36,7 +37,7 @@ describe('Contact', () => {
} catch (err) {
// console.log(err)
assert.equal(err.status, 422)
assert.include(err.message, 'Cannot read property')
assert.include(err.message, 'Cannot read')
}
})
@@ -14,7 +14,8 @@ let ctx
const mockContext = require('../../../../unit/mocks/ctx-mock').context
describe('Logapi', () => {
before(async () => {})
before(async () => {
})
beforeEach(() => {
uut = new LogsApiController()
@@ -35,7 +36,7 @@ describe('Logapi', () => {
assert.fail('Unexpected result')
} catch (err) {
assert.equal(err.status, 422)
assert.include(err.message, 'Cannot read property')
assert.include(err.message, 'Cannot read')
}
})
@@ -69,7 +69,7 @@ describe('#Users-REST-Controller', () => {
} catch (err) {
// console.log(err)
assert.equal(err.status, 422)
assert.include(err.message, 'Cannot read property')
assert.include(err.message, 'Cannot read')
}
})
@@ -91,9 +91,9 @@ describe('#Users-REST-Controller', () => {
assert.property(ctx.response.body, 'user')
assert.property(ctx.response.body, 'token')
// Used by downstream tests.
// testUser = ctx.response.body.user
// console.log('testUser: ', testUser)
// Used by downstream tests.
// testUser = ctx.response.body.user
// console.log('testUser: ', testUser)
})
})
@@ -181,7 +181,7 @@ describe('#Users-REST-Controller', () => {
} catch (err) {
// console.log(err)
assert.equal(err.status, 422)
assert.include(err.message, 'Cannot read property')
assert.include(err.message, 'Cannot read')
}
})
@@ -223,7 +223,7 @@ describe('#Users-REST-Controller', () => {
} catch (err) {
// console.log(err)
assert.equal(err.status, 422)
assert.include(err.message, 'Cannot read property')
assert.include(err.message, 'Cannot read')
}
})
+65
View File
@@ -0,0 +1,65 @@
/*
Unit tests for the bin/server.js file
*/
// Public npm libraries
const assert = require('chai').assert
const sinon = require('sinon')
// Local libraries
const Server = require('../../../bin/server')
describe('#server', () => {
let uut, sandbox
beforeEach(() => {
sandbox = sinon.createSandbox()
uut = new Server()
})
afterEach(() => sandbox.restore())
describe('#startServer', () => {
it('should start the server', async () => {
// Mock dependencies
sandbox.stub(uut.mongoose, 'connect').resolves()
sandbox.stub(uut.controllers, 'initAdapters').resolves()
sandbox.stub(uut.controllers, 'initUseCases').resolves()
sandbox.stub(uut.controllers, 'attachRESTControllers').resolves()
sandbox.stub(uut.adminLib, 'createSystemUser').resolves(true)
sandbox.stub(uut.controllers, 'attachControllers').resolves()
uut.config.env = 'dev'
const result = await uut.startServer()
// console.log('result: ', result)
assert.property(result, 'env')
// Turn off the server.
uut.server.close()
// Restor config env
uut.config.env = 'test'
})
it('should exit on failure', async () => {
// Force an error
sandbox.stub(uut.mongoose, 'connect').rejects(new Error('test error'))
// Prevent default behavior of exiting the program.
sandbox.stub(uut, 'sleep').resolves()
sandbox.stub(uut.process, 'exit').returns()
await uut.startServer()
// Not throwing an error is a success
})
})
describe('#sleep', () => {
it('should execute', async () => {
await uut.sleep(1)
})
})
})
+70
View File
@@ -0,0 +1,70 @@
{"level":"error","message":"Error in lib/contact.js/sendEmail()","timestamp":"2022-06-27T17:36:43.907Z"}
{"level":"error","message":"Error in lib/contact.js/sendEmail()","timestamp":"2022-06-27T17:36:43.909Z"}
{"level":"error","message":"Error in lib/contact.js/sendEmail()","timestamp":"2022-06-27T17:36:43.910Z"}
{"level":"error","message":"Error in lib/contact.js/sendEmail()","timestamp":"2022-06-27T17:36:43.912Z"}
{"level":"error","message":"Error in lib/contact.js/sendEmail()","timestamp":"2022-06-27T17:36:43.915Z"}
{"level":"error","message":"Error in lib/nodemailer.js/sendEmail()","timestamp":"2022-06-27T17:36:58.979Z"}
{"level":"error","message":"Error in lib/nodemailer.js/sendEmail()","timestamp":"2022-06-27T17:36:58.980Z"}
{"level":"error","message":"Error in lib/nodemailer.js/sendEmail()","timestamp":"2022-06-27T17:36:58.981Z"}
{"level":"error","message":"Error in lib/nodemailer.js/sendEmail()","timestamp":"2022-06-27T17:36:58.982Z"}
{"level":"error","message":"Error in lib/nodemailer.js/sendEmail()","timestamp":"2022-06-27T17:36:58.983Z"}
{"level":"error","message":"Error in lib/nodemailer.js/validateEmailArray()","timestamp":"2022-06-27T17:36:59.002Z"}
{"level":"error","message":"Error in lib/nodemailer.js/validateEmailArray()","timestamp":"2022-06-27T17:36:59.003Z"}
{"level":"error","message":"Error in lib/nodemailer.js/getHtmlFromObject()","timestamp":"2022-06-27T17:36:59.005Z"}
{"level":"error","message":"Error in lib/nodemailer.js/getHtmlFromObject()","timestamp":"2022-06-27T17:36:59.006Z"}
{"level":"error","message":"Error in lib/nodemailer.js/getHtmlFromObject()","timestamp":"2022-06-27T17:36:59.008Z"}
{"level":"info","message":"Warning: Can not send JSON RPC response. Can not determine which peer this message came from.","timestamp":"2022-06-27T17:36:59.353Z"}
{"level":"info","message":"Rejecting invalid JSON RPC command.","timestamp":"2022-06-27T17:36:59.354Z"}
{"level":"info","message":"JSON RPC received from peerA, ID: ea442e78-2297-466a-823b-9cbb12c8ddd9, type: request, method: unknownMethod","timestamp":"2022-06-27T17:36:59.355Z"}
{"level":"error","message":"Error in rpc router(): test error","stack":"Error: test error\n at Context.<anonymous> (/home/trout/work/psf/code/ipfs-service-provider/test/unit/controllers/json-rpc/a10-rpc.unit.js:110:49)\n at callFn (/home/trout/work/psf/code/ipfs-service-provider/node_modules/mocha/lib/runnable.js:366:21)\n at Test.Runnable.run (/home/trout/work/psf/code/ipfs-service-provider/node_modules/mocha/lib/runnable.js:354:5)\n at Runner.runTest (/home/trout/work/psf/code/ipfs-service-provider/node_modules/mocha/lib/runner.js:666:10)\n at /home/trout/work/psf/code/ipfs-service-provider/node_modules/mocha/lib/runner.js:789:12\n at next (/home/trout/work/psf/code/ipfs-service-provider/node_modules/mocha/lib/runner.js:581:14)\n at /home/trout/work/psf/code/ipfs-service-provider/node_modules/mocha/lib/runner.js:591:7\n at next (/home/trout/work/psf/code/ipfs-service-provider/node_modules/mocha/lib/runner.js:474:14)\n at Immediate._onImmediate (/home/trout/work/psf/code/ipfs-service-provider/node_modules/mocha/lib/runner.js:559:5)\n at processImmediate (node:internal/timers:466:21)","timestamp":"2022-06-27T17:36:59.357Z"}
{"level":"info","message":"JSON RPC received from peerA, ID: 9ef6ad90-7fc3-4cb3-8769-4498e5512b3d, type: request, method: users","timestamp":"2022-06-27T17:36:59.358Z"}
{"level":"info","message":"JSON RPC received from peerA, ID: bd57a1cf-7f2f-4ff2-93d4-6727eec4d778, type: request, method: auth","timestamp":"2022-06-27T17:36:59.359Z"}
{"level":"info","message":"JSON RPC received from peerA, ID: 8fd9edc8-6a45-4042-ac06-9ace60567cbf, type: request, method: about","timestamp":"2022-06-27T17:36:59.361Z"}
{"level":"info","message":"JSON RPC received from peerA, ID: 1b27624a-e698-4bbe-9183-b860a1a0d78d, type: request, method: unknownMethod","timestamp":"2022-06-27T17:36:59.363Z"}
{"level":"info","message":"JSON RPC received from peerA, ID: 40fabddf-59c6-4910-a22c-63da7387f99a, type: request, method: unknownMethod","timestamp":"2022-06-27T17:36:59.365Z"}
{"level":"error","message":"Error in authUser(): Login credential do not match","stack":"Error: Login credential do not match\n at Context.<anonymous> (/home/trout/work/psf/code/ipfs-service-provider/test/unit/controllers/json-rpc/auth.json-rpc.controller.unit.js:144:18)\n at callFn (/home/trout/work/psf/code/ipfs-service-provider/node_modules/mocha/lib/runnable.js:366:21)\n at Test.Runnable.run (/home/trout/work/psf/code/ipfs-service-provider/node_modules/mocha/lib/runnable.js:354:5)\n at Runner.runTest (/home/trout/work/psf/code/ipfs-service-provider/node_modules/mocha/lib/runner.js:666:10)\n at /home/trout/work/psf/code/ipfs-service-provider/node_modules/mocha/lib/runner.js:789:12\n at next (/home/trout/work/psf/code/ipfs-service-provider/node_modules/mocha/lib/runner.js:581:14)\n at /home/trout/work/psf/code/ipfs-service-provider/node_modules/mocha/lib/runner.js:591:7\n at next (/home/trout/work/psf/code/ipfs-service-provider/node_modules/mocha/lib/runner.js:474:14)\n at Immediate.<anonymous> (/home/trout/work/psf/code/ipfs-service-provider/node_modules/mocha/lib/runner.js:559:5)\n at processImmediate (node:internal/timers:466:21)","timestamp":"2022-06-27T17:37:04.421Z"}
{"level":"error","message":"Error in authUser(): login must be specified","stack":"Error: login must be specified\n at AuthRPC.authUser (/home/trout/work/psf/code/ipfs-service-provider/src/controllers/json-rpc/auth/index.js:78:93)\n at Context.<anonymous> (/home/trout/work/psf/code/ipfs-service-provider/test/unit/controllers/json-rpc/auth.json-rpc.controller.unit.js:165:34)\n at callFn (/home/trout/work/psf/code/ipfs-service-provider/node_modules/mocha/lib/runnable.js:366:21)\n at Test.Runnable.run (/home/trout/work/psf/code/ipfs-service-provider/node_modules/mocha/lib/runnable.js:354:5)\n at Runner.runTest (/home/trout/work/psf/code/ipfs-service-provider/node_modules/mocha/lib/runner.js:666:10)\n at /home/trout/work/psf/code/ipfs-service-provider/node_modules/mocha/lib/runner.js:789:12\n at next (/home/trout/work/psf/code/ipfs-service-provider/node_modules/mocha/lib/runner.js:581:14)\n at /home/trout/work/psf/code/ipfs-service-provider/node_modules/mocha/lib/runner.js:591:7\n at next (/home/trout/work/psf/code/ipfs-service-provider/node_modules/mocha/lib/runner.js:474:14)\n at Immediate._onImmediate (/home/trout/work/psf/code/ipfs-service-provider/node_modules/mocha/lib/runner.js:559:5)\n at processImmediate (node:internal/timers:466:21)","timestamp":"2022-06-27T17:37:04.423Z"}
{"level":"error","message":"Error in authUser(): password must be specified","stack":"Error: password must be specified\n at AuthRPC.authUser (/home/trout/work/psf/code/ipfs-service-provider/src/controllers/json-rpc/auth/index.js:78:284)\n at Context.<anonymous> (/home/trout/work/psf/code/ipfs-service-provider/test/unit/controllers/json-rpc/auth.json-rpc.controller.unit.js:185:34)\n at callFn (/home/trout/work/psf/code/ipfs-service-provider/node_modules/mocha/lib/runnable.js:366:21)\n at Test.Runnable.run (/home/trout/work/psf/code/ipfs-service-provider/node_modules/mocha/lib/runnable.js:354:5)\n at Runner.runTest (/home/trout/work/psf/code/ipfs-service-provider/node_modules/mocha/lib/runner.js:666:10)\n at /home/trout/work/psf/code/ipfs-service-provider/node_modules/mocha/lib/runner.js:789:12\n at next (/home/trout/work/psf/code/ipfs-service-provider/node_modules/mocha/lib/runner.js:581:14)\n at /home/trout/work/psf/code/ipfs-service-provider/node_modules/mocha/lib/runner.js:591:7\n at next (/home/trout/work/psf/code/ipfs-service-provider/node_modules/mocha/lib/runner.js:474:14)\n at Immediate._onImmediate (/home/trout/work/psf/code/ipfs-service-provider/node_modules/mocha/lib/runner.js:559:5)\n at processImmediate (node:internal/timers:466:21)","timestamp":"2022-06-27T17:37:04.425Z"}
{"level":"error","timestamp":"2022-06-27T17:37:04.466Z"}
{"level":"info","message":"Running server in environment: dev","timestamp":"2022-06-27T17:37:04.487Z"}
{"level":"error","message":"Error in lib/users.js/createUser()","timestamp":"2022-06-27T17:37:04.495Z"}
{"level":"error","message":"Error in lib/users.js/createUser()","timestamp":"2022-06-27T17:37:04.495Z"}
{"level":"error","message":"Error in lib/users.js/createUser()","timestamp":"2022-06-27T17:37:04.496Z"}
{"level":"error","message":"Error in lib/users.js/createUser()","timestamp":"2022-06-27T17:37:04.497Z"}
{"level":"error","message":"Error in lib/users.js/createUser()","timestamp":"2022-06-27T17:37:04.497Z"}
{"level":"error","message":"Error in lib/users.js/getAllUsers()","timestamp":"2022-06-27T17:37:04.499Z"}
{"level":"error","message":"Error in lib/users.js/updateUser()","timestamp":"2022-06-27T17:37:04.502Z"}
{"level":"error","message":"Error in lib/users.js/updateUser()","timestamp":"2022-06-27T17:37:04.503Z"}
{"level":"error","message":"Error in lib/users.js/updateUser()","timestamp":"2022-06-27T17:37:04.503Z"}
{"level":"error","message":"Error in lib/users.js/updateUser()","timestamp":"2022-06-27T17:37:04.504Z"}
{"level":"error","message":"Error in lib/users.js/updateUser()","timestamp":"2022-06-27T17:37:04.505Z"}
{"level":"error","message":"Error in lib/users.js/updateUser()","timestamp":"2022-06-27T17:37:04.506Z"}
{"level":"error","message":"Error in lib/users.js/deleteUser()","timestamp":"2022-06-27T17:37:04.508Z"}
{"level":"info","message":"Running server in environment: test","timestamp":"2022-06-27T17:37:04.514Z"}
{"level":"error","message":"Error in lib/users.js/createUser()","timestamp":"2022-06-27T17:37:04.638Z"}
{"level":"error","message":"Error in lib/users.js/createUser()","timestamp":"2022-06-27T17:37:05.273Z"}
{"level":"error","message":"Error in lib/users.js/createUser()","timestamp":"2022-06-27T17:37:05.277Z"}
{"level":"error","message":"Error in lib/users.js/createUser()","timestamp":"2022-06-27T17:37:05.280Z"}
{"level":"error","message":"Error in lib/users.js/createUser()","timestamp":"2022-06-27T17:37:05.286Z"}
{"level":"error","timestamp":"2022-06-27T17:37:05.412Z"}
{"level":"verbose","message":"Calling user and target user do not match! Calling user: 62b9eac1b4f08950b955d27f, Target user: 1","timestamp":"2022-06-27T17:37:05.441Z"}
{"level":"error","message":"Error in lib/users.js/updateUser()","timestamp":"2022-06-27T17:37:05.448Z"}
{"level":"verbose","message":"Calling user and target user do not match! Calling user: 62b9eac1b4f08950b955d27f, Target user: 62b9eac1b4f08950b955d27d","timestamp":"2022-06-27T17:37:05.452Z"}
{"level":"error","message":"Error in lib/users.js/updateUser()","timestamp":"2022-06-27T17:37:05.457Z"}
{"level":"error","message":"Error in lib/users.js/updateUser()","timestamp":"2022-06-27T17:37:05.463Z"}
{"level":"error","message":"Error in lib/users.js/updateUser()","timestamp":"2022-06-27T17:37:05.467Z"}
{"level":"error","message":"Error in lib/users.js/updateUser()","timestamp":"2022-06-27T17:37:05.473Z"}
{"level":"verbose","message":"Calling user and target user do not match! Calling user: 62b9eac0b4f08950b955d274, Target user: 62b9eac1b4f08950b955d27d","timestamp":"2022-06-27T17:37:05.478Z"}
{"level":"verbose","message":"It's ok. The user is an admin.","timestamp":"2022-06-27T17:37:05.478Z"}
{"level":"verbose","message":"Calling user and target user do not match! Calling user: 62b9eac1b4f08950b955d27f, Target user: 1","timestamp":"2022-06-27T17:37:05.600Z"}
{"level":"verbose","message":"Calling user and target user do not match! Calling user: 62b9eac1b4f08950b955d27f, Target user: 62b9eac1b4f08950b955d27d","timestamp":"2022-06-27T17:37:05.603Z"}
{"level":"verbose","message":"Calling user and target user do not match! Calling user: 62b9eac0b4f08950b955d274, Target user: 62b9eac1b4f08950b955d27d","timestamp":"2022-06-27T17:37:05.615Z"}
{"level":"verbose","message":"It's ok. The user is an admin.","timestamp":"2022-06-27T17:37:05.615Z"}
{"level":"error","message":"Error in lib/contact.js/sendEmail()","timestamp":"2022-06-27T17:37:05.619Z"}
{"level":"error","message":"Error in lib/contact.js/sendEmail()","timestamp":"2022-06-27T17:37:05.622Z"}
{"level":"error","message":"Error in lib/contact.js/sendEmail()","timestamp":"2022-06-27T17:37:05.624Z"}
{"level":"error","message":"Error in lib/contact.js/sendEmail()","timestamp":"2022-06-27T17:37:05.627Z"}
{"level":"verbose","message":"Calling user and target user do not match! Calling user: 62b9eac1b4f08950b955d2a6, Target user: Target Id","timestamp":"2022-06-27T17:37:05.754Z"}
{"level":"verbose","message":"Calling user and target user do not match! Calling user: 62b9eac0b4f08950b955d274, Target user: 62b9eac1b4f08950b955d2a6","timestamp":"2022-06-27T17:37:05.756Z"}
{"level":"verbose","message":"It's ok. The user is an admin.","timestamp":"2022-06-27T17:37:05.756Z"}
{"level":"error","message":"Error in lib/users.js/createUser()","timestamp":"2022-06-27T17:37:06.060Z"}
+5 -1
View File
@@ -60,7 +60,8 @@ const bchjs = {
sortAllTxs: () => {}
},
Utxo: {
get: () => {}
get: () => {},
isValid: () => true
},
Transaction: {
get: () => {}
@@ -73,6 +74,9 @@ const bchjs = {
},
Util: {
chunk100: () => {}
},
PsfSlpIndexer: {
getTokenData: () => {}
}
}
+2
View File
@@ -14,6 +14,8 @@ class IPFSCoord {
}
async start () {}
async subscribeToChat() {}
}
module.exports = IPFSCoord
@@ -44,4 +44,17 @@ describe('#use-cases', () => {
}
})
})
describe('#start', () => {
it('should initialize async use cases', async () => {
const result = await uut.start()
assert.equal(result, true)
})
// it('should catch and throw errors', async () => {
// // Force an error
// sandbox.stub()
// })
})
})
+9 -9
View File
@@ -150,7 +150,7 @@ describe('#users-use-case', () => {
await uut.getAllUsers()
// console.log(`users: ${JSON.stringify(users, null, 2)}`)
// assert.isArray(users)
// assert.isArray(users)
})
it('should catch and throw an error', async () => {
@@ -225,8 +225,8 @@ describe('#users-use-case', () => {
// Assert that the expected properties for the user model exist.
// assert.property(result, 'type')
assert.property(result, '_id')
// assert.property(result, 'email')
// assert.property(result, 'name')
// assert.property(result, 'email')
// assert.property(result, 'name')
})
})
@@ -238,7 +238,7 @@ describe('#users-use-case', () => {
assert.fail('Unexpected code path')
} catch (err) {
// console.log(err)
assert.include(err.message, 'Cannot read property')
assert.include(err.message, 'Cannot read')
}
})
@@ -343,7 +343,7 @@ describe('#users-use-case', () => {
// assert.equal(result.name, 'testy tester')
// })
// TODO: verify that an admin can change the type of a user
// TODO: verify that an admin can change the type of a user
})
describe('#authUser', () => {
@@ -353,9 +353,9 @@ describe('#users-use-case', () => {
await uut.authUser('test@test.com', 'password')
// console.log('user: ', user)
// assert.property(user, '_id')
// assert.property(user, 'email')
// assert.property(user, 'name')
// assert.property(user, '_id')
// assert.property(user, 'email')
// assert.property(user, 'name')
})
it('should throw an error if no user matches the login', async () => {
@@ -396,7 +396,7 @@ describe('#users-use-case', () => {
assert.fail('Unexpected code path.')
} catch (err) {
// console.log(err)
assert.include(err.message, 'Cannot read property')
assert.include(err.message, 'Cannot read')
}
})