Example #1
0
    def compare_conditions(
        self,
        subscription: SubscriptionData,
        exception: Optional[Type[Exception]],
        aggregate: str,
        value: Union[int, float],
    ) -> None:
        timer = Timer("test")
        if exception is not None:
            with pytest.raises(exception):
                request = subscription.build_request(
                    self.dataset,
                    datetime.utcnow(),
                    100,
                    timer,
                )
                parse_and_run_query(self.dataset, request, timer)
            return

        request = subscription.build_request(
            self.dataset,
            datetime.utcnow(),
            100,
            timer,
        )
        result = parse_and_run_query(self.dataset, request, timer)

        assert result.result["data"][0][aggregate] == value
Example #2
0
    def test_invalid_time_window(self):
        creator = SubscriptionCreator(self.dataset)
        with raises(InvalidSubscriptionError):
            creator.create(
                SubscriptionData(
                    123,
                    [["platfo", "IN", ["a"]]],
                    [["count()", "", "count"]],
                    timedelta(),
                    timedelta(minutes=1),
                ),
                self.timer,
            )

        with raises(InvalidSubscriptionError):
            creator.create(
                SubscriptionData(
                    123,
                    [["platfo", "IN", ["a"]]],
                    [["count()", "", "count"]],
                    timedelta(hours=48),
                    timedelta(minutes=1),
                ),
                self.timer,
            )
Example #3
0
def test_subscription_task_result_encoder() -> None:
    codec = SubscriptionTaskResultEncoder()

    timestamp = datetime.now()

    entity_subscription = EventsSubscription(data_dict={})
    subscription_data = SubscriptionData(
        project_id=1,
        query="MATCH (events) SELECT count() AS count",
        time_window_sec=60,
        resolution_sec=60,
        entity_subscription=entity_subscription,
    )

    # XXX: This seems way too coupled to the dataset.
    request = subscription_data.build_request(get_dataset("events"), timestamp,
                                              None, Timer("timer"))
    result: Result = {
        "meta": [{
            "type": "UInt64",
            "name": "count"
        }],
        "data": [{
            "count": 1
        }],
    }

    task_result = SubscriptionTaskResult(
        ScheduledSubscriptionTask(
            timestamp,
            SubscriptionWithMetadata(
                EntityKey.EVENTS,
                Subscription(
                    SubscriptionIdentifier(PartitionId(1), uuid.uuid1()),
                    subscription_data,
                ),
                5,
            ),
        ),
        (request, result),
    )

    message = codec.encode(task_result)
    data = json.loads(message.value.decode("utf-8"))
    assert data["version"] == 3
    payload = data["payload"]

    assert payload["subscription_id"] == str(
        task_result.task.task.subscription.identifier)
    assert payload["request"] == request.original_body
    assert payload["result"] == result
    assert payload["timestamp"] == task_result.task.timestamp.isoformat()
    assert payload["entity"] == EntityKey.EVENTS.value
Example #4
0
    def create(self, data: SubscriptionData, timer: Timer) -> SubscriptionIdentifier:
        data.validate()
        self._test_request(data, timer)

        identifier = SubscriptionIdentifier(
            self.__partitioner.build_partition_id(data),
            uuid1(),
        )
        RedisSubscriptionDataStore(
            redis_client, self.entity_key, identifier.partition
        ).create(
            identifier.uuid,
            data,
        )
        return identifier
Example #5
0
    def test(self) -> None:
        creator = SubscriptionCreator(self.dataset, EntityKey.EVENTS)
        subscription = SubscriptionData(
            project_id=1,
            query="MATCH (events) SELECT count() AS count",
            time_window_sec=10 * 60,
            resolution_sec=60,
            entity_subscription=create_entity_subscription(),
        )
        identifier = creator.create(subscription, Timer("test"))
        assert (cast(
            List[Tuple[UUID, SubscriptionData]],
            RedisSubscriptionDataStore(
                redis_client,
                self.entity_key,
                identifier.partition,
            ).all(),
        )[0][1] == subscription)

        SubscriptionDeleter(self.entity_key,
                            identifier.partition).delete(identifier.uuid)
        assert (RedisSubscriptionDataStore(
            redis_client,
            self.entity_key,
            identifier.partition,
        ).all() == [])
