def test_get():
    """
    smartapi = SmartAPI.get(_id)
    smartapi._id
    smartapi.url
    smartapi.version
    ...
    """
    mygene = SmartAPI.get(MYGENE_ID)
    assert mygene._id == MYGENE_ID
    assert mygene.version == 'openapi'
    assert mygene.username == 'tester'
    assert mygene.slug == 'mygene'
    assert mygene['info']['title'] == 'MyGene.info API'
    assert mygene.raw == MYGENE_RAW
    assert mygene.url == MYGENE_URL

    with pytest.raises(AttributeError):
        mygene._id = "NEWID"
    with pytest.raises(AttributeError):
        mygene.url = "http://example.org/"
    with pytest.raises(ValueError):
        mygene.slug = "a"
    with pytest.raises(ValueError):
        mygene.slug = "AAA"
    with pytest.raises(ValueError):
        mygene.slug = "www"
    with pytest.raises(ValueError):
        mygene.slug = "^_^"

    with pytest.raises(NotFoundError):
        SmartAPI.get("NOTEXIST")
def test_get_tags():
    """
    SmartAPI.get_tags()
    SmartAPI.get_tags(field)
    """
    aggs = SmartAPI.get_tags()
    assert aggs == {'Chunlei Wu': 2}
    aggs = SmartAPI.get_tags('tags.name')
    assert 'annotation' in aggs
    assert 'translator' in aggs
    assert 'biothings' in aggs
Exemple #3
0
    def test_post(self):

        _ID = '1ad2cba40cb25cd70d00aa8fba9cfaf3'
        VALID_V3_URL = \
            'https://raw.githubusercontent.com/schurerlab/'\
            'smartAPIs/master/LINCS_Data_Portal_smartAPIs.yml'

        try:
            smartapi = SmartAPI.get(_ID)
            smartapi.delete()
            refresh()
        except NotFoundError:
            pass

        self.request("/api/metadata/",
                     method='POST',
                     data={'url': VALID_V3_URL},
                     expect=401)
        self.request("/api/metadata/",
                     method='POST',
                     data={'url': MYGENE_URL},
                     headers=self.auth_user,
                     expect=409)
        self.request("/api/metadata/",
                     method='POST',
                     headers=self.auth_user,
                     expect=400)
        self.request("/api/metadata/",
                     method='POST',
                     data={'url': "http://invalidhost/file"},
                     headers=self.auth_user,
                     expect=400)
        self.request("/api/metadata/",
                     method='POST',
                     data={
                         'url': VALID_V3_URL,
                         'dryrun': True
                     },
                     headers=self.auth_user)
        refresh()
        assert not SmartAPI.exists(_ID)
        self.request("/api/metadata/",
                     method='POST',
                     data={'url': VALID_V3_URL},
                     headers=self.auth_user)
        refresh()
        assert SmartAPI.exists(_ID)

        try:
            smartapi = SmartAPI.get(_ID)
            smartapi.delete()
        except NotFoundError:
            pass
Exemple #4
0
def refresh_document():
    logger = logging.getLogger("refresh")
    for smartapi in SmartAPI.get_all(1000):
        logger.info(smartapi._id)
        _status = smartapi.refresh()
        logger.info(_status)
        smartapi.save()
Exemple #5
0
    def validate(self, raw):

        try:
            smartapi = SmartAPI(SmartAPI.VALIDATION_ONLY)
            smartapi.raw = raw
            smartapi.validate()

        except (ControllerError, AssertionError) as err:
            raise BadRequest(details=str(err))
        else:
            self.finish({
                'success':
                True,
                'details':
                f'valid SmartAPI ({smartapi.version}) metadata.'
            })
Exemple #6
0
def check_uptime():
    logger = logging.getLogger("uptime")
    for smartapi in SmartAPI.get_all(1000):
        logger.info(smartapi._id)
        _status = smartapi.check()
        logger.info(_status)
        smartapi.save()
