def set_narratorial(self, ctx, params):
        """
        Allows a user to create a Narratorial given a WS they own. Right now
        anyone can do this, but we may restrict in the future to users that
        have a particular role.  Run simply as:
            ns.set_narratorial({'ws':'MyWsName'}) or,
            ns.set_narratorial({'ws':'4231'})
        :param params: instance of type "SetNarratorialParams" (ws field is a
           string, but properly interpreted whether it is a workspace name or
           ID) -> structure: parameter "ws" of String, parameter
           "description" of String
        :returns: instance of type "SetNarratorialResult" -> structure:
        """
        # ctx is the context object
        # return variables are: returnVal
        #BEGIN set_narratorial
        if 'ws' not in params:
            raise ValueError('"ws" field indicating WS name or id is required.')
        if 'description' not in params:
            raise ValueError('"description" field indicating WS name or id is required.')
        ws = Workspace(self.workspaceURL, token=ctx["token"])
        nu = NarratorialUtils()
        nu.set_narratorial(params['ws'], params['description'], ws)
        returnVal = {}
        #END set_narratorial

        # At some point might do deeper type checking...
        if not isinstance(returnVal, dict):
            raise ValueError('Method set_narratorial return value ' +
                             'returnVal is not type dict as required.')
        # return the results
        return [returnVal]
    def test_narratorial_utils_and_listing(self):

        suffix = int(time.time() * 1000)
        wsName = "test_NarrativeService_Narratorial_" + str(suffix)
        ws_info = self.wsClient.create_workspace({'workspace': wsName})
        wsid = ws_info[0]

        nu = NarratorialUtils()
        nu.set_narratorial(wsid, 'some narratorial', self.wsClient)
        nar_info = self.wsClient.save_objects({'workspace': wsName,
                                               'objects': [{'type': 'KBaseNarrative.Narrative',
                                                            'data': {'nbformat_minor': 0,
                                                                     'cells': [],
                                                                     'metadata': {'description': '',
                                                                                  'data_dependencies': []},
                                                                     'nbformat': 4},
                                                            'name': 'narrrrr',
                                                            'provenance': []}]})[0]
        self.wsClient.alter_workspace_metadata({'wsi': {'id': wsid}, 'new': {'narrative': nar_info[0]}})

        nlu = NarrativeListUtils(5000)
        narratorial_list = nlu.list_narratorials(self.wsClient)
        self.assertTrue(len(narratorial_list) > 0)
        found = False
        for nt in narratorial_list:
            self.assertIn('ws', nt)
            self.assertIn('nar', nt)
            self.assertIn('narratorial', nt['ws'][8])
            self.assertIn('narratorial_description', nt['ws'][8])
            self.assertTrue(int(nt['ws'][8]['narrative']), nt['nar'][0])
            if wsid == nt['ws'][0]:
                found = True
                self.assertEqual('some narratorial', nt['ws'][8]['narratorial_description'])

        self.assertTrue(found)

        # remove the narratorial, make sure it doesn't show up anymore
        nu.remove_narratorial(wsid, self.wsClient)

        narratorial_list = nlu.list_narratorials(self.wsClient)
        found = False
        for nt in narratorial_list:
            self.assertIn('ws', nt)
            self.assertIn('nar', nt)
            self.assertTrue(int(nt['ws'][8]['narrative']), nt['nar'][0])
            if wsid == nt['ws'][0]:
                found = True
        self.assertTrue(not found)

        self.wsClient.delete_workspace({'id': wsid})