Example #6
0
    def decode(self, value: bytes) -> SubscriptionData:
        try:
            data = json.loads(value.decode("utf-8"))
        except json.JSONDecodeError:
            raise InvalidQueryException("Invalid JSON")

        return SubscriptionData.from_dict(data, self.entity_key)
Example #7
0
    def test_encode(self):
        result = SubscriptionResult(
            ScheduledTask(
                datetime.now(),
                Subscription(
                    SubscriptionIdentifier(PartitionId(1), uuid.uuid1()),
                    SubscriptionData(
                        1,
                        [],
                        [["count()", "", "count"]],
                        timedelta(minutes=1),
                        timedelta(minutes=1),
                    ),
                ),
            ),
            {"data": {
                "count": 100
            }},
        )

        codec = SubscriptionResultCodec()
        message = codec.encode(result)
        data = json.loads(message.value.decode("utf-8"))
        assert data["version"] == 1
        payload = data["payload"]

        assert payload["subscription_id"] == str(result.task.task.identifier)
        assert payload["values"] == result.result
        assert payload["timestamp"] == result.task.timestamp.isoformat()
Example #8
0
    def test(self):
        executor = SubscriptionExecutor(self.dataset, ThreadPoolExecutor(),
                                        DummyMetricsBackend(strict=True))

        subscription = Subscription(
            SubscriptionIdentifier(PartitionId(0), uuid1()),
            SubscriptionData(
                project_id=self.project_id,
                conditions=[["platform", "IN", ["a"]]],
                aggregations=[["count()", "", "count"]],
                time_window=timedelta(minutes=500),
                resolution=timedelta(minutes=1),
            ),
        )

        now = datetime.utcnow()
        tick = Tick(
            offsets=Interval(1, 2),
            timestamps=Interval(now - timedelta(minutes=1), now),
        )

        result = executor.execute(ScheduledTask(now, subscription),
                                  tick).result()
        assert result["data"][0]["count"] == 10

        result = executor.execute(
            ScheduledTask(
                now + timedelta(minutes=self.minutes) +
                subscription.data.time_window,
                subscription,
            ),
            tick,
        ).result()

        assert result["data"][0]["count"] == 0
Example #9
0
def test_subscription_task_result_encoder() -> None:
    codec = SubscriptionTaskResultEncoder()

    timestamp = datetime.now()

    subscription_data = SubscriptionData(
        1,
        [],
        [["count()", "", "count"]],
        timedelta(minutes=1),
        timedelta(minutes=1),
    )

    # XXX: This seems way too coupled to the dataset.
    request = subscription_data.build_request(get_dataset("events"), timestamp,
                                              None, Timer("timer"))
    result: Result = {
        "meta": [{
            "type": "UInt64",
            "name": "count"
        }],
        "data": [{
            "count": 1
        }],
    }

    task_result = SubscriptionTaskResult(
        ScheduledTask(
            timestamp,
            Subscription(
                SubscriptionIdentifier(PartitionId(1), uuid.uuid1()),
                subscription_data,
            ),
        ),
        (request, result),
    )

    message = codec.encode(task_result)
    data = json.loads(message.value.decode("utf-8"))
    assert data["version"] == 2
    payload = data["payload"]

    assert payload["subscription_id"] == str(task_result.task.task.identifier)
    assert payload["request"] == request.body
    assert payload["result"] == result
    assert payload["timestamp"] == task_result.task.timestamp.isoformat()
Example #10
0
 def subscription(self) -> SubscriptionData:
     return SubscriptionData(
         project_id=self.project_id,
         conditions=[["platform", "IN", ["a"]]],
         aggregations=[["count()", "", "count"]],
         time_window=timedelta(minutes=500),
         resolution=timedelta(minutes=1),
     )
