"use strict";
/**
 * V1 Message Writer
 *
 *  Copyright (C) 2010-2019 R-T Specialty, LLC.
 *
 *  This file is part of liza.
 *
 *  liza is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Tests for Version 1 of the avro message writer
 */
Object.defineProperty(exports, "__esModule", { value: true });
var V1MessageWriter_1 = require("../../src/system/avro/V1MessageWriter");
var ContextError_1 = require("../../src/error/ContextError");
var stream_1 = require("stream");
var avro_js_1 = require("avro-js");
var chai_1 = require("chai");
chai_1.use(require('chai-as-promised'));
var sinon = require('sinon');
describe('system.V1MessageWriter', function () {
    it('Rejects improperly formatted data', function () {
        var delta = createMockDelta();
        var bucket = createMockBucketData();
        var ratedata = createMockBucketData();
        var error = new Error('Oh no');
        var schema = createMockAvroSchema();
        var ts = 123;
        var meta = {
            id: 123,
            quoteSetId: 123,
            entity_name: 'Some Agency',
            entity_id: 234,
            startDate: 345,
            lastUpdate: 456,
        };
        var expected = {
            invalid_paths: 'Foo',
            invalid_data: 'Bar',
        };
        var error_context = ContextError_1.context(error, expected);
        schema.isValid = function () {
            throw error_context;
        };
        var result = new V1MessageWriter_1.V1MessageWriter(createMockEncoderCtor(schema), schema).write(ts, meta, delta, bucket, ratedata);
        return Promise.all([
            chai_1.expect(result).to.eventually.be.rejectedWith(error),
            result.catch(function (e) {
                if (!ContextError_1.hasContext(e)) {
                    return chai_1.expect.fail();
                }
                return chai_1.expect(e.context).to.deep.equal(expected);
            }),
        ]);
    });
    describe('#avroEncode parses', function () {
        [
            {
                label: 'Null value',
                valid: true,
                delta_data: { foo: null },
            },
            {
                label: 'Null array',
                valid: true,
                delta_data: { foo: { array: [null] } },
            },
            {
                label: 'Boolean value',
                valid: true,
                delta_data: { foo: { array: [{ boolean: true }] } },
            },
            {
                label: 'Simple string',
                valid: true,
                delta_data: { foo: { array: [{ string: 'bar' }, { string: 'baz' }] } },
            },
            {
                label: 'Simple int',
                valid: true,
                delta_data: { foo: { array: [{ double: 123 }] } },
            },
            {
                label: 'Nested array',
                valid: true,
                delta_data: { foo: { array: [{ array: [{ string: 'bar' }] }] } },
            },
            {
                label: 'Array with nulls',
                valid: true,
                delta_data: { foo: { array: [{ string: 'bar' }, { string: 'baz' }, null] } },
            },
            {
                label: 'Nested Array with mixed values',
                valid: true,
                delta_data: {
                    foo: { array: [{ array: [{ string: 'bar' }, { double: 123321 }, null] }] },
                },
            },
            {
                label: 'Non-array',
                valid: false,
                delta_data: { foo: 'bar' },
                expected: {
                    invalid_data: 'bar',
                    invalid_paths: ['delta', 'Data', 'bucket', 'foo'],
                },
            },
            {
                label: 'Map objects',
                valid: true,
                delta_data: {
                    foo: {
                        array: [
                            {
                                map: {
                                    bar: {
                                        map: {
                                            baz: { double: 1572903485000 },
                                        },
                                    },
                                },
                            },
                        ],
                    },
                },
            },
        ].forEach(function (_a) {
            var label = _a.label, delta_data = _a.delta_data, valid = _a.valid, expected = _a.expected;
            it(label, function () {
                var data = createMockData(delta_data);
                var schema = avro_js_1.parse(__dirname + '/../../src/system/avro/schema.avsc');
                var sut = new V1MessageWriter_1.V1MessageWriter(createMockEncoderCtor(schema), schema);
                var result = sut.avroEncode(data);
                if (valid) {
                    return chai_1.expect(result)
                        .to.eventually.deep.equal(Buffer.from(''))
                        .then(function (b) {
                        chai_1.expect(typeof b).to.equal('object');
                    });
                }
                else {
                    return Promise.all([
                        chai_1.expect(result).to.eventually.be.rejected,
                        result.catch(function (e) {
                            if (!ContextError_1.hasContext(e)) {
                                return chai_1.expect.fail();
                            }
                            return chai_1.expect(e.context).to.deep.equal(expected);
                        }),
                    ]);
                }
            });
        });
    });
    describe('#setDataTypes annotates', function () {
        [
            {
                label: 'Null',
                delta_data: null,
                expected: null,
            },
            {
                label: 'Null Value',
                delta_data: { foo: null },
                expected: { foo: null },
            },
            {
                label: 'Boolean Value',
                delta_data: { foo: [true] },
                expected: { foo: { array: [{ boolean: true }] } },
            },
            {
                label: 'Simple string',
                delta_data: { foo: ['bar', 'baz'] },
                expected: { foo: { array: [{ string: 'bar' }, { string: 'baz' }] } },
            },
            {
                label: 'Simple int',
                delta_data: { foo: [123] },
                expected: { foo: { array: [{ double: 123 }] } },
            },
            {
                label: 'Nested array',
                delta_data: { foo: [['bar', 'baz']] },
                expected: { foo: { array: [{ array: [{ string: 'bar' }, { string: 'baz' }] }] } },
            },
            {
                label: 'Double nested array',
                delta_data: { foo: [[['bar', 123, null]]] },
                expected: {
                    foo: {
                        array: [{ array: [{ array: [{ string: 'bar' }, { double: 123 }, null] }] }],
                    },
                },
            },
            {
                label: 'Array with nulls',
                delta_data: { foo: ['bar', 'baz', null] },
                expected: { foo: { array: [{ string: 'bar' }, { string: 'baz' }, null] } },
            },
            {
                label: 'Nested Array with mixed values',
                delta_data: { foo: [['bar', 123321, null]] },
                expected: {
                    foo: { array: [{ array: [{ string: 'bar' }, { double: 123321 }, null] }] },
                },
            },
            {
                label: 'Nested Array with mixed values',
                delta_data: {
                    foo: [
                        {
                            bar: {
                                wer: 'qaz',
                                qwe: 1572903485000,
                                asd: true,
                                zxc: null,
                            },
                        },
                    ],
                },
                expected: {
                    foo: {
                        array: [
                            {
                                map: {
                                    bar: {
                                        map: {
                                            wer: { string: 'qaz' },
                                            qwe: { double: 1572903485000 },
                                            asd: { boolean: true },
                                            zxc: null,
                                        },
                                    },
                                },
                            },
                        ],
                    },
                },
            },
        ].forEach(function (_a) {
            var label = _a.label, delta_data = _a.delta_data, expected = _a.expected;
            it(label, function () {
                var encoded = 'FooBar';
                var avroEncoderCtr = createMockEncoder(encoded);
                var stub_schema = {};
                var sut = new V1MessageWriter_1.V1MessageWriter(avroEncoderCtr, stub_schema);
                var actual = sut.setDataTypes(delta_data);
                chai_1.expect(actual).to.deep.equal(expected);
            });
        });
    });
    it('Message is formatted correctly', function () {
        var bucket = { foo: ['bar', 'baz'] };
        var ratedata = {};
        var doc_id = 123;
        var quote_set_id = 123;
        var program = 'mega';
        var entity_name = 'Some Agency';
        var entity_id = 123;
        var startDate = 345;
        var lastUpdate = 456;
        var expDate = 789;
        var schema = createMockAvroSchema();
        var ts = 123;
        var encoder = createMockEncoderCtor(schema);
        var meta = {
            id: doc_id,
            quoteSetId: quote_set_id,
            program: program,
            entity_name: entity_name,
            entity_id: entity_id,
            startDate: startDate,
            lastUpdate: lastUpdate,
            expDate: expDate,
        };
        var delta = {
            type: 'data',
            timestamp: 123123123,
            data: {},
            concluding_save: true,
        };
        var expected = {
            event: {
                id: 'STEP_SAVE',
                ts: ts * 1000,
                actor: 'SERVER',
                step: {
                    EventStep: {
                        transition: 'END',
                        src: '',
                        dest: '',
                    },
                },
            },
            document: {
                id: doc_id,
                quote_set_id: quote_set_id,
                created: {
                    long: startDate * 1000,
                },
                modified: {
                    long: lastUpdate * 1000,
                },
                expires: {
                    long: expDate,
                },
            },
            session: {
                Session: {
                    entity_name: entity_name,
                    entity_id: entity_id,
                },
            },
            data: {
                Data: {
                    bucket: {
                        foo: { array: [{ string: 'bar' }, { string: 'baz' }] },
                    },
                },
            },
            ratedata: {
                Data: {
                    bucket: {},
                },
            },
            delta: {
                Data: {
                    bucket: delta.data,
                },
            },
            program: {
                Program: {
                    id: program,
                    version: '',
                },
            },
        };
        var is_valid_called = false;
        schema.isValid = function (data, _) {
            chai_1.expect(data).to.deep.equal(expected);
            is_valid_called = true;
            return null;
        };
        return chai_1.expect(new V1MessageWriter_1.V1MessageWriter(encoder, schema).write(ts, meta, delta, bucket, ratedata))
            .to.eventually.deep.equal(Buffer.from(''))
            .then(function (_) {
            chai_1.expect(is_valid_called).to.be.true;
        });
    });
});
function createMockEncoder(mock_encoded_data) {
    return function (_schema) {
        var mock = sinon.mock(stream_1.Duplex);
        mock.on = function (_, __) { };
        mock.end = function (_) {
            return mock_encoded_data;
        };
        return mock;
    };
}
function createMockData(delta_data) {
    return {
        event: {
            id: 'RATE',
            ts: 1573856916,
            actor: 'SERVER',
            step: null,
        },
        document: {
            id: 123123,
            quote_set_id: 123123,
            created: { long: 157385691600 },
            modified: { long: 257381491600 },
            top_visited_step: '2',
        },
        session: {
            Session: {
                entity_name: 'Foo',
                entity_id: 123,
            },
        },
        data: null,
        ratedata: null,
        delta: {
            Data: {
                bucket: delta_data,
            },
        },
        program: {
            Program: {
                id: 'quote_server',
                version: 'dadaddwafdwa',
            },
        },
    };
}
function createMockDelta() {
    return {
        type: 'data',
        timestamp: 123123123,
        data: {},
    };
}
function createMockBucketData() {
    return {
        foo: ['bar', 'baz'],
    };
}
function createMockEncoderCtor(stub_schema) {
    var events = {};
    var mock_duplex = {
        on: function (event_name, callback) {
            events[event_name] = callback;
        },
        end: function () {
            events.end();
        },
    };
    return function (schema) {
        chai_1.expect(schema).to.equal(stub_schema);
        return mock_duplex;
    };
}
function createMockAvroSchema() {
    return {
        toBuffer: function () {
            return null;
        },
        isValid: function () {
            return null;
        },
        encode: function () { },
        toString: function () {
            return '';
        },
        fromBuffer: function () {
            return {};
        },
    };
}
//# sourceMappingURL=data:application/json;base64, 