-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
522 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,3 +4,4 @@ node_modules | |
.idea | ||
package-lock.json | ||
yarn.lock | ||
/test-results/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
const got = require('got'); | ||
|
||
const context = require('../helpers/Context') | ||
const { sign256 } = require("../helpers/util"); | ||
|
||
beforeAll(() => context.begin()) | ||
afterAll(() => context.end()) | ||
|
||
test('Adapter can receive messages', async () => { | ||
|
||
const data = { | ||
"msgtype": "text", | ||
"text": { | ||
"content": "我就是我, 是不一样的烟火" | ||
}, | ||
"msgId": "XXXX", | ||
"createAt": 1487561654123, | ||
"conversationType": "2", | ||
"conversationId": "XXXX", | ||
"conversationTitle": "钉钉群标题", | ||
"senderId": "XXXX", | ||
"senderNick": "星星", | ||
"senderCorpId": "XXXX", | ||
"senderStaffId": "XXXX", | ||
"chatbotUserId": "XXXX", | ||
"atUsers": [ | ||
{ | ||
"dingtalkId": "XXXX", | ||
"staffId": "XXXX" | ||
} | ||
] | ||
}; | ||
|
||
const timeStamp = Date.now(); | ||
const sign = sign256(context.app.config.secret, timeStamp); | ||
|
||
const res = await got.post(`http://localhost:8081/hubot/dingtalk/message/`, { | ||
json: data, | ||
headers: { | ||
sign: sign, | ||
timeStamp: timeStamp, | ||
} | ||
}); | ||
|
||
const textMessage = context.app.robot.receive.mock.calls[0][0] | ||
|
||
expect(textMessage).toMatchObject({ | ||
id: data.createAt, | ||
text: data.text.content, | ||
user: { | ||
id: data.senderId | ||
} | ||
}) | ||
expect(res.statusCode).toEqual(200) | ||
expect(JSON.parse(res.body)).toMatchObject({ | ||
msgtype: "empty" | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
const Robot = require("dingtalk-robot-sdk") | ||
|
||
const context = require('../helpers/Context') | ||
const util = require('../helpers/util') | ||
const dingtalk = require('../helpers/mocks/dingtalk') | ||
|
||
const Text = Robot.Text; | ||
|
||
beforeAll(() => context.begin()) | ||
afterAll(async (done) => { | ||
await context.end(); | ||
done(); | ||
}) | ||
|
||
test('Adapter.send sends message to Dingtalk', async () => { | ||
const sendMessage = util.waitForRequest(dingtalk.sendMessage); | ||
|
||
context.app.adapter.send({ | ||
room: "room" | ||
}, 'test message') | ||
|
||
const res = await sendMessage | ||
|
||
const text = new Text(); | ||
text.setContent("test message"); | ||
|
||
expect(res.body).toEqual(text.get()) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
const FakeRobot = require('./mocks/robot') | ||
|
||
class App { | ||
async start() { | ||
this.config = { | ||
secret: "test-client-secret", | ||
type: "sign", | ||
accessToken: "test-client-id", | ||
} | ||
|
||
process.env['HUBOT_DINGTALK_ACCESS_TOKEN'] = this.config.accessToken; | ||
process.env['HUBOT_DINGTALK_SECRET'] = this.config.secret; | ||
process.env['HUBOT_DINGTALK_AUTH_TYPE'] = this.config.type; | ||
|
||
const dingtalkAdapter = require('../../dingtalk') | ||
|
||
this.robot = new FakeRobot(__dirname, "dingtalk", true, "jarvis") | ||
|
||
await this.robot.init(); | ||
|
||
this.adapter = dingtalkAdapter.use(this.robot) | ||
this.client = null; | ||
|
||
// load conf | ||
const conf = this.adapter.read(__dirname) | ||
|
||
conf.forEach((config) => { | ||
if (config.room && config.env && process.env[config.env]) { | ||
this.robot.brain.set(config.room, process.env[config.env]) | ||
} | ||
}) | ||
|
||
await new Promise((resolve, reject) => { | ||
this.adapter.once('connected', () => { | ||
resolve(this.adapter) | ||
}) | ||
|
||
this.adapter.once('error', (error) => { | ||
reject(error) | ||
}) | ||
|
||
|
||
this.adapter.run() | ||
}) | ||
|
||
return this | ||
} | ||
|
||
async stop() { | ||
this.robot.shutdown(); | ||
return this.adapter.close() | ||
} | ||
} | ||
|
||
module.exports = App |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
const App = require('./App') | ||
|
||
class Context { | ||
constructor(options = { app: true, worker: false }) { | ||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 30000 | ||
this.client = null | ||
this.app = null | ||
} | ||
|
||
async begin() { | ||
const startApp = (new App()).start() | ||
const app = await startApp | ||
|
||
this.client = app.client | ||
|
||
this.app = app | ||
|
||
return this | ||
} | ||
|
||
async end() { | ||
if (this.app) { | ||
await this.app.stop() | ||
} | ||
} | ||
} | ||
|
||
module.exports = new Context() | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
[ | ||
{ | ||
"room": "room", | ||
"env": "HUBOT_DINGTALK_ACCESS_TOKEN" | ||
}, | ||
{ | ||
"room": "room2", | ||
"env": "HUBOT_DINGTALK_ACCESS_TOKEN2" | ||
} | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
const nock = require('nock') | ||
|
||
const apiUrl = 'https://oapi.dingtalk.com'; | ||
|
||
function sendMessage(onReply, {} = {}) { | ||
return nock(apiUrl) | ||
.post(uri => uri.includes('/robot/send')) | ||
.reply(200, onReply({ | ||
errmsg: 'ok' | ||
})) | ||
} | ||
|
||
module.exports = { | ||
sendMessage, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
const { EventEmitter } = require('events') | ||
const HttpClient = require('scoped-http-client') | ||
const express = require('express') | ||
const net = require('net') | ||
|
||
const http = function (url, options) { | ||
return HttpClient.create(url, options).header('User-Agent', `Hubot`) | ||
} | ||
|
||
class FakeHttp { | ||
constructor(url) { | ||
this.url = url; | ||
} | ||
|
||
header() { | ||
return this; | ||
} | ||
|
||
post() { | ||
return function (cb) { | ||
console.log(cb.toString()) | ||
cb && cb() | ||
|
||
return (function (_this) { | ||
return function (callback) { | ||
if (callback) { | ||
return callback(null, {}, {}); | ||
} | ||
return _this; | ||
}; | ||
})(this); | ||
} | ||
} | ||
} | ||
|
||
function portIsOccupied(port) { | ||
const server = net.createServer().listen(port) | ||
return new Promise((resolve, reject) => { | ||
server.on('listening', () => { | ||
// console.log(`the server is runnint on port ${port}`) | ||
server.close() | ||
resolve(port) | ||
}) | ||
|
||
server.on('error', (err) => { | ||
if (err.code === 'EADDRINUSE') { | ||
resolve(portIsOccupied(port + (Math.floor((Math.random() * 10) + 1)))) | ||
// console.log(`this port ${port} is occupied.try another.`) | ||
} else { | ||
reject(err) | ||
} | ||
}) | ||
}) | ||
} | ||
|
||
class FakeRobot extends EventEmitter { | ||
constructor() { | ||
super() | ||
this.logger = { | ||
log: function () { | ||
}, | ||
info: function () { | ||
}, | ||
error: function () { | ||
}, | ||
debug: function () { | ||
}, | ||
} | ||
this.receive = jest.fn() | ||
|
||
this.http = http; | ||
this.sockets = []; | ||
|
||
this.brain = { | ||
get: function (name) { | ||
if (name === "room") { | ||
return "token" | ||
} | ||
|
||
return ""; | ||
}, | ||
set: function () { | ||
}, | ||
} | ||
|
||
this.respondPattern = jest.fn() | ||
} | ||
|
||
async init() { | ||
const app = express() | ||
|
||
app.use((req, res, next) => { | ||
res.setHeader('X-Powered-By', `hubot`) | ||
return next() | ||
}) | ||
|
||
app.use(express.query()) | ||
|
||
app.use(express.json()) | ||
|
||
const defaultPort = process.env.EXPRESS_PORT || process.env.PORT || 8081 | ||
const address = process.env.EXPRESS_BIND_ADDRESS || process.env.BIND_ADDRESS || '0.0.0.0' | ||
|
||
try { | ||
let port = await portIsOccupied(defaultPort) | ||
|
||
this.server = app.listen(port, address) | ||
|
||
this.server.on('error', async (err) => { | ||
port = await portIsOccupied(defaultPort + 1) | ||
|
||
this.server = app.listen(port, address) | ||
}) | ||
|
||
this.router = app | ||
|
||
return port; | ||
} catch (error) { | ||
const err = error | ||
this.logger.error(`Error trying to start HTTP server: ${err}\n${err.stack}`) | ||
} | ||
} | ||
|
||
closeServer() { | ||
this.sockets.forEach(function (socket) { | ||
socket.end(); | ||
socket.destroy(); | ||
}); | ||
this.server.close() | ||
} | ||
|
||
shutdown() { | ||
if (this.server) { | ||
this.closeServer() | ||
} | ||
} | ||
} | ||
|
||
module.exports = FakeRobot |
Oops, something went wrong.