Example #11
0
 def test_conditions(self) -> None:
     subscription = SubscriptionData(
         project_id=self.project_id,
         conditions=[["platform", "IN", ["a"]]],
         aggregations=[["count()", "", "count"]],
         time_window=timedelta(minutes=500),
         resolution=timedelta(minutes=1),
     )
     timer = Timer("test")
     request = subscription.build_request(
         self.dataset,
         datetime.utcnow(),
         100,
         timer,
     )
     result = parse_and_run_query(self.dataset, request, timer)
     assert result.result["data"][0]["count"] == 10
Example #12
0
 def subscription(self) -> Sequence[SubscriptionData]:
     return [
         SubscriptionData(
             project_id=self.project_id,
             query="MATCH (events) SELECT count() WHERE in(platform, 'a')",
             time_window_sec=500 * 60,
             resolution_sec=60,
             entity_subscription=create_entity_subscription(),
         ),
         SubscriptionData(
             project_id=self.project_id,
             time_window_sec=500 * 60,
             resolution_sec=60,
             query="MATCH (events) SELECT count() WHERE in(platform, 'a')",
             entity_subscription=create_entity_subscription(),
         ),
     ]
Example #13
0
    def create(self, data: SubscriptionData, timer: Timer) -> SubscriptionIdentifier:
        # We want to test the query out here to make sure it's valid and can run
        # If there is a delegate subscription, we need to run both the SnQL and Legacy validator
        if isinstance(data, DelegateSubscriptionData):
            self._test_request(data.to_snql(), timer)
            self._test_request(data.to_legacy(), timer)
        else:
            self._test_request(data, timer)

        identifier = SubscriptionIdentifier(
            self.__partitioner.build_partition_id(data), uuid1(),
        )
        RedisSubscriptionDataStore(
            redis_client, self.dataset, identifier.partition
        ).create(
            identifier.uuid, data,
        )
        return identifier
Example #14
0
 def decode(self, value: bytes) -> SubscriptionData:
     data = json.loads(value.decode("utf-8"))
     return SubscriptionData(
         project_id=data["project_id"],
         conditions=data["conditions"],
         aggregations=data["aggregations"],
         time_window=timedelta(seconds=data["time_window"]),
         resolution=timedelta(seconds=data["resolution"]),
     )
Example #15
0
    def test_invalid_time_window(self) -> None:
        creator = SubscriptionCreator(self.dataset, EntityKey.EVENTS)
        with raises(InvalidSubscriptionError):
            creator.create(
                SubscriptionData(
                    project_id=123,
                    time_window_sec=0,
                    resolution_sec=60,
                    query=
                    "MATCH (events) SELECT count() AS count WHERE platfo IN tuple('a')",
                    entity_subscription=create_entity_subscription(),
                ),
                self.timer,
            )

        with raises(InvalidSubscriptionError):
            creator.create(
                SubscriptionData(
                    project_id=123,
                    query=("MATCH (events) "
                           "SELECT count() AS count BY time "
                           "WHERE "
                           "platform IN tuple('a') "),
                    time_window_sec=0,
                    resolution_sec=60,
                    entity_subscription=create_entity_subscription(),
                ),
                self.timer,
            )

        with raises(InvalidSubscriptionError):
            creator.create(
                SubscriptionData(
                    project_id=123,
                    time_window_sec=48 * 60 * 60,
                    resolution_sec=60,
                    query=
                    "MATCH (events) SELECT count() AS count WHERE platfo IN tuple('a')",
                    entity_subscription=create_entity_subscription(),
                ),
                self.timer,
            )
Example #16
0
 def build_subscription(self, resolution: timedelta) -> Subscription:
     return Subscription(
         SubscriptionIdentifier(self.partition_id, uuid.uuid4()),
         SubscriptionData(
             project_id=1,
             query="MATCH (events) SELECT count() AS count",
             time_window_sec=60,
             resolution_sec=int(resolution.total_seconds()),
             entity_subscription=create_entity_subscription(),
         ),
     )