def test_get_all():
    """
    SmartAPI.get_all()
    """
    docs = list(SmartAPI.get_all())
    assert len(docs) == 2
    assert docs[0]["info"]["title"] in ["MyGene.info API", "MyChem.info API"]
    assert docs[1]["info"]["title"] in ["MyGene.info API", "MyChem.info API"]
Exemple #8
0
 def get(self):
     """
     /api/suggestion?field=
     Returns aggregations for any field provided
     Used for tag:count on registry
     """
     res = SmartAPI.get_tags(self.args.field)
     self.finish(res)
def test_get_all_from():
    """
    SmartAPI.get_all(from_=1)
    """
    search = APIDoc.search()
    assert search.count() == 2

    docs = list(SmartAPI.get_all(from_=1))
    assert len(docs) == 1
Exemple #10
0
def test_search():
    """
    SmartAPI.exists(_id)
    SmartAPI.find(slug)
    SmartAPI.find(val, field)
    """
    assert SmartAPI.exists(MYGENE_ID)
    assert SmartAPI.exists(MYCHEM_ID)
    assert SmartAPI.find('mygene') == MYGENE_ID
    assert SmartAPI.find('mychem') == MYCHEM_ID
    assert SmartAPI.find('tester', 'username')
    assert SmartAPI.find('gene', 'tags.name') == MYGENE_ID
    assert SmartAPI.find('drug', 'tags.name') == MYCHEM_ID
    assert SmartAPI.find(MYGENE_URL, 'url') == MYGENE_ID
    assert SmartAPI.find(MYCHEM_URL, 'url') == MYCHEM_ID
Exemple #11
0
def _restore(smartapis):
    if indices.exists():
        logging.error("Cannot write to an existing index.")
        return
    indices.reset()
    for smartapi in smartapis:
        logging.info(smartapi["url"])
        _smartapi = SmartAPI(smartapi["url"])
        _smartapi.username = smartapi["username"]
        _smartapi.slug = smartapi["slug"]
        _smartapi.date_created = datetime.fromisoformat(
            smartapi["date_created"])
        _smartapi.last_updated = datetime.fromisoformat(
            smartapi["last_updated"])
        _smartapi.raw = smartapi["raw"].encode()  # to bytes
        _smartapi.save()
Exemple #12
0
def _backup():
    smartapis = []
    for smartapi in SmartAPI.get_all(1000):
        smartapis.append({
            "url": smartapi.url,
            "username": smartapi.username,
            "slug": smartapi.slug,
            "date_created": smartapi.date_created.isoformat(),
            "last_updated": smartapi.last_updated.isoformat(),
            "raw": smartapi.raw.decode()  # to string
        })
    return smartapis
Exemple #13
0
def test_uptime_update():

    mygene = SmartAPI.get(MYGENE_ID)
    mygene.check()  # minimum api document
    assert mygene.uptime.status[0] == 'unknown'  # TODO VERIFY THIS IS IN FACT CORRECT

    mygene.save()
    refresh()

    mygene_doc = APIDoc.get(MYGENE_ID)
    assert mygene_doc._status.uptime_status == 'unknown'

    mychem = SmartAPI.get(MYCHEM_ID)
    mychem.check()  # full api document
    assert mychem.uptime.status[0] == 'unknown'

    mychem.save()
    refresh()

    mychem_doc = APIDoc.get(MYCHEM_ID)
    assert mychem_doc._status.uptime_status == 'unknown'
Exemple #14
0
    async def post(self):
        """
        Add an API document
        """

        if SmartAPI.find(self.args.url, "url"):
            raise HTTPError(409)

        try:
            file = await download_async(self.args.url)
        except DownloadError as err:
            raise BadRequest(details=str(err)) from err

        try:
            smartapi = SmartAPI(self.args.url)
            smartapi.raw = file.raw
            smartapi.validate()
        except (ControllerError, AssertionError) as err:
            raise BadRequest(details=str(err)) from err

        if self.args.dryrun:
            raise Finish({
                'success':
                True,
                'details':
                f"[Dryrun] Valid {smartapi.version} Metadata"
            })

        try:
            smartapi.username = self.current_user['login']
            smartapi.refresh(file)  # populate webdoc meta
            _id = smartapi.save()
        except ControllerError as err:
            raise BadRequest(details=str(err)) from err
        else:
            self.finish({'success': True, '_id': _id})
            await self._notify(smartapi)
