Exemplo n.º 1
0
    async def test_prov(self):

        s_provenance.reset()

        async with self.getTestCore() as real, real.getLocalProxy() as core:

            # Non-existent iden
            self.none(await core.getProvStack('abcd'))

            await core.addTrigger('node:add', '[ test:int=1 ]', info={'form': 'test:str'})
            await s_common.aspin(core.eval('[ test:str=foo ]'))
            await self.agenlen(1, core.eval('test:int'))

            await self.agenlen(0, core.eval('test:int | delnode'))

            splices = await alist(core.splices(0, 1000))

            self.len(9, splices)
            idens = [splice[1]['prov'] for splice in splices]
            self.eq(idens[0], idens[1])
            self.eq(idens[0], idens[2])
            self.eq(idens[3], idens[4])
            self.eq(idens[7], idens[8])

            # node:add and prop:set
            self.eq(idens[5], idens[6])

            # The source splices
            prov1 = await core.getProvStack(idens[0])
            self.eq(({}, ()), prov1)

            # The test:str splices
            prov2 = await core.getProvStack(idens[3])
            rootiden = prov2[1][0][1]['user']
            s2 = ('storm', {'q': '[ test:str=foo ]', 'user': rootiden})
            self.eq((s2, ), prov2[1])

            # Validate that the iden calc itself is correct
            rawprov = ({}, [('storm', (('q', '[ test:str=foo ]'), ('user', rootiden)))])
            hash = hashlib.md5(s_msgpack.en(rawprov)).hexdigest()
            self.eq(hash, idens[3])

            # The trigger splices
            prov3 = await core.getProvStack(idens[5])
            s3 = ('trig', {'cond': 'node:add', 'form': 'test:str', 'tag': None, 'prop': None})
            s4 = ('storm', {'q': '[ test:int=1 ]', 'user': rootiden})
            self.eq((s2, s3, s4), prov3[1])

            # prop:del/node:del
            prov4 = await core.getProvStack(idens[7])

            ds2 = ('storm', {'q': 'test:int | delnode', 'user': rootiden})
            ds3 = ('stormcmd', {'name': 'delnode', 'argv': ()})
            self.eq((ds2, ds3), prov4[1])

            # Test the streaming API
            provstacks = await alist(core.provStacks(0, 1000))
            correct = [(idens[0], prov1), (idens[3], prov2), (idens[5], prov3), (idens[7], prov4)]
            self.eq(provstacks, correct)