Example #17
0
def build_subscription(resolution: timedelta, sequence: int) -> Subscription:
    entity_subscription = EventsSubscription(data_dict={})
    return Subscription(
        SubscriptionIdentifier(PartitionId(1), UUIDS[sequence]),
        SubscriptionData(
            project_id=1,
            time_window_sec=int(timedelta(minutes=5).total_seconds()),
            resolution_sec=int(resolution.total_seconds()),
            query="MATCH events SELECT count()",
            entity_subscription=entity_subscription,
        ),
    )
Example #18
0
 def test_invalid_aggregation(self):
     creator = SubscriptionCreator(self.dataset)
     with raises(QueryException):
         creator.create(
             SubscriptionData(
                 123,
                 [["platform", "IN", ["a"]]],
                 [["cout()", "", "count"]],
                 timedelta(minutes=10),
                 timedelta(minutes=1),
             ),
             self.timer,
         )
Example #19
0
    def test_conditions(self, subscription: SubscriptionData,
                        exception: Optional[Exception]) -> None:
        timer = Timer("test")
        if exception is not None:
            with pytest.raises(exception):
                request = subscription.build_request(
                    self.dataset,
                    datetime.utcnow(),
                    100,
                    timer,
                )
                result = parse_and_run_query(self.dataset, request, timer)
            return

        request = subscription.build_request(
            self.dataset,
            datetime.utcnow(),
            100,
            timer,
        )
        result = parse_and_run_query(self.dataset, request, timer)
        assert result.result["data"][0]["count"] == 10
Example #20
0
 def test(self):
     creator = SubscriptionCreator(self.dataset)
     subscription = SubscriptionData(
         project_id=123,
         conditions=[["platform", "IN", ["a"]]],
         aggregations=[["count()", "", "count"]],
         time_window=timedelta(minutes=10),
         resolution=timedelta(minutes=1),
     )
     identifier = creator.create(subscription, self.timer)
     RedisSubscriptionDataStore(
         redis_client, self.dataset, identifier.partition,
     ).all()[0][1] == subscription
Example #21
0
def build_snql_subscription_data(
    entity_key: EntityKey,
    organization: Optional[int] = None,
) -> SubscriptionData:

    return SubscriptionData(
        project_id=5,
        time_window_sec=500 * 60,
        resolution_sec=60,
        query="MATCH events SELECT count() WHERE in(platform, 'a')",
        entity_subscription=create_entity_subscription(entity_key,
                                                       organization),
    )
def create_subscription() -> None:
    store = RedisSubscriptionDataStore(redis_client, EntityKey.EVENTS,
                                       PartitionId(0))
    store.create(
        uuid.uuid4(),
        SubscriptionData(
            project_id=1,
            time_window_sec=60,
            resolution_sec=60,
            query="MATCH (events) SELECT count()",
            entity_subscription=EventsSubscription(data_dict={}),
        ),
    )
Example #23
0
 def test_invalid_resolution(self):
     creator = SubscriptionCreator(self.dataset)
     with raises(InvalidSubscriptionError):
         creator.create(
             SubscriptionData(
                 123,
                 [["platfo", "IN", ["a"]]],
                 [["count()", "", "count"]],
                 timedelta(minutes=1),
                 timedelta(),
             ),
             Mock(),
         )
Example #24
0
 def test_invalid_condition_column(self):
     creator = SubscriptionCreator(self.dataset)
     with raises(RawQueryException):
         creator.create(
             SubscriptionData(
                 123,
                 [["platfo", "IN", ["a"]]],
                 [["count()", "", "count"]],
                 timedelta(minutes=10),
                 timedelta(minutes=1),
             ),
             Mock(),
         )
Example #25
0
 def test_invalid_aggregation(self) -> None:
     creator = SubscriptionCreator(self.dataset, EntityKey.EVENTS)
     with raises(QueryException):
         creator.create(
             SubscriptionData(
                 project_id=123,
                 time_window_sec=10 * 60,
                 resolution_sec=60,
                 query=
                 "MATCH (events) SELECT cout() AS count WHERE platform IN tuple('a')",
                 entity_subscription=create_entity_subscription(),
             ),
             self.timer,
         )