Exemple #15
0
    def test_delete(self):

        # setup
        assert SmartAPI.exists(MYGENE_ID)

        self.request("/api/metadata/" + MYGENE_ID, method='DELETE', expect=401)
        self.request("/api/metadata/" + MYGENE_ID,
                     method='DELETE',
                     headers=self.evil_user,
                     expect=403)
        self.request("/api/metadata/" + MYGENE_ID,
                     method='DELETE',
                     headers=self.auth_user)

        refresh()
        assert not SmartAPI.exists(MYGENE_ID)

        # teardown
        refresh()
        if not SmartAPI.exists(MYGENE_ID):  # recover the deleted file
            mygene = APIDoc(meta={'id': MYGENE_ID}, **MYGENE_ES)
            mygene._raw = decoder.compress(MYGENE_RAW)
            mygene.save()
        refresh()
Exemple #16
0
    async def put(self, _id):
        """
        Add/Update the URL slug:
            PUT {"slug": "new_slug"}
        Remove a URL slug:
            PUT {"slug": "" }
        Refresh a document:
            PUT {}
        """

        try:
            smartapi = SmartAPI.get(_id)
        except NotFoundError:
            raise HTTPError(404)

        if smartapi.username != self.current_user['login']:
            raise HTTPError(403)

        if self.args.slug is not None:

            if self.args.slug in {'api'}:  #reserved
                raise BadRequest(details='slug is reserved')

            try:  # update slug
                smartapi.slug = self.args.slug or None
                smartapi.save()

            except (ControllerError, ValueError) as err:
                raise BadRequest(details=str(err)) from err

            self.finish({'success': True})

        else:  # refresh
            file = await download_async(smartapi.url, raise_error=False)
            code = smartapi.refresh(file)
            smartapi.save()

            try:
                status = smartapi.webdoc.STATUS(code)
                status = status.name.lower()
            except ValueError:
                status = 'nofile'  # keep the original copy

            self.finish({
                'success': code in (200, 299),
                'status': status,
                'code': code
            })
Exemple #17
0
def update():

    for doc in scan(Elasticsearch(ES_DESTINATION),
                    query={"query": {
                        "match_all": {}
                    }},
                    index="smartapi_docs",
                    scroll="60m"):
        print(doc["_id"])
        smartapi = SmartAPI.get(doc["_id"])
        print(smartapi.check())
        print(smartapi.refresh())
        if smartapi.webdoc.status == 299:
            smartapi.webdoc._status = 200  # change status not reliable during migration
        smartapi.save()
    print()
Exemple #18
0
def test_uptime_status():
    mygene = SmartAPI.get(MYGENE_ID)
    assert mygene.uptime.status[0] is None

    mygene.uptime.update(('good', None))
    assert mygene.uptime.status[0] == 'good'
    mygene.save()
    refresh()
    mygene_doc = APIDoc.get(MYGENE_ID)
    assert mygene_doc._status.uptime_status == 'good'

    mygene.uptime.update((None, None))
    assert mygene.uptime.status[0] is None
    mygene.save()
    refresh()
    mygene_doc = APIDoc.get(MYGENE_ID)
    assert mygene_doc._status.uptime_status is None
Exemple #19
0
    def delete(self, _id):
        """
        Delete API
        """

        try:
            smartapi = SmartAPI.get(_id)
        except NotFoundError:
            raise HTTPError(404)

        if smartapi.username != self.current_user['login']:
            raise HTTPError(403)

        try:
            _id = smartapi.delete()
        except ControllerError as err:
            raise BadRequest(details=str(err)) from err

        self.finish({'success': True, '_id': _id})