Exemplo n.º 2
0
    async def test_cron(self):
        MONO_DELT = 1543827303.0
        unixtime = datetime.datetime(year=2018,
                                     month=12,
                                     day=5,
                                     hour=7,
                                     minute=0,
                                     tzinfo=tz.utc).timestamp()
        sync = asyncio.Event()
        lastquery = None
        s_provenance.reset()

        def timetime():
            return unixtime

        def looptime():
            return unixtime - MONO_DELT

        async def myeval(query, user=None):
            nonlocal lastquery
            lastquery = query
            sync.set()
            return
            yield None

        loop = asyncio.get_running_loop()

        with mock.patch.object(loop, 'time',
                               looptime), mock.patch('time.time', timetime):
            async with self.getTestCoreAndProxy() as (realcore, core):

                outp = self.getTestOutp()
                async with await s_cmdr.getItemCmdr(core, outp=outp) as cmdr:

                    # Various silliness

                    await cmdr.runCmdLine('cron')
                    self.true(outp.expect('Manages cron jobs in a cortex'))
                    await cmdr.runCmdLine('cron timemachine')
                    self.true(outp.expect('invalid choice'))

                    await cmdr.runCmdLine('cron list')
                    self.true(outp.expect('No cron jobs found'))

                    await cmdr.runCmdLine('cron ls')
                    self.true(outp.expect('No cron jobs found'))

                    outp.clear()

                    await cmdr.runCmdLine(
                        "cron add -M+1,beeroclock {[graph:node='*' :type=m1]}")
                    self.true(outp.expect('failed to parse parameter'))

                    await cmdr.runCmdLine(
                        "cron add -m nosuchmonth -d=-2 {#foo}")
                    self.true(outp.expect('failed to parse fixed parameter'))

                    outp.clear()
                    await cmdr.runCmdLine(
                        "cron add -m 8nosuchmonth -d=-2 {#foo}")
                    self.true(outp.expect('failed to parse fixed parameter'))

                    await cmdr.runCmdLine("cron add -d=, {#foo}")
                    self.true(outp.expect('failed to parse day value'))

                    await cmdr.runCmdLine("cron add -dMon -m +3 {#foo}")
                    self.true(
                        outp.expect(
                            'provide a recurrence value with day of week'))

                    await cmdr.runCmdLine("cron add -dMon -m June {#foo}")
                    self.true(
                        outp.expect('fix month or year with day of week'))

                    await cmdr.runCmdLine("cron add -dMon -m +3 -y +2 {#foo}")
                    self.true(outp.expect('more than 1 recurrence'))

                    await cmdr.runCmdLine("cron add --year=2019 {#foo}")
                    self.true(outp.expect('year may not be a fixed value'))

                    await cmdr.runCmdLine("cron add {#foo}")
                    self.true(
                        outp.expect('must provide at least one optional'))

                    await cmdr.runCmdLine("cron add -H3 -M +4 {#foo}")
                    self.true(outp.expect('fixed unit may not be larger'))

                    outp.clear()
                    await cmdr.runCmdLine('cron add -d Tuesday,1 {#foo}')
                    self.true(outp.expect('failed to parse day value'))

                    outp.clear()
                    await cmdr.runCmdLine('cron add -d Fri,3 {#foo}')
                    self.true(outp.expect('failed to parse day value'))

                    outp.clear()
                    await cmdr.runCmdLine('cron add }')
                    self.true(outp.expect('BadSyntax'))

                    ##################
                    oldsplices = len(await alist(core.splices(0, 1000)))

                    # Start simple: add a cron job that creates a node every minute
                    outp.clear()
                    await cmdr.runCmdLine(
                        "cron add -M +1 {[graph:node='*' :type=m1]}")
                    self.true(outp.expect('Created cron job'))
                    guid = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]

                    unixtime += 60
                    await cmdr.runCmdLine('cron list')
                    self.true(outp.expect(':type=m1'))

                    # Make sure it ran
                    await self.agenlen(1, core.eval('graph:node:type=m1'))

                    # Make sure the provenance of the new splices looks right
                    splices = await alist(core.splices(oldsplices, 1000))
                    self.gt(len(splices), 1)
                    aliases = [splice[1]['prov'] for splice in splices]
                    self.true(all(a == aliases[0] for a in aliases))
                    prov = await core.getProvStack(aliases[0])
                    rootiden = prov[1][1][1]['user']
                    correct = ({}, (('cron', {
                        'iden': guid
                    }), ('storm', {
                        'q': "[graph:node='*' :type=m1]",
                        'user': rootiden
                    })))
                    self.eq(prov, correct)

                    await cmdr.runCmdLine(
                        f"cron mod {guid[:6]} {{[graph:node='*' :type=m2]}}")
                    self.true(outp.expect('Modified cron job'))
                    await cmdr.runCmdLine(
                        f"cron edit xxx {{[graph:node='*' :type=m2]}}")
                    self.true(outp.expect('does not match'))
                    await cmdr.runCmdLine(f"cron mod xxx yyy")
                    self.true(
                        outp.expect(
                            'expected second argument to start with {'))

                    # Make sure the old one didn't run and the new query ran
                    unixtime += 60
                    await self.agenlen(1, core.eval('graph:node:type=m1'))
                    await self.agenlen(1, core.eval('graph:node:type=m2'))

                    outp.clear()

                    # Delete the job
                    await cmdr.runCmdLine(f"cron del {guid}")
                    self.true(outp.expect('Deleted cron job'))
                    await cmdr.runCmdLine(f"cron del xxx")
                    self.true(outp.expect('does not match'))
                    await cmdr.runCmdLine(f"cron rm xxx")
                    self.true(outp.expect('does not match'))

                    # Make sure deleted job didn't run
                    unixtime += 60
                    await self.agenlen(1, core.eval('graph:node:type=m1'))
                    await self.agenlen(1, core.eval('graph:node:type=m2'))

                    # Test fixed minute, i.e. every hour at 17 past
                    unixtime = datetime.datetime(year=2018,
                                                 month=12,
                                                 day=5,
                                                 hour=7,
                                                 minute=10,
                                                 tzinfo=tz.utc).timestamp()
                    await cmdr.runCmdLine(
                        "cron add -M 17 {[graph:node='*' :type=m3]}")
                    guid = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]

                    unixtime += 7 * MINSECS

                    # Make sure it runs.  We add the cron list to give the cron scheduler a chance to run
                    await cmdr.runCmdLine('cron list')
                    await self.agenlen(1, core.eval('graph:node:type=m3'))
                    await cmdr.runCmdLine(f"cron del {guid}")

                    ##################

                    # Test day increment
                    await cmdr.runCmdLine(
                        "cron add -d +2 {[graph:node='*' :type=d1]}")
                    self.true(outp.expect('Created cron job'))
                    guid1 = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]

                    unixtime += DAYSECS

                    # Make sure it *didn't* run
                    await self.agenlen(0, core.eval('graph:node:type=d1'))

                    unixtime += DAYSECS

                    # Make sure it runs.  We add the cron list to give the cron scheduler a chance to run

                    await cmdr.runCmdLine('cron list')
                    await self.agenlen(1, core.eval('graph:node:type=d1'))

                    unixtime += DAYSECS * 2
                    await cmdr.runCmdLine('cron list')
                    await self.agenlen(2, core.eval('graph:node:type=d1'))

                    ##################

                    # Test fixed day of week: every Monday and Thursday at 3am
                    unixtime = datetime.datetime(
                        year=2018,
                        month=12,
                        day=11,
                        hour=7,
                        minute=10,
                        tzinfo=tz.utc).timestamp()  # A Tuesday

                    await cmdr.runCmdLine(
                        "cron add -H 3 -d Mon,Thursday {[graph:node='*' :type=d2]}"
                    )
                    guid2 = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]
                    unixtime = datetime.datetime(
                        year=2018,
                        month=12,
                        day=13,
                        hour=3,
                        minute=10,
                        tzinfo=tz.utc).timestamp()  # Now Thursday
                    await cmdr.runCmdLine('cron list')
                    await self.agenlen(1, core.eval('graph:node:type=d2'))

                    await cmdr.runCmdLine(f"cron del {guid1}")
                    await cmdr.runCmdLine(f"cron del {guid2}")

                    await cmdr.runCmdLine(
                        "cron add -H 3 -d Noday {[graph:node='*' :type=d2]}")
                    self.true(outp.expect('failed to parse day value "Noday"'))

                    ##################

                    # Test fixed day of month: second-to-last day of month
                    await cmdr.runCmdLine(
                        "cron add -d-2 -mDec {[graph:node='*' :type=d3]}")
                    guid = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]

                    unixtime = datetime.datetime(
                        year=2018,
                        month=12,
                        day=29,
                        hour=0,
                        minute=0,
                        tzinfo=tz.utc).timestamp()  # Now Thursday
                    await cmdr.runCmdLine('cron list')
                    await self.agenlen(0, core.eval('graph:node:type=d3')
                                       )  # Not yet
                    unixtime += DAYSECS
                    await cmdr.runCmdLine('cron list')
                    await self.agenlen(1, core.eval('graph:node:type=d3'))
                    await cmdr.runCmdLine(f"cron del {guid}")

                    ##################

                    # Test month increment

                    await cmdr.runCmdLine(
                        "cron add -m +2 -d=4 {[graph:node='*' :type=month1]}")

                    unixtime = datetime.datetime(
                        year=2019,
                        month=2,
                        day=4,
                        hour=0,
                        minute=0,
                        tzinfo=tz.utc).timestamp()  # Now Thursday
                    await cmdr.runCmdLine('cron list')
                    await self.agenlen(1, core.eval('graph:node:type=month1'))

                    ##################

                    # Test year increment

                    await cmdr.runCmdLine(
                        "cron add -y +2 {[graph:node='*' :type=year1]}")
                    guid2 = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]
                    unixtime = datetime.datetime(
                        year=2021,
                        month=1,
                        day=1,
                        hour=0,
                        minute=0,
                        tzinfo=tz.utc).timestamp()  # Now Thursday
                    await cmdr.runCmdLine('cron list')
                    await self.agenlen(1, core.eval('graph:node:type=year1'))

                    # Make sure second-to-last day works for February
                    await cmdr.runCmdLine(
                        "cron add -m February -d=-2 {[graph:node='*' :type=year2]}"
                    )
                    unixtime = datetime.datetime(
                        year=2021,
                        month=2,
                        day=27,
                        hour=0,
                        minute=0,
                        tzinfo=tz.utc).timestamp()  # Now Thursday
                    await cmdr.runCmdLine('cron list')
                    await self.agenlen(1, core.eval('graph:node:type=year2'))

                    ##################

                    # Test 'at' command
                    outp.clear()
                    await cmdr.runCmdLine('at')
                    self.true(outp.expect('Adds a non-recurring'))

                    await cmdr.runCmdLine('at --not-a-real-flag')
                    self.true(outp.expect('the following arguments'))

                    await cmdr.runCmdLine('at {#foo} {#bar}')
                    self.true(outp.expect('only a single query'))

                    await cmdr.runCmdLine('at {#foo}')
                    self.true(outp.expect('at least'))

                    await cmdr.runCmdLine('at +1')
                    self.true(outp.expect('missing unit'))

                    await cmdr.runCmdLine('at +1parsec')
                    self.true(outp.expect('Trouble parsing'))

                    await cmdr.runCmdLine('at +1day')
                    self.true(outp.expect('Missing query'))

                    await cmdr.runCmdLine(
                        "at +5 minutes {[graph:node='*' :type=at1]}")
                    unixtime += 5 * MINSECS
                    await cmdr.runCmdLine('cron list')
                    await self.agenlen(1, core.eval('graph:node:type=at1'))

                    await cmdr.runCmdLine(
                        "at +1 day +7 days {[graph:node='*' :type=at2]}")
                    guid = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]
                    unixtime += DAYSECS
                    await self.agenlen(1, core.eval('graph:node:type=at2'))
                    unixtime += 6 * DAYSECS + 1
                    await cmdr.runCmdLine('cron list')
                    await self.agenlen(2, core.eval('graph:node:type=at2'))

                    await cmdr.runCmdLine(
                        "at 202104170415 {[graph:node='*' :type=at3]}")

                    unixtime = datetime.datetime(
                        year=2021,
                        month=4,
                        day=17,
                        hour=4,
                        minute=15,
                        tzinfo=tz.utc).timestamp()  # Now Thursday
                    await cmdr.runCmdLine('cron list')
                    await self.agenlen(1, core.eval('graph:node:type=at3'))
                    outp.clear()

                    ##################

                    # Test 'stat' command
                    await cmdr.runCmdLine(f'cron stat xxx')
                    self.true(outp.expect('provided iden does not match any'))

                    await cmdr.runCmdLine(f'cron stat {guid[:6]}')
                    self.true(
                        outp.expect(
                            'last result:     finished successfully with 1 nodes'
                        ))
                    self.true(outp.expect('entries:         <None>'))
                    await cmdr.runCmdLine(f'cron stat {guid2[:6]}')
                    self.true(
                        outp.expect(
                            "{'month': 1, 'hour': 0, 'minute': 0, 'dayofmonth': 1}"
                        ))
                    outp.clear()

                    ##################

                    # Test 'enable' 'disable' commands
                    await cmdr.runCmdLine(f'cron enable xxx')
                    self.true(outp.expect('provided iden does not match any'))
                    outp.clear()

                    await cmdr.runCmdLine(f'cron disable xxx')
                    self.true(outp.expect('provided iden does not match any'))
                    outp.clear()

                    await cmdr.runCmdLine(f'cron disable {guid[:6]}')
                    await cmdr.runCmdLine(f'cron stat {guid[:6]}')
                    self.true(outp.expect(f'enabled:         N'))
                    outp.clear()
                    await cmdr.runCmdLine(f'cron enable {guid[:6]}')
                    await cmdr.runCmdLine(f'cron stat {guid[:6]}')
                    self.true(outp.expect(f'enabled:         Y'))
                    outp.clear()

                    ###################

                    # Delete an expired at job
                    outp.clear()
                    await cmdr.runCmdLine(f"cron del {guid}")
                    self.true(outp.expect('Deleted cron job'))

                    ##################

                    # Test the aliases
                    outp.clear()
                    await cmdr.runCmdLine('cron add --hourly 15 {#bar}')
                    guid = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]
                    await cmdr.runCmdLine(f'cron stat {guid[:6]}')
                    self.true(outp.expect("{'minute': 15}"))

                    outp.clear()
                    await cmdr.runCmdLine('cron add --daily 05:47 {#bar}')
                    guid = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]
                    await cmdr.runCmdLine(f'cron stat {guid[:6]}')
                    self.true(outp.expect("{'hour': 5, 'minute': 47"))

                    outp.clear()
                    await cmdr.runCmdLine('cron add --monthly=-1:12:30 {#bar}')
                    guid = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]
                    await cmdr.runCmdLine(f'cron stat {guid[:6]}')
                    self.true(
                        outp.expect(
                            "{'hour': 12, 'minute': 30, 'dayofmonth': -1}"))

                    outp.clear()
                    await cmdr.runCmdLine(
                        'cron add --yearly 04:17:12:30 {#bar}')
                    guid = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]
                    await cmdr.runCmdLine(f'cron stat {guid[:6]}')
                    self.true(
                        outp.expect(
                            "{'month': 4, 'hour': 12, 'minute': 30, 'dayofmonth': 17}"
                        ))

                    outp.clear()
                    await cmdr.runCmdLine('cron add --yearly 04:17:12 {#bar}')
                    self.true(outp.expect('Failed to parse parameter'))

                    outp.clear()
                    await cmdr.runCmdLine('cron add --daily xx:xx {#bar}')
                    self.true(outp.expect('Failed to parse ..ly parameter'))

                    outp.clear()
                    await cmdr.runCmdLine('cron add --hourly 1 -M 17 {#bar}')
                    self.true(outp.expect('may not use both'))
