def assert_metadata_is(sid, orig_md, correct_dependent_md):
            result_md = self._assert_get_song(sid)

            with Check() as check:
                for name, expt in md_expectations.items():
                    if name in orig_md:
                        # TODO really need to factor out to test_utils?

                        # Check mutability if it's not volatile or dependent.
                        if not expt.volatile and expt.depends_on is None:
                            same, message = test_utils.md_entry_same(name, orig_md, result_md)
                            check.equal(not expt.mutable, same, "metadata mutability incorrect: " + message)

                        # Check dependent md.
                        if expt.depends_on is not None:
                            same, message = test_utils.md_entry_same(name, correct_dependent_md, result_md)
                            check.true(same, "dependent metadata incorrect: " + message)
Beispiel #2
0
        def assert_metadata_is(sid, orig_md, correct_dependent_md):
            result_md = self._assert_get_song(sid)

            with Check() as check:
                for name, expt in md_expectations.items():
                    if name in orig_md:
                        #TODO really need to factor out to test_utils?

                        #Check mutability if it's not volatile or dependent.
                        if not expt.volatile and expt.depends_on is None:
                            same, message = test_utils.md_entry_same(name, orig_md, result_md)
                            check.equal(not expt.mutable, same,
                                        "metadata mutability incorrect: " + message)

                        #Check dependent md.
                        if expt.depends_on is not None:
                            same, message = test_utils.md_entry_same(
                                name, correct_dependent_md, result_md
                            )
                            check.true(same, "dependent metadata incorrect: " + message)
from gmusicapi.compat import json
from gmusicapi.exceptions import CallFailure, ValidationException
from gmusicapi.protocol.metadata import md_expectations
from gmusicapi.protocol.shared import Call, authtypes
from gmusicapi.utils import utils, jsarray

base_url = 'https://play.google.com/music/'
service_url = base_url + 'services/'

#Shared response schemas, built to include metadata expectations.
song_schema = {
    "type":
    "object",
    "properties":
    dict((name, expt.get_schema()) for name, expt in md_expectations.items()),
    #don't allow metadata not in expectations
    "additionalProperties":
    False
}

song_array = {"type": "array", "items": song_schema}