Exemple #20
0
def test_delete(myvariant):

    mv = SmartAPI.get(myvariant)
    mv.delete()

    refresh()

    assert not APIDoc.exists(myvariant)

    URL = "http://example.com/valid.json"
    with open(os.path.join(dirname, './validate/openapi-pass.json'), 'rb') as file:
        smartapi = SmartAPI(URL)
        smartapi.raw = file.read()
        with pytest.raises(NotFoundError):
            smartapi.delete()
Exemple #21
0
def migrate():

    for doc in scan(Elasticsearch(ES_ORIGIN),
                    query={"query": {
                        "match_all": {}
                    }},
                    index="smartapi_oas3",
                    doc_type="api"):
        print(doc["_id"])
        if not doc['_source']['_meta'].get('_archived'):
            url = doc['_source']['_meta']['url']
            raw = decoder.decompress(
                base64.urlsafe_b64decode(doc['_source']['~raw']))

            smartapi = SmartAPI(url)
            smartapi.raw = raw
            smartapi.date_created = parser.parse(
                doc['_source']['_meta']['timestamp']).replace(
                    tzinfo=timezone.utc)
            smartapi.username = doc['_source']['_meta']['github_username']
            smartapi.slug = doc['_source']['_meta'].get('slug')
            smartapi.save()
    print()
Exemple #22
0
def test_refresh_update():

    mychem = SmartAPI.get(MYCHEM_ID)
    assert mychem.webdoc.status is None

    # NOTE
    # the following update and the updates thereafter will be applied
    # https://github.com/NCATS-Tangerine/translator-api-registry/commit/b01baa5

    mychem.refresh()
    assert mychem.webdoc.status == 299  # new version
    assert mychem.webdoc.timestamp > datetime(2020, 1, 1, tzinfo=timezone.utc)
    _ts0 = mychem.webdoc.timestamp

    mychem.refresh()
    assert mychem.webdoc.status == 200  # already latest
    assert mychem.webdoc.timestamp >= _ts0  # could be cached internally

    mychem.save()
    refresh()
    mychem_doc = APIDoc.get(MYCHEM_ID)
    assert mychem_doc._status.refresh_status == 200
Exemple #23
0
def test_save(openapi):
    """
    SmartAPI.slug.validate(slug)
    smartapi.slug
    smartapi.save()
    """
    _t0 = datetime.now(timezone.utc)
    time.sleep(0.1)
    URL = "http://example.com/valid.json"
    with pytest.raises(ValueError):
        SmartAPI.slug.validate("a")
    with pytest.raises(ValueError):
        SmartAPI.slug.validate("AAA")
    with pytest.raises(ValueError):
        SmartAPI.slug.validate("www")
    with pytest.raises(ValueError):
        SmartAPI.slug.validate("^_^")
    with open(os.path.join(dirname, './validate/openapi-pass.json'), 'rb') as file:
        raw = file.read()
        smartapi = SmartAPI(URL)
        with pytest.raises(ControllerError):
            smartapi.raw = None
        smartapi.raw = raw
        smartapi.slug = "mygene"
        smartapi.validate()
        with pytest.raises(ControllerError):
            smartapi.save()
        smartapi.username = "******"
        with pytest.raises(ConflictError):
            smartapi.save()
        smartapi.slug = "mychem"
        with pytest.raises(ConflictError):
            smartapi.save()
        smartapi.slug = "openapi"
        smartapi.save()
        refresh()
        assert SmartAPI.find("openapi") == smartapi._id
        assert smartapi.date_created > _t0
        assert smartapi.last_updated > _t0
        assert smartapi.date_created == smartapi.last_updated
        apidoc = APIDoc.get(smartapi._id)
        assert apidoc._meta.date_created == smartapi.date_created
        assert apidoc._meta.last_updated == smartapi.last_updated
        _t1 = smartapi.date_created
        smartapi.save()  # no change
        refresh()
        assert SmartAPI.find("openapi") == smartapi._id
        assert smartapi.date_created == _t1
        assert smartapi.last_updated == _t1
        assert smartapi.date_created == smartapi.last_updated
        apidoc = APIDoc.get(smartapi._id)
        assert apidoc._meta.date_created == smartapi.date_created
        assert apidoc._meta.last_updated == smartapi.last_updated
        smartapi.slug = None
        smartapi.save()
        refresh()
        assert not SmartAPI.find("openapi")
        found = SmartAPI.get(openapi)
        assert dict(smartapi) == dict(found)
        assert smartapi.username == found.username
        assert smartapi.slug == found.slug
        assert smartapi.url == found.url
        assert smartapi.date_created == _t1
        assert smartapi.last_updated == _t1
        assert smartapi.date_created == smartapi.last_updated
        apidoc = APIDoc.get(smartapi._id)
        assert apidoc._meta.date_created == smartapi.date_created
        assert apidoc._meta.last_updated == smartapi.last_updated
        smartapi.raw = raw  # should trigger ts update
        smartapi.save()
        refresh()
        assert smartapi.date_created == _t1
        assert smartapi.last_updated > _t1
        apidoc = APIDoc.get(smartapi._id)
        assert apidoc._meta.date_created == smartapi.date_created
        assert apidoc._meta.last_updated == smartapi.last_updated
