<commit_before>async = require('async')
should = require('should')
{ NS, TestServer } = require('./test_server')

describe "MAM", ->
    server = new TestServer()

    it "must replay PubSub events to the sender", (done) ->
        @timeout 5000
        mam_begin = new Date().toISOString() #TODO: timezone?

        async.series [(cb) ->
            # We need some data! So publish 2 posts, retract one, add an
            # affiliation and a subscription, and change a channel title. We
            # also add another post in a channel not followed by Picard to check
            # he's not notified of it.
            iqs = [
                server.makePublishIq("<EMAIL>", "buddycloud.example.org",
                    "mam-A-1", "/user/riker@enterprise.sf/posts",
                    content: "Test post A1", id: "mampost-A-1"),
                server.makePublishIq("<EMAIL>", "buddycloud.example.org",
                    "mam-A-2", "/user/picard@enterprise.sf/posts",
                    content: "Test post A2", id: "mampost-A-2"),
                server.makePublishIq("<EMAIL>", "buddycloud.example.org",
                    "mam-A-3", "/user/laforge@enterprise.sf/posts",
                    content: "Test post A3", id: "mampost-A-3"),
                server.makePubsubSetIq("<EMAIL>", "buddycloud.example.org", "mam-A-4")
                    .c("retract", node: "/user/picard@enterprise.sf/posts")
                    .c("item", id: "mampost-A-2"),

                server.makePubsubSetIq("<EMAIL>", "buddycloud.example.org", "mam-A-5")
                    .c("subscribe",
                        jid: "<EMAIL>"
                        node: "/user/mam-user.1@enterprise.sf/posts"),
                server.makePubsubSetIq("<EMAIL>", "buddycloud.example.org", "mam-A-6")
                    .c("subscribe",
                        jid: "<EMAIL>"
                        node: "/user/mam-user.1@enterprise.sf/posts"),
                server.makePubsubSetIq("<EMAIL>", "buddycloud.example.org", "mam-A-7")
                    .c("subscribe",
                        jid: "<EMAIL>"
                        node: "/user/mam-user.2@enterprise.sf/posts"),

                server.makePubsubOwnerSetIq("<EMAIL>", "buddycloud.example.org", "mam-A-8")
                    .c("affiliations", node: "/user/mam-user.1@enterprise.sf/posts")
                    .c("affiliation", jid: "<EMAIL>", affiliation: "publisher"),
                server.makePubsubOwnerSetIq("<EMAIL>", "buddycloud.example.org", "mam-A-9")
                    .c("affiliations", node: "/user/mam-user.2@enterprise.sf/posts")
                    .c("affiliation", jid: "<EMAIL>", affiliation: "publisher"),

                server.makePubsubOwnerSetIq("<EMAIL>", "buddycloud.example.org", "mam-A-10")
                    .c("configure", node: "/user/picard@enterprise.sf/status")
                    .cnode(server.makeForm("submit", NS.PUBSUB_NODE_CONFIG, "pubsub#title": "Test title mam-A-10")),

                server.makePubsubOwnerSetIq("<EMAIL>", "buddycloud.example.org", "mam-A-11")
                    .c("configure", node: "/user/data@enterprise.sf/status")
                    .cnode(server.makeForm("submit", NS.PUBSUB_NODE_CONFIG, "pubsub#title": "Test title mam-A-11")),

                server.makePubsubOwnerSetIq("<EMAIL>", "buddycloud.example.org", "mam-A-12")
                    .c("configure", node: "/user/riker@enterprise.sf/status")
                    .cnode(server.makeForm("submit", NS.PUBSUB_NODE_CONFIG, "pubsub#title": "Test title mam-A-12"))
            ]
            async.forEachSeries iqs, (iq, cb2) ->
                id = iq.root().attrs.id
                server.doTest iq, "got-iq-#{id}", cb2, (iq) ->
                    iq.attrs.should.have.property "type", "result"
            , cb

        , (cb) ->
            # Now send MAM request
            iq = server.makeIq("get", "picard@enterprise.sf/abc", "buddycloud.example.org", "mam-B-1")
                .c("query", xmlns: NS.MAM, queryid: "mamq-B-1")
                .c("start").t(mam_begin)

            posts = {}
            goodPosts = ["mampost-A-1", "mampost-A-2"]
            badPosts = ["mampost-A-3"]

            subscriptions = []
            goodSubscriptions = [
                ["<EMAIL>", "/user/mam-user.1@enterprise.sf/posts"],
                ["<EMAIL>","/user/mam-user.1@enterprise.sf/posts"]]
            badSubscriptions = [["<EMAIL>", "/user/mam-user.2@enterprise.sf/posts"]]

            affiliations = []
            goodAffiliations = [["/user/mam-user.1@enterprise.sf/posts", "<EMAIL>"]]
            badAffiliations = [["/user/mam-user.2@enterprise.sf/posts", "<EMAIL>.sf"]]

            configurations = []
            goodConfigurations = ["/user/picard@enterprise.sf/status", "/user/riker@enterprise.sf/status"]
            badConfigurations = ["/user/data@enterprise.sf/status"]

            iqReceived = false

            server.on "got-message-picard@enterprise.sf/abc", (msg) ->
                iqReceived.should.be.false
                msg.attrs.should.have.property("type", "headline")

                resEl = msg.getChild("result", NS.MAM)
                should.exist resEl, "missing element: <result/>"
                resEl.attrs.should.have.property "queryid", "mamq-B-1"

                fwdEl = msg.getChild("forwarded", NS.FORWARD)
                should.exist fwdEl, "missing element: <forwarded/>"

                evt = fwdEl.getChild("message")
                    ?.getChild("event", NS.PUBSUB_EVENT)
                should.exist evt, "missing element: <event/>"
                evt.children.should.not.have.length 0

                for el in evt.children
                    if el.is "items"
                        item = el.getChild "item"
                        should.exist item, "missing element: <item/>"
                        item.attrs.should.have.property "id"
                        id = item.attrs.id
                        if id not of posts
                            posts[id] = 0
                        posts[id] += 1

                    else if el.is "subscription"
                        el.attrs.should.have.property "jid"
                        el.attrs.should.have.property "node"
                        subscriptions.push [el.attrs.jid, el.attrs.node]

                    else if el.is "affiliations"
                        el.attrs.should.have.property "node"
                        for aff in el.getChildren("affiliation")
                            aff.attrs.should.have.property "jid"
                            aff.attrs.should.have.property "affiliation"
                            affiliations.push [el.attrs.node, aff.attrs.jid]

                    else if el.is "configuration"
                        el.attrs.should.have.property "node"
                        configurations.push el.attrs.node

                    else
                        el.should.not.exist

            server.on "got-message-picard@enterprise.sf/def", (msg) ->
                throw new Error("MAM reply for non-sender!")

            server.doTest iq, "got-iq-mam-B-1", cb, (iq) ->
                iqReceived = true
                server.removeAllListeners "got-message-picard@enterprise.sf/abc"
                server.once "got-message-picard@enterprise.sf/abc", (msg) ->
                    throw new Error("message after result iq")
                iq.attrs.should.have.property "type", "result"

                for id in goodPosts
                    posts.should.have.property( id, 1)
                for id in badPosts
                    posts.should.not.have.property(id)

                for aff in goodAffiliations
                    affiliations.should.includeEql aff
                for aff in badAffiliations
                    affiliations.should.not.includeEql aff

                for sub in goodSubscriptions
                    subscriptions.should.includeEql sub
                for sub in badSubscriptions
                    subscriptions.should.not.includeEql sub

                for conf in goodConfigurations
                    configurations.should.include conf
                for conf in badConfigurations
                    configurations.should.not.include conf

        ], (err) ->
            # Wait a second before removing listeners for unwanted messages
            setTimeout ->
                server.removeAllListeners "got-message-picard@enterprise.sf/abc"
                server.removeAllListeners "got-message-picard@enterprise.sf/def"
                done err
            , 1000


    it.skip "must fail when there are too many results", (done) -><commit_msg>Test if MAM validates dates correctly<commit_after>async = require('async')