Exemplo n.º 3
0
    async def test_prov(self):

        s_provenance.reset()

        async with self.getTestCore() as real, real.getLocalProxy() as core:

            # Non-existent iden
            self.none(await core.getProvStack('abcd'))

            await real.view.addTrigger({
                'cond': 'node:add',
                'form': 'test:str',
                'storm': '[ test:int=1 ]',
            })
            await s_common.aspin(core.eval('[ test:str=foo ]'))
            await self.agenlen(1, core.eval('test:int'))

            await self.agenlen(0, core.eval('test:int | delnode'))

            splices = await alist(core.splices(None, 1000))

            self.len(9, splices)
            idens = [splice[1][1].get('prov') for splice in splices]

            # source splices
            self.eq(idens[0], idens[1])
            self.eq(idens[0], idens[2])

            # test:str add
            self.eq(idens[3], idens[4])

            # trigger
            self.eq(idens[5], idens[6])

            # test:int delnode
            self.eq(idens[7], idens[8])

            provs = [await core.getProvStack(iden) for iden in idens]

            # The meta:source splices
            self.eq(({}, (('init', {'meth': '_initCoreMods'}),)), provs[0])

            # The test:str splices
            prov = provs[3][1]
            rootiden = prov[0][1]['user']
            s2 = ('storm', {'q': '[ test:str=foo ]', 'user': rootiden})
            self.eq((s2, ), prov)

            # Validate that the iden calc itself is correct
            rawprov = ({}, [('storm', (('q', '[ test:str=foo ]'), ('user', rootiden)))])
            hash = hashlib.md5(s_msgpack.en(rawprov)).hexdigest()
            self.eq(hash, idens[3])

            # The trigger splices
            prov = provs[5][1]
            s3 = ('trig', {'cond': 'node:add', 'form': 'test:str', 'tag': None, 'prop': None})
            s4 = ('storm', {'q': '[ test:int=1 ]', 'user': rootiden})
            self.eq((s2, s3, s4), prov)

            # prop:del/node:del
            prov = provs[7][1]
            ds2 = ('storm', {'q': 'test:int | delnode', 'user': rootiden})
            ds3 = ('stormcmd', {'name': 'delnode', 'argv': ()})
            self.eq((ds2, ds3), prov)

            # Test the streaming API
            provstacks = await alist(core.provStacks(0, 1000))
            correct = [(idens[0], provs[0]), (idens[5], provs[5]), (idens[3], provs[3]), (idens[7], provs[7])]
            self.eq(provstacks, correct)

            # Force recursion exception to be thrown
            q = '.created ' + '| uniq' * 257
            with self.raises(s_exc.RecursionLimitHit) as cm:
                _ = await real.nodes(q)
            self.eq(cm.exception.get('type'), 'stormcmd')
            self.eq(cm.exception.get('info'), {'name': 'uniq', 'argv': ()})
            baseframe = cm.exception.get('baseframe')
            name, args = baseframe
            self.eq(name, 'storm')
            self.eq(args[0], ('q', q))
            recent_frames = cm.exception.get('recent_frames')
            self.len(6, recent_frames)
            for frame in recent_frames:
                self.eq(frame, ('stormcmd', (('argv', ()), ('name', 'uniq'))))

            # Run a feed function and validate the user is recorded.
            await core.addFeedData('syn.nodes', [(('test:int', 1138), {})])
            # We have to brute force the last prov stack to get the data
            # Since we don't have splices to track
            stacks = await alist(core.provStacks(0, 1000))
            feed_stack = stacks[-1]
            frame = feed_stack[1][1][0]
            self.eq(frame[0], 'feed:data')
            self.eq(frame[1].get('name'), 'syn.nodes')
            self.isin('user', frame[1])