Example #26
0
 def create(self, data: SubscriptionData,
            timer: Timer) -> SubscriptionIdentifier:
     # We want to test the query out here to make sure it's valid and can run
     request = data.build_request(self.dataset, datetime.utcnow(), None,
                                  timer)
     parse_and_run_query(self.dataset, request, timer)
     identifier = SubscriptionIdentifier(
         self.__partitioner.build_partition_id(data),
         uuid1(),
     )
     RedisSubscriptionDataStore(redis_client, self.dataset,
                                identifier.partition).create(
                                    identifier.uuid,
                                    data,
                                )
     return identifier
Example #27
0
    def test(self):
        creator = SubscriptionCreator(self.dataset)
        subscription = SubscriptionData(
            project_id=1,
            conditions=[],
            aggregations=[["count()", "", "count"]],
            time_window=timedelta(minutes=10),
            resolution=timedelta(minutes=1),
        )
        identifier = creator.create(subscription, Timer("test"))
        RedisSubscriptionDataStore(
            redis_client, self.dataset, identifier.partition,
        ).all()[0][1] == subscription

        SubscriptionDeleter(self.dataset, identifier.partition).delete(identifier.uuid)
        RedisSubscriptionDataStore(
            redis_client, self.dataset, identifier.partition,
        ).all() == []
Example #28
0
 def test_all(self):
     store = self.build_store()
     assert store.all() == []
     subscription_id = uuid1()
     store.create(subscription_id, self.subscription)
     assert store.all() == [(subscription_id, self.subscription)]
     new_subscription = SubscriptionData(
         project_id=self.project_id,
         conditions=[["platform", "IN", ["b"]]],
         aggregations=[["count()", "", "something"]],
         time_window=timedelta(minutes=400),
         resolution=timedelta(minutes=2),
     )
     new_subscription_id = uuid1()
     store.create(new_subscription_id, new_subscription)
     assert sorted(store.all(), key=lambda row: row[0]) == [
         (subscription_id, self.subscription),
         (new_subscription_id, new_subscription),
     ]
Example #29
0
    def test_partitions(self):
        store_1 = self.build_store("1")
        store_2 = self.build_store("2")
        subscription_id = uuid1()
        store_1.create(subscription_id, self.subscription)
        assert store_2.all() == []
        assert store_1.all() == [(subscription_id, self.subscription)]

        new_subscription = SubscriptionData(
            project_id=self.project_id,
            conditions=[["platform", "IN", ["b"]]],
            aggregations=[["count()", "", "something"]],
            time_window=timedelta(minutes=400),
            resolution=timedelta(minutes=2),
        )
        new_subscription_id = uuid1()
        store_2.create(new_subscription_id, new_subscription)
        assert store_1.all() == [(subscription_id, self.subscription)]
        assert store_2.all() == [(new_subscription_id, new_subscription)]
Example #30
0
def test_subscription_task_encoder() -> None:
    encoder = SubscriptionScheduledTaskEncoder()

    subscription_data = SubscriptionData(
        project_id=1,
        query="MATCH events SELECT count()",
        time_window_sec=60,
        resolution_sec=60,
        entity_subscription=EventsSubscription(data_dict={}),
    )

    subscription_id = uuid.UUID("91b46cb6224f11ecb2ddacde48001122")

    epoch = datetime(1970, 1, 1)

    tick_upper_offset = 5

    subscription_with_metadata = SubscriptionWithMetadata(
        EntityKey.EVENTS,
        Subscription(SubscriptionIdentifier(PartitionId(1), subscription_id),
                     subscription_data),
        tick_upper_offset,
    )

    task = ScheduledSubscriptionTask(timestamp=epoch,
                                     task=subscription_with_metadata)

    encoded = encoder.encode(task)

    assert encoded.key == b"1/91b46cb6224f11ecb2ddacde48001122"

    assert encoded.value == (
        b"{"
        b'"timestamp":"1970-01-01T00:00:00",'
        b'"entity":"events",'
        b'"task":{'
        b'"data":{"project_id":1,"time_window":60,"resolution":60,"query":"MATCH events SELECT count()"}},'
        b'"tick_upper_offset":5'
        b"}")

    decoded = encoder.decode(encoded)

    assert decoded == task