<commit_before>"use strict";

const sinon = require("sinon");
const stream = require("stream");
const EventEmitter = require("events");

describe("Connection", function() {
	let fakes, Connection;

	beforeEach(() => {
		fakes = {
			config: sinon.stub(),
			EndpointManager: sinon.stub(),
			endpointManager: new EventEmitter(),
		}

		fakes.EndpointManager.returns(fakes.endpointManager);

		Connection = require("../lib/connection")(fakes)
	})

	describe("constructor", function () {

		context("called without `new`", () => {
			it("returns a new instance", () => {
				expect(Connection()).to.be.an.instanceof(Connection);
			});
		});

		it("prepares the configuration with passed options", () => {
			let options = { production: true };
			let connection = Connection(options);

			expect(fakes.config).to.be.calledWith(options);
		});

		describe("EndpointManager instance", function() {
			it("is created", () => {
				Connection();

				expect(fakes.EndpointManager).to.be.calledOnce;
				expect(fakes.EndpointManager).to.be.calledWithNew;
			});

			it("is passed the prepared configuration", () => {
				const returnSentinel = { "configKey": "configValue"};
				fakes.config.returns(returnSentinel);

				Connection({});
				expect(fakes.EndpointManager).to.be.calledWith(returnSentinel);
			});
		});
	});

	describe("pushNotification", () => {

		beforeEach(() => {
			fakes.config.returnsArg(0);
			fakes.endpointManager.getStream = sinon.stub();

			fakes.EndpointManager.returns(fakes.endpointManager);
		});

		context("a single stream is available", () => {

			context("a single token is passed", () => {
				let promise;

				context("transmission succeeds", () => {
					beforeEach( done => {
						const connection = new Connection( { address: "testapi" } );

						fakes.stream = new FakeStream("abcd1234", 200);
						fakes.endpointManager.getStream.onCall(0).returns(fakes.stream);

						promise = connection.pushNotification(notificationDouble(), "abcd1234");
						promise.then( () => done() );
					});

					it("attempts to acquire one stream", () => {
						expect(fakes.endpointManager.getStream).to.be.calledOnce;
					});

					it("sends the required headers", () => {
						expect(fakes.stream.headers).to.be.calledWith( {
							":scheme": "https",
							":method": "POST",
							":authority": "testapi",
							":path": "/3/device/abcd1234",
							"content-length": Buffer.byteLength(notificationDouble().compile()),
						});
					});

					it("writes the notification data to the pipe", () => {
						const writtenData = fakes.stream._transform.firstCall.args[0];
						expect(writtenData).to.deep.equal(Buffer(notificationDouble().compile()));
					});

					it("ends the stream", () => {
						expect(() => fakes.stream.write("ended?")).to.throw("write after end");
					});

					it("resolves with the device token in the success array", () => {
						return expect(promise).to.become([[{"device": "abcd1234"}], []]);
					});
				});

				context("error occurs", () => {
					let promise;

					beforeEach(() => {
						const connection = new Connection( { address: "testapi" } );

						fakes.stream = new FakeStream("abcd1234", 400, { "reason" : "BadDeviceToken" });
						fakes.endpointManager.getStream.onCall(0).returns(fakes.stream);

						promise = connection.pushNotification(notificationDouble(), "abcd1234");
					});

					it("resolves with the device token, status code and response in the failed array", () => {
						return expect(promise).to.eventually.deep.equal([[], [{"device": "abcd1234", "status": 400, "response": { "reason" : "BadDeviceToken" }}]])
					});
				});
			});

			context("no new stream is returned but the endpoint later wakes up", () => {

				it("sends the required headers to the newly available stream", () => {
					const connection = new Connection( { address: "testapi" } );

					fakes.stream = new FakeStream("abcd1234", 200);
					fakes.endpointManager.getStream.onCall(0).returns(null);
					fakes.endpointManager.getStream.onCall(1).returns(fakes.stream);
					let promise = connection.pushNotification(notificationDouble(), "abcd1234");

					expect(fakes.stream.headers).to.not.be.called;

					fakes.endpointManager.emit("wakeup");
					return promise.then(() => {
						expect(fakes.stream.headers).to.be.calledWith( {
							":scheme": "https",
							":method": "POST",
							":authority": "testapi",
							":path": "/3/device/abcd1234",
							"content-length": Buffer.byteLength(notificationDouble().compile()),
						} );
					});
				});

				it("writes the notification data to the pipe", () => {
				});
			});
		});

		xcontext("transmission succeeds", () => {
			it("resolves with the device token in the success array", () => {
			});
		});
		xcontext("error occurs", () => {
			it("resolves with the device token, status code and response in the failed array", () => {
			});
		});

		xcontext("when 10 tokens are passed", () => {
			context("streams are always returned", () => {
				it("sends the required headers for each stream", () => {
				});
				it("writes the notification data for each stream", () => {
				});
				it("resolves with the successful notifications", () => {
				});
				it("resolves with the device token, status code and response of the unsuccessful notifications", () => {
				});
			});<commit_msg>Add a missing test for the delayed write<commit_after>"use strict";

const sinon = require("sinon");
const stream = require("stream");
const EventEmitter = require("events");

describe("Connection", function() {
	let fakes, Connection;

	beforeEach(() => {
		fakes = {
			config: sinon.stub(),
			EndpointManager: sinon.stub(),
			endpointManager: new EventEmitter(),
		}

		fakes.EndpointManager.returns(fakes.endpointManager);

		Connection = require("../lib/connection")(fakes)
	})

	describe("constructor", function () {

		context("called without `new`", () => {
			it("returns a new instance", () => {
				expect(Connection()).to.be.an.instanceof(Connection);
			});
		});

		it("prepares the configuration with passed options", () => {
			let options = { production: true };
			let connection = Connection(options);

			expect(fakes.config).to.be.calledWith(options);
		});

		describe("EndpointManager instance", function() {
			it("is created", () => {
				Connection();

				expect(fakes.EndpointManager).to.be.calledOnce;
				expect(fakes.EndpointManager).to.be.calledWithNew;
			});

			it("is passed the prepared configuration", () => {
				const returnSentinel = { "configKey": "configValue"};
				fakes.config.returns(returnSentinel);

				Connection({});
				expect(fakes.EndpointManager).to.be.calledWith(returnSentinel);
			});
		});
	});

	describe("pushNotification", () => {

		beforeEach(() => {
			fakes.config.returnsArg(0);
			fakes.endpointManager.getStream = sinon.stub();

			fakes.EndpointManager.returns(fakes.endpointManager);
		});

		context("a single stream is available", () => {

			context("a single token is passed", () => {
				let promise;

				context("transmission succeeds", () => {
					beforeEach( done => {
						const connection = new Connection( { address: "testapi" } );

						fakes.stream = new FakeStream("abcd1234", 200);
						fakes.endpointManager.getStream.onCall(0).returns(fakes.stream);

						promise = connection.pushNotification(notificationDouble(), "abcd1234");
						promise.then( () => done() );
					});

					it("attempts to acquire one stream", () => {
						expect(fakes.endpointManager.getStream).to.be.calledOnce;
					});

					it("sends the required headers", () => {
						expect(fakes.stream.headers).to.be.calledWith( {
							":scheme": "https",
							":method": "POST",
							":authority": "testapi",
							":path": "/3/device/abcd1234",
							"content-length": Buffer.byteLength(notificationDouble().compile()),
						});
					});

					it("writes the notification data to the pipe", () => {
						const writtenData = fakes.stream._transform.firstCall.args[0];
						expect(writtenData).to.deep.equal(Buffer(notificationDouble().compile()));
					});

					it("ends the stream", () => {
						expect(() => fakes.stream.write("ended?")).to.throw("write after end");
					});

					it("resolves with the device token in the success array", () => {
						return expect(promise).to.become([[{"device": "abcd1234"}], []]);
					});
				});

				context("error occurs", () => {
					let promise;

					beforeEach(() => {
						const connection = new Connection( { address: "testapi" } );

						fakes.stream = new FakeStream("abcd1234", 400, { "reason" : "BadDeviceToken" });
						fakes.endpointManager.getStream.onCall(0).returns(fakes.stream);

						promise = connection.pushNotification(notificationDouble(), "abcd1234");
					});

					it("resolves with the device token, status code and response in the failed array", () => {
						return expect(promise).to.eventually.deep.equal([[], [{"device": "abcd1234", "status": 400, "response": { "reason" : "BadDeviceToken" }}]])
					});
				});
			});

			context("no new stream is returned but the endpoint later wakes up", () => {
				let promise

				beforeEach( done => {
					const connection = new Connection( { address: "testapi" } );

					fakes.stream = new FakeStream("abcd1234", 200);
					fakes.endpointManager.getStream.onCall(0).returns(null);
					fakes.endpointManager.getStream.onCall(1).returns(fakes.stream);
					let promise = connection.pushNotification(notificationDouble(), "abcd1234");

					expect(fakes.stream.headers).to.not.be.called;

					fakes.endpointManager.emit("wakeup");

					promise.then( () => { done(); } )
				});

				it("sends the required headers to the newly available stream", () => {
					expect(fakes.stream.headers).to.be.calledWith( {
						":scheme": "https",
						":method": "POST",
						":authority": "testapi",
						":path": "/3/device/abcd1234",
						"content-length": Buffer.byteLength(notificationDouble().compile()),
					});
				});

				it("writes the notification data to the pipe", () => {
					const writtenData = fakes.stream._transform.firstCall.args[0];
					expect(writtenData).to.deep.equal(Buffer(notificationDouble().compile()));
				});
			});
		});

		xcontext("transmission succeeds", () => {
			it("resolves with the device token in the success array", () => {
			});
		});
		xcontext("error occurs", () => {
			it("resolves with the device token, status code and response in the failed array", () => {
			});
		});

		xcontext("when 10 tokens are passed", () => {
			context("streams are always returned", () => {
				it("sends the required headers for each stream", () => {
				});
				it("writes the notification data for each stream", () => {
				});
				it("resolves with the successful notifications", () => {
				});
				it("resolves with the device token, status code and response of the unsuccessful notifications", () => {
				});
			});
{'fraction_non_alphanumeric': 0.17664340800587588, 'fraction_numerical': 0.011476312890194637, 'mean_word_length': 3.451573355128729, 'pattern_counts': {'":': 46, '<': 3, '<?xml version=': 0, '>': 76, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6050225', 'n_tokens_mistral': 4136, 'n_tokens_neox': 3151, 'n_words': 673}