Exemplo n.º 4
0
    async def test_cron(self):
        MONO_DELT = 1543827303.0
        unixtime = datetime.datetime(year=2018, month=12, day=5, hour=7, minute=0, tzinfo=tz.utc).timestamp()
        s_provenance.reset()

        def timetime():
            return unixtime

        def looptime():
            return unixtime - MONO_DELT

        loop = asyncio.get_running_loop()

        with mock.patch.object(loop, 'time', looptime), mock.patch('time.time', timetime):
            async with self.getTestCoreAndProxy() as (realcore, core):

                outp = self.getTestOutp()
                async with await s_cmdr.getItemCmdr(core, outp=outp) as cmdr:

                    # Various silliness

                    await cmdr.runCmdLine('cron')
                    self.true(outp.expect('Manages cron jobs in a cortex'))
                    await cmdr.runCmdLine('cron timemachine')
                    self.true(outp.expect('invalid choice'))

                    await cmdr.runCmdLine('cron list')
                    self.true(outp.expect('No cron jobs found'))

                    await cmdr.runCmdLine('cron ls')
                    self.true(outp.expect('No cron jobs found'))

                    outp.clear()

                    await cmdr.runCmdLine("cron add -M+1,beeroclock {[graph:node='*' :type=m1]}")
                    self.true(outp.expect('failed to parse parameter'))

                    await cmdr.runCmdLine("cron add -m nosuchmonth -d=-2 {#foo}")
                    self.true(outp.expect('failed to parse fixed parameter'))

                    outp.clear()
                    await cmdr.runCmdLine("cron add -m 8nosuchmonth -d=-2 {#foo}")
                    self.true(outp.expect('failed to parse fixed parameter'))

                    await cmdr.runCmdLine("cron add -d Mon -m +3 {#foo}")
                    self.true(outp.expect('provide a recurrence value with day of week'))

                    await cmdr.runCmdLine("cron add -dMon -m June {#foo}")
                    self.true(outp.expect('fix month or year with day of week'))

                    await cmdr.runCmdLine("cron add -dMon -m +3 -y +2 {#foo}")
                    self.true(outp.expect('more than 1 recurrence'))

                    await cmdr.runCmdLine("cron add --year=2019 {#foo}")
                    self.true(outp.expect('year may not be a fixed value'))

                    await cmdr.runCmdLine("cron add {#foo}")
                    self.true(outp.expect('must provide at least one optional'))

                    await cmdr.runCmdLine("cron add -H3 -M +4 {#foo}")
                    self.true(outp.expect('fixed unit may not be larger'))

                    outp.clear()
                    await cmdr.runCmdLine('cron add -d Tuesday,1 {#foo}')
                    self.true(outp.expect('failed to parse day value'))

                    outp.clear()
                    await cmdr.runCmdLine('cron add -d Fri,3 {#foo}')
                    self.true(outp.expect('failed to parse day value'))

                    outp.clear()
                    await cmdr.runCmdLine('cron add }')
                    self.true(outp.expect('BadSyntax'))

                    # add a mechanism on which we can wait...
                    await realcore.nodes('$lib.queue.add(foo)')

                    async def getNextFoo():
                        return await asyncio.wait_for(realcore.callStorm('''
                            $foo = $lib.queue.get(foo)
                            ($offs, $retn) = $foo.get()
                            $foo.cull($offs)
                            return($retn)
                        '''), timeout=5)

                    ##################
                    # Start simple: add a cron job that creates a node every minute
                    outp.clear()
                    await cmdr.runCmdLine("cron add -M +1 {$lib.queue.get(foo).put(bar)}")
                    self.true(outp.expect('Created cron job'))
                    guid = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]

                    unixtime += 60
                    self.eq('bar', await getNextFoo())

                    await cmdr.runCmdLine('cron list')
                    self.true(outp.expect('(bar)'))

                    # Make sure it ran
                    await cmdr.runCmdLine(f"cron mod {guid[:6]} {{$lib.queue.get(foo).put(baz)}}")
                    self.true(outp.expect('Modified cron job'))
                    await cmdr.runCmdLine(f"cron edit xxx {{[graph:node='*' :type=m2]}}")
                    self.true(outp.expect('does not match'))
                    await cmdr.runCmdLine(f"cron mod xxx yyy")
                    self.true(outp.expect('expected second argument to start with {'))

                    # Make sure the old one didn't run and the new query ran
                    unixtime += 60
                    self.eq('baz', await getNextFoo())

                    outp.clear()

                    # Delete the job
                    await cmdr.runCmdLine(f"cron del {guid}")
                    self.true(outp.expect('Deleted cron job'))
                    await cmdr.runCmdLine(f"cron del xxx")
                    self.true(outp.expect('does not match'))
                    await cmdr.runCmdLine(f"cron rm xxx")
                    self.true(outp.expect('does not match'))

                    # Make sure deleted job didn't run
                    unixtime += 60
                    await asyncio.sleep(0)
                    self.eq(0, await realcore.callStorm('return($lib.queue.get(foo).size())'))

                    # Test fixed minute, i.e. every hour at 17 past
                    unixtime = datetime.datetime(year=2018, month=12, day=5, hour=7, minute=10,
                                                 tzinfo=tz.utc).timestamp()
                    await cmdr.runCmdLine("cron add -M 17 {$lib.queue.get(foo).put(faz)}")
                    guid = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]

                    unixtime += 7 * MINSECS

                    self.eq('faz', await getNextFoo())
                    await cmdr.runCmdLine(f"cron del {guid}")

                    ##################

                    # Test day increment
                    await cmdr.runCmdLine("cron add -d +2 {$lib.queue.get(foo).put(d1)}")
                    self.true(outp.expect('Created cron job'))
                    guid1 = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]

                    unixtime += DAYSECS

                    # Make sure it *didn't* run
                    await asyncio.sleep(0)
                    self.eq(0, await realcore.callStorm('return($lib.queue.get(foo).size())'))

                    unixtime += DAYSECS

                    self.eq('d1', await getNextFoo())

                    unixtime += DAYSECS * 2

                    outp.clear()
                    self.eq('d1', await getNextFoo())
                    await cmdr.runCmdLine(f"cron del {guid1}")
                    outp.expect('Deleted cron job')

                    ##################

                    # Test fixed day of week: every Monday and Thursday at 3am
                    unixtime = datetime.datetime(year=2018, month=12, day=11, hour=7, minute=10,
                                                 tzinfo=tz.utc).timestamp()  # A Tuesday

                    outp.clear()
                    await cmdr.runCmdLine("cron add -H 3 -d Mon,Thursday {$lib.queue.get(foo).put(d2)}")
                    self.true(outp.expect('Created cron job'))

                    guid2 = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]
                    unixtime = datetime.datetime(year=2018, month=12, day=12, hour=3, minute=10,
                                                 tzinfo=tz.utc).timestamp()  # Now Wednesday

                    outp.clear()
                    await cmdr.runCmdLine(f'cron stat {guid2}')
                    self.true(outp.expect('last start time: Never'))

                    unixtime = datetime.datetime(year=2018, month=12, day=13, hour=3, minute=10,
                                                 tzinfo=tz.utc).timestamp()  # Now Thursday

                    self.eq('d2', await getNextFoo())

                    outp.clear()
                    await cmdr.runCmdLine(f'cron stat {guid2}')
                    self.true(outp.expect('last start time: 2018'))
                    self.true(outp.expect('dayofweek       0'))

                    outp.clear()
                    await cmdr.runCmdLine(f"cron del {guid2}")
                    outp.expect('Deleted cron job')

                    await cmdr.runCmdLine("cron add -H 3 -d Noday {[graph:node='*' :type=d2]}")
                    self.true(outp.expect('failed to parse day value "Noday"'))

                    ##################

                    # Test fixed day of month: second-to-last day of month
                    await cmdr.runCmdLine("cron add -d-2 -mDec {$lib.queue.get(foo).put(d3)}")
                    guid = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]

                    unixtime = datetime.datetime(year=2018, month=12, day=29, hour=0, minute=0,
                                                 tzinfo=tz.utc).timestamp()  # Now Thursday

                    unixtime += DAYSECS

                    self.eq('d3', await getNextFoo())

                    outp.clear()
                    await cmdr.runCmdLine(f"cron del {guid}")
                    outp.expect('Deleted cron job')

                    ##################

                    # Test month increment

                    outp.clear()
                    await cmdr.runCmdLine("cron add -m +2 -d=4 {$lib.queue.get(foo).put(month1)}")
                    guid = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]
                    self.true(outp.expect('Created cron job'))

                    unixtime = datetime.datetime(year=2019, month=2, day=4, hour=0, minute=0,
                                                 tzinfo=tz.utc).timestamp()  # Now Thursday

                    self.eq('month1', await getNextFoo())

                    outp.clear()
                    await cmdr.runCmdLine(f"cron del {guid}")
                    outp.expect('Deleted cron job')

                    ##################

                    # Test year increment

                    outp.clear()
                    await cmdr.runCmdLine("cron add -y +2 {$lib.queue.get(foo).put(year1)}")
                    guid2 = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]
                    self.true(outp.expect('Created cron job'))

                    unixtime = datetime.datetime(year=2021, month=1, day=1, hour=0, minute=0,
                                                 tzinfo=tz.utc).timestamp()  # Now Thursday
                    self.eq('year1', await getNextFoo())

                    outp.clear()
                    await cmdr.runCmdLine(f'cron stat {guid2[:6]}')
                    self.true(outp.expect("{'month': 1, 'hour': 0, 'minute': 0, 'dayofmonth': 1}"))

                    outp.clear()
                    await cmdr.runCmdLine(f"cron del {guid2}")
                    outp.expect('Deleted cron job')

                    # Make sure second-to-last day works for February
                    outp.clear()
                    await cmdr.runCmdLine("cron add -m February -d=-2 {$lib.queue.get(foo).put(year2)}")
                    self.true(outp.expect('Created cron job'))

                    unixtime = datetime.datetime(year=2021, month=2, day=27, hour=0, minute=0,
                                                 tzinfo=tz.utc).timestamp()  # Now Thursday

                    self.eq('year2', await getNextFoo())

                    ##################

                    # Test 'at' command
                    outp.clear()
                    await cmdr.runCmdLine('at')
                    self.true(outp.expect('Adds a non-recurring'))

                    await cmdr.runCmdLine('at --not-a-real-flag')
                    self.true(outp.expect('the following arguments'))

                    await cmdr.runCmdLine('at {#foo} {#bar}')
                    self.true(outp.expect('only a single query'))

                    await cmdr.runCmdLine('at {#foo}')
                    self.true(outp.expect('at least'))

                    await cmdr.runCmdLine('at +1')
                    self.true(outp.expect('missing unit'))

                    await cmdr.runCmdLine('at +1parsec')
                    self.true(outp.expect('Trouble parsing'))

                    await cmdr.runCmdLine('at +1day')
                    self.true(outp.expect('Missing query'))

                    await cmdr.runCmdLine("at +5 minutes {$lib.queue.get(foo).put(at1)}")

                    unixtime += 5 * MINSECS

                    self.eq('at1', await getNextFoo())

                    await cmdr.runCmdLine("at +1 day +7 days {$lib.queue.get(foo).put(at2)}")
                    guid = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]

                    unixtime += DAYSECS

                    self.eq('at2', await getNextFoo())

                    unixtime += 6 * DAYSECS + 1

                    self.eq('at2', await getNextFoo())

                    await cmdr.runCmdLine("at 202104170415 {$lib.queue.get(foo).put(at3)}")

                    unixtime = datetime.datetime(year=2021, month=4, day=17, hour=4, minute=15,
                                                 tzinfo=tz.utc).timestamp()  # Now Thursday

                    self.eq('at3', await getNextFoo())
                    outp.clear()

                    ##################

                    # Test 'stat' command
                    await cmdr.runCmdLine(f'cron stat xxx')
                    self.true(outp.expect('provided iden does not match any'))

                    await cmdr.runCmdLine(f'cron stat {guid[:6]}')
                    self.true(outp.expect('last result:     finished successfully with 0 nodes'))
                    self.true(outp.expect('entries:         <None>'))

                    ##################

                    # Test 'enable' 'disable' commands
                    await cmdr.runCmdLine(f'cron enable xxx')
                    self.true(outp.expect('provided iden does not match any'))
                    outp.clear()

                    await cmdr.runCmdLine(f'cron disable xxx')
                    self.true(outp.expect('provided iden does not match any'))
                    outp.clear()

                    await cmdr.runCmdLine(f'cron disable {guid[:6]}')
                    await cmdr.runCmdLine(f'cron stat {guid[:6]}')
                    self.true(outp.expect(f'enabled:         N'))
                    outp.clear()
                    await cmdr.runCmdLine(f'cron enable {guid[:6]}')
                    await cmdr.runCmdLine(f'cron stat {guid[:6]}')
                    self.true(outp.expect(f'enabled:         Y'))
                    outp.clear()

                    ###################

                    # Delete an expired at job
                    outp.clear()
                    await cmdr.runCmdLine(f"cron del {guid}")
                    self.true(outp.expect('Deleted cron job'))

                    ##################

                    # Test the aliases
                    outp.clear()
                    await cmdr.runCmdLine('cron add --hourly 15 {#bar}')
                    guid = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]
                    await cmdr.runCmdLine(f'cron stat {guid[:6]}')
                    self.true(outp.expect("{'minute': 15}"))

                    outp.clear()
                    await cmdr.runCmdLine('cron add --daily 05:47 {#bar}')
                    guid = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]
                    await cmdr.runCmdLine(f'cron stat {guid[:6]}')
                    self.true(outp.expect("{'hour': 5, 'minute': 47"))

                    outp.clear()
                    await cmdr.runCmdLine('cron add --monthly=-1:12:30 {#bar}')
                    guid = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]
                    await cmdr.runCmdLine(f'cron stat {guid[:6]}')
                    self.true(outp.expect("{'hour': 12, 'minute': 30, 'dayofmonth': -1}"))

                    outp.clear()
                    await cmdr.runCmdLine('cron add --yearly 04:17:12:30 {#bar}')
                    guid = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]
                    await cmdr.runCmdLine(f'cron stat {guid[:6]}')
                    self.true(outp.expect("{'month': 4, 'hour': 12, 'minute': 30, 'dayofmonth': 17}"))

                    outp.clear()
                    await cmdr.runCmdLine('cron add --yearly 04:17:12 {#bar}')
                    self.true(outp.expect('Failed to parse parameter'))

                    outp.clear()
                    await cmdr.runCmdLine('cron add --daily xx:xx {#bar}')
                    self.true(outp.expect('Failed to parse ..ly parameter'))

                    outp.clear()
                    await cmdr.runCmdLine('cron add --hourly 1 -M 17 {#bar}')
                    self.true(outp.expect('may not use both'))

                # Test manipulating cron jobs as another user
                bond = await realcore.auth.addUser('bond')

                async with realcore.getLocalProxy(user='******') as tcore:
                    toutp = self.getTestOutp()
                    tcmdr = await s_cmdr.getItemCmdr(tcore, outp=toutp)

                    await tcmdr.runCmdLine('cron list')
                    self.true(toutp.expect('No cron jobs found'))

                    toutp.clear()
                    await tcmdr.runCmdLine(f'cron disable {guid[:6]}')
                    self.true(toutp.expect('provided iden does not match'))

                    toutp.clear()
                    await tcmdr.runCmdLine(f'cron enable {guid[:6]}')
                    self.true(toutp.expect('provided iden does not match'))

                    toutp.clear()
                    await tcmdr.runCmdLine(f'cron edit {guid[:6]} {{#foo}}')
                    self.true(toutp.expect('provided iden does not match'))

                    toutp.clear()
                    await tcmdr.runCmdLine(f'cron del {guid[:6]}')
                    self.true(toutp.expect('provided iden does not match'))

                    # Give explicit perm
                    await core.addUserRule(bond.iden, (True, ('cron', 'get')))

                    toutp.clear()
                    await tcmdr.runCmdLine('cron list')
                    self.true(toutp.expect('root'))

                    await core.addUserRule(bond.iden, (True, ('cron', 'set')))

                    toutp.clear()
                    await tcmdr.runCmdLine(f'cron disable {guid[:6]}')
                    self.true(toutp.expect('Disabled cron job'))

                    toutp.clear()
                    await tcmdr.runCmdLine(f'cron enable {guid[:6]}')
                    self.true(toutp.expect('Enabled cron job'))

                    toutp.clear()
                    await tcmdr.runCmdLine(f'cron edit {guid[:6]} {{#foo}}')
                    self.true(toutp.expect('Modified cron job'))

                    await core.addUserRule(bond.iden, (True, ('cron', 'del')))

                    toutp.clear()
                    await tcmdr.runCmdLine(f'cron del {guid[:6]}')
                    self.true(toutp.expect('Deleted cron job'))
