-
Notifications
You must be signed in to change notification settings - Fork 79
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(messages): add Message Pact support
- Adds support for invoking the pact-message binary from the latest standalone package - Upgrades standalone to 1.33.1
- Loading branch information
Showing
7 changed files
with
280 additions
and
0 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
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,73 @@ | ||
import chai = require("chai"); | ||
import chaiAsPromised = require("chai-as-promised"); | ||
import messageFactory from "./message"; | ||
import { dirname } from "path"; | ||
const path = require("path"); | ||
const expect = chai.expect; | ||
chai.use(chaiAsPromised); | ||
|
||
describe("Message Spec", () => { | ||
const currentDir = (process && process.mainModule) ? path.dirname(process.mainModule.filename) : ""; | ||
const validJSON = `{ "description": "a test mesage", "content": { "name": "Mary" } }`; | ||
|
||
context("when not given any message content", () => { | ||
it("should throw an Error", () => { | ||
expect(() => messageFactory({ | ||
consumer: "a-consumer", | ||
dir: currentDir | ||
})).to.throw(Error); | ||
}); | ||
}); | ||
|
||
context("when not given a consumer", () => { | ||
it("should throw an Error", () => { | ||
expect(() => messageFactory({ | ||
provider: "a-provider", | ||
dir: currentDir, | ||
content: validJSON | ||
})).to.throw(Error); | ||
}); | ||
}); | ||
context("when not given a provider", () => { | ||
it("should throw an Error", () => { | ||
expect(() => messageFactory({ | ||
consumer: "a-provider", | ||
dir: currentDir, | ||
content: validJSON | ||
})).to.throw(Error); | ||
}); | ||
}); | ||
|
||
context("when not given a pact dir", () => { | ||
it("should throw an Error", () => { | ||
expect(() => messageFactory({ | ||
consumer: "a-consumer", | ||
content: validJSON | ||
})).to.throw(Error); | ||
}); | ||
}); | ||
|
||
context("when given an invalid JSON document", () => { | ||
it("should throw an Error", () => { | ||
expect(() => messageFactory({ | ||
consumer: "some-consumer", | ||
provider: "a-provider", | ||
dir: currentDir, | ||
content: `{ "unparseable" }` | ||
})).to.throw(Error); | ||
}); | ||
}); | ||
|
||
context("when given the correct arguments", () => { | ||
it("should return a message object", () => { | ||
const message = messageFactory({ | ||
consumer: "some-consumer", | ||
provider: "a-provider", | ||
dir: currentDir, | ||
content: validJSON | ||
}); | ||
expect(message).to.be.a("object"); | ||
expect(message).to.respondTo("createMessage"); | ||
}); | ||
}); | ||
}); |
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,93 @@ | ||
import fs = require("fs"); | ||
import q = require("q"); | ||
import logger from "./logger"; | ||
import pactUtil, { DEFAULT_ARG, SpawnArguments } from "./pact-util"; | ||
import pactStandalone from "./pact-standalone"; | ||
import path = require("path"); | ||
const mkdirp = require("mkdirp"); | ||
const checkTypes = require("check-types"); | ||
|
||
export class Message { | ||
public readonly options: MessageOptions; | ||
private readonly __argMapping = { | ||
"content": DEFAULT_ARG, | ||
"pactFileWriteMode": DEFAULT_ARG, | ||
"dir": "--pact_dir", | ||
"consumer": "--consumer", | ||
"provider": "--provider", | ||
}; | ||
|
||
constructor(options: MessageOptions) { | ||
options = options || {}; | ||
options.pactFileWriteMode = options.pactFileWriteMode || "update"; | ||
|
||
checkTypes.assert.nonEmptyString(options.consumer, "Must provide the consumer name"); | ||
checkTypes.assert.nonEmptyString(options.provider, "Must provide the provider name"); | ||
checkTypes.assert.nonEmptyString(options.content, "Must provide message content"); | ||
checkTypes.assert.nonEmptyString(options.dir, "Must provide pact output dir"); | ||
|
||
if (options.dir) { | ||
try { | ||
fs.statSync(path.normalize(options.dir)).isDirectory(); | ||
} catch (e) { | ||
mkdirp.sync(path.normalize(options.dir)); | ||
} | ||
} | ||
|
||
if (options.content) { | ||
try { | ||
JSON.parse(options.content); | ||
} catch (e) { | ||
throw new Error("Unable to parse message content to JSON, invalid json supplied"); | ||
} | ||
} | ||
|
||
if (options.consumer) { | ||
checkTypes.assert.string(options.consumer); | ||
} | ||
|
||
if (options.provider) { | ||
checkTypes.assert.string(options.provider); | ||
} | ||
|
||
checkTypes.assert.includes(["overwrite", "update", "merge"], options.pactFileWriteMode); | ||
|
||
if ((options.pactBrokerUsername && !options.pactBrokerPassword) || (options.pactBrokerPassword && !options.pactBrokerUsername)) { | ||
throw new Error("Must provide both Pact Broker username and password. None needed if authentication on Broker is disabled."); | ||
} | ||
|
||
this.options = options; | ||
} | ||
|
||
public createMessage(): q.Promise<any> { | ||
logger.info(`Creating message pact`); | ||
const deferred = q.defer<any>(); | ||
const instance = pactUtil.spawnBinary(`${pactStandalone.messagePath}`, this.options, this.__argMapping); | ||
const output: any[] = []; | ||
instance.stdout.on("data", (l) => output.push(l)); | ||
instance.stderr.on("data", (l) => output.push(l)); | ||
instance.once("close", (code) => { | ||
const o = output.join("\n"); | ||
logger.info(o); | ||
|
||
if (code === 0) { | ||
return deferred.resolve(o); | ||
} else { | ||
return deferred.reject(o); | ||
} | ||
|
||
}); | ||
|
||
return deferred.promise; | ||
} | ||
} | ||
|
||
export default (options: MessageOptions) => new Message(options); | ||
|
||
export interface MessageOptions extends SpawnArguments { | ||
content?: string; | ||
dir?: string; | ||
consumer?: string; | ||
provider?: string; | ||
pactFileWriteMode?: "overwrite" | "update" | "merge"; | ||
} |
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
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,43 @@ | ||
import chai = require("chai"); | ||
import chaiAsPromised = require("chai-as-promised"); | ||
import fs = require("fs"); | ||
import messageFactory from "../src/message"; | ||
import path = require("path"); | ||
import logger from "../src/logger"; | ||
chai.use(chaiAsPromised); | ||
|
||
const rimraf = require("rimraf"); | ||
const expect = chai.expect; | ||
|
||
describe("Message Integration Spec", () => { | ||
const pactDir = (process && process.mainModule) ? `${path.dirname(process.mainModule.filename)}/pacts` : "/tmp/pacts"; | ||
const contractFile = `${pactDir}/consumer-provider.json`; | ||
|
||
const validJSON = `{ "description": "a test mesage", "content": { "name": "Mary" } }`; | ||
|
||
context("when given a successful contract", () => { | ||
before(() => { | ||
try { | ||
if (fs.statSync(contractFile)) { | ||
rimraf(pactDir, () => logger.debug("removed existing pacts")); | ||
} | ||
} catch (e) { } | ||
}); | ||
|
||
it("should return a successful promise", (done) => { | ||
const message = messageFactory({ | ||
consumer: "consumer", | ||
provider: "provider", | ||
dir: `${pactDir}`, | ||
content: validJSON | ||
}); | ||
|
||
const promise = message.createMessage(); | ||
|
||
promise.then(() => { | ||
expect(fs.statSync(contractFile).isFile()).to.eql(true); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
}); |