Exemple #24
0
def resave():
    # when index mappings are changed
    logger = logging.getLogger("resave")
    for smartapi in SmartAPI.get_all(1000):
        logger.info(smartapi._id)
        smartapi.save()
Exemple #25
0
def test_refresh_status():

    with open(os.path.join(dirname, 'mygene_full.yml'), 'rb') as file:
        MYGENE_FULL = file.read()

    mygene = SmartAPI.get(MYGENE_ID)  # minimum
    assert mygene.webdoc.status is None
    assert 'components' not in mygene

    mygene.webdoc.update(File(200, MYGENE_FULL, None, None))  # new content

    assert mygene.webdoc.status == 299  # updated
    assert 'components' in mygene
    assert mygene.webdoc.timestamp > datetime(2020, 1, 1)
    _ts0 = mygene.webdoc.timestamp

    mygene.save()
    refresh()

    mygene_doc = APIDoc.get(MYGENE_ID)
    assert mygene_doc._status.refresh_status == 299
    assert 'components' in mygene_doc

    mygene.webdoc.update(File(200, MYGENE_FULL, None, None))  # no change

    assert mygene.webdoc.status == 200  # latest
    assert 'components' in mygene
    assert mygene.webdoc.timestamp > _ts0

    mygene.save()
    refresh()

    mygene_doc = APIDoc.get(MYGENE_ID)
    assert mygene_doc._status.refresh_status == 200
    assert 'components' in mygene_doc

    mygene.webdoc.update(File(404, None, None, None))  # link broken

    assert mygene.webdoc.status == 404
    assert 'components' in mygene  # do not affect main copy

    mygene.save()
    refresh()

    mygene_doc = APIDoc.get(MYGENE_ID)
    assert mygene_doc._status.refresh_status == 404
    assert 'components' in mygene_doc

    mygene.webdoc.update(File(200, MYGENE_FULL, None, None))  # link back working

    assert mygene.webdoc.status == 200  # latest
    assert 'components' in mygene

    mygene.save()
    refresh()

    mygene_doc = APIDoc.get(MYGENE_ID)
    assert mygene_doc._status.refresh_status == 200
    assert 'components' in mygene_doc

    mygene.webdoc.update(File(200, b'{"openapi":"3.0.0"}', None, None))  # invalid

    assert mygene.webdoc.status == 499  # invalid
    assert 'components' in mygene  # do not affect main copy

    mygene.save()
    refresh()

    mygene_doc = APIDoc.get(MYGENE_ID)
    assert mygene_doc._status.refresh_status == 499
    assert 'components' in mygene_doc