Exemplo n.º 5
0
    async def test_cron(self):
        MONO_DELT = 1543827303.0
        unixtime = datetime.datetime(year=2018,
                                     month=12,
                                     day=5,
                                     hour=7,
                                     minute=0,
                                     tzinfo=tz.utc).timestamp()
        sync = asyncio.Event()
        lastquery = None
        s_provenance.reset()

        def timetime():
            return unixtime

        def looptime():
            return unixtime - MONO_DELT

        async def myeval(query, user=None):
            nonlocal lastquery
            lastquery = query
            sync.set()
            return
            yield None

        loop = asyncio.get_running_loop()

        with mock.patch.object(loop, 'time',
                               looptime), mock.patch('time.time', timetime):
            async with self.getTestCoreAndProxy() as (realcore, core):

                outp = self.getTestOutp()
                async with await s_cmdr.getItemCmdr(core, outp=outp) as cmdr:

                    async def waitForCron(guid):
                        '''
                        Because the wall clock is "frozen" for this test unless we manually advance it, we can't sleep
                        non-zero amounts.  However, we are running in the same asyncio loop as the agenda.  Just
                        sleep(0) in a loop until the cron job is not running anymore
                        '''
                        for _ in range(30):
                            await asyncio.sleep(0)
                            crons = await core.listCronJobs()
                            cron = [c for c in crons
                                    if c.get('iden') == guid][0]
                            if not cron['isrunning']:
                                break
                        else:
                            # the cron job didn't finish after ten sleeps?!
                            self.true(0)

                    # Various silliness

                    await cmdr.runCmdLine('cron')
                    self.true(outp.expect('Manages cron jobs in a cortex'))
                    await cmdr.runCmdLine('cron timemachine')
                    self.true(outp.expect('invalid choice'))

                    await cmdr.runCmdLine('cron list')
                    self.true(outp.expect('No cron jobs found'))

                    await cmdr.runCmdLine('cron ls')
                    self.true(outp.expect('No cron jobs found'))

                    outp.clear()

                    await cmdr.runCmdLine(
                        "cron add -M+1,beeroclock {[graph:node='*' :type=m1]}")
                    self.true(outp.expect('failed to parse parameter'))

                    await cmdr.runCmdLine(
                        "cron add -m nosuchmonth -d=-2 {#foo}")
                    self.true(outp.expect('failed to parse fixed parameter'))

                    outp.clear()
                    await cmdr.runCmdLine(
                        "cron add -m 8nosuchmonth -d=-2 {#foo}")
                    self.true(outp.expect('failed to parse fixed parameter'))

                    await cmdr.runCmdLine("cron add -d=, {#foo}")
                    self.true(outp.expect('failed to parse day value'))

                    await cmdr.runCmdLine("cron add -dMon -m +3 {#foo}")
                    self.true(
                        outp.expect(
                            'provide a recurrence value with day of week'))

                    await cmdr.runCmdLine("cron add -dMon -m June {#foo}")
                    self.true(
                        outp.expect('fix month or year with day of week'))

                    await cmdr.runCmdLine("cron add -dMon -m +3 -y +2 {#foo}")
                    self.true(outp.expect('more than 1 recurrence'))

                    await cmdr.runCmdLine("cron add --year=2019 {#foo}")
                    self.true(outp.expect('year may not be a fixed value'))

                    await cmdr.runCmdLine("cron add {#foo}")
                    self.true(
                        outp.expect('must provide at least one optional'))

                    await cmdr.runCmdLine("cron add -H3 -M +4 {#foo}")
                    self.true(outp.expect('fixed unit may not be larger'))

                    outp.clear()
                    await cmdr.runCmdLine('cron add -d Tuesday,1 {#foo}')
                    self.true(outp.expect('failed to parse day value'))

                    outp.clear()
                    await cmdr.runCmdLine('cron add -d Fri,3 {#foo}')
                    self.true(outp.expect('failed to parse day value'))

                    outp.clear()
                    await cmdr.runCmdLine('cron add }')
                    self.true(outp.expect('BadSyntax'))

                    ##################
                    # Start simple: add a cron job that creates a node every minute
                    outp.clear()
                    await cmdr.runCmdLine(
                        "cron add -M +1 {[graph:node='*' :type=m1]}")
                    self.true(outp.expect('Created cron job'))
                    guid = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]

                    unixtime += 60
                    await asyncio.sleep(0)
                    await cmdr.runCmdLine('cron list')
                    self.true(outp.expect(':type=m1'))

                    # Make sure it ran
                    await self.agenlen(1, core.eval('graph:node:type=m1'))

                    await cmdr.runCmdLine(
                        f"cron mod {guid[:6]} {{[graph:node='*' :type=m2]}}")
                    self.true(outp.expect('Modified cron job'))
                    await cmdr.runCmdLine(
                        f"cron edit xxx {{[graph:node='*' :type=m2]}}")
                    self.true(outp.expect('does not match'))
                    await cmdr.runCmdLine(f"cron mod xxx yyy")
                    self.true(
                        outp.expect(
                            'expected second argument to start with {'))

                    # Make sure the old one didn't run and the new query ran
                    unixtime += 60
                    await asyncio.sleep(0)
                    outp.clear()
                    await self.agenlen(1, core.eval('graph:node:type=m1'))
                    await self.agenlen(1, core.eval('graph:node:type=m2'))

                    outp.clear()

                    # Delete the job
                    await cmdr.runCmdLine(f"cron del {guid}")
                    self.true(outp.expect('Deleted cron job'))
                    await cmdr.runCmdLine(f"cron del xxx")
                    self.true(outp.expect('does not match'))
                    await cmdr.runCmdLine(f"cron rm xxx")
                    self.true(outp.expect('does not match'))

                    # Make sure deleted job didn't run
                    unixtime += 60
                    await asyncio.sleep(0)
                    await self.agenlen(1, core.eval('graph:node:type=m1'))
                    await self.agenlen(1, core.eval('graph:node:type=m2'))

                    # Test fixed minute, i.e. every hour at 17 past
                    unixtime = datetime.datetime(year=2018,
                                                 month=12,
                                                 day=5,
                                                 hour=7,
                                                 minute=10,
                                                 tzinfo=tz.utc).timestamp()
                    await cmdr.runCmdLine(
                        "cron add -M 17 {[graph:node='*' :type=m3]}")
                    guid = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]

                    unixtime += 7 * MINSECS
                    await asyncio.sleep(0)

                    # Make sure it runs.  We add the cron list to give the cron scheduler a chance to run
                    await cmdr.runCmdLine('cron list')
                    await self.agenlen(1, core.eval('graph:node:type=m3'))
                    await cmdr.runCmdLine(f"cron del {guid}")

                    ##################

                    # Test day increment
                    await cmdr.runCmdLine(
                        "cron add -d +2 {[graph:node='*' :type=d1]}")
                    self.true(outp.expect('Created cron job'))
                    guid1 = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]

                    unixtime += DAYSECS
                    await asyncio.sleep(0)

                    # Make sure it *didn't* run
                    await self.agenlen(0, core.eval('graph:node:type=d1'))

                    unixtime += DAYSECS
                    await asyncio.sleep(0)

                    # Make sure it runs.  We add the cron list to give the cron scheduler a chance to run

                    await cmdr.runCmdLine('cron list')
                    await self.agenlen(1, core.eval('graph:node:type=d1'))

                    unixtime += DAYSECS * 2
                    await asyncio.sleep(0)
                    await cmdr.runCmdLine('cron list')
                    await self.agenlen(2, core.eval('graph:node:type=d1'))

                    ##################

                    # Test fixed day of week: every Monday and Thursday at 3am
                    unixtime = datetime.datetime(
                        year=2018,
                        month=12,
                        day=11,
                        hour=7,
                        minute=10,
                        tzinfo=tz.utc).timestamp()  # A Tuesday
                    await asyncio.sleep(0)

                    await cmdr.runCmdLine(
                        "cron add -H 3 -d Mon,Thursday {[graph:node='*' :type=d2]}"
                    )
                    guid2 = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]
                    unixtime = datetime.datetime(
                        year=2018,
                        month=12,
                        day=13,
                        hour=3,
                        minute=10,
                        tzinfo=tz.utc).timestamp()  # Now Thursday
                    await asyncio.sleep(0)
                    await cmdr.runCmdLine('cron list')
                    await self.agenlen(1, core.eval('graph:node:type=d2'))

                    await cmdr.runCmdLine(f"cron del {guid1}")
                    await cmdr.runCmdLine(f"cron del {guid2}")

                    await cmdr.runCmdLine(
                        "cron add -H 3 -d Noday {[graph:node='*' :type=d2]}")
                    self.true(outp.expect('failed to parse day value "Noday"'))

                    ##################

                    # Test fixed day of month: second-to-last day of month
                    await cmdr.runCmdLine(
                        "cron add -d-2 -mDec {[graph:node='*' :type=d3]}")
                    guid = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]

                    unixtime = datetime.datetime(
                        year=2018,
                        month=12,
                        day=29,
                        hour=0,
                        minute=0,
                        tzinfo=tz.utc).timestamp()  # Now Thursday
                    await asyncio.sleep(0)
                    await cmdr.runCmdLine('cron list')
                    await self.agenlen(0, core.eval('graph:node:type=d3')
                                       )  # Not yet
                    unixtime += DAYSECS
                    await asyncio.sleep(0)
                    await cmdr.runCmdLine('cron list')
                    await self.agenlen(1, core.eval('graph:node:type=d3'))
                    await cmdr.runCmdLine(f"cron del {guid}")

                    ##################

                    # Test month increment

                    await cmdr.runCmdLine(
                        "cron add -m +2 -d=4 {[graph:node='*' :type=month1]}")

                    unixtime = datetime.datetime(
                        year=2019,
                        month=2,
                        day=4,
                        hour=0,
                        minute=0,
                        tzinfo=tz.utc).timestamp()  # Now Thursday
                    await asyncio.sleep(0)
                    await cmdr.runCmdLine('cron list')
                    await self.agenlen(1, core.eval('graph:node:type=month1'))

                    ##################

                    # Test year increment

                    await cmdr.runCmdLine(
                        "cron add -y +2 {[graph:node='*' :type=year1]}")
                    guid2 = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]
                    unixtime = datetime.datetime(
                        year=2021,
                        month=1,
                        day=1,
                        hour=0,
                        minute=0,
                        tzinfo=tz.utc).timestamp()  # Now Thursday
                    await asyncio.sleep(0)
                    await cmdr.runCmdLine('cron list')
                    await self.agenlen(1, core.eval('graph:node:type=year1'))

                    # Make sure second-to-last day works for February
                    await cmdr.runCmdLine(
                        "cron add -m February -d=-2 {[graph:node='*' :type=year2]}"
                    )
                    unixtime = datetime.datetime(
                        year=2021,
                        month=2,
                        day=27,
                        hour=0,
                        minute=0,
                        tzinfo=tz.utc).timestamp()  # Now Thursday
                    await asyncio.sleep(0)
                    await cmdr.runCmdLine('cron list')
                    await self.agenlen(1, core.eval('graph:node:type=year2'))

                    ##################

                    # Test 'at' command
                    outp.clear()
                    await cmdr.runCmdLine('at')
                    self.true(outp.expect('Adds a non-recurring'))

                    await cmdr.runCmdLine('at --not-a-real-flag')
                    self.true(outp.expect('the following arguments'))

                    await cmdr.runCmdLine('at {#foo} {#bar}')
                    self.true(outp.expect('only a single query'))

                    await cmdr.runCmdLine('at {#foo}')
                    self.true(outp.expect('at least'))

                    await cmdr.runCmdLine('at +1')
                    self.true(outp.expect('missing unit'))

                    await cmdr.runCmdLine('at +1parsec')
                    self.true(outp.expect('Trouble parsing'))

                    await cmdr.runCmdLine('at +1day')
                    self.true(outp.expect('Missing query'))

                    await cmdr.runCmdLine(
                        "at +5 minutes {[graph:node='*' :type=at1]}")

                    unixtime += 5 * MINSECS
                    await asyncio.sleep(0)

                    await cmdr.runCmdLine('cron list')
                    await self.agenlen(1, core.eval('graph:node:type=at1'))

                    await cmdr.runCmdLine(
                        "at +1 day +7 days {[graph:node='*' :type=at2]}")
                    guid = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]

                    unixtime += DAYSECS

                    await waitForCron(guid)

                    await self.agenlen(1, core.eval('graph:node:type=at2'))

                    unixtime += 6 * DAYSECS + 1
                    await asyncio.sleep(0)

                    await cmdr.runCmdLine('cron list')
                    await self.agenlen(2, core.eval('graph:node:type=at2'))

                    await cmdr.runCmdLine(
                        "at 202104170415 {[graph:node='*' :type=at3]}")

                    unixtime = datetime.datetime(
                        year=2021,
                        month=4,
                        day=17,
                        hour=4,
                        minute=15,
                        tzinfo=tz.utc).timestamp()  # Now Thursday
                    await asyncio.sleep(0)

                    await cmdr.runCmdLine('cron list')
                    await self.agenlen(1, core.eval('graph:node:type=at3'))
                    outp.clear()

                    ##################

                    # Test 'stat' command
                    await cmdr.runCmdLine(f'cron stat xxx')
                    self.true(outp.expect('provided iden does not match any'))

                    await cmdr.runCmdLine(f'cron stat {guid[:6]}')
                    self.true(
                        outp.expect(
                            'last result:     finished successfully with 1 nodes'
                        ))
                    self.true(outp.expect('entries:         <None>'))
                    await cmdr.runCmdLine(f'cron stat {guid2[:6]}')
                    self.true(
                        outp.expect(
                            "{'month': 1, 'hour': 0, 'minute': 0, 'dayofmonth': 1}"
                        ))
                    outp.clear()

                    ##################

                    # Test 'enable' 'disable' commands
                    await cmdr.runCmdLine(f'cron enable xxx')
                    self.true(outp.expect('provided iden does not match any'))
                    outp.clear()

                    await cmdr.runCmdLine(f'cron disable xxx')
                    self.true(outp.expect('provided iden does not match any'))
                    outp.clear()

                    await cmdr.runCmdLine(f'cron disable {guid[:6]}')
                    await cmdr.runCmdLine(f'cron stat {guid[:6]}')
                    self.true(outp.expect(f'enabled:         N'))
                    outp.clear()
                    await cmdr.runCmdLine(f'cron enable {guid[:6]}')
                    await cmdr.runCmdLine(f'cron stat {guid[:6]}')
                    self.true(outp.expect(f'enabled:         Y'))
                    outp.clear()

                    ###################

                    # Delete an expired at job
                    outp.clear()
                    await cmdr.runCmdLine(f"cron del {guid}")
                    self.true(outp.expect('Deleted cron job'))

                    ##################

                    # Test the aliases
                    outp.clear()
                    await cmdr.runCmdLine('cron add --hourly 15 {#bar}')
                    guid = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]
                    await cmdr.runCmdLine(f'cron stat {guid[:6]}')
                    self.true(outp.expect("{'minute': 15}"))

                    outp.clear()
                    await cmdr.runCmdLine('cron add --daily 05:47 {#bar}')
                    guid = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]
                    await cmdr.runCmdLine(f'cron stat {guid[:6]}')
                    self.true(outp.expect("{'hour': 5, 'minute': 47"))

                    outp.clear()
                    await cmdr.runCmdLine('cron add --monthly=-1:12:30 {#bar}')
                    guid = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]
                    await cmdr.runCmdLine(f'cron stat {guid[:6]}')
                    self.true(
                        outp.expect(
                            "{'hour': 12, 'minute': 30, 'dayofmonth': -1}"))

                    outp.clear()
                    await cmdr.runCmdLine(
                        'cron add --yearly 04:17:12:30 {#bar}')
                    guid = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]
                    await cmdr.runCmdLine(f'cron stat {guid[:6]}')
                    self.true(
                        outp.expect(
                            "{'month': 4, 'hour': 12, 'minute': 30, 'dayofmonth': 17}"
                        ))

                    outp.clear()
                    await cmdr.runCmdLine('cron add --yearly 04:17:12 {#bar}')
                    self.true(outp.expect('Failed to parse parameter'))

                    outp.clear()
                    await cmdr.runCmdLine('cron add --daily xx:xx {#bar}')
                    self.true(outp.expect('Failed to parse ..ly parameter'))

                    outp.clear()
                    await cmdr.runCmdLine('cron add --hourly 1 -M 17 {#bar}')
                    self.true(outp.expect('may not use both'))

                # Test manipulating cron jobs as another user
                await realcore.auth.addUser('bond')

                async with realcore.getLocalProxy(user='******') as tcore:
                    toutp = self.getTestOutp()
                    tcmdr = await s_cmdr.getItemCmdr(tcore, outp=toutp)

                    await tcmdr.runCmdLine('cron list')
                    self.true(toutp.expect('No cron jobs found'))

                    toutp.clear()
                    await tcmdr.runCmdLine(f'cron disable {guid[:6]}')
                    self.true(toutp.expect('provided iden does not match'))

                    toutp.clear()
                    await tcmdr.runCmdLine(f'cron enable {guid[:6]}')
                    self.true(toutp.expect('provided iden does not match'))

                    toutp.clear()
                    await tcmdr.runCmdLine(f'cron edit {guid[:6]} {{#foo}}')
                    self.true(toutp.expect('provided iden does not match'))

                    toutp.clear()
                    await tcmdr.runCmdLine(f'cron del {guid[:6]}')
                    self.true(toutp.expect('provided iden does not match'))

                    # Give explicit perm
                    await core.addUserRule('bond', (True, ('cron', 'get')))

                    toutp.clear()
                    await tcmdr.runCmdLine('cron list')
                    self.true(toutp.expect('root'))

                    await core.addUserRule('bond', (True, ('cron', 'set')))

                    toutp.clear()
                    await tcmdr.runCmdLine(f'cron disable {guid[:6]}')
                    self.true(toutp.expect('Disabled cron job'))

                    toutp.clear()
                    await tcmdr.runCmdLine(f'cron enable {guid[:6]}')
                    self.true(toutp.expect('Enabled cron job'))

                    toutp.clear()
                    await tcmdr.runCmdLine(f'cron edit {guid[:6]} {{#foo}}')
                    self.true(toutp.expect('Modified cron job'))

                    await core.addUserRule('bond', (True, ('cron', 'del')))

                    toutp.clear()
                    await tcmdr.runCmdLine(f'cron del {guid[:6]}')
                    self.true(toutp.expect('Deleted cron job'))
