diff --git a/src/AbstractConfigATestCase.php b/src/AbstractConfigATestCase.php deleted file mode 100644 index c7f46e3..0000000 --- a/src/AbstractConfigATestCase.php +++ /dev/null @@ -1,152 +0,0 @@ -newConfigA(); - static::assertInstanceOf(IConfig::class, $config); - static::assertInstanceOf(IConfigA::class, $config); - static::assertInstanceOf(AbstractConfigA::class, $config); - } - - /** - * Test a valid config creation. - */ - public function testValidConfig() - { - $configArr = [ - 'ashost' => 'sap.example.com', - 'sysnr' => '000', - 'client' => '01', - 'user' => 'username', - 'passwd' => 'password', - 'gwhost' => 'gw.example.com', - 'gwserv' => 'abc', - 'lang' => 'EN', - 'trace' => IConfigA::TRACE_FULL - ]; - $configJson = json_encode($configArr); - $config = $this->newConfigA($configJson); - $this->assertValidModuleConfig( - $config->generateConfig(), - 'sap.example.com', - '000', - '01', - 'username', - 'password', - 'gw.example.com', - 'abc', - 'EN', - IConfigA::TRACE_FULL - ); - } - - /** - * Data provider for incomplete config. - * @return array - */ - public static function incompleteConfig() - { - return [ - [ - [ - 'ashost' => 'sap.example.com', - 'sysnr' => '000', - 'client' => '01', - 'user' => 'username' - ], - 'passwd' - ], - [ - [ - 'ashost' => 'sap.example.com', - 'sysnr' => '000', - 'user' => 'username', - 'passwd' => 'password', - 'gwhost' => 'gw.example.com', - 'gwserv' => 'abc', - 'lang' => 'EN', - 'trace' => IConfigA::TRACE_BRIEF - ], - 'client' - ] - ]; - } - - /** - * Test incomplete config exception. - * @param array $configArr - * @param string $missing - * @dataProvider incompleteConfig - */ - public function testIncompleteConfig($configArr, $missing) - { - $configJson = json_encode($configArr); - $config = $this->newConfigA($configJson); - $expectedMsg = sprintf('Missing mandatory key %s.', $missing); - $this->setExpectedException(IncompleteConfigException::class, $expectedMsg); - $config->generateConfig(); - } - - /** - * Return a new instance of a PHP/SAP config type A. - * @param array|string|null $config PHP/SAP config JSON/array. Default: null - * @return \phpsap\interfaces\IConfigA - */ - abstract public function newConfigA($config = null); - - /** - * Assert the actual module configuration variable. - * @param mixed $configSaprfc - * @param string $ashost - * @param string $sysnr - * @param string $client - * @param string $user - * @param string $passwd - * @param string $gwhost - * @param string $gwserv - * @param string $lang - * @param int $trace - */ - abstract public function assertValidModuleConfig( - $configSaprfc, - $ashost, - $sysnr, - $client, - $user, - $passwd, - $gwhost, - $gwserv, - $lang, - $trace - ); -} diff --git a/src/AbstractConfigBTestCase.php b/src/AbstractConfigBTestCase.php deleted file mode 100644 index d30e604..0000000 --- a/src/AbstractConfigBTestCase.php +++ /dev/null @@ -1,147 +0,0 @@ -newConfigB(); - static::assertInstanceOf(IConfig::class, $config); - static::assertInstanceOf(IConfigB::class, $config); - static::assertInstanceOf(AbstractConfigB::class, $config); - } - - /** - * Test a valid config creation. - */ - public function testValidConfig() - { - $configArr = [ - 'client' => '02', - 'user' => 'username', - 'passwd' => 'password', - 'mshost' => 'sap.example.com', - 'r3name' => 'system_id', - 'group' => 'logon_group', - 'lang' => 'EN', - 'trace' => IConfigB::TRACE_VERBOSE - ]; - $configJson = json_encode($configArr); - $config = $this->newConfigB($configJson); - $this->assertValidModuleConfig( - $config->generateConfig(), - '02', - 'username', - 'password', - 'sap.example.com', - 'system_id', - 'logon_group', - 'EN', - IConfigB::TRACE_VERBOSE - ); - } - - /** - * Data provider for incomplete config. - * @return array - */ - public static function incompleteConfig() - { - return [ - [ - [ - 'client' => '02', - 'user' => 'username', - 'passwd' => 'password', - 'r3name' => 'system_id', - 'group' => 'logon_group' - ], - 'mshost' - ], - [ - [ - 'user' => 'username', - 'passwd' => 'password', - 'mshost' => 'sap.example.com', - 'group' => 'logon_group', - 'lang' => 'EN', - 'trace' => IConfigB::TRACE_OFF - ], - 'client' - ] - ]; - } - - /** - * Test incomplete config exception. - * @param array $configArr - * @param string $missing - * @dataProvider incompleteConfig - */ - public function testIncompleteConfig($configArr, $missing) - { - $configJson = json_encode($configArr); - $config = $this->newConfigB($configJson); - $expectedMsg = sprintf('Missing mandatory key %s.', $missing); - $this->setExpectedException(IncompleteConfigException::class, $expectedMsg); - $config->generateConfig(); - } - - /** - * Return a new instance of a PHP/SAP config type B. - * @param array|string|null $config PHP/SAP config JSON/array. Default: null - * @return \phpsap\interfaces\IConfigB - */ - abstract public function newConfigB($config = null); - - /** - * Assert the actual module configuration variable. - * @param mixed $configSaprfc - * @param string $client - * @param string $user - * @param string $passwd - * @param string $mshost - * @param string $r3name - * @param string $group - * @param string $lang - * @param int $trace - */ - abstract public function assertValidModuleConfig( - $configSaprfc, - $client, - $user, - $passwd, - $mshost, - $r3name, - $group, - $lang, - $trace - ); -} diff --git a/src/AbstractConnectionTestCase.php b/src/AbstractConnectionTestCase.php deleted file mode 100644 index fc26150..0000000 --- a/src/AbstractConnectionTestCase.php +++ /dev/null @@ -1,126 +0,0 @@ -getModuleName())) { - //load functions mocking SAP RFC module functions or class methods - $this->mockSuccessfulConnect(); - //load a bogus config - $config = $this->getSampleSapConfig(); - } else { - //load a valid config - $config = $this->getSapConfig(); - } - $connection = $this->newConnection($config); - static::assertFalse($connection->isConnected()); - $connection->connect(); - static::assertTrue($connection->isConnected()); - $connection->connect(); - static::assertTrue($connection->isConnected()); - $connection->close(); - static::assertFalse($connection->isConnected()); - } - - /** - * Mock the SAP RFC module for a failed connection attempt. - */ - abstract protected function mockFailedConnect(); - - /** - * Test a failed connection attempt using either the module or its mockup. - * @expectedException \phpsap\exceptions\ConnectionFailedException - */ - public function testFailedConnect() - { - if (!extension_loaded($this->getModuleName())) { - //load functions mocking SAP RFC module functions or class methods - $this->mockFailedConnect(); - //load a bogus config - $config = $this->getSampleSapConfig(); - } else { - //load an invalid config - $config = $this->getSampleSapConfig(); - } - $connection = $this->newConnection($config); - $connection->connect(); - } - - /** - * Mock the SAP RFC module for a successful attempt to ping a connection. - */ - abstract protected function mockSuccessfulPing(); - - /** - * Test a successful attempt to ping a connection using either the module or its - * mockup. - */ - public function testSuccessfulPing() - { - if (!extension_loaded($this->getModuleName())) { - //load functions mocking SAP RFC module functions or class methods - $this->mockSuccessfulPing(); - //load a bogus config - $config = $this->getSampleSapConfig(); - } else { - //load a valid config - $config = $this->getSapConfig(); - } - $connection = $this->newConnection($config); - $result = $connection->ping(); - static::assertTrue($result); - } - - /** - * Mock the SAP RFC module for a failed attempt to ping a connection. - */ - abstract protected function mockFailedPing(); - - /** - * Test a failed attempt to ping a connection using either the module or its - * mockup. - */ - public function testFailedPing() - { - if (!extension_loaded($this->getModuleName())) { - //load functions mocking SAP RFC module functions or class methods - $this->mockFailedPing(); - //load a bogus config - $config = $this->getSampleSapConfig(); - } else { - static::markTestSkipped('Cannot test a failing ping with SAP module loaded.'); - } - $connection = $this->newConnection($config); - $result = $connection->ping(); - static::assertFalse($result); - } -} diff --git a/src/AbstractFunctionTestCase.php b/src/AbstractFunctionTestCase.php deleted file mode 100644 index 149f70f..0000000 --- a/src/AbstractFunctionTestCase.php +++ /dev/null @@ -1,218 +0,0 @@ -getModuleName())) { - //load functions mocking SAP RFC module functions or class methods - $this->mockSuccessfulFunctionCall(); - //load a bogus config - $config = $this->getSampleSapConfig(); - } else { - //load a valid config - $config = $this->getSapConfig(); - } - $connection = $this->newConnection($config); - $function = $connection->prepareFunction('RFC_PING'); - $result = $function->invoke(); - static::assertSame([], $result); - } - - /** - * Mock the SAP RFC module for an unknown function call exception. - */ - abstract protected function mockUnknownFunctionException(); - - /** - * Test invoking an unknown function an receiving an exception. - * @expectedException \phpsap\exceptions\UnknownFunctionException - * @expectedExceptionMessageRegExp "^Unknown function RFC_PINGG: .*" - */ - public function testUnknownFunctionException() - { - if (!extension_loaded($this->getModuleName())) { - //load functions mocking SAP RFC module functions or class methods - $this->mockUnknownFunctionException(); - //load a bogus config - $config = $this->getSampleSapConfig(); - } else { - //load a valid config - $config = $this->getSapConfig(); - } - $connection = $this->newConnection($config); - $function = $connection->prepareFunction('RFC_PINGG'); - $function->invoke(); - } - - /** - * Mock the SAP RFC module for a successful SAP remote function call with - * parameters and results. - */ - abstract protected function mockRemoteFunctionCallWithParametersAndResults(); - - /** - * Test successful SAP remote function call with parameters and results. - */ - public function testRemoteFunctionCallWithParametersAndResults() - { - if (!extension_loaded($this->getModuleName())) { - //load functions mocking SAP RFC module functions or class methods - $this->mockRemoteFunctionCallWithParametersAndResults(); - //load a bogus config - $config = $this->getSampleSapConfig(); - } else { - //load a valid config - $config = $this->getSapConfig(); - } - //prepare a DateTime object for testing SAP date and time. - $testDateTime = new \DateTime('2019-10-30 10:20:30'); - //prepare function call parameter - $test_in = [ - 'RFCFLOAT' => 70.11, - 'RFCCHAR1' => 'A', - 'RFCINT2' => 4095, - 'RFCINT1' => 163, - 'RFCCHAR4' => 'QqMh', - 'RFCINT4' => 416639, - 'RFCHEX3' => '53', //=S - 'RFCCHAR2' => 'XC', - 'RFCTIME' => $testDateTime->format(SapDateTime::SAP_TIME), - 'RFCDATE' => $testDateTime->format(SapDateTime::SAP_DATE), - 'RFCDATA1' => 'qKWjmNfad32rfS9Z', - 'RFCDATA2' => 'xi82ph2zJ8BCVtlR' - ]; - //remote function call - $jsonFile = __DIR__ . DIRECTORY_SEPARATOR . 'RFC_WALK_THRU_TEST.json'; - $result = $this->newConnection($config) - ->prepareFunction('RFC_WALK_THRU_TEST') - ->setApi(new RemoteApi(file_get_contents($jsonFile))) - ->setParam('TEST_IN', $test_in) - ->setParam('DESTINATIONS', [ - ['RFCDEST' => 'AOP3'] - ]) - ->invoke(); - //assert basics - static::assertInternalType('array', $result); - static::assertArrayHasKey('TEST_OUT', $result); - //create a link for programmer's convenience ... - $test_out = &$result['TEST_OUT']; - /** - * Assert float value. - */ - static::assertArrayHasKey('RFCFLOAT', $test_out, 'Missing RFCFLOAT in TEST_OUT!'); - static::assertSame(70.11, $test_out['RFCFLOAT'], 'Test IN and OUT of RFCFLOAT don\'t match!'); - /** - * Assert integer values. - */ - static::assertArrayHasKey('RFCINT1', $test_out, 'Missing RFCINT1 in TEST_OUT!'); - static::assertSame(163, $test_out['RFCINT1'], 'Test IN and OUT of RFCINT1 don\'t match!'); - static::assertArrayHasKey('RFCINT2', $test_out, 'Missing RFCINT2 in TEST_OUT!'); - static::assertSame(4095, $test_out['RFCINT2'], 'Test IN and OUT of RFCINT2 don\'t match!'); - static::assertArrayHasKey('RFCINT4', $test_out, 'Missing RFCINT4 in TEST_OUT!'); - static::assertSame(416639, $test_out['RFCINT4'], 'Test IN and OUT of RFCINT4 don\'t match!'); - /** - * Assert DateTime objects. - */ - static::assertArrayHasKey('RFCTIME', $test_out, 'Missing RFCTIME in TEST_OUT!'); - static::assertInstanceOf(\DateTime::class, $test_out['RFCTIME'], 'Test OUT of RFCTIME is not DateTime!'); - static::assertSame($testDateTime->format('H:i:s'), $test_out['RFCTIME']->format('H:i:s')); - static::assertArrayHasKey('RFCDATE', $test_out, 'Missing RFCDATE in TEST_OUT!'); - static::assertInstanceOf(\DateTime::class, $test_out['RFCDATE'], 'Test OUT of RFCDATE is not DateTime!'); - static::assertSame($testDateTime->format('Y-m-d'), $test_out['RFCDATE']->format('Y-m-d')); - /** - * Assert hexadecimal value. - */ - static::assertArrayHasKey('RFCHEX3', $test_out, 'Missing RFCHEX3 in TEST_OUT!'); - static::assertSame('S', $test_out['RFCHEX3'], 'Test IN and OUT of RFCHEX3 don\'t match!'); - /** - * Assert string values. - */ - static::assertArrayHasKey('RFCCHAR1', $test_out, 'Missing RFCCHAR1 in TEST_OUT!'); - static::assertSame('A', $test_out['RFCCHAR1'], 'Test IN and OUT of RFCCHAR1 don\'t match!'); - static::assertArrayHasKey('RFCCHAR2', $test_out, 'Missing RFCCHAR2 in TEST_OUT!'); - static::assertSame('XC', $test_out['RFCCHAR2'], 'Test IN and OUT of RFCCHAR2 don\'t match!'); - static::assertArrayHasKey('RFCCHAR4', $test_out, 'Missing RFCCHAR4 in TEST_OUT!'); - static::assertSame('QqMh', $test_out['RFCCHAR4'], 'Test IN and OUT of RFCCHAR4 don\'t match!'); - static::assertArrayHasKey('RFCDATA1', $test_out, 'Missing RFCDATA1 in TEST_OUT!'); - static::assertSame('qKWjmNfad32rfS9Z', $test_out['RFCDATA1'], 'Test IN and OUT of RFCDATA1 don\'t match!'); - static::assertArrayHasKey('RFCDATA2', $test_out, 'Missing RFCDATA2 in TEST_OUT!'); - static::assertSame('xi82ph2zJ8BCVtlR', $test_out['RFCDATA2'], 'Test IN and OUT of RFCDATA2 don\'t match!'); - /** - * Assert empty table parameter 'DESTINATIONS'. - */ - static::assertArrayHasKey('DESTINATIONS', $result); - static::assertEmpty($result['DESTINATIONS']); - /** - * Assert return table 'LOG' and that RFCDEST is the same as in the - * 'DESTINATIONS' table parameter. - */ - static::assertArrayHasKey('LOG', $result); - static::assertArrayHasKey(0, $result['LOG']); - static::assertInternalType('array', $result['LOG'][0]); - static::assertArrayHasKey('RFCDEST', $result['LOG'][0]); - static::assertSame('AOP3', $result['LOG'][0]['RFCDEST']); - } - - /** - * Mock the SAP RFC module for a failed SAP remote function call with parameters. - */ - abstract protected function mockFailedRemoteFunctionCallWithParameters(); - - /** - * Test a failed remote function call with parameters. - * @expectedException \phpsap\exceptions\FunctionCallException - * @expectedExceptionMessageRegExp "^Function call RFC_READ_TABLE failed: .*" - */ - public function testFailedRemoteFunctionCallWithParameters() - { - if (!extension_loaded($this->getModuleName())) { - //load functions mocking SAP RFC module functions or class methods - $this->mockFailedRemoteFunctionCallWithParameters(); - //load a bogus config - $config = $this->getSampleSapConfig(); - } else { - //load a valid config - $config = $this->getSapConfig(); - } - //try to invoke a function call using an invalid parameter value - $jsonFile = __DIR__ . DIRECTORY_SEPARATOR . 'RFC_READ_TABLE.json'; - $this->newConnection($config) - ->prepareFunction('RFC_READ_TABLE') - ->setApi(new RemoteApi(file_get_contents($jsonFile))) - ->setParam('QUERY_TABLE', '&') - ->invoke(); - } -} diff --git a/src/AbstractSapRfcTestCase.php b/src/AbstractSapRfcTestCase.php new file mode 100644 index 0000000..931a81a --- /dev/null +++ b/src/AbstractSapRfcTestCase.php @@ -0,0 +1,357 @@ +mockConnectionFailed(); + } + $saprfc = static::newSapRfc('RFC_PING', null, new ConfigTypeA([ + 'ashost' => 'sap.example.com', + 'sysnr' => '001', + 'client' => '002', + 'user' => 'username', + 'passwd' => 'password' + ]), static::getApi('RFC_PING')); + static::assertInstanceOf(IFunction::class, $saprfc); + $cfg = $saprfc->getConfiguration(); + static::assertInstanceOf(IConfigTypeA::class, $cfg); + static::assertSame('sap.example.com', $cfg->getAshost()); + static::assertSame('001', $cfg->getSysnr()); + static::assertSame('002', $cfg->getClient()); + //Set a clearly non-existing hostname to cause a connection failure. + $saprfc->getConfiguration()->setAshost('prod.sap.example.com'); + static::assertSame('prod.sap.example.com', $cfg->getAshost()); + /** + * Try to establish a connection, which should fail because of example.com. + */ + $saprfc->invoke(); + } + + /** + * Test SAP RFC connection type B configuration. + * @expectedException \phpsap\interfaces\exceptions\IConnectionFailedException + */ + public function testConnectionConfigTypeB() + { + if (!extension_loaded(static::getModuleName())) { + //load functions mocking SAP RFC module functions or class methods + $this->mockConnectionFailed(); + } + $saprfc = static::newSapRfc('RFC_PING', null, new ConfigTypeB([ + 'mshost' => 'msg.sap.example.com', + 'group' => 'grp01', + 'client' => '003', + 'user' => 'username', + 'passwd' => 'password' + ]), static::getApi('RFC_PING')); + static::assertInstanceOf(IFunction::class, $saprfc); + /** + * @var IConfigTypeB $cfg + */ + $cfg = $saprfc->getConfiguration(); + static::assertInstanceOf(IConfigTypeB::class, $cfg); + static::assertSame('msg.sap.example.com', $cfg->getMshost()); + static::assertSame('grp01', $cfg->getGroup()); + static::assertSame('003', $cfg->getClient()); + $saprfc->getConfiguration()->setMshost('grp01msg.sap.example.com'); + static::assertSame('grp01msg.sap.example.com', $cfg->getMshost()); + /** + * Try to establish a connection, which should fail because of example.com. + */ + $saprfc->invoke(); + } + + /** + * Mock the SAP RFC module for a successful connection attempt. + */ + abstract protected function mockSuccessfulRfcPing(); + + /** + * Test a successful SAP remote function call to RFC_PING. + */ + public function testSuccessfulRfcPing() + { + if (!extension_loaded(static::getModuleName())) { + //load functions mocking SAP RFC module functions or class methods + $this->mockSuccessfulRfcPing(); + //load a bogus config + $config = static::getSampleSapConfig(); + } else { + //load a valid config + $config = static::getActualSapConfig(); + } + $rfcPing = static::newSapRfc('RFC_PING', null, $config); + static::assertInstanceOf(IFunction::class, $rfcPing); + $result = $rfcPing->invoke(); + static::assertSame([], $result); + } + + /** + * Data provider for incomplete configurations. + * @return array + */ + public static function provideIncompleteConfig() + { + return [ + [null], + [new ConfigTypeA()], + [new ConfigTypeA([ + ConfigTypeA::JSON_CLIENT => '001', + ConfigTypeA::JSON_USER => 'username', + ConfigTypeA::JSON_PASSWD => 'password' + ])], + [new ConfigTypeA([ + ConfigTypeA::JSON_ASHOST => 'sap.example.com', + ConfigTypeA::JSON_CLIENT => '001', + ConfigTypeA::JSON_USER => 'username', + ConfigTypeA::JSON_PASSWD => 'password' + ])], + [new ConfigTypeA([ + ConfigTypeA::JSON_SYSNR => '00', + ConfigTypeA::JSON_CLIENT => '001', + ConfigTypeA::JSON_USER => 'username', + ConfigTypeA::JSON_PASSWD => 'password' + ])], + [new ConfigTypeA([ + ConfigTypeA::JSON_GWHOST => 'sapgw.example.com', + ConfigTypeA::JSON_CLIENT => '001', + ConfigTypeA::JSON_USER => 'username', + ConfigTypeA::JSON_PASSWD => 'password' + ])], + [new ConfigTypeA([ + ConfigTypeA::JSON_GWSERV => 'sapsrv', + ConfigTypeA::JSON_CLIENT => '001', + ConfigTypeA::JSON_USER => 'username', + ConfigTypeA::JSON_PASSWD => 'password' + ])], + [new ConfigTypeB()], + [new ConfigTypeB([ + ConfigTypeA::JSON_CLIENT => '001', + ConfigTypeA::JSON_USER => 'username', + ConfigTypeA::JSON_PASSWD => 'password' + ])], + [new ConfigTypeB([ + ConfigTypeB::JSON_R3NAME => 'name', + ConfigTypeA::JSON_CLIENT => '001', + ConfigTypeA::JSON_USER => 'username', + ConfigTypeA::JSON_PASSWD => 'password' + ])], + [new ConfigTypeB([ + ConfigTypeB::JSON_GROUP => 'group', + ConfigTypeA::JSON_CLIENT => '001', + ConfigTypeA::JSON_USER => 'username', + ConfigTypeA::JSON_PASSWD => 'password' + ])], + [new ConfigTypeB([ + ConfigTypeB::JSON_MSHOST => 'mshost.example.com', + ConfigTypeB::JSON_LANG => 'DE', + ConfigTypeB::JSON_TRACE => ConfigTypeB::TRACE_FULL + ])] + ]; + } + + /** + * Test a failed connection attempt using either the module or its mockup. + * @param \phpsap\interfaces\Config\IConfiguration $config + * @dataProvider provideIncompleteConfig + * @expectedException \phpsap\exceptions\IncompleteConfigException + */ + public function testIncompleteConfig($config) + { + /** + * Connection with empty configuration will be considered incomplete. + */ + static::newSapRfc('RFC_PING', null, $config, static::getApi('RFC_PING')) + ->invoke(); + } + + /** + * Mock the SAP RFC module for an unknown function call exception. + */ + abstract protected function mockUnknownFunctionException(); + + /** + * Test invoking an unknown function an receiving an exception. + * @expectedException \phpsap\exceptions\UnknownFunctionException + * @expectedExceptionMessageRegExp "^Unknown function RFC_PINGG: .*" + */ + public function testUnknownFunctionException() + { + if (!extension_loaded(static::getModuleName())) { + //load functions mocking SAP RFC module functions or class methods + $this->mockUnknownFunctionException(); + //load a bogus config + $config = static::getSampleSapConfig(); + } else { + //load a valid config + $config = static::getActualSapConfig(); + } + static::newSapRfc('RFC_PINGG', null, $config)->invoke(); + } + + /** + * Mock the SAP RFC module for a successful SAP remote function call with + * parameters and results. + */ + abstract protected function mockRemoteFunctionCallWithParametersAndResults(); + + /** + * Test successful SAP remote function call with parameters and results. + */ + public function testRemoteFunctionCallWithParametersAndResults() + { + if (!extension_loaded(static::getModuleName())) { + //load functions mocking SAP RFC module functions or class methods + $this->mockRemoteFunctionCallWithParametersAndResults(); + //load a bogus config + $config = static::getSampleSapConfig(); + } else { + //load a valid config + $config = static::getActualSapConfig(); + } + //prepare a DateTime object for testing SAP date and time. + $testDateTime = new \DateTime('2019-10-30 10:20:30'); + //prepare function call parameter + $test_in = [ + 'RFCFLOAT' => 70.11, + 'RFCCHAR1' => 'A', + 'RFCINT2' => 4095, + 'RFCINT1' => 163, + 'RFCCHAR4' => 'QqMh', + 'RFCINT4' => 416639, + 'RFCHEX3' => '53', //=S + 'RFCCHAR2' => 'XC', + 'RFCTIME' => $testDateTime->format(SapDateTime::SAP_TIME), + 'RFCDATE' => $testDateTime->format(SapDateTime::SAP_DATE), + 'RFCDATA1' => 'qKWjmNfad32rfS9Z', + 'RFCDATA2' => 'xi82ph2zJ8BCVtlR' + ]; + //remote function call + $result = static::newSapRfc('RFC_WALK_THRU_TEST') + ->setConfiguration($config) + ->setApi(static::getApi('RFC_WALK_THRU_TEST')) + ->setParam('TEST_IN', $test_in) + ->setParam('DESTINATIONS', [ + ['RFCDEST' => 'AOP3'] + ]) + ->invoke(); + //assert basics + static::assertInternalType('array', $result); + static::assertArrayHasKey('TEST_OUT', $result); + //create a link for programmer's convenience ... + $test_out = &$result['TEST_OUT']; + /** + * Assert float value. + */ + static::assertArrayHasKey('RFCFLOAT', $test_out, 'Missing RFCFLOAT in TEST_OUT!'); + static::assertSame(70.11, $test_out['RFCFLOAT'], 'Test IN and OUT of RFCFLOAT don\'t match!'); + /** + * Assert integer values. + */ + static::assertArrayHasKey('RFCINT1', $test_out, 'Missing RFCINT1 in TEST_OUT!'); + static::assertSame(163, $test_out['RFCINT1'], 'Test IN and OUT of RFCINT1 don\'t match!'); + static::assertArrayHasKey('RFCINT2', $test_out, 'Missing RFCINT2 in TEST_OUT!'); + static::assertSame(4095, $test_out['RFCINT2'], 'Test IN and OUT of RFCINT2 don\'t match!'); + static::assertArrayHasKey('RFCINT4', $test_out, 'Missing RFCINT4 in TEST_OUT!'); + static::assertSame(416639, $test_out['RFCINT4'], 'Test IN and OUT of RFCINT4 don\'t match!'); + /** + * Assert DateTime objects. + */ + static::assertArrayHasKey('RFCTIME', $test_out, 'Missing RFCTIME in TEST_OUT!'); + static::assertArrayHasKey('RFCDATE', $test_out, 'Missing RFCDATE in TEST_OUT!'); + static::assertInstanceOf(\DateTime::class, $test_out['RFCTIME'], 'Test OUT of RFCTIME is not DateTime!'); + static::assertSame($testDateTime->format('H:i:s'), $test_out['RFCTIME']->format('H:i:s')); + static::assertInstanceOf(\DateTime::class, $test_out['RFCDATE'], 'Test OUT of RFCDATE is not DateTime!'); + static::assertSame($testDateTime->format('Y-m-d'), $test_out['RFCDATE']->format('Y-m-d')); + /** + * Assert hexadecimal value. + */ + static::assertArrayHasKey('RFCHEX3', $test_out, 'Missing RFCHEX3 in TEST_OUT!'); + static::assertSame('S', $test_out['RFCHEX3'], 'Test IN and OUT of RFCHEX3 don\'t match!'); + /** + * Assert string values. + */ + static::assertArrayHasKey('RFCCHAR1', $test_out, 'Missing RFCCHAR1 in TEST_OUT!'); + static::assertSame('A', $test_out['RFCCHAR1'], 'Test IN and OUT of RFCCHAR1 don\'t match!'); + static::assertArrayHasKey('RFCCHAR2', $test_out, 'Missing RFCCHAR2 in TEST_OUT!'); + static::assertSame('XC', $test_out['RFCCHAR2'], 'Test IN and OUT of RFCCHAR2 don\'t match!'); + static::assertArrayHasKey('RFCCHAR4', $test_out, 'Missing RFCCHAR4 in TEST_OUT!'); + static::assertSame('QqMh', $test_out['RFCCHAR4'], 'Test IN and OUT of RFCCHAR4 don\'t match!'); + static::assertArrayHasKey('RFCDATA1', $test_out, 'Missing RFCDATA1 in TEST_OUT!'); + static::assertSame('qKWjmNfad32rfS9Z', $test_out['RFCDATA1'], 'Test IN and OUT of RFCDATA1 don\'t match!'); + static::assertArrayHasKey('RFCDATA2', $test_out, 'Missing RFCDATA2 in TEST_OUT!'); + static::assertSame('xi82ph2zJ8BCVtlR', $test_out['RFCDATA2'], 'Test IN and OUT of RFCDATA2 don\'t match!'); + /** + * Assert empty table parameter 'DESTINATIONS'. + */ + static::assertArrayHasKey('DESTINATIONS', $result); + static::assertEmpty($result['DESTINATIONS']); + /** + * Assert return table 'LOG' and that RFCDEST is the same as in the + * 'DESTINATIONS' table parameter. + */ + static::assertArrayHasKey('LOG', $result); + static::assertArrayHasKey(0, $result['LOG']); + static::assertInternalType('array', $result['LOG'][0]); + static::assertArrayHasKey('RFCDEST', $result['LOG'][0]); + static::assertSame('AOP3', $result['LOG'][0]['RFCDEST']); + } + + /** + * Mock the SAP RFC module for a failed SAP remote function call with parameters. + */ + abstract protected function mockFailedRemoteFunctionCallWithParameters(); + + /** + * Test a failed remote function call with parameters. + * @expectedException \phpsap\exceptions\FunctionCallException + * @expectedExceptionMessageRegExp "^Function call RFC_READ_TABLE failed: .*" + */ + public function testFailedRemoteFunctionCallWithParameters() + { + if (!extension_loaded(static::getModuleName())) { + //load functions mocking SAP RFC module functions or class methods + $this->mockFailedRemoteFunctionCallWithParameters(); + //load a bogus config + $config = static::getSampleSapConfig(); + } else { + //load a valid config + $config = static::getActualSapConfig(); + } + static::newSapRfc('RFC_READ_TABLE') + ->setConfiguration($config) + ->setParam('QUERY_TABLE', '&') + ->invoke(); + } +} diff --git a/src/AbstractTestCase.php b/src/AbstractTestCase.php index 2dcf5f5..6961489 100644 --- a/src/AbstractTestCase.php +++ b/src/AbstractTestCase.php @@ -1,19 +1,19 @@ 'sap.example.com', - 'sysnr' => '001', - 'client' => '002', - 'user' => 'username', - 'passwd' => 'password' + 'ashost' => 'sap.example.com', + 'sysnr' => '001', + 'client' => '002', + 'user' => 'username', + 'passwd' => 'password' ]; /** * AbstractTestCase constructor. - * @param null $name - * @param array $data - * @param string $dataName + * @param string|null $name + * @param array $data + * @param string $dataName */ public function __construct($name = null, array $data = [], $dataName = '') { parent::__construct($name, $data, $dataName); - SapRfcModuleMocks::requireFile($this->getModuleTemplateFile()); - SapRfcModuleMocks::validModuleFunctions($this->getValidModuleFunctions()); + SapRfcModuleMocks::requireFile(static::getModuleTemplateFile()); + SapRfcModuleMocks::validModuleFunctions(static::getValidModuleFunctions()); } /** * Get a sample SAP config. - * @return array + * @return ConfigTypeA */ - protected function getSampleSapConfig() + public static function getSampleSapConfig() { - return static::$sampleSapConfig; + return new ConfigTypeA(static::$sampleSapConfig); } /** * Load an actual sap configuration. - * @return array + * @return ConfigTypeA|ConfigTypeB */ - protected function getSapConfig() + public static function getActualSapConfig() { - $configFile = $this->getSapConfigFile(); + /** + * Actual implementation has to return the path of a valid configuration file. + */ + $configFile = static::getSapConfigFile(); if (file_exists($configFile) !== true) { throw new \RuntimeException(sprintf( 'Cannot find config file %s!', $configFile )); } - + /** + * Try to read the configuration file. + */ if (($configJson = file_get_contents($configFile)) === false) { throw new \RuntimeException(sprintf( 'Cannot read from config file %s!', $configFile )); } + /** + * Let the Config* classes decide what to do with the given string. + * In case the string is not JSON, an exception will be thrown. + */ + return ConfigCommon::jsonDecode($configJson); + } - if (($configArr = json_decode($configJson, true)) === null) { + /** + * Load an actual SAP remote function call API description from file. + * @param string $remoteFunction + * @return \phpsap\classes\Api\RemoteApi + */ + public static function getApi($remoteFunction) + { + $file = __DIR__ . DIRECTORY_SEPARATOR; + $file .= sprintf('%s.json', $remoteFunction); + if (file_exists($file) !== true) { throw new \RuntimeException(sprintf( - 'Invalid JSON format in config file %s!', - $configFile + 'Cannot find SAP remote function API file %s!', + $file )); } - return $configArr; + /** + * Try to read the configuration file. + */ + if (($json = file_get_contents($file)) === false) { + throw new \RuntimeException(sprintf( + 'Cannot read from SAP remote function API file %s!', + $file + )); + } + return RemoteApi::jsonDecode($json); + } + + /** + * Initialize the remote function call with at least a name. + * In order to add SAP remote function call parameters, an API needs to be + * defined. In case no SAP remote function call API has been defined, it will be + * queried on the fly by connecting to the SAP remote system. In order to + * connect to the SAP remote system, you need a connection configuration. + * @param string $name SAP remote function name. + * @param array|null $params SAP remote function call parameters. Default: null + * @param \phpsap\interfaces\Config\IConfiguration|null $config Connection configuration. Default: null + * @param \phpsap\interfaces\Api\IApi|null $api SAP remote function call API. Default: null + * @return IFunction + * @throws \phpsap\interfaces\exceptions\IInvalidArgumentException + */ + public static function newSapRfc($name, array $params = null, IConfiguration $config = null, IApi $api = null) + { + $class = static::getClassName(); + return new $class($name, $params, $config, $api); } /** @@ -94,34 +142,33 @@ public static function mock($name, $logic) SapRfcModuleMocks::singleton()->mock($name, $logic); } + /** + * Return the name of the class, used for testing. + * @return string + */ + abstract public static function getClassName(); + /** * Get the name of the PHP module. * @return string */ - abstract public function getModuleName(); + abstract public static function getModuleName(); /** * Get the path to the PHP/SAP configuration file. * @return string */ - abstract public function getSapConfigFile(); + abstract public static function getSapConfigFile(); /** * Get the path to the filename containing the SAP RFC module mockups. * @return string */ - abstract public function getModuleTemplateFile(); + abstract public static function getModuleTemplateFile(); /** * Get an array of valid SAP RFC module function or class method names. * @return array */ - abstract public function getValidModuleFunctions(); - - /** - * Create a new instance of a PHP/SAP connection class. - * @param array|string|null $config The PHP/SAP configuration. Default: null - * @return \phpsap\interfaces\IConnection - */ - abstract public function newConnection($config = null); + abstract public static function getValidModuleFunctions(); } diff --git a/src/RFC_PING.json b/src/RFC_PING.json new file mode 100644 index 0000000..c44dc44 --- /dev/null +++ b/src/RFC_PING.json @@ -0,0 +1,3 @@ +[ + +] \ No newline at end of file