Exemple #26
0
    def test_update_slug(self):

        mygene = SmartAPI.get(MYGENE_ID)
        assert mygene.slug == "mygene"

        self.request("/api/metadata/" + MYGENE_ID,
                     method='PUT',
                     data={"slug": "mygeeni"},
                     expect=401)
        self.request("/api/metadata/" + MYGENE_ID,
                     method='PUT',
                     data={"slug": "mygeeni"},
                     headers=self.evil_user,
                     expect=403)
        self.request("/api/metadata/" + MYGENE_ID,
                     method='PUT',
                     data={"slug": "my"},
                     headers=self.auth_user,
                     expect=400)
        self.request("/api/metadata/" + MYGENE_ID,
                     method='PUT',
                     data={"slug": "www"},
                     headers=self.auth_user,
                     expect=400)
        self.request("/api/metadata/" + MYGENE_ID,
                     method='PUT',
                     data={"slug": "MYGENE"},
                     headers=self.auth_user,
                     expect=400)
        self.request("/api/metadata/" + MYGENE_ID,
                     method='PUT',
                     data={"slug": "mygene!!"},
                     headers=self.auth_user,
                     expect=400)
        self.request("/api/metadata/" + MYGENE_ID,
                     method='PUT',
                     data={"slug": "mygeeni"},
                     headers=self.auth_user)

        refresh()
        assert not SmartAPI.find("mygene")
        assert SmartAPI.find("mygeeni")

        self.request("/api/metadata/" + MYGENE_ID,
                     method='PUT',
                     data={"slug": ""},
                     headers=self.auth_user)

        refresh()
        assert not SmartAPI.find("mygeeni")
        assert not SmartAPI.find("mygene")

        self.request("/api/metadata/" + MYGENE_ID,
                     method='PUT',
                     data={"slug": "mygene"},
                     headers=self.auth_user)
        refresh()
        assert not SmartAPI.find("mygeeni")
        assert SmartAPI.find("mygene")

        # teardown
        refresh()
        if not SmartAPI.find("mygene"):
            mygene = APIDoc(meta={'id': MYGENE_ID}, **MYGENE_ES)
            mygene._raw = decoder.compress(MYGENE_RAW)
            mygene.save()
Exemple #27
0
def setup_fixture():
    """
    Index 2 documents.
    """
    reset()

    # save initial docs with paths already transformed
    mygene = SmartAPI(MYGENE_URL)
    mygene.raw = MYGENE_RAW
    mygene.username = '******'
    mygene.slug = 'mygene'
    mygene.save()

    mychem = SmartAPI(MYCHEM_URL)
    mychem.raw = MYCHEM_RAW
    mychem.username = '******'
    mychem.slug = 'mychem'
    mychem.save()

    # refresh index
    refresh()
Exemple #28
0
def setup():
    """
    setup state called once for the class
    """
    reset()

    mygene = SmartAPI(MYGENE_URL)
    mygene.username = '******'
    mygene.refresh()
    mygene.check()
    mygene.save()

    mychem = SmartAPI(MYCHEM_URL)
    mychem.username = '******'
    mychem.refresh()
    mychem.check()
    mychem.save()

    refresh()
Exemple #29
0
def test_validation():
    """
    smartapi.validate()
    """
    URL = "http://example.com/invalid.json"
    with open(os.path.join(dirname, './validate/openapi-pass.json'), 'rb') as file:
        smartapi = SmartAPI(URL)
        smartapi.raw = file.read()
        smartapi.validate()
    with open(os.path.join(dirname, './validate/swagger-pass.json'), 'rb') as file:
        smartapi = SmartAPI(URL)
        smartapi.raw = file.read()
        smartapi.validate()
    with open(os.path.join(dirname, './validate/x-translator-pass.json'), 'rb') as file:
        smartapi = SmartAPI(URL)
        smartapi.raw = file.read()
        smartapi.validate()
    with open(os.path.join(dirname, './validate/x-translator-fail-1.yml'), 'rb') as file:
        smartapi = SmartAPI(URL)
        smartapi.raw = file.read()
        with pytest.raises(ControllerError):
            smartapi.validate()
    with open(os.path.join(dirname, './validate/x-translator-fail-2.yml'), 'rb') as file:
        smartapi = SmartAPI(URL)
        smartapi.raw = file.read()
        with pytest.raises(ControllerError):
            smartapi.validate()
    smartapi = SmartAPI(URL)
    smartapi.raw = b'{}'
    with pytest.raises(ControllerError):
        smartapi.validate()