pl_schema = {
    "type": "object",
    "properties": {
        "continuation": {
            "type": "boolean"
        },
        "playlist": song_array,
        "playlistId": {
from gmusicapi.compat import json
from gmusicapi.exceptions import CallFailure, ValidationException
from gmusicapi.protocol.metadata import md_expectations
from gmusicapi.protocol.shared import Call, authtypes
from gmusicapi.utils import utils

base_url = 'https://play.google.com/music/'
service_url = base_url + 'services/'

#Shared response schemas, built to include metadata expectations.
song_schema = {
    "type": "object",
    "properties": dict(
        (name, expt.get_schema()) for
        name, expt in md_expectations.items()
    ),
    #don't allow metadata not in expectations
    "additionalProperties": False
}

song_array = {
    "type": "array",
    "items": song_schema
}

pl_schema = {
    "type": "object",
    "properties": {
        "continuation": {"type": "boolean"},
        "playlist": song_array,
    def test_change_song_metadata(self):
        """Change a song's metadata, then restore it."""
        #Get a random song's metadata.
        orig_md = [s for s in self.library if s["id"] == self.r_song_id][0]
        log.debug("original md: %s", repr(orig_md))

        #Generate noticably changed metadata for ones we can change.
        #Changing immutable ones voids the request (although we get back success:True and our expected values).
        new_md = copy.deepcopy(orig_md)

        for name, expt in md_expectations.items():
            if name in orig_md and expt.mutable:
                old_val = orig_md[name]
                new_val = test_utils.modify_md(name, old_val)

                log.debug("%s: %s modified to %s", name, repr(old_val), repr(new_val))
                self.assertNotEqual(new_val, old_val)
                new_md[name] = new_val

        #Make the call to change the metadata.
        #This should succeed, even though we _shouldn't_ be able to change some entries.
        #The call only fails if you give the wrong datatype.
        self.api.change_song_metadata(new_md)


        #Recreate the dependent md to what they should be (based on how orig_md was changed)
        correct_dependent_md = {}
        for name, expt in md_expectations.items():
            if expt.depends_on and name in orig_md:
                master_name = expt.depends_on
                correct_dependent_md[name] = expt.dependent_transformation(new_md[master_name])

                # master_key, trans = dependent_md[name]
                # correct_dependent_md[dep_key] = trans(new_md[master_key])

                log.debug("dependents (%s): %s -> %s", name, new_md[master_name], correct_dependent_md[name])

        #The library needs to be refreshed to flush the changes.
        #This might not happen right away, so we allow a few retries.

        max_attempts = 3
        sleep_for = 3

        attempts = 0
        success = False

        #TODO: this is cludgey, and should be pulled out with the below retry logic.
        while not success and attempts < max_attempts:
            time.sleep(sleep_for)
            self.library = self.api.get_all_songs()

            attempts += 1

            result_md = [s for s in self.library if s["id"] == orig_md["id"]][0]
            log.debug("result md: %s", repr(result_md))


            try:
                #Verify everything went as expected:
                for name, expt in md_expectations.items():
                    if name in orig_md:
                        #Check mutability if it's not volatile or dependent.
                        if not expt.volatile and expt.depends_on is None:
                            same, message = test_utils.md_entry_same(name, orig_md, result_md)
                            self.assertEqual(same, (not expt.mutable), "metadata mutability incorrect: " + message)

                        #Check dependent md.
                        if expt.depends_on is not None:
                            same, message = test_utils.md_entry_same(name, correct_dependent_md, result_md)
                            self.assertTrue(same, "dependent metadata incorrect: " + message)

            except AssertionError:
                log.info("retrying server for changed metadata")
                if not attempts < max_attempts: raise
            else:
                success = True


        #Revert the metadata.
        self.api.change_song_metadata(orig_md)

        #Verify everything is as it was.

        attempts = 0
        success = False

        while not success and attempts < max_attempts:
            time.sleep(sleep_for)
            self.library = self.api.get_all_songs()

            attempts += 1

            result_md = [s for s in self.library if s["id"] == orig_md["id"]][0]
            log.debug("result md: %s", repr(result_md))

            try:
                for name in orig_md:
                    #If it's not volatile, it should be back to what it was.
                    if not md_expectations[name].volatile:
                        same, message = test_utils.md_entry_same(name, orig_md, result_md)
                        self.assertTrue(same, "failed to revert: " + message)

            except AssertionError:
                log.info("retrying server for reverted metadata")
                if not attempts < max_attempts:
                    raise
            else:
                success = True
    def change_metadata(self):
        orig_md = self._assert_get_song(self.song.sid)

        # Change all mutable entries.

        new_md = copy(orig_md)

        for name, expt in md_expectations.items():
            if name in orig_md and expt.mutable:
                old_val = orig_md[name]
                new_val = test_utils.modify_md(name, old_val)

                assert_not_equal(new_val, old_val)
                new_md[name] = new_val

        #TODO check into attempting to mutate non mutables
        self.wc.change_song_metadata(new_md)

        #Recreate the dependent md to what they should be (based on how orig_md was changed)
        correct_dependent_md = {}
        for name, expt in md_expectations.items():
            if expt.depends_on and name in orig_md:
                master_name = expt.depends_on
                correct_dependent_md[name] = expt.dependent_transformation(
                    new_md[master_name])

        @retry
        def assert_metadata_is(sid, orig_md, correct_dependent_md):
            result_md = self._assert_get_song(sid)

            with Check() as check:
                for name, expt in md_expectations.items():
                    if name in orig_md:
                        #TODO really need to factor out to test_utils?

                        #Check mutability if it's not volatile or dependent.
                        if not expt.volatile and expt.depends_on is None:
                            same, message = test_utils.md_entry_same(
                                name, orig_md, result_md)
                            check.equal(
                                not expt.mutable, same,
                                "metadata mutability incorrect: " + message)

                        #Check dependent md.
                        if expt.depends_on is not None:
                            same, message = test_utils.md_entry_same(
                                name, correct_dependent_md, result_md)
                            check.true(
                                same,
                                "dependent metadata incorrect: " + message)

        assert_metadata_is(self.song.sid, orig_md, correct_dependent_md)

        #Revert the metadata.
        self.wc.change_song_metadata(orig_md)

        @retry
        def assert_metadata_reverted(sid, orig_md):
            result_md = self._assert_get_song(sid)

            with Check() as check:
                for name in orig_md:
                    #If it's not volatile, it should be back to what it was.
                    if not md_expectations[name].volatile:
                        same, message = test_utils.md_entry_same(
                            name, orig_md, result_md)
                        check.true(same, "failed to revert: " + message)

        assert_metadata_reverted(self.song.sid, orig_md)
    def change_metadata(self):
        orig_md = self._assert_get_song(self.song.sid)

        # Change all mutable entries.

        new_md = copy(orig_md)

        for name, expt in md_expectations.items():
            if name in orig_md and expt.mutable:
                old_val = orig_md[name]
                new_val = test_utils.modify_md(name, old_val)

                assert_not_equal(new_val, old_val)
                new_md[name] = new_val

        # TODO check into attempting to mutate non mutables
        self.wc.change_song_metadata(new_md)

        # Recreate the dependent md to what they should be (based on how orig_md was changed)
        correct_dependent_md = {}
        for name, expt in md_expectations.items():
            if expt.depends_on and name in orig_md:
                master_name = expt.depends_on
                correct_dependent_md[name] = expt.dependent_transformation(new_md[master_name])

        @retry
        def assert_metadata_is(sid, orig_md, correct_dependent_md):
            result_md = self._assert_get_song(sid)

            with Check() as check:
                for name, expt in md_expectations.items():
                    if name in orig_md:
                        # TODO really need to factor out to test_utils?

                        # Check mutability if it's not volatile or dependent.
                        if not expt.volatile and expt.depends_on is None:
                            same, message = test_utils.md_entry_same(name, orig_md, result_md)
                            check.equal(not expt.mutable, same, "metadata mutability incorrect: " + message)

                        # Check dependent md.
                        if expt.depends_on is not None:
                            same, message = test_utils.md_entry_same(name, correct_dependent_md, result_md)
                            check.true(same, "dependent metadata incorrect: " + message)

        assert_metadata_is(self.song.sid, orig_md, correct_dependent_md)

        # Revert the metadata.
        self.wc.change_song_metadata(orig_md)

        @retry
        def assert_metadata_reverted(sid, orig_md):
            result_md = self._assert_get_song(sid)

            with Check() as check:
                for name in orig_md:
                    # If it's not volatile, it should be back to what it was.
                    if not md_expectations[name].volatile:
                        same, message = test_utils.md_entry_same(name, orig_md, result_md)
                        check.true(same, "failed to revert: " + message)

        assert_metadata_reverted(self.song.sid, orig_md)
import validictory

from gmusicapi.compat import json
from gmusicapi.exceptions import CallFailure, ValidationException
from gmusicapi.protocol.metadata import md_expectations
from gmusicapi.protocol.shared import Call, authtypes
from gmusicapi.utils import utils, jsarray

base_url = "https://play.google.com/music/"
service_url = base_url + "services/"

# Shared response schemas, built to include metadata expectations.
song_schema = {
    "type": "object",
    "properties": dict((name, expt.get_schema()) for name, expt in md_expectations.items()),
    # don't allow metadata not in expectations
    "additionalProperties": False,
}

song_array = {"type": "array", "items": song_schema}

pl_schema = {
    "type": "object",
    "properties": {
        "continuation": {"type": "boolean"},
        "playlist": song_array,
        "playlistId": {"type": "string"},
        "unavailableTrackCount": {"type": "integer"},
        # unsure what this field does. sometimes it's not there.
        "token": {"type": "string", "required": False},
from gmusicapi.compat import json
from gmusicapi.exceptions import CallFailure, ValidationException
from gmusicapi.protocol.metadata import md_expectations
from gmusicapi.protocol.shared import Call, authtypes
from gmusicapi.utils import utils

base_url = 'https://play.google.com/music/'
service_url = base_url + 'services/'

#Shared response schemas, built to include metadata expectations.
song_schema = {
    "type": "object",
    "properties": dict(
        (name, expt.get_schema()) for
        name, expt in md_expectations.items()
    ),
    #don't allow metadata not in expectations
    "additionalProperties": False
}

song_array = {
    "type": "array",
    "items": song_schema
}

pl_schema = {
    "type": "object",
    "properties": {
        "continuation": {"type": "boolean"},
        "playlist": song_array,
Beispiel #10
0
    def test_change_song_metadata(self):
        """Change a song's metadata, then restore it."""
        #Get a random song's metadata.
        orig_md = [s for s in self.library if s["id"] == self.r_song_id][0]
        log.debug("original md: %s", repr(orig_md))

        #Generate noticably changed metadata for ones we can change.
        #Changing immutable ones voids the request (although we get back success:True and our expected values).
        new_md = copy.deepcopy(orig_md)

        for name, expt in md_expectations.items():
            if name in orig_md and expt.mutable:
                old_val = orig_md[name]
                new_val = test_utils.modify_md(name, old_val)

                log.debug("%s: %s modified to %s", name, repr(old_val),
                          repr(new_val))
                self.assertNotEqual(new_val, old_val)
                new_md[name] = new_val

        #Make the call to change the metadata.
        #This should succeed, even though we _shouldn't_ be able to change some entries.
        #The call only fails if you give the wrong datatype.
        self.api.change_song_metadata(new_md)

        #Recreate the dependent md to what they should be (based on how orig_md was changed)
        correct_dependent_md = {}
        for name, expt in md_expectations.items():
            if expt.depends_on and name in orig_md:
                master_name = expt.depends_on
                correct_dependent_md[name] = expt.dependent_transformation(
                    new_md[master_name])

                # master_key, trans = dependent_md[name]
                # correct_dependent_md[dep_key] = trans(new_md[master_key])

                log.debug("dependents (%s): %s -> %s", name,
                          new_md[master_name], correct_dependent_md[name])

        #The library needs to be refreshed to flush the changes.
        #This might not happen right away, so we allow a few retries.

        max_attempts = 3
        sleep_for = 3

        attempts = 0
        success = False

        #TODO: this is cludgey, and should be pulled out with the below retry logic.
        while not success and attempts < max_attempts:
            time.sleep(sleep_for)
            self.library = self.api.get_all_songs()

            attempts += 1

            result_md = [s for s in self.library
                         if s["id"] == orig_md["id"]][0]
            log.debug("result md: %s", repr(result_md))

            try:
                #Verify everything went as expected:
                for name, expt in md_expectations.items():
                    if name in orig_md:
                        #Check mutability if it's not volatile or dependent.
                        if not expt.volatile and expt.depends_on is None:
                            same, message = test_utils.md_entry_same(
                                name, orig_md, result_md)
                            self.assertEqual(
                                same, (not expt.mutable),
                                "metadata mutability incorrect: " + message)

                        #Check dependent md.
                        if expt.depends_on is not None:
                            same, message = test_utils.md_entry_same(
                                name, correct_dependent_md, result_md)
                            self.assertTrue(
                                same,
                                "dependent metadata incorrect: " + message)

            except AssertionError:
                log.info("retrying server for changed metadata")
                if not attempts < max_attempts: raise
            else:
                success = True

        #Revert the metadata.
        self.api.change_song_metadata(orig_md)

        #Verify everything is as it was.

        attempts = 0
        success = False

        while not success and attempts < max_attempts:
            time.sleep(sleep_for)
            self.library = self.api.get_all_songs()

            attempts += 1

            result_md = [s for s in self.library
                         if s["id"] == orig_md["id"]][0]
            log.debug("result md: %s", repr(result_md))

            try:
                for name in orig_md:
                    #If it's not volatile, it should be back to what it was.
                    if not md_expectations[name].volatile:
                        same, message = test_utils.md_entry_same(
                            name, orig_md, result_md)
                        self.assertTrue(same, "failed to revert: " + message)

            except AssertionError:
                log.info("retrying server for reverted metadata")
                if not attempts < max_attempts:
                    raise
            else:
                success = True