Exemplo n.º 6
0
    async def test_cron(self):
        MONO_DELT = 1543827303.0
        unixtime = datetime.datetime(year=2018, month=12, day=5, hour=7, minute=0, tzinfo=tz.utc).timestamp()
        sync = asyncio.Event()
        lastquery = None
        s_provenance.reset()

        def timetime():
            return unixtime

        def looptime():
            return unixtime - MONO_DELT

        async def myeval(query, user=None):
            nonlocal lastquery
            lastquery = query
            sync.set()
            return
            yield None

        loop = asyncio.get_running_loop()

        with mock.patch.object(loop, 'time', looptime), mock.patch('time.time', timetime):
            async with self.getTestCoreAndProxy() as (realcore, core):

                outp = self.getTestOutp()
                async with await s_cmdr.getItemCmdr(core, outp=outp) as cmdr:

                    # Various silliness

                    await cmdr.runCmdLine('cron')
                    self.true(outp.expect('Manages cron jobs in a cortex'))
                    await cmdr.runCmdLine('cron timemachine')
                    self.true(outp.expect('invalid choice'))

                    await cmdr.runCmdLine('cron list')
                    self.true(outp.expect('No cron jobs found'))

                    outp.clear()

                    await cmdr.runCmdLine("cron add -M+1,beeroclock {[graph:node='*' :type=m1]}")
                    self.true(outp.expect('failed to parse parameter'))

                    await cmdr.runCmdLine("cron add -m nosuchmonth -d=-2 {#foo}")
                    self.true(outp.expect('failed to parse fixed parameter'))

                    outp.clear()
                    await cmdr.runCmdLine("cron add -m 8nosuchmonth -d=-2 {#foo}")
                    self.true(outp.expect('failed to parse fixed parameter'))

                    await cmdr.runCmdLine("cron add -d=, {#foo}")
                    self.true(outp.expect('failed to parse day value'))

                    await cmdr.runCmdLine("cron add -dMon -m +3 {#foo}")
                    self.true(outp.expect('provide a recurrence value with day of week'))

                    await cmdr.runCmdLine("cron add -dMon -m June {#foo}")
                    self.true(outp.expect('fix month or year with day of week'))

                    await cmdr.runCmdLine("cron add -dMon -m +3 -y +2 {#foo}")
                    self.true(outp.expect('more than 1 recurrence'))

                    await cmdr.runCmdLine("cron add --year=2019 {#foo}")
                    self.true(outp.expect('year may not be a fixed value'))

                    await cmdr.runCmdLine("cron add {#foo}")
                    self.true(outp.expect('must provide at least one optional'))

                    await cmdr.runCmdLine("cron add -H3 -M +4 {#foo}")
                    self.true(outp.expect('fixed unit may not be larger'))

                    outp.clear()
                    await cmdr.runCmdLine('cron add -d Tuesday,1 {#foo}')
                    self.true(outp.expect('failed to parse day value'))

                    outp.clear()
                    await cmdr.runCmdLine('cron add -d Fri,3 {#foo}')
                    self.true(outp.expect('failed to parse day value'))

                    outp.clear()
                    await cmdr.runCmdLine('cron add }')
                    self.true(outp.expect('query parameter must start with {'))

                    ##################
                    oldsplices = len(await alist(core.splices(0, 1000)))

                    # Start simple: add a cron job that creates a node every minute
                    outp.clear()
                    await cmdr.runCmdLine("cron add -M +1 {[graph:node='*' :type=m1]}")
                    self.true(outp.expect('Created cron job'))
                    guid = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]

                    unixtime += 60
                    await cmdr.runCmdLine('cron list')
                    self.true(outp.expect(':type=m1'))

                    # Make sure it ran
                    await self.agenlen(1, core.eval('graph:node:type=m1'))

                    # Make sure the provenance of the new splices looks right
                    splices = await alist(core.splices(oldsplices, 1000))
                    self.gt(len(splices), 1)
                    aliases = [splice[1]['prov'] for splice in splices]
                    self.true(all(a == aliases[0] for a in aliases))
                    prov = await core.getProvStack(aliases[0])
                    rootiden = prov[1][1][1]['user']
                    correct = ({}, (
                               ('cron', {'iden': guid}),
                               ('storm', {'q': "[graph:node='*' :type=m1]", 'user': rootiden})))
                    self.eq(prov, correct)

                    await cmdr.runCmdLine(f"cron mod {guid[:6]} {{[graph:node='*' :type=m2]}}")
                    self.true(outp.expect('Modified cron job'))
                    await cmdr.runCmdLine(f"cron mod xxx {{[graph:node='*' :type=m2]}}")
                    self.true(outp.expect('does not match'))
                    await cmdr.runCmdLine(f"cron mod xxx yyy")
                    self.true(outp.expect('expected second argument to start with {'))

                    # Make sure the old one didn't run and the new query ran
                    unixtime += 60
                    await self.agenlen(1, core.eval('graph:node:type=m1'))
                    await self.agenlen(1, core.eval('graph:node:type=m2'))

                    outp.clear()

                    # Delete the job
                    await cmdr.runCmdLine(f"cron del {guid}")
                    self.true(outp.expect('Deleted cron job'))
                    await cmdr.runCmdLine(f"cron del xxx")
                    self.true(outp.expect('does not match'))

                    # Make sure deleted job didn't run
                    unixtime += 60
                    await self.agenlen(1, core.eval('graph:node:type=m1'))
                    await self.agenlen(1, core.eval('graph:node:type=m2'))

                    # Test fixed minute, i.e. every hour at 17 past
                    unixtime = datetime.datetime(year=2018, month=12, day=5, hour=7, minute=10,
                                                 tzinfo=tz.utc).timestamp()
                    await cmdr.runCmdLine("cron add -M 17 {[graph:node='*' :type=m3]}")
                    guid = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]

                    unixtime += 7 * MINSECS

                    # Make sure it runs.  We add the cron list to give the cron scheduler a chance to run
                    await cmdr.runCmdLine('cron list')
                    await self.agenlen(1, core.eval('graph:node:type=m3'))
                    await cmdr.runCmdLine(f"cron del {guid}")

                    ##################

                    # Test day increment
                    await cmdr.runCmdLine("cron add -d +2 {[graph:node='*' :type=d1]}")
                    self.true(outp.expect('Created cron job'))
                    guid1 = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]

                    unixtime += DAYSECS

                    # Make sure it *didn't* run
                    await self.agenlen(0, core.eval('graph:node:type=d1'))

                    unixtime += DAYSECS

                    # Make sure it runs.  We add the cron list to give the cron scheduler a chance to run

                    await cmdr.runCmdLine('cron list')
                    await self.agenlen(1, core.eval('graph:node:type=d1'))

                    unixtime += DAYSECS * 2
                    await cmdr.runCmdLine('cron list')
                    await self.agenlen(2, core.eval('graph:node:type=d1'))

                    ##################

                    # Test fixed day of week: every Monday and Thursday at 3am
                    unixtime = datetime.datetime(year=2018, month=12, day=11, hour=7, minute=10,
                                                 tzinfo=tz.utc).timestamp()  # A Tuesday

                    await cmdr.runCmdLine("cron add -H 3 -d Mon,Thursday {[graph:node='*' :type=d2]}")
                    guid2 = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]
                    unixtime = datetime.datetime(year=2018, month=12, day=13, hour=3, minute=10,
                                                 tzinfo=tz.utc).timestamp()  # Now Thursday
                    await cmdr.runCmdLine('cron list')
                    await self.agenlen(1, core.eval('graph:node:type=d2'))

                    await cmdr.runCmdLine(f"cron del {guid1}")
                    await cmdr.runCmdLine(f"cron del {guid2}")

                    await cmdr.runCmdLine("cron add -H 3 -d Noday {[graph:node='*' :type=d2]}")
                    self.true(outp.expect('failed to parse day value "Noday"'))

                    ##################

                    # Test fixed day of month: second-to-last day of month
                    await cmdr.runCmdLine("cron add -d-2 -mDec {[graph:node='*' :type=d3]}")
                    guid = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]

                    unixtime = datetime.datetime(year=2018, month=12, day=29, hour=0, minute=0,
                                                 tzinfo=tz.utc).timestamp()  # Now Thursday
                    await cmdr.runCmdLine('cron list')
                    await self.agenlen(0, core.eval('graph:node:type=d3'))  # Not yet
                    unixtime += DAYSECS
                    await cmdr.runCmdLine('cron list')
                    await self.agenlen(1, core.eval('graph:node:type=d3'))
                    await cmdr.runCmdLine(f"cron del {guid}")

                    ##################

                    # Test month increment

                    await cmdr.runCmdLine("cron add -m +2 -d=4 {[graph:node='*' :type=month1]}")

                    unixtime = datetime.datetime(year=2019, month=2, day=4, hour=0, minute=0,
                                                 tzinfo=tz.utc).timestamp()  # Now Thursday
                    await cmdr.runCmdLine('cron list')
                    await self.agenlen(1, core.eval('graph:node:type=month1'))

                    ##################

                    # Test year increment

                    await cmdr.runCmdLine("cron add -y +2 {[graph:node='*' :type=year1]}")
                    guid2 = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]
                    unixtime = datetime.datetime(year=2021, month=1, day=1, hour=0, minute=0,
                                                 tzinfo=tz.utc).timestamp()  # Now Thursday
                    await cmdr.runCmdLine('cron list')
                    await self.agenlen(1, core.eval('graph:node:type=year1'))

                    # Make sure second-to-last day works for February
                    await cmdr.runCmdLine("cron add -m February -d=-2 {[graph:node='*' :type=year2]}")
                    unixtime = datetime.datetime(year=2021, month=2, day=27, hour=0, minute=0,
                                                 tzinfo=tz.utc).timestamp()  # Now Thursday
                    await cmdr.runCmdLine('cron list')
                    await self.agenlen(1, core.eval('graph:node:type=year2'))

                    ##################

                    # Test 'at' command
                    outp.clear()
                    await cmdr.runCmdLine('at')
                    self.true(outp.expect('Adds a non-recurring'))

                    await cmdr.runCmdLine('at --not-a-real-flag')
                    self.true(outp.expect('the following arguments'))

                    await cmdr.runCmdLine('at {#foo} {#bar}')
                    self.true(outp.expect('only a single query'))

                    await cmdr.runCmdLine('at {#foo}')
                    self.true(outp.expect('at least'))

                    await cmdr.runCmdLine('at +1')
                    self.true(outp.expect('missing unit'))

                    await cmdr.runCmdLine('at +1parsec')
                    self.true(outp.expect('Trouble parsing'))

                    await cmdr.runCmdLine('at +1day')
                    self.true(outp.expect('Missing query'))

                    await cmdr.runCmdLine("at +5 minutes {[graph:node='*' :type=at1]}")
                    unixtime += 5 * MINSECS
                    await cmdr.runCmdLine('cron list')
                    await self.agenlen(1, core.eval('graph:node:type=at1'))

                    await cmdr.runCmdLine("at +1 day +7 days {[graph:node='*' :type=at2]}")
                    guid = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]
                    unixtime += DAYSECS
                    await self.agenlen(1, core.eval('graph:node:type=at2'))
                    unixtime += 6 * DAYSECS + 1
                    await cmdr.runCmdLine('cron list')
                    await self.agenlen(2, core.eval('graph:node:type=at2'))

                    await cmdr.runCmdLine("at 202104170415 {[graph:node='*' :type=at3]}")

                    unixtime = datetime.datetime(year=2021, month=4, day=17, hour=4, minute=15,
                                                 tzinfo=tz.utc).timestamp()  # Now Thursday
                    await cmdr.runCmdLine('cron list')
                    await self.agenlen(1, core.eval('graph:node:type=at3'))
                    ##################

                    # Test 'stat' command

                    await cmdr.runCmdLine(f'cron stat xxx')
                    self.true(outp.expect('provided iden does not match any'))

                    await cmdr.runCmdLine(f'cron stat {guid[:6]}')
                    self.true(outp.expect('last result:     finished successfully with 1 nodes'))
                    self.true(outp.expect('entries:         <None>'))
                    await cmdr.runCmdLine(f'cron stat {guid2[:6]}')
                    self.true(outp.expect("{'month': 1, 'hour': 0, 'minute': 0, 'dayofmonth': 1}"))

                    ##################

                    # Delete an expired at job
                    outp.clear()
                    await cmdr.runCmdLine(f"cron del {guid}")
                    self.true(outp.expect('Deleted cron job'))

                    ##################

                    # Test the aliases
                    outp.clear()
                    await cmdr.runCmdLine('cron add --hourly 15 {#bar}')
                    guid = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]
                    await cmdr.runCmdLine(f'cron stat {guid[:6]}')
                    self.true(outp.expect("{'minute': 15}"))

                    outp.clear()
                    await cmdr.runCmdLine('cron add --daily 05:47 {#bar}')
                    guid = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]
                    await cmdr.runCmdLine(f'cron stat {guid[:6]}')
                    self.true(outp.expect("{'hour': 5, 'minute': 47"))

                    outp.clear()
                    await cmdr.runCmdLine('cron add --monthly=-1:12:30 {#bar}')
                    guid = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]
                    await cmdr.runCmdLine(f'cron stat {guid[:6]}')
                    self.true(outp.expect("{'hour': 12, 'minute': 30, 'dayofmonth': -1}"))

                    outp.clear()
                    await cmdr.runCmdLine('cron add --yearly 04:17:12:30 {#bar}')
                    guid = outp.mesgs[-1].strip().rsplit(' ', 1)[-1]
                    await cmdr.runCmdLine(f'cron stat {guid[:6]}')
                    self.true(outp.expect("{'month': 4, 'hour': 12, 'minute': 30, 'dayofmonth': 17}"))

                    outp.clear()
                    await cmdr.runCmdLine('cron add --yearly 04:17:12 {#bar}')
                    self.true(outp.expect('Failed to parse parameter'))

                    outp.clear()
                    await cmdr.runCmdLine('cron add --daily xx:xx {#bar}')
                    self.true(outp.expect('Failed to parse ..ly parameter'))

                    outp.clear()
                    await cmdr.runCmdLine('cron add --hourly 1 -M 17 {#bar}')
                    self.true(outp.expect('may not use both'))