Exemple #30
0
    def test_update_doc(self):

        self.request("/api/metadata/" + MYCHEM_ID, method="PUT", expect=401)
        self.request("/api/metadata/notexists",
                     method="PUT",
                     headers=self.auth_user,
                     expect=404)
        self.request("/api/metadata/" + MYCHEM_ID,
                     method="PUT",
                     headers=self.evil_user,
                     expect=403)

        res = self.request("/api/metadata/" + MYCHEM_ID,
                           method="PUT",
                           headers=self.auth_user).json()
        assert res["success"]
        assert res["code"] == 299
        assert res["status"] == "updated"

        mychem = SmartAPI.get(MYCHEM_ID)
        assert mychem.webdoc.status == 299
        assert mychem.webdoc.timestamp
        ts0 = mychem.webdoc.timestamp

        res = self.request("/api/metadata/" + MYCHEM_ID,
                           method="PUT",
                           headers=self.auth_user).json()
        assert res["success"]
        assert res["code"] == 200
        assert res["status"] == "not_modified"

        mychem = SmartAPI.get(MYCHEM_ID)
        assert mychem.webdoc.status == 200
        assert mychem.webdoc.timestamp >= ts0

        # setup
        mygene_ref = SmartAPI(self.get_url('/test/mygene.yml'))
        mygene_ref.raw = MYGENE_RAW
        mygene_ref.username = '******'
        mygene_ref.save()

        # first request, same file, minimul version
        res = self.request("/api/metadata/" + mygene_ref._id,
                           method="PUT",
                           headers=self.auth_user).json()
        assert res["success"]
        assert res["code"] == 200
        assert res["status"] == "not_modified"

        mygene = SmartAPI.get(mygene_ref._id)
        assert mygene.webdoc.status == 200

        # second request, full version, updated
        res = self.request("/api/metadata/" + mygene_ref._id,
                           method="PUT",
                           headers=self.auth_user).json()
        assert res["success"]
        assert res["code"] == 299
        assert res["status"] == "updated"

        mygene = SmartAPI.get(mygene_ref._id)
        assert mygene.webdoc.status == 299

        # third request, link temporarily unavailable
        res = self.request("/api/metadata/" + mygene_ref._id,
                           method="PUT",
                           headers=self.auth_user).json()
        assert not res["success"]
        assert res["code"] == 404
        assert res["status"] == "nofile"

        mygene = SmartAPI.get(mygene_ref._id)
        assert mygene.webdoc.status == 404

        # fourth request, link back up, new version doesn't pass validation
        res = self.request("/api/metadata/" + mygene_ref._id,
                           method="PUT",
                           headers=self.auth_user).json()
        assert not res["success"]
        assert res["code"] == 499
        assert res["status"] == "invalid"

        mygene = SmartAPI.get(mygene_ref._id)
        assert mygene.webdoc.status == 499

        # fifth request, link restored to a working version
        res = self.request("/api/metadata/" + mygene_ref._id,
                           method="PUT",
                           headers=self.auth_user).json()
        assert res["success"]
        assert res["code"] == 200
        assert res["status"] == "not_modified"

        mygene = SmartAPI.get(mygene_ref._id)
        assert mygene.webdoc.status == 200

        # setup
        mygene_ref_2 = SmartAPI('http://invalidhost/mygene.yml')
        mygene_ref_2.raw = MYGENE_RAW
        mygene_ref_2.username = '******'
        mygene_ref_2.save()

        res = self.request("/api/metadata/" + mygene_ref_2._id,
                           method="PUT",
                           headers=self.auth_user).json()
        assert not res["success"]
        assert res["code"] == 599
        assert res["status"] == "nofile"

        mygene = SmartAPI.get(mygene_ref_2._id)
        assert mygene.webdoc.status == 599