def test_queryset_with_struct(random_workspace, mocker): total_docs = 4 docs = [] for doc_id in range(total_docs): doc = jina_pb2.DocumentProto() doc.text = f'I am doc{doc_id}' NdArray(doc.embedding).value = np.array([doc_id]) doc.tags['label'] = f'label{doc_id % 2 + 1}' docs.append(doc) f = (Flow() .add(uses='- !FilterQL | {lookups: {tags__label__in: [label1, label2]}, traversal_paths: [r]}')) def validate_all_docs(resp): assert len(resp.docs) == total_docs def validate_label2_docs(resp): assert len(resp.docs) == total_docs / 2 mock1 = mocker.Mock() mock2 = mocker.Mock() with f: # keep all the docs f.index(docs, on_done=mock1) # keep only the docs with label2 qs = QueryLang({'name': 'FilterQL', 'priority': 1, 'parameters': {'lookups': {'tags__label': 'label2'}, 'traversal_paths': ['r']}}) f.index(docs, queryset=qs, on_done=mock2) mock1.assert_called_once() validate_callback(mock1, validate_all_docs) mock2.assert_called_once() validate_callback(mock2, validate_label2_docs)
def test_delete_kv(config, mocker, as_string): flow_file = 'flow_kv.yml' def validate_result_factory(num_matches): def validate_results(resp): assert len(resp.docs) == num_matches return validate_results with Flow.load_config(flow_file) as index_flow: index_flow.index(inputs=random_docs(0, 10)) validate_index_size(10) mock = mocker.Mock() with Flow.load_config(flow_file) as search_flow: search_flow.search(inputs=chain(random_docs(2, 5), random_docs(100, 120)), on_done=mock) mock.assert_called_once() validate_callback(mock, validate_result_factory(3)) with Flow.load_config(flow_file) as index_flow: index_flow.delete(ids=get_ids_to_delete(0, 3, as_string)) validate_index_size(7) mock = mocker.Mock() with Flow.load_config(flow_file) as search_flow: search_flow.search(inputs=random_docs(2, 4), on_done=mock) mock.assert_called_once() validate_callback(mock, validate_result_factory(1))
def test_bad_flow_customized(mocker, restful): def validate(req): bad_routes = [ r for r in req.routes if r.status.code == jina_pb2.StatusProto.ERROR ] assert req.status.code == jina_pb2.StatusProto.ERROR assert bad_routes[0].pod == 'r2/ZEDRuntime' assert bad_routes[0].status.exception.name == 'ZeroDivisionError' f = (Flow(restful=restful).add(name='r1').add( name='r2', uses='!DummyCrafterExcept').add(name='r3', uses='!BaseEncoder')) with f: pass on_error_mock = mocker.Mock() # always test two times, make sure the flow still works after it fails on the first with f: f.index(['abbcs', 'efgh'], on_error=on_error_mock) f.index(['abbcs', 'efgh'], on_error=on_error_mock) validate_callback(on_error_mock, validate)
def test_chatbot(tmpdir, mocker, helloworld_args): # test the index and query flow. def validate_response(resp): assert len(resp.data.docs) == 1 for doc in resp.data.docs: assert len(doc.matches) == 1 assert ('testing positive means that you have the virus' in doc.matches[0].tags['answer']) mock_on_done = mocker.Mock() mock_on_fail = mocker.Mock() flow = _get_flow(helloworld_args) with flow as f: f.index(inputs=Document( text= 'Does testing positive mean that I have the virus and that I will develop symptoms?', tags={ "wrong_answer": "You should take precaution with any containers, Elliott says. \"The plasticgrocery bags I’d throw out right away, wash your hands and then clean yourfood. Chances (of infection) are low,\" she said. \"But better yet, bring yourown bags! It’s better for the environment anyway.\"", "answer": "Yes, testing positive means that you have the virus, but it does not mean that you will develop symptoms. Some people who have the virus don't have any symptoms at all.\n\nAt the same time, testing negative does not necessarily mean that you don't have the virus.", }, ), ) f.search( inputs=Document( content= 'Does testing positive mean that I have the virus and that I will develop symptoms?' ), on_done=mock_on_done, on_fail=mock_on_fail, ) mock_on_fail.assert_not_called() validate_callback(mock_on_done, validate_response)
def test_sparse_pipeline(mocker, docs_to_index): def validate(response): assert len(response.data.docs) == 10 for doc in response.data.docs: for i, match in enumerate(doc.matches): assert match.id == docs_to_index[i].id assert isinstance(match.embedding, sparse.coo_matrix) f = Flow().add(uses=DummyCSRSparseIndexEncoder) mock = mocker.Mock() error_mock = mocker.Mock() with f: f.index( inputs=docs_to_index, on_done=mock, ) f.search( inputs=docs_to_index[0], parameters={ 'doc': docs_to_index[0], 'top_k': 1 }, on_done=mock, on_error=error_mock, ) mock.assert_called_once() validate_callback(mock, validate) error_mock.assert_not_called()
def test_flow(docker_compose, doc_to_index, client_instance, mocker): def validate_resp(resp): assert len(resp.data.docs) == 2 assert resp.data.docs[0].text == 'test' assert resp.data.docs[1].text == 'test' mock = mocker.Mock() workspace_id = create_workspace(filepaths=[flow_yaml], dirpath=pod_dir) assert wait_for_workspace(workspace_id) flow_id = create_flow( workspace_id=workspace_id, filename='flow.yml', ) client_instance.search(inputs=[doc_to_index], on_done=mock) assert_request(method='get', url=f'http://{JINAD_HOST}:8000/flows/{flow_id}') assert_request( method='delete', url=f'http://{JINAD_HOST}:8000/flows/{flow_id}', # payload={'workspace': False}, ) mock.assert_called_once() validate_callback(mock, validate_resp)
def test_on_error_callback(mocker, restful): def validate1(): raise NotImplementedError class MyExecutor(Executor): @requests def foo(self, **kwargs): raise NotImplementedError def validate2(x, *args): x = x.routes assert len(x) == 4 # gateway, r1, r3, gateway badones = [r for r in x if r.status.code == jina_pb2.StatusProto.ERROR] assert badones[0].pod == 'r3/ZEDRuntime' f = Flow(restful=restful).add(name='r1').add(name='r3', uses=MyExecutor) on_error_mock = mocker.Mock() with f: f.index( [Document(text='abbcs'), Document(text='efgh')], on_done=validate1, on_error=on_error_mock, ) validate_callback(on_error_mock, validate2)
def test_evaluation_from_file( random_workspace, index_groundtruth, evaluate_docs, index_yaml, search_yaml, restful, mocker, monkeypatch, ): monkeypatch.setenv("RESTFUL", restful) with Flow.load_config(index_yaml) as index_gt_flow: index_gt_flow.index(inputs=index_groundtruth, request_size=10) def validate_evaluation_response(resp): assert len(resp.docs) == 97 assert len(resp.groundtruths) == 97 for doc in resp.docs: assert len(doc.evaluations) == 1 assert doc.evaluations[0].value == 1.0 assert not doc.tags['groundtruth'] for gt in resp.groundtruths: assert gt.tags['groundtruth'] mock = mocker.Mock() with Flow.load_config(search_yaml) as evaluate_flow: evaluate_flow.search(inputs=evaluate_docs, on_done=mock) mock.assert_called_once() validate_callback(mock, validate_evaluation_response)
def test_bad_flow_skip_exec_join(mocker, restful): """Make sure the exception wont affect the gather/reduce ops""" def validate(req): bad_routes = [ r for r in req.routes if r.status.code >= jina_pb2.StatusProto.ERROR ] assert len(bad_routes) == 1 assert req.status.code == jina_pb2.StatusProto.ERROR assert bad_routes[0].pod == 'r1/ZEDRuntime' f = ( Flow(restful=restful, on_error_strategy=OnErrorStrategy.SKIP_EXECUTOR) .add(name='r1', uses='DummyCrafter') .add(name='r2') .add(name='r3', needs='r1') .needs(['r3', 'r2']) ) on_error_mock = mocker.Mock() # always test two times, make sure the flow still works after it fails on the first with f: f.index(['abbcs', 'efgh'], on_error=on_error_mock) validate_callback(on_error_mock, validate)
def test_sort_ql(mocker): def validate(req): # print('---------------------------') assert req.docs[-1].tags['id'] < req.docs[0].tags['id'] assert req.docs[0].matches[-1].tags['id'] < req.docs[0].matches[ 0].tags['id'] assert req.docs[0].chunks[-1].tags['id'] < req.docs[0].chunks[0].tags[ 'id'] response_mock = mocker.Mock() f = (Flow().add(uses='DummySegmenter').add( uses= '- !SortQL | {field: tags__id, reverse: true, traversal_paths: [r, c, m]}' )) with f: f.index(random_docs(10), on_done=response_mock) validate_callback(response_mock, validate) response_mock_2 = mocker.Mock() f = (Flow().add(uses='DummySegmenter').add( uses= '- !SortQL | {field: tags__id, reverse: false, traversal_paths: [r, c, m]}' ).add(uses='- !ReverseQL | {traversal_paths: [r, c, m]}')) with f: f.index(random_docs(10), on_done=response_mock_2) validate_callback(response_mock_2, validate)
def test_shelf_in_flow(uses, mocker): m1 = used_memory() # shelve does not support embed > 1000?? # _dbm.error: cannot add item to database # HASH: Out of overflow pages. Increase page size docs = random_docs(10000, embed_dim=1000) f = Flow().add(uses=os.path.join(cur_dir, uses)) with f: f.index(docs) m2 = used_memory() d = jina_pb2.DocumentProto() def validate(req): m4 = used_memory() print( f'before: {m1}, after index: {m2}, after loading: {m3} after searching {m4}' ) mock = mocker.Mock() with f: m3 = used_memory() f.search([d], on_done=mock) shutil.rmtree('test-workspace', ignore_errors=False, onerror=None) mock.assert_called_once() validate_callback(mock, validate)
def test_select_ql(mocker): def validate(req): assert req.docs[0].text == '' assert req.docs[-1].text == '' assert req.docs[0].matches[0].text == '' assert req.docs[0].chunks[0].text == '' f = (Flow().add(uses='DummySegmenter').add( uses= '- !SelectQL | {fields: [uri, matches, chunks], traversal_paths: [r, c, m]}' )) response_mock = mocker.Mock() with f: f.index(random_docs(10), on_done=response_mock) f = (Flow().add(uses='DummySegmenter').add( uses='- !ExcludeQL | {fields: [text], traversal_paths: [r, c, m]}')) validate_callback(response_mock, validate) response_mock_2 = mocker.Mock() with f: f.index(random_docs(10), on_done=response_mock_2) validate_callback(response_mock_2, validate)
def test_reduce_all_root_chunks(mocker, docs): def input_fn(): return docs def validate(req): assert len(req.index.docs) == 6 for doc in req.index.docs: assert len(doc.chunks) == 1 assert doc.chunks[0].modality in ['mode1', 'mode2'] response_mock = mocker.Mock() flow = (Flow().add(name='segmenter', uses='MockSegmenterReduce').add( name='encoder1', uses=os.path.join(cur_dir, 'yaml/mockencoder-mode1.yml')).add( name='encoder2', uses=os.path.join(cur_dir, 'yaml/mockencoder-mode2.yml'), needs=['segmenter'], ).add( name='reducer', uses='- !ReduceAllDriver | {traversal_paths: [r]}', needs=['encoder1', 'encoder2'], )) with flow: flow.index(input_fn=input_fn, on_done=response_mock) validate_callback(response_mock, validate)
def test_match2docranker_batching_flow(ranker, mocker): NUM_DOCS_QUERIES = 15 NUM_MATCHES = 10 queries = DocumentSet([]) for i in range(NUM_DOCS_QUERIES): query = Document(id=f'query-{i}') for j in range(NUM_MATCHES): m = Document(id=f'match-{i}-{j}', tags={'dummy_score': j}) query.matches.append(m) queries.append(query) def validate_response(resp): assert len(resp.search.docs) == NUM_DOCS_QUERIES for i, query in enumerate(resp.search.docs): for j, match in enumerate(query.matches, 1): assert match.id == f'match-{i}-{NUM_MATCHES - j}' assert match.score.value == NUM_MATCHES - j mock = mocker.Mock() with Flow().add(name='ranker', uses=ranker) as f: f.search(inputs=queries, on_done=mock) mock.assert_called_once() validate_callback(mock, validate_response)
def test_delete_vector(config, mocker, index_conf, index_names, num_shards): def _validate_result_factory(num_matches): def _validate_results(resp): assert len(resp.docs) == 7 for doc in resp.docs: assert len(doc.matches) == num_matches return _validate_results with get_index_flow(index_conf, num_shards) as index_flow: index_flow.index(inputs=random_docs(0, 201), request_size=100) for index_name in index_names: validate_index_size(201, index_name) with get_delete_flow(index_conf, num_shards) as index_flow: index_flow.delete(ids=[d.id for d in random_docs(0, 30)], request_size=100) with get_delete_flow(index_conf, num_shards) as index_flow: index_flow.delete(ids=[d.id for d in random_docs(100, 150)], request_size=100) for index_name in index_names: validate_index_size(121, index_name) mock = mocker.Mock() with get_search_flow(index_conf, num_shards) as search_flow: search_flow.search(inputs=random_docs(28, 35), on_done=mock, request_size=100) mock.assert_called_once() validate_callback(mock, _validate_result_factory(10))
def test_search_non_existent(config, mocker): yaml_file = 'index_kv_simple.yml' def validate_results(resp): assert len(resp.docs) == 3 with Flow().add( uses=os.path.join(cur_dir, 'yaml', yaml_file), shards=2, ) as index_flow: index_flow.index(inputs=random_docs(0, 3), request_size=1) mock = mocker.Mock() with Flow(read_only=True).add( uses=os.path.join(cur_dir, 'yaml', yaml_file), shards=2, uses_after='_merge_root', polling='all', ) as search_flow: search_flow.search(inputs=random_docs(0, 5), on_done=mock, request_size=5) mock.assert_called_once() validate_callback(mock, validate_results)
def test_delete_kv(config, mocker, num_shards): index_conf = 'index_kv.yml' index_name = 'kvidx' def _validate_result_factory(num_matches): def _validate_results(resp): assert len(resp.docs) == num_matches return _validate_results with get_index_flow(index_conf, num_shards) as index_flow: index_flow.index(inputs=random_docs(0, 201), request_size=100) validate_index_size(201, index_name) with get_delete_flow(index_conf, num_shards) as delete_flow: delete_flow.delete(ids=[d.id for d in random_docs(0, 30)], request_size=100) with get_delete_flow(index_conf, num_shards) as delete_flow: delete_flow.delete(ids=[d.id for d in random_docs(100, 150)], request_size=100) validate_index_size(121, index_name) mock = mocker.Mock() with get_search_flow(index_conf, num_shards, '_merge_root') as search_flow: search_flow.search(inputs=random_docs(28, 35), on_done=mock, request_size=100) mock.assert_called_once() validate_callback(mock, _validate_result_factory(5))
def test_indexer_with_ref_indexer_compound_move(random_workspace_move, parallel, index_docs, mocker, uses_no_docker): top_k = 10 with Flow.load_config(os.path.join(cur_dir, 'compound-index.yml')) as index_flow: index_flow.index(inputs=index_docs, request_size=10) mock = mocker.Mock() shutil.copytree(os.environ['JINA_TEST_INDEXER_WITH_REF_INDEXER'], os.environ['JINA_TEST_INDEXER_WITH_REF_INDEXER_QUERY']) shutil.rmtree(os.environ['JINA_TEST_INDEXER_WITH_REF_INDEXER']) def validate_response(resp): assert len(resp.search.docs) == 1 assert len(resp.search.docs[0].matches) == top_k query_document = Document() query_document.embedding = np.array([1, 1]) with Flow.load_config(os.path.join(cur_dir, 'compound-query.yml')) as query_flow: query_flow.search(inputs=[query_document], on_done=mock, top_k=top_k) mock.assert_called_once() validate_callback(mock, validate_response)
def test_flow_with_modalitys_simple(mocker, restful): def validate(req): for d in req.index.docs: assert d.modality in ['mode1', 'mode2'] def input_function(): doc1 = DocumentProto() doc1.modality = 'mode1' doc2 = DocumentProto() doc2.modality = 'mode2' doc3 = DocumentProto() doc3.modality = 'mode1' return [doc1, doc2, doc3] response_mock = mocker.Mock() flow = ( Flow(restful=restful) .add(name='chunk_seg', parallel=3) .add( name='encoder12', parallel=2, uses='- !FilterQL | {lookups: {modality__in: [mode1, mode2]}, traversal_paths: [c]}', ) ) with flow: flow.index(inputs=input_function, on_done=response_mock) validate_callback(response_mock, validate)
def test_bad_flow_customized(mocker, protocol): def validate(req, e: Exception): bad_routes = [ r for r in req.routes if r.status.code == jina_pb2.StatusProto.ERROR ] assert req.status.code == jina_pb2.StatusProto.ERROR assert bad_routes[0].executor == 'r2' assert bad_routes[0].status.exception.name == 'ZeroDivisionError' f = ( Flow(protocol=protocol) .add(name='r1') .add(name='r2', uses='!DummyCrafterExcept') .add(name='r3', uses='!BaseExecutor') ) with f: pass on_error_mock = mocker.Mock() # always test two times, make sure the flow still works after it fails on the first with f: f.index([Document(text='abbcs'), Document(text='efgh')], on_error=on_error_mock) f.index([Document(text='abbcs'), Document(text='efgh')], on_error=on_error_mock) validate_callback(on_error_mock, validate)
def test_bad_flow(mocker, restful): def validate(req): bad_routes = [ r for r in req.routes if r.status.code == jina_pb2.StatusProto.ERROR ] assert req.status.code == jina_pb2.StatusProto.ERROR assert bad_routes[0].pod == 'r1/ZEDRuntime' from jina import Executor, requests class BadExecutor(Executor): @requests def foo(self, **kwargs): raise NotImplementedError f = (Flow(restful=restful).add( name='r1', uses=BadExecutor).add(name='r2').add(name='r3')) on_error_mock = mocker.Mock() # always test two times, make sure the flow test_bad_flow_customizedstill works after it fails on the first with f: f.index([Document(text='abbcs'), Document(text='efgh')], on_error=on_error_mock) f.index([Document(text='abbcs'), Document(text='efgh')], on_error=on_error_mock) validate_callback(on_error_mock, validate)
def test_except_with_shards(mocker, protocol): def validate(req, e: Exception): assert req.status.code == jina_pb2.StatusProto.ERROR err_routes = [ r.status for r in req.routes if r.status.code == jina_pb2.StatusProto.ERROR ] assert len(err_routes) == 1 assert err_routes[0].exception.executor == 'DummyCrafterExcept' assert err_routes[0].exception.name == 'ZeroDivisionError' f = ( Flow(protocol=protocol) .add(name='r1') .add(name='r2', uses=DummyCrafterExcept, shards=3) .add(name='r3', uses=MyExecutor) ) with f: pass on_error_mock = mocker.Mock() # always test two times, make sure the flow still works after it fails on the first with f: f.index([Document(text='abbcs'), Document(text='efgh')], on_error=on_error_mock) f.index([Document(text='abbcs'), Document(text='efgh')], on_error=on_error_mock) validate_callback(on_error_mock, validate)
def test_topk_override(config, mocker): NDOCS = 3 TOPK_OVERRIDE = 11 def validate(resp): assert len(resp.search.docs) == NDOCS for doc in resp.search.docs: assert len(doc.matches) == TOPK_OVERRIDE # Making queryset top_k_queryset = QueryLang( { 'name': 'VectorSearchDriver', 'parameters': {'top_k': TOPK_OVERRIDE}, 'priority': 1, } ) with Flow.load_config('flow.yml') as index_flow: index_flow.index(inputs=random_docs(100)) mock = mocker.Mock() with Flow.load_config('flow.yml') as search_flow: search_flow.search( inputs=random_docs(NDOCS), on_done=mock, queryset=[top_k_queryset] ) mock.assert_called_once() validate_callback(mock, validate)
def test_flow_with_publish_driver(mocker, restful): from jina import Executor, requests class DummyOneHotTextEncoder(Executor): @requests def foo(self, docs, **kwargs): for d in docs: d.embedding = np.array([1, 2, 3]) def validate(req): for d in req.docs: assert d.embedding is not None response_mock = mocker.Mock() f = (Flow(restful=restful).add(name='r2', uses=DummyOneHotTextEncoder).add( name='r3', uses=DummyOneHotTextEncoder, needs='gateway').join(needs=['r2', 'r3'])) with f: f.index([Document(text='text_1'), Document(text='text_2')], on_done=response_mock) validate_callback(response_mock, validate)
def test_bad_flow_skip_handle(mocker, protocol): def validate(req): bad_routes = [ r for r in req.routes if r.status.code >= jina_pb2.StatusProto.ERROR ] assert len(bad_routes) == 3 assert req.status.code == jina_pb2.StatusProto.ERROR assert bad_routes[0].pod == 'r1/ZEDRuntime' assert bad_routes[1].pod == 'r2/ZEDRuntime' assert bad_routes[1].status.code == jina_pb2.StatusProto.ERROR_CHAINED assert bad_routes[2].pod == 'r3/ZEDRuntime' assert bad_routes[2].status.code == jina_pb2.StatusProto.ERROR_CHAINED f = (Flow(protocol=protocol, on_error_strategy=OnErrorStrategy.SKIP_HANDLE).add( name='r1', uses='!DummyCrafterSkip').add(name='r2').add(name='r3')) on_error_mock = mocker.Mock() # always test two times, make sure the flow still works after it fails on the first with f: f.index([Document(text='abbcs'), Document(text='efgh')], on_error=on_error_mock) validate_callback(on_error_mock, validate)
def test_fashion(helloworld_args, query_document, mocker): """Regression test for fashion example.""" def validate_response(resp): assert len(resp.search.docs) == 1 for doc in resp.search.docs: assert len(doc.matches) == 10 hello_world(helloworld_args) flow_query_path = os.path.join(resource_filename('jina', 'resources'), 'fashion') mock_on_done = mocker.Mock() mock_on_fail = mocker.Mock() with Flow.load_config( os.path.join(flow_query_path, 'helloworld.flow.query.yml')) as f: f.search( inputs=[query_document], on_done=mock_on_done, on_fail=mock_on_fail, top_k=10, ) mock_on_fail.assert_not_called() validate_callback(mock_on_done, validate_response)
def test_update_kv(config, mocker): flow_file = 'flow_kv.yml' NUMBER_OF_SEARCHES = 1 docs_before = list(random_docs(0, 10)) docs_updated = list(random_docs(0, 10)) def validate_results(resp): assert len(resp.docs) == NUMBER_OF_SEARCHES with Flow.load_config(flow_file) as index_flow: index_flow.index(inputs=docs_before) validate_index_size(10) mock = mocker.Mock() with Flow.load_config(flow_file) as search_flow: search_docs = list(random_docs(0, NUMBER_OF_SEARCHES)) search_flow.search(inputs=search_docs, on_done=mock) mock.assert_called_once() validate_callback(mock, validate_results) with Flow.load_config(flow_file) as index_flow: index_flow.update(inputs=docs_updated) validate_index_size(10) mock = mocker.Mock() with Flow.load_config(flow_file) as search_flow: search_flow.search(inputs=random_docs(0, NUMBER_OF_SEARCHES), on_done=mock) mock.assert_called_once() validate_callback(mock, validate_results)
def test_message_docs_different_matches_types(input_doc_with_matches, mocker): def validate_matches_fn(resp): assert len(resp.search.docs) == 1 doc = resp.search.docs[0] assert int(doc.tags['id']) == 1 assert len(doc.matches) == 3 match0 = doc.matches[0] assert int(match0.tags['id']) == 10 assert match0.text == text np.testing.assert_almost_equal(random_np_array, NdArray(match0.embedding).value) match1 = doc.matches[1] assert int(match1.tags['id']) == 20 np.testing.assert_almost_equal(random_np_array, NdArray(match1.blob).value) match2 = doc.matches[2] assert int(match2.tags['id']) == 30 assert match2.buffer == buffer mock = mocker.Mock() with Flow().add() as f: f.search(inputs=[input_doc_with_matches], on_done=mock) mock.assert_called_once() validate_callback(mock, validate_matches_fn)
def test_except_with_parallel(mocker, restful): def validate(req): assert req.status.code == jina_pb2.StatusProto.ERROR err_routes = [ r.status for r in req.routes if r.status.code == jina_pb2.StatusProto.ERROR ] assert len(err_routes) == 2 assert err_routes[0].exception.executor == 'DummyCrafterExcept' assert err_routes[1].exception.executor == 'BaseEncoder' assert err_routes[0].exception.name == 'ZeroDivisionError' assert err_routes[1].exception.name == 'NotImplementedError' f = (Flow(restful=restful).add(name='r1').add(name='r2', uses='!DummyCrafterExcept', parallel=3).add( name='r3', uses='!BaseEncoder')) with f: pass on_error_mock = mocker.Mock() # always test two times, make sure the flow still works after it fails on the first with f: f.index(['abbcs', 'efgh'], on_error=on_error_mock) f.index(['abbcs', 'efgh'], on_error=on_error_mock) validate_callback(on_error_mock, validate)
def test_dummy_seg(mocker, restful): mock = mocker.Mock() f = Flow(restful=restful).add(uses='DummySegment') with f: f.index(inputs=random_docs(10, chunks_per_doc=0), on_done=mock) mock.assert_called_once() validate_callback(mock, validate)