should = require('should')
{ NS, TestServer } = require('./test_server')

describe "MAM", ->
    server = new TestServer()

    it "must replay PubSub events to the sender", (done) ->
        @timeout 5000
        mam_begin = new Date().toISOString() #TODO: timezone?

        async.series [(cb) ->
            # We need some data! So publish 2 posts, retract one, add an
            # affiliation and a subscription, and change a channel title. We
            # also add another post in a channel not followed by Picard to check
            # he's not notified of it.
            iqs = [
                server.makePublishIq("<EMAIL>", "buddycloud.example.org",
                    "mam-A-1", "/user/riker@enterprise.sf/posts",
                    content: "Test post A1", id: "mampost-A-1"),
                server.makePublishIq("<EMAIL>", "buddycloud.example.org",
                    "mam-A-2", "/user/picard@enterprise.sf/posts",
                    content: "Test post A2", id: "mampost-A-2"),
                server.makePublishIq("<EMAIL>", "buddycloud.example.org",
                    "mam-A-3", "/user/laforge@<EMAIL>.sf/posts",
                    content: "Test post A3", id: "mampost-A-3"),
                server.makePubsubSetIq("<EMAIL>", "buddycloud.example.org", "mam-A-4")
                    .c("retract", node: "/user/picard@enterprise.sf/posts")
                    .c("item", id: "mampost-A-2"),

                server.makePubsubSetIq("<EMAIL>", "buddycloud.example.org", "mam-A-5")
                    .c("subscribe",
                        jid: "<EMAIL>"
                        node: "/user/mam-user.1@enterprise.sf/posts"),
                server.makePubsubSetIq("<EMAIL>", "buddycloud.example.org", "mam-A-6")
                    .c("subscribe",
                        jid: "<EMAIL>"
                        node: "/user/mam-user.1@enterprise.sf/posts"),
                server.makePubsubSetIq("<EMAIL>", "buddycloud.example.org", "mam-A-7")
                    .c("subscribe",
                        jid: "<EMAIL>"
                        node: "/user/mam-user.2@enterprise.sf/posts"),

                server.makePubsubOwnerSetIq("<EMAIL>", "buddycloud.example.org", "mam-A-8")
                    .c("affiliations", node: "/user/mam-user.1@enterprise.sf/posts")
                    .c("affiliation", jid: "<EMAIL>", affiliation: "publisher"),
                server.makePubsubOwnerSetIq("<EMAIL>", "buddycloud.example.org", "mam-A-9")
                    .c("affiliations", node: "/user/mam-user.2@enterprise.sf/posts")
                    .c("affiliation", jid: "<EMAIL>", affiliation: "publisher"),

                server.makePubsubOwnerSetIq("<EMAIL>", "buddycloud.example.org", "mam-A-10")
                    .c("configure", node: "/user/<EMAIL>@enterprise.sf/status")
                    .cnode(server.makeForm("submit", NS.PUBSUB_NODE_CONFIG, "pubsub#title": "Test title mam-A-10")),

                server.makePubsubOwnerSetIq("<EMAIL>", "buddycloud.example.org", "mam-A-11")
                    .c("configure", node: "/user/data@enterprise.sf/status")
                    .cnode(server.makeForm("submit", NS.PUBSUB_NODE_CONFIG, "pubsub#title": "Test title mam-A-11")),

                server.makePubsubOwnerSetIq("<EMAIL>", "buddycloud.example.org", "mam-A-12")
                    .c("configure", node: "/user/riker@enterprise.sf/status")
                    .cnode(server.makeForm("submit", NS.PUBSUB_NODE_CONFIG, "pubsub#title": "Test title mam-A-12"))
            ]
            async.forEachSeries iqs, (iq, cb2) ->
                id = iq.root().attrs.id
                server.doTest iq, "got-iq-#{id}", cb2, (iq) ->
                    iq.attrs.should.have.property "type", "result"
            , cb

        , (cb) ->
            # Now send MAM request
            iq = server.makeIq("get", "<EMAIL>/abc", "buddycloud.example.org", "mam-B-1")
                .c("query", xmlns: NS.MAM, queryid: "mamq-B-1")
                .c("start").t(mam_begin)

            posts = {}
            goodPosts = ["mampost-A-1", "mampost-A-2"]
            badPosts = ["mampost-A-3"]

            subscriptions = []
            goodSubscriptions = [
                ["<EMAIL>", "/user/mam-user.1@enterprise.sf/posts"],
                ["<EMAIL>","/user/mam-user.1@enterprise.sf/posts"]]
            badSubscriptions = [["<EMAIL>", "/user/mam-user.2@enterprise.sf/posts"]]

            affiliations = []
            goodAffiliations = [["/user/mam-user.1@enterprise.sf/posts", "<EMAIL>"]]
            badAffiliations = [["/user/mam-user.2@enterprise.sf/posts", "<EMAIL>"]]

            configurations = []
            goodConfigurations = ["/user/picard@enterprise.sf/status", "/user/riker@enterprise.sf/status"]
            badConfigurations = ["/user/data@enterprise.sf/status"]

            iqReceived = false

            server.on "got-message-picard@enterprise.sf/abc", (msg) ->
                iqReceived.should.be.false
                msg.attrs.should.have.property("type", "headline")

                resEl = msg.getChild("result", NS.MAM)
                should.exist resEl, "missing element: <result/>"
                resEl.attrs.should.have.property "queryid", "mamq-B-1"

                fwdEl = msg.getChild("forwarded", NS.FORWARD)
                should.exist fwdEl, "missing element: <forwarded/>"

                evt = fwdEl.getChild("message")
                    ?.getChild("event", NS.PUBSUB_EVENT)
                should.exist evt, "missing element: <event/>"
                evt.children.should.not.have.length 0

                for el in evt.children
                    if el.is "items"
                        item = el.getChild "item"
                        should.exist item, "missing element: <item/>"
                        item.attrs.should.have.property "id"
                        id = item.attrs.id
                        if id not of posts
                            posts[id] = 0
                        posts[id] += 1

                    else if el.is "subscription"
                        el.attrs.should.have.property "jid"
                        el.attrs.should.have.property "node"
                        subscriptions.push [el.attrs.jid, el.attrs.node]

                    else if el.is "affiliations"
                        el.attrs.should.have.property "node"
                        for aff in el.getChildren("affiliation")
                            aff.attrs.should.have.property "jid"
                            aff.attrs.should.have.property "affiliation"
                            affiliations.push [el.attrs.node, aff.attrs.jid]

                    else if el.is "configuration"
                        el.attrs.should.have.property "node"
                        configurations.push el.attrs.node

                    else
                        el.should.not.exist

            server.on "got-message-picard@enterprise.sf/def", (msg) ->
                throw new Error("MAM reply for non-sender!")

            server.doTest iq, "got-iq-mam-B-1", cb, (iq) ->
                iqReceived = true
                server.removeAllListeners "got-message-picard@enterprise.sf/abc"
                server.once "got-message-picard@enterprise.sf/abc", (msg) ->
                    throw new Error("message after result iq")
                iq.attrs.should.have.property "type", "result"

                for id in goodPosts
                    posts.should.have.property( id, 1)
                for id in badPosts
                    posts.should.not.have.property(id)

                for aff in goodAffiliations
                    affiliations.should.includeEql aff
                for aff in badAffiliations
                    affiliations.should.not.includeEql aff

                for sub in goodSubscriptions
                    subscriptions.should.includeEql sub
                for sub in badSubscriptions
                    subscriptions.should.not.includeEql sub

                for conf in goodConfigurations
                    configurations.should.include conf
                for conf in badConfigurations
                    configurations.should.not.include conf

        ], (err) ->
            # Wait a second before removing listeners for unwanted messages
            setTimeout ->
                server.removeAllListeners "got-message-picard@enterprise.sf/abc"
                server.removeAllListeners "got-message-picard@enterprise.sf/def"
                done err
            , 1000


    it "must fail if a date is invalid", (done) ->
        good_dates = [
            "1969-07-21T02:56:15Z",
            "1969-07-20T21:56:15-05:00",
        ]
        bad_dates = [
            "1969-07-21 02:56:15Z",
            "1969-07-21T02:56:15",
            "01:23:45",
            "notadate",
        ]
        n = 0

        testMamDate = (date, cb, check) ->
            n += 1
            iq = server.makeIq("get", "picard<EMAIL>.sf/abc", "buddycloud.example.org", "mam-C-#{n}")
                    .c("query", xmlns: NS.MAM)
                    .c("start").t(date)
            server.doTest iq, "got-iq-mam-C-#{n}", cb, check

        async.series [(cb) ->
            # Test good dates
            async.forEachSeries good_dates, (date, cb2) ->
                testMamDate date, cb2, (iq) ->
                    iq.attrs.should.have.property "type", "result", date
            , cb

        , (cb) ->
            # Test bad dates
            async.forEachSeries bad_dates, (date, cb2) ->
                testMamDate date, cb2, (iq) ->
                    iq.attrs.should.have.property "type", "error", date
            , cb
        ], done


    it.skip "must fail when there are too many results", (done) ->
{'fraction_non_alphanumeric': 0.13527564171991768, 'fraction_numerical': 0.010397487273908806, 'mean_word_length': 1.5238485718190515, 'pattern_counts': {'":': 6, '<': 59, '<?xml version=': 0, '>': 93, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 3}, 'pii_count': 51, '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': '2706626', 'n_tokens_mistral': 5617, 'n_tokens_neox': 5237, 'n_words': 1001}